summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/freetype/freetype.pro1
-rw-r--r--src/3rdparty/harfbuzz-ng/NEWS311
-rw-r--r--src/3rdparty/harfbuzz-ng/README3
-rw-r--r--src/3rdparty/harfbuzz-ng/TODO16
-rw-r--r--src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro37
-rw-r--r--src/3rdparty/harfbuzz-ng/include/harfbuzz/hb-ot-math.h1
-rw-r--r--src/3rdparty/harfbuzz-ng/qt_attribution.json1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-atomic-private.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-blob.cc1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-blob.h24
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer-private.hh114
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer-serialize.cc88
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.cc489
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.h254
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cache-private.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-common.cc52
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-common.h59
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-coretext.cc267
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-coretext.h6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-deprecated.h10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-face.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-face.h34
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-fallback-shape.cc143
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-font-private.hh290
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-font.cc586
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-font.h246
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-open-file-private.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-open-type-private.hh45
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cbdt-table.hh384
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh125
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc466
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-font.h2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-glyf-table.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-head-table.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common-private.hh551
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh54
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh253
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh87
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh91
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-math-table.hh722
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-private.hh208
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc305
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h75
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-map-private.hh37
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc125
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-math.cc272
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-math.h209
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh105
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh119
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.hh56
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-win1256.hh323
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc249
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-default.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hangul.cc10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hebrew.cc16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh2026
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh45
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.cc718
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc151
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc17
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-private.hh37
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh588
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-private.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-table.cc224
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc99
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback-private.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc67
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc77
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-private.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc196
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc187
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-tag.h8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot.h1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-private.hh51
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set-private.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set.h52
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape-plan-private.hh9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc107
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape-plan.h37
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape.cc17
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape.h10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-unicode-private.hh61
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-unicode.cc6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-unicode.h71
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-utf-private.hh46
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-version.h12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb.h4
-rw-r--r--src/3rdparty/pcre/COPYING5
-rw-r--r--src/3rdparty/pcre/config.h41
-rw-r--r--src/3rdparty/pcre/patches/README3
-rw-r--r--src/3rdparty/pcre/pcre.h677
-rw-r--r--src/3rdparty/pcre/pcre.pro46
-rw-r--r--src/3rdparty/pcre/pcre16_byte_order.c45
-rw-r--r--src/3rdparty/pcre/pcre16_chartables.c45
-rw-r--r--src/3rdparty/pcre/pcre16_compile.c45
-rw-r--r--src/3rdparty/pcre/pcre16_config.c45
-rw-r--r--src/3rdparty/pcre/pcre16_dfa_exec.c45
-rw-r--r--src/3rdparty/pcre/pcre16_exec.c45
-rw-r--r--src/3rdparty/pcre/pcre16_fullinfo.c45
-rw-r--r--src/3rdparty/pcre/pcre16_get.c45
-rw-r--r--src/3rdparty/pcre/pcre16_globals.c45
-rw-r--r--src/3rdparty/pcre/pcre16_jit_compile.c45
-rw-r--r--src/3rdparty/pcre/pcre16_maketables.c45
-rw-r--r--src/3rdparty/pcre/pcre16_newline.c45
-rw-r--r--src/3rdparty/pcre/pcre16_ord2utf16.c90
-rw-r--r--src/3rdparty/pcre/pcre16_refcount.c45
-rw-r--r--src/3rdparty/pcre/pcre16_string_utils.c45
-rw-r--r--src/3rdparty/pcre/pcre16_study.c45
-rw-r--r--src/3rdparty/pcre/pcre16_tables.c45
-rw-r--r--src/3rdparty/pcre/pcre16_ucd.c45
-rw-r--r--src/3rdparty/pcre/pcre16_utf16_utils.c130
-rw-r--r--src/3rdparty/pcre/pcre16_valid_utf16.c137
-rw-r--r--src/3rdparty/pcre/pcre16_version.c45
-rw-r--r--src/3rdparty/pcre/pcre16_xclass.c45
-rw-r--r--src/3rdparty/pcre/pcre_byte_order.c319
-rw-r--r--src/3rdparty/pcre/pcre_config.c190
-rw-r--r--src/3rdparty/pcre/pcre_fullinfo.c245
-rw-r--r--src/3rdparty/pcre/pcre_get.c669
-rw-r--r--src/3rdparty/pcre/pcre_globals.c86
-rw-r--r--src/3rdparty/pcre/pcre_refcount.c92
-rw-r--r--src/3rdparty/pcre/pcre_string_utils.c211
-rw-r--r--src/3rdparty/pcre/pcre_version.c98
-rw-r--r--src/3rdparty/pcre2/AUTHORS (renamed from src/3rdparty/pcre/AUTHORS)17
-rw-r--r--src/3rdparty/pcre2/LICENCE (renamed from src/3rdparty/pcre/LICENCE)36
-rwxr-xr-xsrc/3rdparty/pcre2/import_from_pcre2_tarball.sh (renamed from src/3rdparty/pcre/import_from_pcre_tarball.sh)143
-rw-r--r--src/3rdparty/pcre2/pcre2.pro52
-rw-r--r--src/3rdparty/pcre2/qt_attribution.json (renamed from src/3rdparty/pcre/qt_attribution.json)9
-rw-r--r--src/3rdparty/pcre2/src/config.h52
-rw-r--r--src/3rdparty/pcre2/src/pcre2.h732
-rw-r--r--src/3rdparty/pcre2/src/pcre2_auto_possess.c1289
-rw-r--r--src/3rdparty/pcre2/src/pcre2_chartables.c (renamed from src/3rdparty/pcre/pcre_chartables.c)14
-rw-r--r--src/3rdparty/pcre2/src/pcre2_compile.c (renamed from src/3rdparty/pcre/pcre_compile.c)9000
-rw-r--r--src/3rdparty/pcre2/src/pcre2_config.c218
-rw-r--r--src/3rdparty/pcre2/src/pcre2_context.c391
-rw-r--r--src/3rdparty/pcre2/src/pcre2_dfa_match.c (renamed from src/3rdparty/pcre/pcre_dfa_exec.c)1452
-rw-r--r--src/3rdparty/pcre2/src/pcre2_error.c322
-rw-r--r--src/3rdparty/pcre2/src/pcre2_find_bracket.c218
-rw-r--r--src/3rdparty/pcre2/src/pcre2_internal.h (renamed from src/3rdparty/pcre/pcre_internal.h)2042
-rw-r--r--src/3rdparty/pcre2/src/pcre2_intmodedep.h852
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_compile.c (renamed from src/3rdparty/pcre/pcre_jit_compile.c)1803
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_match.c189
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_misc.c227
-rw-r--r--src/3rdparty/pcre2/src/pcre2_maketables.c (renamed from src/3rdparty/pcre/pcre_maketables.c)59
-rw-r--r--src/3rdparty/pcre2/src/pcre2_match.c (renamed from src/3rdparty/pcre/pcre_exec.c)3540
-rw-r--r--src/3rdparty/pcre2/src/pcre2_match_data.c147
-rw-r--r--src/3rdparty/pcre2/src/pcre2_newline.c (renamed from src/3rdparty/pcre/pcre_newline.c)151
-rw-r--r--src/3rdparty/pcre2/src/pcre2_ord2utf.c (renamed from src/3rdparty/pcre/pcre_ord2utf8.c)68
-rw-r--r--src/3rdparty/pcre2/src/pcre2_pattern_info.c410
-rw-r--r--src/3rdparty/pcre2/src/pcre2_printint.c832
-rw-r--r--src/3rdparty/pcre2/src/pcre2_serialize.c265
-rw-r--r--src/3rdparty/pcre2/src/pcre2_string_utils.c201
-rw-r--r--src/3rdparty/pcre2/src/pcre2_study.c (renamed from src/3rdparty/pcre/pcre_study.c)1043
-rw-r--r--src/3rdparty/pcre2/src/pcre2_substitute.c850
-rw-r--r--src/3rdparty/pcre2/src/pcre2_substring.c542
-rw-r--r--src/3rdparty/pcre2/src/pcre2_tables.c (renamed from src/3rdparty/pcre/pcre_tables.c)440
-rw-r--r--src/3rdparty/pcre2/src/pcre2_ucd.c (renamed from src/3rdparty/pcre/pcre_ucd.c)4481
-rw-r--r--src/3rdparty/pcre2/src/pcre2_ucp.h (renamed from src/3rdparty/pcre/ucp.h)56
-rw-r--r--src/3rdparty/pcre2/src/pcre2_valid_utf.c (renamed from src/3rdparty/pcre/pcre_valid_utf8.c)271
-rw-r--r--src/3rdparty/pcre2/src/pcre2_xclass.c (renamed from src/3rdparty/pcre/pcre_xclass.c)49
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitConfig.h (renamed from src/3rdparty/pcre/sljit/sljitConfig.h)2
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h (renamed from src/3rdparty/pcre/sljit/sljitConfigInternal.h)4
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitExecAllocator.c (renamed from src/3rdparty/pcre/sljit/sljitExecAllocator.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitLir.c (renamed from src/3rdparty/pcre/sljit/sljitLir.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitLir.h (renamed from src/3rdparty/pcre/sljit/sljitLir.h)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c (renamed from src/3rdparty/pcre/sljit/sljitNativeARM_32.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c (renamed from src/3rdparty/pcre/sljit/sljitNativeARM_64.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c (renamed from src/3rdparty/pcre/sljit/sljitNativeARM_T2_32.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c (renamed from src/3rdparty/pcre/sljit/sljitNativeMIPS_32.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c (renamed from src/3rdparty/pcre/sljit/sljitNativeMIPS_64.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c (renamed from src/3rdparty/pcre/sljit/sljitNativeMIPS_common.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativePPC_32.c (renamed from src/3rdparty/pcre/sljit/sljitNativePPC_32.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativePPC_64.c (renamed from src/3rdparty/pcre/sljit/sljitNativePPC_64.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c (renamed from src/3rdparty/pcre/sljit/sljitNativePPC_common.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_32.c (renamed from src/3rdparty/pcre/sljit/sljitNativeSPARC_32.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_common.c (renamed from src/3rdparty/pcre/sljit/sljitNativeSPARC_common.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeTILEGX-encoder.c (renamed from src/3rdparty/pcre/sljit/sljitNativeTILEGX-encoder.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeTILEGX_64.c (renamed from src/3rdparty/pcre/sljit/sljitNativeTILEGX_64.c)0
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c (renamed from src/3rdparty/pcre/sljit/sljitNativeX86_32.c)18
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c (renamed from src/3rdparty/pcre/sljit/sljitNativeX86_64.c)30
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c (renamed from src/3rdparty/pcre/sljit/sljitNativeX86_common.c)55
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitUtils.c (renamed from src/3rdparty/pcre/sljit/sljitUtils.c)0
-rw-r--r--src/3rdparty/sqlite.pri3
-rw-r--r--src/3rdparty/sqlite/qt_attribution.json2
-rw-r--r--src/3rdparty/sqlite/sqlite3.c31535
-rw-r--r--src/3rdparty/sqlite/sqlite3.h2334
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNative.java6
-rw-r--r--src/android/templates/res/values/libs.xml2
-rw-r--r--src/angle/src/QtANGLE/QtANGLE.pro (renamed from src/angle/src/libGLESv2/libGLESv2.pro)65
-rw-r--r--src/angle/src/common/common.pri18
-rw-r--r--src/angle/src/libEGL/libEGL.pro27
-rw-r--r--src/angle/src/src.pro2
-rw-r--r--src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentfilter.cpp14
-rw-r--r--src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentmap.cpp14
-rw-r--r--src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp5
-rw-r--r--src/concurrent/qtconcurrentfilter.cpp18
-rw-r--r--src/concurrent/qtconcurrentmap.cpp18
-rw-r--r--src/concurrent/qtconcurrentrun.cpp20
-rw-r--r--src/concurrent/qtconcurrentrun.h24
-rw-r--r--src/corelib/configure.json27
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h14
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm14
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp19
-rw-r--r--src/corelib/doc/src/objectmodel/signalsandslots.qdoc3
-rw-r--r--src/corelib/global/global.pri23
-rw-r--r--src/corelib/global/qcompilerdetection.h1
-rw-r--r--src/corelib/global/qflags.h11
-rw-r--r--src/corelib/global/qfloat16.cpp130
-rw-r--r--src/corelib/global/qfloat16.h258
-rw-r--r--src/corelib/global/qfloat16_p.h95
-rw-r--r--src/corelib/global/qglobal.cpp369
-rw-r--r--src/corelib/global/qglobal.h62
-rw-r--r--src/corelib/global/qglobal_p.h32
-rw-r--r--src/corelib/global/qhooks.cpp2
-rw-r--r--src/corelib/global/qlibraryinfo.cpp2
-rw-r--r--src/corelib/global/qlogging.cpp6
-rw-r--r--src/corelib/global/qnamespace.h9
-rw-r--r--src/corelib/global/qnamespace.qdoc23
-rw-r--r--src/corelib/global/qnumeric_p.h4
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp491
-rw-r--r--src/corelib/global/qoperatingsystemversion.h129
-rw-r--r--src/corelib/global/qoperatingsystemversion_darwin.mm56
-rw-r--r--src/corelib/global/qoperatingsystemversion_p.h87
-rw-r--r--src/corelib/global/qoperatingsystemversion_win.cpp171
-rw-r--r--src/corelib/global/qprocessordetection.h7
-rw-r--r--src/corelib/global/qsysinfo.h55
-rw-r--r--src/corelib/global/qsystemdetection.h1
-rw-r--r--src/corelib/global/qtypeinfo.h11
-rw-r--r--src/corelib/global/qtypetraits.h55
-rw-r--r--src/corelib/io/io.pri4
-rw-r--r--src/corelib/io/qdatastream.cpp53
-rw-r--r--src/corelib/io/qdatastream.h295
-rw-r--r--src/corelib/io/qdebug.h12
-rw-r--r--src/corelib/io/qdir.cpp67
-rw-r--r--src/corelib/io/qdir.h2
-rw-r--r--src/corelib/io/qfileinfo.cpp18
-rw-r--r--src/corelib/io/qfileselector.cpp13
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp30
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp53
-rw-r--r--src/corelib/io/qfilesystementry.cpp2
-rw-r--r--src/corelib/io/qfilesystemiterator_win.cpp7
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h2
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp53
-rw-r--r--src/corelib/io/qfilesystemwatcher_p.h10
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp286
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h15
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp4
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp27
-rw-r--r--src/corelib/io/qlockfile_unix.cpp1
-rw-r--r--src/corelib/io/qloggingregistry.cpp90
-rw-r--r--src/corelib/io/qloggingregistry_p.h7
-rw-r--r--src/corelib/io/qprocess.cpp6
-rw-r--r--src/corelib/io/qprocess.h15
-rw-r--r--src/corelib/io/qprocess_darwin.mm (renamed from src/gui/painting/qgammatables.cpp)32
-rw-r--r--src/corelib/io/qprocess_p.h6
-rw-r--r--src/corelib/io/qprocess_unix.cpp62
-rw-r--r--src/corelib/io/qprocess_win.cpp49
-rw-r--r--src/corelib/io/qsavefile.cpp20
-rw-r--r--src/corelib/io/qsavefile.h7
-rw-r--r--src/corelib/io/qsettings.cpp250
-rw-r--r--src/corelib/io/qsettings_mac.cpp20
-rw-r--r--src/corelib/io/qsettings_p.h18
-rw-r--r--src/corelib/io/qsettings_win.cpp31
-rw-r--r--src/corelib/io/qstorageinfo.cpp22
-rw-r--r--src/corelib/io/qstorageinfo.h3
-rw-r--r--src/corelib/io/qstorageinfo_p.h1
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp53
-rw-r--r--src/corelib/io/qtemporarydir.cpp27
-rw-r--r--src/corelib/io/qtemporarydir.h1
-rw-r--r--src/corelib/io/qtextstream.cpp15
-rw-r--r--src/corelib/io/qurl.cpp9
-rw-r--r--src/corelib/io/qurl.h4
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.cpp2
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel.cpp29
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel.h25
-rw-r--r--src/corelib/itemmodels/qstringlistmodel.h2
-rw-r--r--src/corelib/kernel/kernel.pri9
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.h2
-rw-r--r--src/corelib/kernel/qcore_foundation.mm72
-rw-r--r--src/corelib/kernel/qcore_mac_objc.mm54
-rw-r--r--src/corelib/kernel/qcore_mac_p.h6
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp95
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h5
-rw-r--r--src/corelib/kernel/qcoreapplication_win.cpp85
-rw-r--r--src/corelib/kernel/qcoreevent.cpp1
-rw-r--r--src/corelib/kernel/qcoreevent.h2
-rw-r--r--src/corelib/kernel/qdeadlinetimer.cpp108
-rw-r--r--src/corelib/kernel/qdeadlinetimer.h32
-rw-r--r--src/corelib/kernel/qeventdispatcher_cf.mm3
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp10
-rw-r--r--src/corelib/kernel/qeventdispatcher_win_p.h2
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp12
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h14
-rw-r--r--src/corelib/kernel/qmetaobject_p.h12
-rw-r--r--src/corelib/kernel/qmetatype.cpp110
-rw-r--r--src/corelib/kernel/qmetatype.h8
-rw-r--r--src/corelib/kernel/qmetatype_p.h2
-rw-r--r--src/corelib/kernel/qobject.cpp142
-rw-r--r--src/corelib/kernel/qobject.h29
-rw-r--r--src/corelib/kernel/qobjectdefs.h36
-rw-r--r--src/corelib/kernel/qobjectdefs_impl.h9
-rw-r--r--src/corelib/kernel/qppsobject.cpp3
-rw-r--r--src/corelib/kernel/qppsobject_p.h1
-rw-r--r--src/corelib/kernel/qsharedmemory_win.cpp32
-rw-r--r--src/corelib/kernel/qsystemsemaphore_systemv.cpp26
-rw-r--r--src/corelib/kernel/qtcore_eval.cpp2
-rw-r--r--src/corelib/kernel/qtimer.h16
-rw-r--r--src/corelib/kernel/qvariant.cpp2
-rw-r--r--src/corelib/kernel/qwineventnotifier.h2
-rw-r--r--src/corelib/mimetypes/qmimeglobpattern_p.h6
-rw-r--r--src/corelib/mimetypes/qmimetypeparser.cpp3
-rw-r--r--src/corelib/plugin/qelfparser_p.cpp48
-rw-r--r--src/corelib/plugin/qlibrary_unix.cpp10
-rw-r--r--src/corelib/plugin/quuid.cpp4
-rw-r--r--src/corelib/statemachine/qfinalstate_p.h34
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp2
-rw-r--r--src/corelib/thread/qgenericatomic.h24
-rw-r--r--src/corelib/thread/qmutex.cpp15
-rw-r--r--src/corelib/thread/qmutex.h12
-rw-r--r--src/corelib/thread/qthread.cpp8
-rw-r--r--src/corelib/thread/qthread_unix.cpp8
-rw-r--r--src/corelib/thread/qthreadpool.cpp55
-rw-r--r--src/corelib/thread/qthreadpool.h5
-rw-r--r--src/corelib/thread/qthreadpool_p.h3
-rw-r--r--src/corelib/tools/qarraydata.cpp51
-rw-r--r--src/corelib/tools/qarraydata.h11
-rw-r--r--src/corelib/tools/qarraydataops.h14
-rw-r--r--src/corelib/tools/qbytearray.cpp163
-rw-r--r--src/corelib/tools/qbytearray.h17
-rw-r--r--src/corelib/tools/qbytearraymatcher.cpp108
-rw-r--r--src/corelib/tools/qbytearraymatcher.h81
-rw-r--r--src/corelib/tools/qchar.cpp4
-rw-r--r--src/corelib/tools/qcollator.h2
-rw-r--r--src/corelib/tools/qcollator_icu.cpp5
-rw-r--r--src/corelib/tools/qcollator_macx.cpp7
-rw-r--r--src/corelib/tools/qcollator_p.h9
-rw-r--r--src/corelib/tools/qcollator_posix.cpp2
-rw-r--r--src/corelib/tools/qcollator_win.cpp5
-rw-r--r--src/corelib/tools/qdatetime.cpp77
-rw-r--r--src/corelib/tools/qdatetime_p.h7
-rw-r--r--src/corelib/tools/qeasingcurve.h2
-rw-r--r--src/corelib/tools/qhash.cpp25
-rw-r--r--src/corelib/tools/qhash.h1
-rw-r--r--src/corelib/tools/qlist.h1
-rw-r--r--src/corelib/tools/qlocale.cpp74
-rw-r--r--src/corelib/tools/qlocale.h4
-rw-r--r--src/corelib/tools/qlocale.qdoc11
-rw-r--r--src/corelib/tools/qlocale_mac.mm33
-rw-r--r--src/corelib/tools/qlocale_p.h7
-rw-r--r--src/corelib/tools/qlocale_win.cpp15
-rw-r--r--src/corelib/tools/qmap.h5
-rw-r--r--src/corelib/tools/qregularexpression.cpp565
-rw-r--r--src/corelib/tools/qringbuffer.cpp1
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h4
-rw-r--r--src/corelib/tools/qstring.cpp199
-rw-r--r--src/corelib/tools/qstring.h69
-rw-r--r--src/corelib/tools/qstring_compat.cpp2
-rw-r--r--src/corelib/tools/qstringbuilder.h22
-rw-r--r--src/corelib/tools/qtimezone.h12
-rw-r--r--src/corelib/tools/qtimezoneprivate.cpp249
-rw-r--r--src/corelib/tools/qtimezoneprivate_android.cpp54
-rw-r--r--src/corelib/tools/qtimezoneprivate_icu.cpp4
-rw-r--r--src/corelib/tools/qtimezoneprivate_mac.mm7
-rw-r--r--src/corelib/tools/qtimezoneprivate_p.h34
-rw-r--r--src/corelib/tools/qtimezoneprivate_tz.cpp139
-rw-r--r--src/corelib/tools/qtimezoneprivate_win.cpp4
-rw-r--r--src/corelib/tools/qvarlengtharray.h15
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc28
-rw-r--r--src/corelib/tools/qvector.h8
-rw-r--r--src/corelib/tools/qvsnprintf.cpp2
-rw-r--r--src/corelib/tools/tools.pri3
-rw-r--r--src/corelib/xml/qxmlutils_p.h2
-rw-r--r--src/dbus/Qt5DBusMacros.cmake3
-rw-r--r--src/dbus/qdbusconnection.h5
-rw-r--r--src/dbus/qdbusconnection_p.h3
-rw-r--r--src/dbus/qdbusconnectioninterface.h4
-rw-r--r--src/dbus/qdbusinternalfilters.cpp3
-rw-r--r--src/dbus/qdbusutil_p.h6
-rw-r--r--src/dbus/qdbusxmlgenerator.cpp11
-rw-r--r--src/gui/accessible/qaccessiblecache.cpp14
-rw-r--r--src/gui/configure.json44
-rw-r--r--src/gui/doc/qtgui.qdocconf3
-rw-r--r--src/gui/doc/src/external-resources.qdoc12
-rw-r--r--src/gui/doc/src/includes/qiconengine-virtualhookhelper.qdocinc3
-rw-r--r--src/gui/gui.pro10
-rw-r--r--src/gui/image/qicon.cpp106
-rw-r--r--src/gui/image/qicon_p.h2
-rw-r--r--src/gui/image/qiconengine.cpp102
-rw-r--r--src/gui/image/qiconengine.h12
-rw-r--r--src/gui/image/qiconloader.cpp48
-rw-r--r--src/gui/image/qiconloader_p.h5
-rw-r--r--src/gui/image/qimage.cpp165
-rw-r--r--src/gui/image/qimage.h1
-rw-r--r--src/gui/image/qimage_conversions.cpp56
-rw-r--r--src/gui/image/qimage_darwin.mm34
-rw-r--r--src/gui/image/qimagereader.cpp37
-rw-r--r--src/gui/image/qimagewriter.cpp14
-rw-r--r--src/gui/image/qpixmap_raster.cpp25
-rw-r--r--src/gui/image/qpixmap_raster_p.h2
-rw-r--r--src/gui/image/qpnghandler.cpp2
-rw-r--r--src/gui/image/qppmhandler.cpp59
-rw-r--r--src/gui/image/qxbmhandler.cpp2
-rw-r--r--src/gui/image/qxpmhandler.cpp3
-rw-r--r--src/gui/kernel/qevent.cpp98
-rw-r--r--src/gui/kernel/qevent.h9
-rw-r--r--src/gui/kernel/qevent_p.h9
-rw-r--r--src/gui/kernel/qguiapplication.cpp128
-rw-r--r--src/gui/kernel/qguiapplication_p.h8
-rw-r--r--src/gui/kernel/qkeysequence.cpp2
-rw-r--r--src/gui/kernel/qoffscreensurface.cpp37
-rw-r--r--src/gui/kernel/qoffscreensurface.h3
-rw-r--r--src/gui/kernel/qplatformdialoghelper.cpp21
-rw-r--r--src/gui/kernel/qplatformdialoghelper.h5
-rw-r--r--src/gui/kernel/qplatforminputcontextfactory.cpp2
-rw-r--r--src/gui/kernel/qplatformintegration.cpp11
-rw-r--r--src/gui/kernel/qplatformintegration.h4
-rw-r--r--src/gui/kernel/qplatformmenu.cpp5
-rw-r--r--src/gui/kernel/qplatformmenu.h2
-rw-r--r--src/gui/kernel/qplatformscreen.cpp88
-rw-r--r--src/gui/kernel/qplatformscreen.h15
-rw-r--r--src/gui/kernel/qplatformtheme.cpp26
-rw-r--r--src/gui/kernel/qplatformtheme.h4
-rw-r--r--src/gui/kernel/qplatformwindow.cpp38
-rw-r--r--src/gui/kernel/qplatformwindow.h4
-rw-r--r--src/gui/kernel/qrasterwindow.cpp8
-rw-r--r--src/gui/kernel/qrasterwindow.h1
-rw-r--r--src/gui/kernel/qscreen.cpp36
-rw-r--r--src/gui/kernel/qscreen.h7
-rw-r--r--src/gui/kernel/qstylehints.cpp55
-rw-r--r--src/gui/kernel/qstylehints.h4
-rw-r--r--src/gui/kernel/qsurface.cpp2
-rw-r--r--src/gui/kernel/qsurface.h3
-rw-r--r--src/gui/kernel/qtouchdevice.h1
-rw-r--r--src/gui/kernel/qtouchdevice_p.h7
-rw-r--r--src/gui/kernel/qwindow.cpp264
-rw-r--r--src/gui/kernel/qwindow.h15
-rw-r--r--src/gui/kernel/qwindow_p.h22
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp586
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h75
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h23
-rw-r--r--src/gui/opengl/opengl.pri6
-rw-r--r--src/gui/opengl/qopengl.cpp21
-rw-r--r--src/gui/opengl/qopengl.h21
-rw-r--r--src/gui/opengl/qopengldebug.h5
-rw-r--r--src/gui/opengl/qopenglengineshadermanager.cpp201
-rw-r--r--src/gui/opengl/qopenglengineshadermanager_p.h1
-rw-r--r--src/gui/opengl/qopenglengineshadersource_p.h517
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp43
-rw-r--r--src/gui/opengl/qopenglfunctions.h568
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp136
-rw-r--r--src/gui/opengl/qopenglpaintengine_p.h74
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache.cpp376
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache_p.h100
-rw-r--r--src/gui/opengl/qopenglshaderprogram.cpp545
-rw-r--r--src/gui/opengl/qopenglshaderprogram.h12
-rw-r--r--src/gui/opengl/qopengltexture.cpp92
-rw-r--r--src/gui/opengl/qopengltexture.h6
-rw-r--r--src/gui/opengl/qopengltexture_p.h5
-rw-r--r--src/gui/opengl/qopengltextureblitter.cpp4
-rw-r--r--src/gui/opengl/qopengltexturecache.cpp2
-rw-r--r--src/gui/opengl/qopengltexturecache_p.h28
-rw-r--r--src/gui/opengl/qopengltextureglyphcache.cpp24
-rw-r--r--src/gui/painting/painting.pri3
-rw-r--r--src/gui/painting/qbrush.cpp31
-rw-r--r--src/gui/painting/qcolorprofile.cpp87
-rw-r--r--src/gui/painting/qcolorprofile_p.h157
-rw-r--r--src/gui/painting/qcoregraphics.mm62
-rw-r--r--src/gui/painting/qcoregraphics_p.h34
-rw-r--r--src/gui/painting/qdrawhelper.cpp1741
-rw-r--r--src/gui/painting/qdrawhelper_avx2.cpp423
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp74
-rw-r--r--src/gui/painting/qdrawhelper_neon_p.h2
-rw-r--r--src/gui/painting/qdrawhelper_p.h18
-rw-r--r--src/gui/painting/qdrawhelper_sse4.cpp55
-rw-r--r--src/gui/painting/qmemrotate.cpp275
-rw-r--r--src/gui/painting/qmemrotate_p.h13
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp69
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h2
-rw-r--r--src/gui/painting/qpainter.h3
-rw-r--r--src/gui/painting/qpdf.cpp13
-rw-r--r--src/gui/painting/qregion.cpp2
-rw-r--r--src/gui/painting/qrgba64.h14
-rw-r--r--src/gui/painting/qrgba64_p.h101
-rw-r--r--src/gui/painting/qtransform.cpp8
-rw-r--r--src/gui/painting/qtriangulator.cpp40
-rw-r--r--src/gui/painting/qtriangulator_p.h17
-rw-r--r--src/gui/text/qcssparser.cpp6
-rw-r--r--src/gui/text/qfontengine.cpp7
-rw-r--r--src/gui/text/qfontengine_p.h1
-rw-r--r--src/gui/text/qharfbuzzng.cpp117
-rw-r--r--src/gui/text/qinputcontrol.cpp51
-rw-r--r--src/gui/text/qinputcontrol_p.h1
-rw-r--r--src/gui/text/qplatformfontdatabase.cpp21
-rw-r--r--src/gui/text/qplatformfontdatabase.h1
-rw-r--r--src/gui/text/qtextdocument.cpp21
-rw-r--r--src/gui/text/qtextdocument.h1
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp14
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp2
-rw-r--r--src/gui/text/qtextengine.cpp28
-rw-r--r--src/gui/text/qtexthtmlparser.cpp67
-rw-r--r--src/gui/text/qtextlayout.cpp10
-rw-r--r--src/gui/util/qdesktopservices.cpp9
-rw-r--r--src/network/access/access.pri8
-rw-r--r--src/network/access/qftp.cpp13
-rw-r--r--src/network/access/qhsts.cpp512
-rw-r--r--src/network/access/qhsts_p.h145
-rw-r--r--src/network/access/qhstspolicy.cpp216
-rw-r--r--src/network/access/qhstspolicy.h102
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp46
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp44
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp11
-rw-r--r--src/network/access/qhttpnetworkreply.cpp8
-rw-r--r--src/network/access/qhttpnetworkreply_p.h2
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp21
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h6
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp7
-rw-r--r--src/network/access/qhttpthreaddelegate_p.h3
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h1
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp177
-rw-r--r--src/network/access/qnetworkaccessmanager.h15
-rw-r--r--src/network/access/qnetworkaccessmanager_p.h12
-rw-r--r--src/network/access/qnetworkdiskcache.cpp2
-rw-r--r--src/network/access/qnetworkreply.cpp25
-rw-r--r--src/network/access/qnetworkreply.h1
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp99
-rw-r--r--src/network/access/qnetworkreplyhttpimpl_p.h7
-rw-r--r--src/network/access/qnetworkrequest.cpp48
-rw-r--r--src/network/access/qnetworkrequest.h12
-rw-r--r--src/network/bearer/qnetworkconfiguration.cpp38
-rw-r--r--src/network/bearer/qnetworkconfiguration.h3
-rw-r--r--src/network/bearer/qnetworkconfiguration_p.h6
-rw-r--r--src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp14
-rw-r--r--src/network/kernel/kernel.pri3
-rw-r--r--src/network/kernel/qdnslookup.cpp4
-rw-r--r--src/network/kernel/qhostaddress.cpp86
-rw-r--r--src/network/kernel/qhostaddress.h10
-rw-r--r--src/network/kernel/qhostinfo.cpp156
-rw-r--r--src/network/kernel/qhostinfo.h63
-rw-r--r--src/network/kernel/qhostinfo_p.h42
-rw-r--r--src/network/kernel/qnetworkdatagram.cpp2
-rw-r--r--src/network/kernel/qnetworkdatagram.h2
-rw-r--r--src/network/kernel/qnetworkdatagram_p.h32
-rw-r--r--src/network/kernel/qnetworkproxy.cpp19
-rw-r--r--src/network/kernel/qnetworkproxy.h4
-rw-r--r--src/network/socket/qabstractsocket.cpp36
-rw-r--r--src/network/socket/qlocalserver.h3
-rw-r--r--src/network/socket/qnativesocketengine.cpp32
-rw-r--r--src/network/socket/qnativesocketengine_p.h8
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp5
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp14
-rw-r--r--src/network/socket/qnativesocketengine_winrt.cpp2
-rw-r--r--src/network/socket/qsctpserver.h2
-rw-r--r--src/network/socket/qsctpsocket.h2
-rw-r--r--src/network/socket/qsocks5socketengine.cpp19
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters.cpp2
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters.h2
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_dummy.cpp2
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_openssl.cpp2
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters_p.h2
-rw-r--r--src/network/ssl/qsslerror.cpp4
-rw-r--r--src/network/ssl/qsslsocket.cpp8
-rw-r--r--src/network/ssl/qsslsocket_mac.cpp437
-rw-r--r--src/network/ssl/qsslsocket_winrt.cpp8
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp8
-rw-r--r--src/opengl/qgl.h9
-rw-r--r--src/platformheaders/windowsfunctions/qwindowswindowfunctions.h9
-rw-r--r--src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc32
-rw-r--r--src/platformheaders/xcbfunctions/qxcbscreenfunctions.h32
-rw-r--r--src/platformsupport/devicediscovery/qdevicediscovery_p.h2
-rw-r--r--src/platformsupport/devicediscovery/qdevicediscovery_static.cpp4
-rw-r--r--src/platformsupport/eglconvenience/qeglconvenience.cpp18
-rw-r--r--src/platformsupport/eglconvenience/qeglplatformcontext.cpp352
-rw-r--r--src/platformsupport/fbconvenience/qfbcursor.cpp18
-rw-r--r--src/platformsupport/fbconvenience/qfbcursor_p.h11
-rw-r--r--src/platformsupport/fbconvenience/qfbscreen.cpp159
-rw-r--r--src/platformsupport/fbconvenience/qfbscreen_p.h21
-rw-r--r--src/platformsupport/fbconvenience/qfbwindow.cpp53
-rw-r--r--src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp5
-rw-r--r--src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h4
-rw-r--r--src/platformsupport/fontdatabases/fontdatabases.pro4
-rw-r--r--src/platformsupport/fontdatabases/freetype/freetype.pri (renamed from src/platformsupport/fontdatabases/basic/basic.pri)4
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp (renamed from src/platformsupport/fontdatabases/basic/qfontengine_ft.cpp)127
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h (renamed from src/platformsupport/fontdatabases/basic/qfontengine_ft_p.h)9
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase.cpp (renamed from src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp)99
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase_p.h (renamed from src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h)8
-rw-r--r--src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h4
-rw-r--r--src/platformsupport/fontdatabases/mac/coretext.pri25
-rw-r--r--src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm315
-rw-r--r--src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h23
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm50
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h3
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp10
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp6
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h4
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h8
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp14
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h26
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp12
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h1
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp4
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h4
-rw-r--r--src/platformsupport/fontdatabases/windows/windows.pri1
-rw-r--r--src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase.cpp23
-rw-r--r--src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase_p.h4
-rw-r--r--src/platformsupport/input/evdevkeyboard/qevdevkeyboard_defaultmap_p.h4
-rw-r--r--src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp4
-rw-r--r--src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp4
-rw-r--r--src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp4
-rw-r--r--src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h175
-rw-r--r--src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp272
-rw-r--r--src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h30
-rw-r--r--src/platformsupport/kmsconvenience/kmsconvenience.pro20
-rw-r--r--src/platformsupport/kmsconvenience/qkmsdevice.cpp662
-rw-r--r--src/platformsupport/kmsconvenience/qkmsdevice_p.h170
-rw-r--r--src/platformsupport/linuxaccessibility/atspiadaptor.cpp2
-rw-r--r--src/platformsupport/platformcompositor/qopenglcompositor_p.h1
-rw-r--r--src/platformsupport/platformsupport.pro4
-rw-r--r--src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp2
-rw-r--r--src/platformsupport/themes/genericunix/genericunix.pri5
-rw-r--r--src/platformsupport/themes/genericunix/qgenericunixthemes.cpp2
-rw-r--r--src/plugins/bearer/corewlan/qcorewlanengine.mm40
-rw-r--r--src/plugins/generic/bsdkeyboard/main.cpp32
-rw-r--r--src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp32
-rw-r--r--src/plugins/generic/bsdkeyboard/qbsdkeyboard.h32
-rw-r--r--src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h36
-rw-r--r--src/plugins/generic/bsdmouse/main.cpp34
-rw-r--r--src/plugins/generic/bsdmouse/qbsdmouse.cpp34
-rw-r--r--src/plugins/generic/bsdmouse/qbsdmouse.h34
-rw-r--r--src/plugins/generic/generic.pro4
-rw-r--r--src/plugins/platforms/android/android.pro6
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp14
-rw-r--r--src/plugins/platforms/android/extract.cpp23
-rw-r--r--src/plugins/platforms/android/qandroidplatformfontdatabase.cpp4
-rw-r--r--src/plugins/platforms/android/qandroidplatformfontdatabase.h4
-rw-r--r--src/plugins/platforms/android/qandroidplatformforeignwindow.cpp5
-rw-r--r--src/plugins/platforms/android/qandroidplatformforeignwindow.h3
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp20
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.h1
-rw-r--r--src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp73
-rw-r--r--src/plugins/platforms/android/qandroidplatformoffscreensurface.h67
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglcontext.cpp13
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.h2
-rw-r--r--src/plugins/platforms/bsdfb/main.cpp34
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbintegration.cpp34
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbintegration.h34
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbscreen.cpp36
-rw-r--r--src/plugins/platforms/bsdfb/qbsdfbscreen.h34
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro2
-rw-r--r--src/plugins/platforms/cocoa/images/copyarrowcursor.pngbin1976 -> 0 bytes
-rw-r--r--src/plugins/platforms/cocoa/images/forbiddencursor.pngbin1745 -> 0 bytes
-rw-r--r--src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.pngbin356 -> 0 bytes
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.mm24
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm3
-rw-r--r--src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm14
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm9
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm55
-rw-r--r--src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm14
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm3
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm17
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h14
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm122
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm7
-rw-r--r--src/plugins/platforms/cocoa/qcocoaresources.qrc17
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h84
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm969
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.mm12
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h9
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm227
-rw-r--r--src/plugins/platforms/cocoa/qnsviewaccessibility.mm3
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.h8
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm73
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp21
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp18
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h2
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp5
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp21
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp19
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp166
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp9
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp27
-rw-r--r--src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h4
-rw-r--r--src/plugins/platforms/eglfs/api/api.pri13
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscontext_p.h10
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor.cpp4
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor_p.h16
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp11
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration.cpp62
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration_p.h45
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h4
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen.cpp11
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen_p.h22
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow.cpp42
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow_p.h50
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h14
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.json3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro27
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp136
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h74
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp178
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h85
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp56
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp36
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h15
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp25
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h12
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp19
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h12
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp27
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h14
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp31
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h19
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp17
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h8
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp462
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h61
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp121
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h48
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp59
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h62
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h10
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h12
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h14
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp2
-rw-r--r--src/plugins/platforms/eglfs/eglfsdeviceintegration.pro5
-rw-r--r--src/plugins/platforms/eglfs/qeglfsmain.cpp2
-rw-r--r--src/plugins/platforms/integrity/main.cpp34
-rw-r--r--src/plugins/platforms/integrity/qintegrityfbintegration.cpp34
-rw-r--r--src/plugins/platforms/integrity/qintegrityfbintegration.h34
-rw-r--r--src/plugins/platforms/integrity/qintegrityfbscreen.cpp36
-rw-r--r--src/plugins/platforms/integrity/qintegrityfbscreen.h34
-rw-r--r--src/plugins/platforms/integrity/qintegrityhidmanager.cpp34
-rw-r--r--src/plugins/platforms/integrity/qintegrityhidmanager.h34
-rw-r--r--src/plugins/platforms/ios/kernel.pro7
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro6
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm34
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h34
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm34
-rw-r--r--src/plugins/platforms/ios/qiosbackingstore.mm12
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm49
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm7
-rw-r--r--src/plugins/platforms/ios/qiosmessagedialog.mm3
-rw-r--r--src/plugins/platforms/ios/qiosoptionalplugininterface.h34
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm12
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.h34
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm43
-rw-r--r--src/plugins/platforms/ios/quiview.mm26
-rw-r--r--src/plugins/platforms/linuxfb/linuxfb.pro14
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp412
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h68
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp13
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbintegration.h4
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp2
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.h6
-rw-r--r--src/plugins/platforms/minimal/qminimalintegration.cpp40
-rw-r--r--src/plugins/platforms/minimal/qminimalintegration.h3
-rw-r--r--src/plugins/platforms/minimalegl/minimalegl.pro7
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglintegration.cpp12
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglintegration.h3
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglscreen.cpp14
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglscreen.h4
-rw-r--r--src/plugins/platforms/mirclient/mirclient.pro18
-rw-r--r--src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp102
-rw-r--r--src/plugins/platforms/mirclient/qmirclientappstatecontroller.h62
-rw-r--r--src/plugins/platforms/mirclient/qmirclientbackingstore.cpp12
-rw-r--r--src/plugins/platforms/mirclient/qmirclientbackingstore.h1
-rw-r--r--src/plugins/platforms/mirclient/qmirclientclipboard.cpp303
-rw-r--r--src/plugins/platforms/mirclient/qmirclientclipboard.h37
-rw-r--r--src/plugins/platforms/mirclient/qmirclientcursor.cpp43
-rw-r--r--src/plugins/platforms/mirclient/qmirclientcursor.h2
-rw-r--r--src/plugins/platforms/mirclient/qmirclientdebugextension.cpp79
-rw-r--r--src/plugins/platforms/mirclient/qmirclientdebugextension.h63
-rw-r--r--src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp50
-rw-r--r--src/plugins/platforms/mirclient/qmirclientdesktopwindow.h53
-rw-r--r--src/plugins/platforms/mirclient/qmirclientglcontext.cpp159
-rw-r--r--src/plugins/platforms/mirclient/qmirclientglcontext.h28
-rw-r--r--src/plugins/platforms/mirclient/qmirclientinput.cpp331
-rw-r--r--src/plugins/platforms/mirclient/qmirclientinput.h10
-rw-r--r--src/plugins/platforms/mirclient/qmirclientintegration.cpp255
-rw-r--r--src/plugins/platforms/mirclient/qmirclientintegration.h47
-rw-r--r--src/plugins/platforms/mirclient/qmirclientlogging.h24
-rw-r--r--src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp103
-rw-r--r--src/plugins/platforms/mirclient/qmirclientnativeinterface.h19
-rw-r--r--src/plugins/platforms/mirclient/qmirclientplugin.cpp10
-rw-r--r--src/plugins/platforms/mirclient/qmirclientplugin.h3
-rw-r--r--src/plugins/platforms/mirclient/qmirclientscreen.cpp278
-rw-r--r--src/plugins/platforms/mirclient/qmirclientscreen.h41
-rw-r--r--src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp161
-rw-r--r--src/plugins/platforms/mirclient/qmirclientscreenobserver.h78
-rw-r--r--src/plugins/platforms/mirclient/qmirclientwindow.cpp819
-rw-r--r--src/plugins/platforms/mirclient/qmirclientwindow.h50
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.cpp4
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenwindow.cpp7
-rw-r--r--src/plugins/platforms/platforms.pro2
-rw-r--r--src/plugins/platforms/qnx/qnx.pro14
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp8
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.h4
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp6
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.h8
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp2
-rw-r--r--src/plugins/platforms/vnc/main.cpp2
-rw-r--r--src/plugins/platforms/vnc/qvnc.cpp8
-rw-r--r--src/plugins/platforms/vnc/qvnc_p.h9
-rw-r--r--src/plugins/platforms/vnc/qvncclient.cpp4
-rw-r--r--src/plugins/platforms/vnc/qvncintegration.cpp29
-rw-r--r--src/plugins/platforms/vnc/qvncintegration.h18
-rw-r--r--src/plugins/platforms/vnc/qvncscreen.cpp24
-rw-r--r--src/plugins/platforms/vnc/qvncscreen.h14
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.h2
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp17
-rw-r--r--src/plugins/platforms/windows/openglblacklists/default.json14
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h13
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.h12
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.cpp7
-rw-r--r--src/plugins/platforms/windows/qwindowsclipboard.h20
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp158
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h39
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp527
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.h18
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp94
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.h18
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowseglcontext.h34
-rw-r--r--src/plugins/platforms/windows/qwindowsgdiintegration.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsgdinativeinterface.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp7
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.h31
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp7
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.h26
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp43
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h39
-rw-r--r--src/plugins/platforms/windows/qwindowsinternalmimedata.h6
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp7
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp54
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp11
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.cpp16
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.h20
-rw-r--r--src/plugins/platforms/windows/qwindowsole.cpp11
-rw-r--r--src/plugins/platforms/windows/qwindowsole.h12
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.h10
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp13
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h53
-rw-r--r--src/plugins/platforms/windows/qwindowsservices.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowssessionmanager.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowssessionmanager.h14
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.h21
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp133
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h14
-rw-r--r--src/plugins/platforms/windows/qwindowsthreadpoolrunner.h36
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp178
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h153
-rw-r--r--src/plugins/platforms/windows/windows.pri4
-rw-r--r--src/plugins/platforms/winrt/qwinrtclipboard.cpp14
-rw-r--r--src/plugins/platforms/winrt/qwinrtclipboard.h4
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.cpp29
-rw-r--r--src/plugins/platforms/winrt/qwinrtdrag.h27
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp143
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.h5
-rw-r--r--src/plugins/platforms/winrt/qwinrtfileengine.cpp8
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp17
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp43
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.h2
-rw-r--r--src/plugins/platforms/winrt/qwinrttheme.cpp101
-rw-r--r--src/plugins/platforms/winrt/qwinrtwindow.cpp2
-rw-r--r--src/plugins/platforms/winrt/winrt.pro3
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp16
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.cpp5
-rw-r--r--src/plugins/platforms/xcb/qxcbclipboard.h10
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp75
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h101
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp57
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp26
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h1
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h14
-rw-r--r--src/plugins/platforms/xcb/qxcbmime.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp3
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp11
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h30
-rw-r--r--src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp1
-rw-r--r--src/plugins/platforms/xcb/qxcbsystemtraytracker.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp45
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h44
-rw-r--r--src/plugins/platformthemes/gtk3/gtk3.pro1
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp64
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h2
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3menu.cpp36
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3menu.h34
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3theme.cpp23
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintdevice.cpp2
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql.cpp12
-rw-r--r--src/plugins/sqldrivers/tds/qsql_tds.cpp7
-rw-r--r--src/printsupport/configure.json27
-rw-r--r--src/printsupport/dialogs/qabstractprintdialog.h13
-rw-r--r--src/printsupport/dialogs/qabstractprintdialog_p.h2
-rw-r--r--src/printsupport/dialogs/qpagesetupdialog.h9
-rw-r--r--src/printsupport/dialogs/qpagesetupdialog_mac.mm4
-rw-r--r--src/printsupport/dialogs/qpagesetupdialog_p.h3
-rw-r--r--src/printsupport/dialogs/qprintdialog.h10
-rw-r--r--src/printsupport/dialogs/qprintdialog_mac.mm4
-rw-r--r--src/printsupport/dialogs/qprintpreviewdialog.cpp8
-rw-r--r--src/printsupport/dialogs/qprintpreviewdialog.h3
-rw-r--r--src/printsupport/kernel/qplatformprintplugin.cpp14
-rw-r--r--src/printsupport/kernel/qprintengine_win.cpp43
-rw-r--r--src/printsupport/kernel/qprinter.cpp138
-rw-r--r--src/printsupport/kernel/qprinter.h159
-rw-r--r--src/sql/configure.json5
-rw-r--r--src/sql/models/qsqlrelationaltablemodel.cpp6
-rw-r--r--src/sql/models/qsqltablemodel.cpp4
-rw-r--r--src/src.pro22
-rw-r--r--src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp11
-rw-r--r--src/testlib/qbenchmark_p.h4
-rw-r--r--src/testlib/qplaintestlogger.cpp2
-rw-r--r--src/testlib/qteamcitylogger.cpp23
-rw-r--r--src/testlib/qtest.h6
-rw-r--r--src/testlib/qtestaccessible.h6
-rw-r--r--src/testlib/qtestblacklist.cpp9
-rw-r--r--src/testlib/qtestcase.cpp87
-rw-r--r--src/testlib/qtestcase.h6
-rw-r--r--src/testlib/qtestsystem.h4
-rw-r--r--src/testlib/qtestutil_macos.mm34
-rw-r--r--src/testlib/qtestutil_macos_p.h34
-rw-r--r--src/tools/bootstrap/bootstrap.pro6
-rw-r--r--src/tools/moc/generator.cpp50
-rw-r--r--src/tools/moc/main.cpp2
-rw-r--r--src/tools/moc/moc.cpp29
-rw-r--r--src/tools/moc/mwerks_mac.cpp227
-rw-r--r--src/tools/moc/mwerks_mac.h54
-rw-r--r--src/tools/moc/preprocessor.cpp45
-rw-r--r--src/tools/moc/preprocessor.h1
-rw-r--r--src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp19
-rw-r--r--src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp4
-rw-r--r--src/tools/qfloat16-tables/gen_qfloat16_tables.cpp161
-rw-r--r--src/tools/qfloat16-tables/qfloat16-tables.pro9
-rw-r--r--src/tools/rcc/main.cpp15
-rw-r--r--src/tools/rcc/rcc.cpp5
-rw-r--r--src/tools/uic/cpp/cppwriteincludes.cpp24
-rw-r--r--src/tools/uic/cpp/cppwriteincludes.h4
-rw-r--r--src/tools/uic/cpp/cppwriteinitialization.cpp29
-rw-r--r--src/tools/uic/main.cpp6
-rw-r--r--src/tools/uic/uic.pro2
-rw-r--r--src/widgets/accessible/complexwidgets.cpp1
-rw-r--r--src/widgets/accessible/qaccessiblewidget.cpp6
-rw-r--r--src/widgets/accessible/qaccessiblewidgetfactory.cpp5
-rw-r--r--src/widgets/accessible/qaccessiblewidgets.cpp7
-rw-r--r--src/widgets/accessible/qaccessiblewidgets_p.h2
-rw-r--r--src/widgets/accessible/simplewidgets.cpp59
-rw-r--r--src/widgets/accessible/simplewidgets_p.h2
-rw-r--r--src/widgets/configure.json183
-rw-r--r--src/widgets/dialogs/dialogs.pri12
-rw-r--r--src/widgets/dialogs/qcolordialog.cpp11
-rw-r--r--src/widgets/dialogs/qcolordialog.h9
-rw-r--r--src/widgets/dialogs/qdialog.cpp9
-rw-r--r--src/widgets/dialogs/qdialog.h2
-rw-r--r--src/widgets/dialogs/qdialog_p.h14
-rw-r--r--src/widgets/dialogs/qerrormessage.cpp24
-rw-r--r--src/widgets/dialogs/qerrormessage.h9
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp39
-rw-r--r--src/widgets/dialogs/qfiledialog.h12
-rw-r--r--src/widgets/dialogs/qfiledialog_p.h16
-rw-r--r--src/widgets/dialogs/qfileinfogatherer.cpp48
-rw-r--r--src/widgets/dialogs/qfileinfogatherer_p.h4
-rw-r--r--src/widgets/dialogs/qfontdialog.cpp3
-rw-r--r--src/widgets/dialogs/qfontdialog.h11
-rw-r--r--src/widgets/dialogs/qinputdialog.h11
-rw-r--r--src/widgets/dialogs/qmessagebox.cpp6
-rw-r--r--src/widgets/dialogs/qmessagebox.h11
-rw-r--r--src/widgets/dialogs/qprogressdialog.h9
-rw-r--r--src/widgets/dialogs/qsidebar.cpp10
-rw-r--r--src/widgets/dialogs/qsidebar_p.h9
-rw-r--r--src/widgets/dialogs/qwizard.cpp6
-rw-r--r--src/widgets/dialogs/qwizard.h9
-rw-r--r--src/widgets/dialogs/qwizard_win.cpp12
-rw-r--r--src/widgets/effects/qgraphicseffect.h5
-rw-r--r--src/widgets/graphicsview/qgraph_p.h2
-rw-r--r--src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp14
-rw-r--r--src/widgets/graphicsview/qgraphicsanchorlayout_p.h2
-rw-r--r--src/widgets/graphicsview/qgraphicsitem.cpp3
-rw-r--r--src/widgets/graphicsview/qgraphicsview.cpp19
-rw-r--r--src/widgets/graphicsview/qgraphicsview.h2
-rw-r--r--src/widgets/itemviews/qabstractitemdelegate.cpp2
-rw-r--r--src/widgets/itemviews/qabstractitemview.cpp6
-rw-r--r--src/widgets/itemviews/qabstractitemview.h4
-rw-r--r--src/widgets/itemviews/qabstractitemview_p.h12
-rw-r--r--src/widgets/itemviews/qdatawidgetmapper.cpp58
-rw-r--r--src/widgets/itemviews/qheaderview.cpp19
-rw-r--r--src/widgets/itemviews/qheaderview_p.h6
-rw-r--r--src/widgets/itemviews/qitemdelegate.cpp1
-rw-r--r--src/widgets/itemviews/qitemeditorfactory.cpp13
-rw-r--r--src/widgets/itemviews/qlistview.cpp14
-rw-r--r--src/widgets/itemviews/qlistwidget.h3
-rw-r--r--src/widgets/itemviews/qstyleditemdelegate.cpp1
-rw-r--r--src/widgets/itemviews/qtableview.cpp10
-rw-r--r--src/widgets/itemviews/qtableview.h4
-rw-r--r--src/widgets/itemviews/qtableview_p.h2
-rw-r--r--src/widgets/itemviews/qtablewidget.h3
-rw-r--r--src/widgets/itemviews/qtreewidget.h3
-rw-r--r--src/widgets/kernel/kernel.pri7
-rw-r--r--src/widgets/kernel/qaction.cpp2
-rw-r--r--src/widgets/kernel/qapplication.cpp70
-rw-r--r--src/widgets/kernel/qapplication_p.h6
-rw-r--r--src/widgets/kernel/qdesktopwidget_p.h1
-rw-r--r--src/widgets/kernel/qformlayout.cpp6
-rw-r--r--src/widgets/kernel/qformlayout.h2
-rw-r--r--src/widgets/kernel/qgesture.cpp2
-rw-r--r--src/widgets/kernel/qgesture.h3
-rw-r--r--src/widgets/kernel/qlayout.cpp8
-rw-r--r--src/widgets/kernel/qopenglwidget.cpp14
-rw-r--r--src/widgets/kernel/qsizepolicy.cpp39
-rw-r--r--src/widgets/kernel/qsizepolicy.h128
-rw-r--r--src/widgets/kernel/qtooltip.cpp5
-rw-r--r--src/widgets/kernel/qwhatsthis.cpp6
-rw-r--r--src/widgets/kernel/qwidget.cpp133
-rw-r--r--src/widgets/kernel/qwidget.h11
-rw-r--r--src/widgets/kernel/qwidgetbackingstore.cpp22
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp25
-rw-r--r--src/widgets/kernel/qwidgetwindow_p.h1
-rw-r--r--src/widgets/kernel/qwindowcontainer.cpp8
-rw-r--r--src/widgets/styles/qcommonstyle.cpp44
-rw-r--r--src/widgets/styles/qdrawutil.cpp6
-rw-r--r--src/widgets/styles/qdrawutil.h4
-rw-r--r--src/widgets/styles/qfusionstyle.cpp42
-rw-r--r--src/widgets/styles/qmacstyle.qdoc39
-rw-r--r--src/widgets/styles/qmacstyle_mac.mm907
-rw-r--r--src/widgets/styles/qmacstyle_mac_p.h6
-rw-r--r--src/widgets/styles/qmacstyle_mac_p_p.h12
-rw-r--r--src/widgets/styles/qpixmapstyle.cpp25
-rw-r--r--src/widgets/styles/qstylehelper.cpp2
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp68
-rw-r--r--src/widgets/styles/qstylesheetstyle_p.h29
-rw-r--r--src/widgets/styles/qwindowsstyle.cpp2
-rw-r--r--src/widgets/styles/qwindowsvistastyle.cpp14
-rw-r--r--src/widgets/styles/qwindowsvistastyle_p_p.h5
-rw-r--r--src/widgets/styles/qwindowsxpstyle.cpp20
-rw-r--r--src/widgets/util/qcompleter.cpp11
-rw-r--r--src/widgets/util/qscroller.h2
-rw-r--r--src/widgets/util/qscrollerproperties.h2
-rw-r--r--src/widgets/util/qsystemtrayicon.cpp138
-rw-r--r--src/widgets/util/qsystemtrayicon.h1
-rw-r--r--src/widgets/util/qsystemtrayicon_p.h19
-rw-r--r--src/widgets/util/qsystemtrayicon_qpa.cpp19
-rw-r--r--src/widgets/util/qsystemtrayicon_win.cpp60
-rw-r--r--src/widgets/util/qsystemtrayicon_x11.cpp22
-rw-r--r--src/widgets/util/qundostack.cpp156
-rw-r--r--src/widgets/util/qundostack.h3
-rw-r--r--src/widgets/util/qundostack_p.h3
-rw-r--r--src/widgets/util/util.pri22
-rw-r--r--src/widgets/widgets/qabstractbutton.h2
-rw-r--r--src/widgets/widgets/qabstractscrollarea.cpp1
-rw-r--r--src/widgets/widgets/qabstractslider.cpp4
-rw-r--r--src/widgets/widgets/qabstractslider.h2
-rw-r--r--src/widgets/widgets/qabstractslider_p.h2
-rw-r--r--src/widgets/widgets/qabstractspinbox.cpp8
-rw-r--r--src/widgets/widgets/qbuttongroup_p.h34
-rw-r--r--src/widgets/widgets/qcalendarwidget.cpp6
-rw-r--r--src/widgets/widgets/qcheckbox.h2
-rw-r--r--src/widgets/widgets/qcombobox.cpp4
-rw-r--r--src/widgets/widgets/qcommandlinkbutton.h2
-rw-r--r--src/widgets/widgets/qdatetimeedit.cpp2
-rw-r--r--src/widgets/widgets/qdatetimeedit.h2
-rw-r--r--src/widgets/widgets/qdatetimeedit_p.h1
-rw-r--r--src/widgets/widgets/qdial.h9
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.cpp9
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.h4
-rw-r--r--src/widgets/widgets/qdockarealayout.cpp4
-rw-r--r--src/widgets/widgets/qdockwidget.cpp4
-rw-r--r--src/widgets/widgets/qdockwidget.h2
-rw-r--r--src/widgets/widgets/qfontcombobox.h2
-rw-r--r--src/widgets/widgets/qgroupbox.cpp4
-rw-r--r--src/widgets/widgets/qlabel.cpp6
-rw-r--r--src/widgets/widgets/qlabel.h2
-rw-r--r--src/widgets/widgets/qlineedit.cpp15
-rw-r--r--src/widgets/widgets/qlineedit.h3
-rw-r--r--src/widgets/widgets/qlineedit_p.cpp53
-rw-r--r--src/widgets/widgets/qlineedit_p.h11
-rw-r--r--src/widgets/widgets/qmaccocoaviewcontainer_mac.mm29
-rw-r--r--src/widgets/widgets/qmainwindow.h2
-rw-r--r--src/widgets/widgets/qmainwindowlayout.cpp3
-rw-r--r--src/widgets/widgets/qmdisubwindow.cpp4
-rw-r--r--src/widgets/widgets/qmenu.cpp4
-rw-r--r--src/widgets/widgets/qmenu.h8
-rw-r--r--src/widgets/widgets/qmenubar.cpp7
-rw-r--r--src/widgets/widgets/qplaintextedit_p.h3
-rw-r--r--src/widgets/widgets/qprogressbar.cpp4
-rw-r--r--src/widgets/widgets/qpushbutton.cpp30
-rw-r--r--src/widgets/widgets/qpushbutton.h2
-rw-r--r--src/widgets/widgets/qpushbutton_p.h6
-rw-r--r--src/widgets/widgets/qradiobutton.h2
-rw-r--r--src/widgets/widgets/qscrollbar.h10
-rw-r--r--src/widgets/widgets/qslider.h9
-rw-r--r--src/widgets/widgets/qsplitter.cpp92
-rw-r--r--src/widgets/widgets/qsplitter.h1
-rw-r--r--src/widgets/widgets/qsplitter_p.h1
-rw-r--r--src/widgets/widgets/qtabbar.cpp63
-rw-r--r--src/widgets/widgets/qtabbar_p.h4
-rw-r--r--src/widgets/widgets/qtabwidget.cpp3
-rw-r--r--src/widgets/widgets/qtextedit.h2
-rw-r--r--src/widgets/widgets/qtextedit_p.h11
-rw-r--r--src/widgets/widgets/qtoolbar.h8
-rw-r--r--src/widgets/widgets/qtoolbutton.h9
-rw-r--r--src/widgets/widgets/qwidgettextcontrol.cpp46
-rw-r--r--src/widgets/widgets/qwidgettextcontrol_p.h2
-rw-r--r--src/widgets/widgets/qwidgettextcontrol_p_p.h2
-rw-r--r--src/widgets/widgets/widgets.pri101
-rw-r--r--src/winmain/qtmain_winrt.cpp26
-rw-r--r--src/xml/dom/qdom.cpp2
-rw-r--r--src/xml/sax/qxml.cpp2
-rw-r--r--src/xml/sax/qxml.h2
-rw-r--r--src/xml/sax/qxml_p.h6
1138 files changed, 78276 insertions, 44111 deletions
diff --git a/src/3rdparty/freetype/freetype.pro b/src/3rdparty/freetype/freetype.pro
index 390a6da749..47ac9122ae 100644
--- a/src/3rdparty/freetype/freetype.pro
+++ b/src/3rdparty/freetype/freetype.pro
@@ -24,6 +24,7 @@ SOURCES += \
$$PWD/src/base/ftbbox.c \
$$PWD/src/base/ftdebug.c \
$$PWD/src/base/ftglyph.c \
+ $$PWD/src/base/ftfntfmt.c \
$$PWD/src/base/ftinit.c \
$$PWD/src/base/ftlcdfil.c \
$$PWD/src/base/ftmm.c \
diff --git a/src/3rdparty/harfbuzz-ng/NEWS b/src/3rdparty/harfbuzz-ng/NEWS
index f2b0a32401..8c3ef117dd 100644
--- a/src/3rdparty/harfbuzz-ng/NEWS
+++ b/src/3rdparty/harfbuzz-ng/NEWS
@@ -1,3 +1,314 @@
+Overview of changes leading to 1.4.1
+Thursday, January 5, 2017
+====================================
+
+- Always build and use UCDN for Unicode data by default.
+ Reduces dependence on version of Unicode data in glib,
+ specially in the Windows bundles we are shipping, which
+ have very old glib.
+
+
+Overview of changes leading to 1.4.0
+Thursday, January 5, 2017
+====================================
+
+- Merged "OpenType GX" branch which adds core of support for
+ OpenType 1.8 Font Variations. To that extent, the relevant
+ new API is:
+
+New API:
+hb_font_set_var_coords_normalized()
+
+ with supporting API:
+
+New API:
+HB_OT_LAYOUT_NO_VARIATIONS_INDEX
+hb_ot_layout_table_find_feature_variations()
+hb_ot_layout_feature_with_variations_get_lookups()
+hb_shape_plan_create2()
+hb_shape_plan_create_cached2()
+
+ Currently variations in GSUB/GPOS/GDEF are fully supported,
+ and no other tables are supported. In particular, fvar/avar
+ are NOT supported, hence the hb_font_set_var_coords_normalized()
+ taking normalized coordinates. API to take design coordinates
+ will be added in the future.
+
+ HVAR/VVAR/MVAR support will also be added to hb-ot-font in the
+ future.
+
+- Fix regression in GDEF glyph class processing.
+- Add decompositions for Chakma, Limbu, and Balinese in USE shaper.
+- Misc fixes.
+
+
+Overview of changes leading to 1.3.4
+Monday, December 5, 2016
+====================================
+
+- Fix vertical glyph origin in hb-ot-font.
+- Implement CBDT/CBLC color font glyph extents in hb-ot-font.
+
+
+Overview of changes leading to 1.3.3
+Wednesday, September 28, 2016
+====================================
+
+- Implement parsing of OpenType MATH table.
+New API:
+HB_OT_TAG_MATH
+HB_OT_MATH_SCRIPT
+hb_ot_math_constant_t
+hb_ot_math_kern_t
+hb_ot_math_glyph_variant_t
+hb_ot_math_glyph_part_flags_t
+hb_ot_math_glyph_part_t
+hb_ot_math_has_data
+hb_ot_math_get_constant
+hb_ot_math_get_glyph_italics_correction
+hb_ot_math_get_glyph_top_accent_attachment
+hb_ot_math_get_glyph_kerning
+hb_ot_math_is_glyph_extended_shape
+hb_ot_math_get_glyph_variants
+hb_ot_math_get_min_connector_overlap
+hb_ot_math_get_glyph_assembly
+
+
+Overview of changes leading to 1.3.2
+Wednesday, September 27, 2016
+====================================
+
+- Fix build of hb-coretext on older OS X versions.
+
+
+Overview of changes leading to 1.3.1
+Wednesday, September 7, 2016
+====================================
+
+- Blacklist bad GDEF of more fonts (Padauk).
+- More CoreText backend crash fixes with OS X 10.9.5.
+- Misc fixes.
+
+
+Overview of changes leading to 1.3.0
+Thursday, July 21, 2016
+====================================
+
+- Update to Unicode 9.0.0
+- Move Javanese from Indic shaper to Universal Shaping Engine.
+- Allow MultipleSubst to delete a glyph (matching Windows engine).
+- Update Universal Shaping Engine to latest draft from Microsoft.
+- DirectWrite backend improvements. Note: this backend is for testing ONLY.
+- CoreText backend improvements with unreachable fonts.
+- Implement symbol fonts (cmap 3.0.0) in hb-ft and hb-ot-font.
+- Blacklist bad GDEF of more fonts (Tahoma & others).
+- Misc fixes.
+
+
+Overview of changes leading to 1.2.7
+Monday, May 2, 2016
+====================================
+
+- Blacklist another version of Times New Roman (Bold) Italic from Windows 7.
+- Fix Mongolian Free Variation Selectors shaping with certain fonts.
+- Fix Tibetan shorthand contractions shaping.
+- Improved list of language tag mappings.
+- Unbreak build on Windows CE.
+- Make 'glyf' table loading lazy in hb-ot-font.
+
+
+Overview of changes leading to 1.2.6
+Friday, April 8, 2016
+====================================
+
+- Blacklist GDEF table of another set of Times New Roman (Bold) Italic.
+- DirectWrite backend improvements. Note: DirectWrite backend is
+ exclusively for our internal testing and should NOT be used in any
+ production system whatsoever.
+
+
+Overview of changes leading to 1.2.5
+Monday, April 4, 2016
+====================================
+
+- Fix GDEF mark-filtering-set, which was broken in 1.2.3.
+
+
+Overview of changes leading to 1.2.4
+Thursday, March 17, 2016
+====================================
+
+- Synthesize GDEF glyph class for any glyph that does not have one in GDEF.
+ I really hope we don't discover broken fonts that shape badly with this
+ change.
+- Misc build and other minor fixes.
+- API changes:
+ - Added HB_NDEBUG. It's fine for production systems to define this to
+ disable high-overhead debugging checks. However, I also reduced the
+ overhead of those checks, so it's a non-issue right now. You can
+ forget it. Just not defining anything at all is fine.
+
+
+Overview of changes leading to 1.2.3
+Thursday, February 25, 2016
+====================================
+
+- Blacklist GDEF table of certain versions of Times New Roman (Bold) Italic,
+ due to bug in glyph class of ASCII double-quote character. This should
+ address "regression" introduced in 1.2.0 when we switched mark zeroing
+ in most shapers from BY_UNICODE_LATE to BY_GDEF_LATE.
+ This fourth release in a week should finally stablize things...
+
+- hb-ot-font's get_glyph() implementation saw some optimizations. Though,
+ might be really hard to measure in real-world situations.
+
+- Also, two rather small API changes:
+
+We now disable some time-consuming internal bookkeeping if built with NDEBUG
+defined. This is a first time that we use NDEBUG to disable debug code. If
+there exist production systems that do NOT want to enable NDEBUG, please let
+me know and I'll add HB_NDEBUG.
+
+Added get_nominal_glyph() and get_variation_glyph() instead of get_glyph()
+
+New API:
+- hb_font_get_nominal_glyph_func_t
+- hb_font_get_variation_glyph_func_t
+- hb_font_funcs_set_nominal_glyph_func()
+- hb_font_funcs_set_variation_glyph_func()
+- hb_font_get_nominal_glyph()
+- hb_font_get_variation_glyph()
+
+Deprecated API:
+- hb_font_get_glyph_func_t
+- hb_font_funcs_set_glyph_func()
+
+Clients that implement their own font-funcs are encouraged to replace
+their get_glyph() implementation with a get_nominal_glyph() and
+get_variation_glyph() pair. The variation version can assume that
+variation_selector argument is not zero. Old (deprecated) functions
+will continue working indefinitely using internal gymnastics; it is
+just more efficient to use the new functions.
+
+
+Overview of changes leading to 1.2.2
+Wednesday, February 24, 2016
+====================================
+
+- Fix regression with mark positioning with fonts that have
+ non-zero mark advances. This was introduced in 1.2.0 while
+ trying to make mark and cursive attachments to work together.
+ I have partially reverted that, so this version is much more
+ like what we had before. All clients who updated to 1.2.0
+ should update to this version.
+
+
+Overview of changes leading to 1.2.1
+Tuesday, February 23, 2016
+====================================
+
+- CoreText: Fix bug with wrong scale if font scale was changed later.
+ https://github.com/libass/libass/issues/212
+- CoreText: Drastically speed up font initialization.
+- CoreText: Fix tiny leak.
+- Group ZWJ/ZWNJ with previous syllable under cluster-level=0.
+ https://github.com/behdad/harfbuzz/issues/217
+- Add test/shaping/README.md about how to add tests to the suite.
+
+
+Overview of changes leading to 1.2.0
+Friday, February 19, 2016
+====================================
+
+- Fix various issues (hangs mostly) in case of memory allocation failure.
+- Change mark zeroing types of most shapers from BY_UNICODE_LATE to
+ BY_GDEF_LATE. This seems to be what Uniscribe does.
+- Change mark zeroing of USE shaper from NONE to BY_GDEF_EARLY. That's
+ what Windows does.
+- Allow GPOS cursive connection on marks, and fix the interaction with
+ mark attachment. This work resulted in some changes to how mark
+ attachments work. See:
+ https://github.com/behdad/harfbuzz/issues/211
+ https://github.com/behdad/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
+- Graphite2 shaper: improved negative advance handling (eg. Nastaliq).
+- Add nmake-based build system for Windows.
+- Minor speedup.
+- Misc. improvements.
+
+
+Overview of changes leading to 1.1.3
+Monday, January 11, 2016
+====================================
+
+- Ported Indic shaper to Unicode 8.0 data.
+- Universal Shaping Engine fixes.
+- Speed up CoreText shaper when font fallback happens in CoreText.
+- Documentation improvements, thanks to Khaled Hosny.
+- Very rough directwrite shaper for testing, thanks to Ebrahim Byagowi.
+- Misc bug fixes.
+- New API:
+
+ * Font extents:
+ hb_font_extents_t
+ hb_font_get_font_extents_func_t
+ hb_font_get_font_h_extents_func_t
+ hb_font_get_font_v_extents_func_t
+ hb_font_funcs_set_font_h_extents_func
+ hb_font_funcs_set_font_v_extents_func
+ hb_font_get_h_extents
+ hb_font_get_v_extents
+ hb_font_get_extents_for_direction
+
+ * Buffer message (aka debug):
+ hb_buffer_message_func_t
+ hb_buffer_set_message_func()
+ Actual message protocol to be fleshed out later.
+
+
+Overview of changes leading to 1.1.2
+Wednesday, November 26, 2015
+====================================
+
+- Fix badly-broken fallback shaper that affected terminology.
+ https://github.com/behdad/harfbuzz/issues/187
+- Fix y_scaling in Graphite shaper.
+- API changes:
+ * An unset glyph_h_origin() function in font-funcs now (sensibly)
+ implies horizontal origin at 0,0. Ie, the nil callback returns
+ true instead of false. As such, implementations that have a
+ glyph_h_origin() that simply returns true, can remove that function
+ with HarfBuzz >= 1.1.2. This results in a tiny speedup.
+
+
+Overview of changes leading to 1.1.1
+Wednesday, November 24, 2015
+====================================
+
+- Build fixes, specially for hb-coretext.
+
+
+Overview of changes leading to 1.1.0
+Wednesday, November 18, 2015
+====================================
+
+- Implement 'stch' stretch feature for Syriac Abbreviation Mark.
+ https://github.com/behdad/harfbuzz/issues/141
+- Disable use of decompose_compatibility() callback.
+- Implement "shaping" of various Unicode space characters, even
+ if the font does not support them.
+ https://github.com/behdad/harfbuzz/issues/153
+- If font does not support U+2011 NO-BREAK HYPHEN, fallback to
+ U+2010 HYPHEN.
+- Changes resulting from libFuzzer continuous fuzzing:
+ * Reject font tables that need more than 8 edits,
+ * Bound buffer growth during shaping to 32x,
+ * Fix assertions and other issues at OOM / buffer max-growth.
+- Misc fixes and optimizations.
+- API changes:
+ * All fonts created with hb_font_create() now inherit from
+ (ie. have parent) hb_font_get_empty().
+
+
Overview of changes leading to 1.0.6
Thursday, October 15, 2015
====================================
diff --git a/src/3rdparty/harfbuzz-ng/README b/src/3rdparty/harfbuzz-ng/README
index dea10688f3..69a1bdd9ff 100644
--- a/src/3rdparty/harfbuzz-ng/README
+++ b/src/3rdparty/harfbuzz-ng/README
@@ -1,6 +1,7 @@
[![Build Status](https://travis-ci.org/behdad/harfbuzz.svg)](https://travis-ci.org/behdad/harfbuzz)
+[![Build Status](https://ci.appveyor.com/api/projects/status/4oaq58ns2h0m2soa?svg=true)](https://ci.appveyor.com/project/behdad/harfbuzz)
[![Coverage Status](https://img.shields.io/coveralls/behdad/harfbuzz.svg)](https://coveralls.io/r/behdad/harfbuzz)
-[![Coverity Scan](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/5450)
+[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
This is HarfBuzz, a text shaping library.
diff --git a/src/3rdparty/harfbuzz-ng/TODO b/src/3rdparty/harfbuzz-ng/TODO
index e1aa39c4c0..4f37f605b1 100644
--- a/src/3rdparty/harfbuzz-ng/TODO
+++ b/src/3rdparty/harfbuzz-ng/TODO
@@ -9,26 +9,14 @@ General fixes:
- mask propagation? (when ligation, "or" the masks).
-- Warn at compile time (and runtime with HB_DEBUG?) if no Unicode / font
- funcs found / set.
-- Do proper rounding when scaling from font space? May be a non-issue.
-
-- Misc features:
- * init/medi/fina/isol for non-cursive scripts
-
-
-API issues to fix before 1.0:
-============================
+API issues:
+===========
- API to accept a list of languages?
- Add init_func to font_funcs. Adjust ft.
-- hb-ft load_flags issues.
-
-- Add pkg-config files for glue codes (harfbuzz-glib, etc)
-
- 'const' for getter APIs? (use mutable internally)
- Remove hb_ot_shape_glyphs_closure()?
diff --git a/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro b/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro
index 4ba2ee3ec4..3b7b11c8ee 100644
--- a/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro
+++ b/src/3rdparty/harfbuzz-ng/harfbuzz-ng.pro
@@ -13,10 +13,15 @@ load(qt_helper_lib)
SHAPERS += opentype # HB's main shaper; enabling it should be enough most of the time
# native shaper on Apple platforms; could be used alone to handle both OT and AAT fonts
-darwin:!if(watchos:CONFIG(simulator, simulator|device)): SHAPERS += coretext
+darwin: SHAPERS += coretext
+
+# fallback shaper: not really useful with opentype or coretext shaper
+#SHAPERS += fallback
DEFINES += HAVE_CONFIG_H
DEFINES += HB_NO_UNICODE_FUNCS HB_DISABLE_DEPRECATED
+DEFINES += HB_NDEBUG
+DEFINES += HB_EXTERN=
# platform/compiler specific definitions
DEFINES += HAVE_ATEXIT
@@ -57,6 +62,7 @@ HEADERS += \
$$PWD/src/hb-object-private.hh \
$$PWD/src/hb-open-file-private.hh \
$$PWD/src/hb-open-type-private.hh \
+ $$PWD/src/hb-ot-cbdt-table.hh \
$$PWD/src/hb-ot-cmap-table.hh \
$$PWD/src/hb-ot-glyf-table.hh \
$$PWD/src/hb-ot-head-table.hh \
@@ -64,6 +70,8 @@ HEADERS += \
$$PWD/src/hb-ot-hmtx-table.hh \
$$PWD/src/hb-ot-maxp-table.hh \
$$PWD/src/hb-ot-name-table.hh \
+ $$PWD/src/hb-ot-os2-table.hh \
+ $$PWD/src/hb-ot-post-table.hh \
$$PWD/src/hb-private.hh \
$$PWD/src/hb-set-private.hh \
$$PWD/src/hb-shape-plan-private.hh \
@@ -94,6 +102,7 @@ contains(SHAPERS, opentype) {
$$PWD/src/hb-ot-font.cc \
$$PWD/src/hb-ot-layout.cc \
$$PWD/src/hb-ot-map.cc \
+ $$PWD/src/hb-ot-math.cc \
$$PWD/src/hb-ot-shape.cc \
$$PWD/src/hb-ot-shape-complex-arabic.cc \
$$PWD/src/hb-ot-shape-complex-default.cc \
@@ -116,11 +125,13 @@ contains(SHAPERS, opentype) {
$$PWD/src/hb-ot-layout-gsubgpos-private.hh \
$$PWD/src/hb-ot-layout-gsub-table.hh \
$$PWD/src/hb-ot-layout-jstf-table.hh \
+ $$PWD/src/hb-ot-layout-math-table.hh \
$$PWD/src/hb-ot-layout-private.hh \
$$PWD/src/hb-ot-map-private.hh \
$$PWD/src/hb-ot-shape-complex-arabic-fallback.hh \
$$PWD/src/hb-ot-shape-complex-arabic-private.hh \
$$PWD/src/hb-ot-shape-complex-arabic-table.hh \
+# $$PWD/src/hb-ot-shape-complex-arabic-win1256.hh \ # disabled with HB_NO_WIN1256
$$PWD/src/hb-ot-shape-complex-indic-machine.hh \
$$PWD/src/hb-ot-shape-complex-indic-private.hh \
$$PWD/src/hb-ot-shape-complex-myanmar-machine.hh \
@@ -135,6 +146,7 @@ contains(SHAPERS, opentype) {
$$PWD/src/hb-ot.h \
$$PWD/src/hb-ot-font.h \
$$PWD/src/hb-ot-layout.h \
+ $$PWD/src/hb-ot-math.h \
$$PWD/src/hb-ot-shape.h \
$$PWD/src/hb-ot-tag.h
}
@@ -155,4 +167,27 @@ contains(SHAPERS, coretext) {
# On Mac OS they are part of the ApplicationServices umbrella framework,
# even in 10.8 where they were also made available stand-alone.
LIBS_PRIVATE += -framework ApplicationServices
+
+ # CoreText is documented to be available on watchOS, but the headers aren't present
+ # in the watchOS Simulator SDK like they are supposed to be. Work around the problem
+ # by adding the device SDK's headers to the search path as a fallback.
+ # rdar://25314492, rdar://27844864
+ watchos:simulator {
+ simulator_system_frameworks = $$xcodeSDKInfo(Path, $${simulator.sdk})/System/Library/Frameworks
+ device_system_frameworks = $$xcodeSDKInfo(Path, $${device.sdk})/System/Library/Frameworks
+ for (arch, QMAKE_APPLE_SIMULATOR_ARCHS) {
+ QMAKE_CXXFLAGS += \
+ -Xarch_$${arch} \
+ -F$$simulator_system_frameworks \
+ -Xarch_$${arch} \
+ -F$$device_system_frameworks
+ }
+ }
+}
+
+contains(SHAPERS, fallback)|isEmpty(SHAPERS) {
+ DEFINES += HAVE_FALLBACK
+
+ SOURCES += \
+ $$PWD/src/hb-fallback-shape.cc
}
diff --git a/src/3rdparty/harfbuzz-ng/include/harfbuzz/hb-ot-math.h b/src/3rdparty/harfbuzz-ng/include/harfbuzz/hb-ot-math.h
new file mode 100644
index 0000000000..d1b9e5ff80
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/include/harfbuzz/hb-ot-math.h
@@ -0,0 +1 @@
+#include "../../src/hb-ot-math.h"
diff --git a/src/3rdparty/harfbuzz-ng/qt_attribution.json b/src/3rdparty/harfbuzz-ng/qt_attribution.json
index 4d3eb79150..a5eee600d6 100644
--- a/src/3rdparty/harfbuzz-ng/qt_attribution.json
+++ b/src/3rdparty/harfbuzz-ng/qt_attribution.json
@@ -6,6 +6,7 @@
"Description": "HarfBuzz is an OpenType text shaping engine.",
"Homepage": "http://harfbuzz.org",
+ "Version": "1.4.1",
"License": "MIT License",
"LicenseId": "MIT",
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-atomic-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-atomic-private.hh
index 8179571ad2..100ba539e3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-atomic-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-atomic-private.hh
@@ -119,6 +119,31 @@ typedef unsigned int hb_atomic_int_impl_t;
#define hb_atomic_ptr_impl_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
+#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__)
+
+#include <builtins.h>
+
+
+static inline int hb_fetch_and_add(volatile int* AI, unsigned int V) {
+ __lwsync();
+ int result = __fetch_and_add(AI, V);
+ __isync();
+ return result;
+}
+static inline int hb_compare_and_swaplp(volatile long* P, long O, long N) {
+ __sync();
+ int result = __compare_and_swaplp (P, &O, N);
+ __sync();
+ return result;
+}
+
+typedef int hb_atomic_int_impl_t;
+#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
+#define hb_atomic_int_impl_add(AI, V) hb_fetch_and_add (&(AI), (V))
+
+#define hb_atomic_ptr_impl_get(P) (__sync(), (void *) *(P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N) hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
+
#elif !defined(HB_NO_MT)
#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
index a6870dc06e..fb48f03cab 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
@@ -104,7 +104,6 @@ hb_blob_create (const char *data,
if (!length ||
length >= 1u << 31 ||
- data + length < data /* overflows */ ||
!(blob = hb_object_create<hb_blob_t> ())) {
if (destroy)
destroy (user_data);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-blob.h b/src/3rdparty/harfbuzz-ng/src/hb-blob.h
index b2419abfd2..ef3fc98c05 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-blob.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-blob.h
@@ -64,7 +64,7 @@ typedef enum {
typedef struct hb_blob_t hb_blob_t;
-hb_blob_t *
+HB_EXTERN hb_blob_t *
hb_blob_create (const char *data,
unsigned int length,
hb_memory_mode_t mode,
@@ -77,21 +77,21 @@ hb_blob_create (const char *data,
* modify the parent data as that data may be
* shared among multiple sub-blobs.
*/
-hb_blob_t *
+HB_EXTERN hb_blob_t *
hb_blob_create_sub_blob (hb_blob_t *parent,
unsigned int offset,
unsigned int length);
-hb_blob_t *
+HB_EXTERN hb_blob_t *
hb_blob_get_empty (void);
-hb_blob_t *
+HB_EXTERN hb_blob_t *
hb_blob_reference (hb_blob_t *blob);
-void
+HB_EXTERN void
hb_blob_destroy (hb_blob_t *blob);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_blob_set_user_data (hb_blob_t *blob,
hb_user_data_key_t *key,
void * data,
@@ -99,25 +99,25 @@ hb_blob_set_user_data (hb_blob_t *blob,
hb_bool_t replace);
-void *
+HB_EXTERN void *
hb_blob_get_user_data (hb_blob_t *blob,
hb_user_data_key_t *key);
-void
+HB_EXTERN void
hb_blob_make_immutable (hb_blob_t *blob);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_blob_is_immutable (hb_blob_t *blob);
-unsigned int
+HB_EXTERN unsigned int
hb_blob_get_length (hb_blob_t *blob);
-const char *
+HB_EXTERN const char *
hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
-char *
+HB_EXTERN char *
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer-private.hh
index 7fed7386b0..bca308da2f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-private.hh
@@ -35,9 +35,36 @@
#include "hb-unicode-private.hh"
+#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
+#define HB_BUFFER_MAX_EXPANSION_FACTOR 32
+#endif
+#ifndef HB_BUFFER_MAX_LEN_MIN
+#define HB_BUFFER_MAX_LEN_MIN 8192
+#endif
+#ifndef HB_BUFFER_MAX_LEN_DEFAULT
+#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
+#endif
+
ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
+HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
+HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
+
+enum hb_buffer_scratch_flags_t {
+ HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u,
+ HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u,
+ HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
+ HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
+ HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
+ /* Reserved for complex shapers' internal use. */
+ HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
+ HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u,
+ HB_BUFFER_SCRATCH_FLAG_COMPLEX2 = 0x04000000u,
+ HB_BUFFER_SCRATCH_FLAG_COMPLEX3 = 0x08000000u,
+};
+HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
+
/*
* hb_buffer_t
@@ -52,6 +79,8 @@ struct hb_buffer_t {
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
+ hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
+ unsigned int max_len; /* Maximum allowed len. */
/* Buffer contents */
hb_buffer_content_type_t content_type;
@@ -76,17 +105,13 @@ struct hb_buffer_t {
inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
- inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; }
- inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
+ inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
+ inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
inline bool has_separate_output (void) const { return info != out_info; }
unsigned int serial;
- /* These reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
- uint8_t allocated_var_bytes[8];
- const char *allocated_var_owner[8];
-
/* Text before / after the main buffer contents.
* Always in Unicode, and ordered outward.
* Index 0 is for "pre-context", 1 for "post-context". */
@@ -94,6 +119,52 @@ struct hb_buffer_t {
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
+ /* Debugging API */
+ hb_buffer_message_func_t message_func;
+ void *message_data;
+ hb_destroy_func_t message_destroy;
+
+ /* Internal debugging. */
+ /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
+#ifndef HB_NDEBUG
+ uint8_t allocated_var_bits;
+#endif
+ inline void allocate_var (unsigned int start, unsigned int count)
+ {
+#ifndef HB_NDEBUG
+ unsigned int end = start + count;
+ assert (end <= 8);
+ unsigned int bits = (1u<<end) - (1u<<start);
+ assert (0 == (allocated_var_bits & bits));
+ allocated_var_bits |= bits;
+#endif
+ }
+ inline void deallocate_var (unsigned int start, unsigned int count)
+ {
+#ifndef HB_NDEBUG
+ unsigned int end = start + count;
+ assert (end <= 8);
+ unsigned int bits = (1u<<end) - (1u<<start);
+ assert (bits == (allocated_var_bits & bits));
+ allocated_var_bits &= ~bits;
+#endif
+ }
+ inline void assert_var (unsigned int start, unsigned int count)
+ {
+#ifndef HB_NDEBUG
+ unsigned int end = start + count;
+ assert (end <= 8);
+ unsigned int bits = (1u<<end) - (1u<<start);
+ assert (bits == (allocated_var_bits & bits));
+#endif
+ }
+ inline void deallocate_var_all (void)
+ {
+#ifndef HB_NDEBUG
+ allocated_var_bits = 0;
+#endif
+ }
+
/* Methods */
@@ -106,11 +177,6 @@ struct hb_buffer_t {
{ return len - idx; }
inline unsigned int next_serial (void) { return serial++; }
- HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner);
- HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner);
- HB_INTERNAL void assert_var (unsigned int byte_i, unsigned int count, const char *owner);
- HB_INTERNAL void deallocate_var_all (void);
-
HB_INTERNAL void add (hb_codepoint_t codepoint,
unsigned int cluster);
HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
@@ -203,18 +269,28 @@ struct hb_buffer_t {
inline void clear_context (unsigned int side) { context_len[side] = 0; }
HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
+
+ inline bool messaging (void) { return unlikely (message_func); }
+ inline bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
+ {
+ if (!messaging ())
+ return true;
+ va_list ap;
+ va_start (ap, fmt);
+ bool ret = message_impl (font, fmt, ap);
+ va_end (ap);
+ return ret;
+ }
+ HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
};
-#define HB_BUFFER_XALLOCATE_VAR(b, func, var, owner) \
+#define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
- sizeof (b->info[0].var), owner)
-#define HB_BUFFER_ALLOCATE_VAR(b, var) \
- HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var)
-#define HB_BUFFER_DEALLOCATE_VAR(b, var) \
- HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var (), #var)
-#define HB_BUFFER_ASSERT_VAR(b, var) \
- HB_BUFFER_XALLOCATE_VAR (b, assert_var, var (), #var)
+ sizeof (b->info[0].var))
+#define HB_BUFFER_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var ())
+#define HB_BUFFER_DEALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ())
+#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ())
#endif /* HB_BUFFER_PRIVATE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-serialize.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer-serialize.cc
index 7839cbc3f0..63a0f34669 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-serialize.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-serialize.cc
@@ -36,11 +36,12 @@ static const char *serialize_formats[] = {
/**
* hb_buffer_serialize_list_formats:
*
- *
+ * Returns a list of supported buffer serialization formats.
*
* Return value: (transfer none):
+ * A string array of buffer serialization formats. Should not be freed.
*
- * Since: 0.9.2
+ * Since: 0.9.7
**/
const char **
hb_buffer_serialize_list_formats (void)
@@ -50,14 +51,17 @@ hb_buffer_serialize_list_formats (void)
/**
* hb_buffer_serialize_format_from_string:
- * @str:
- * @len:
+ * @str: (array length=len) (element-type uint8_t): a string to parse
+ * @len: length of @str, or -1 if string is %NULL terminated
*
- *
+ * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
+ * @str is a valid buffer serialization format, use
+ * hb_buffer_serialize_list_formats() to get the list of supported formats.
*
* Return value:
+ * The parsed #hb_buffer_serialize_format_t.
*
- * Since: 0.9.2
+ * Since: 0.9.7
**/
hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len)
@@ -68,13 +72,15 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
/**
* hb_buffer_serialize_format_to_string:
- * @format:
+ * @format: an #hb_buffer_serialize_format_t to convert.
*
- *
+ * Converts @format to the string corresponding it, or %NULL if it is not a valid
+ * #hb_buffer_serialize_format_t.
*
- * Return value:
+ * Return value: (transfer none):
+ * A %NULL terminated string corresponding to @format. Should not be freed.
*
- * Since: 0.9.2
+ * Since: 0.9.7
**/
const char *
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
@@ -242,24 +248,51 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
return end - start;
}
-/* Returns number of items, starting at start, that were serialized. */
/**
* hb_buffer_serialize_glyphs:
- * @buffer: a buffer.
- * @start:
- * @end:
- * @buf: (array length=buf_size):
- * @buf_size:
- * @buf_consumed: (out):
- * @font:
- * @format:
- * @flags:
+ * @buffer: an #hb_buffer_t buffer.
+ * @start: the first item in @buffer to serialize.
+ * @end: the last item in @buffer to serialize.
+ * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
+ * write serialized buffer into.
+ * @buf_size: the size of @buf.
+ * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
+ * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
+ * read glyph names and extents. If %NULL, and empty font will be used.
+ * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
+ * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
+ * to serialize.
*
- *
+ * Serializes @buffer into a textual representation of its glyph content,
+ * useful for showing the contents of the buffer, for example during debugging.
+ * There are currently two supported serialization formats:
+ *
+ * ## text
+ * A human-readable, plain text format.
+ * The serialized glyphs will look something like:
+ *
+ * ```
+ * [uni0651=0@518,0+0|uni0628=0+1897]
+ * ```
+ * - The serialized glyphs are delimited with `[` and `]`.
+ * - Glyphs are separated with `|`
+ * - Each glyph starts with glyph name, or glyph index if
+ * #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
+ * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
+ * - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
+ * - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
+ * - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
+ * - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the
+ * #hb_glyph_extents_t in the format
+ * `&lt;x_bearing,y_bearing,width,height&gt;`
+ *
+ * ## json
+ * TODO.
*
* Return value:
+ * The number of serialized items.
*
- * Since: 0.9.2
+ * Since: 0.9.7
**/
unsigned int
hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
@@ -267,8 +300,8 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
unsigned int end,
char *buf,
unsigned int buf_size,
- unsigned int *buf_consumed, /* May be NULL */
- hb_font_t *font, /* May be NULL */
+ unsigned int *buf_consumed,
+ hb_font_t *font,
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags)
{
@@ -282,6 +315,9 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+ if (!buffer->have_positions)
+ flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
+
if (unlikely (start == end))
return 0;
@@ -355,7 +391,7 @@ parse_int (const char *pp, const char *end, int32_t *pv)
/**
* hb_buffer_deserialize_glyphs:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t buffer.
* @buf: (array length=buf_len):
* @buf_len:
* @end_ptr: (out):
@@ -366,7 +402,7 @@ parse_int (const char *pp, const char *end, int32_t *pv)
*
* Return value:
*
- * Since: 0.9.2
+ * Since: 0.9.7
**/
hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
index 50710dd23e..3940a3dbf8 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
@@ -35,8 +35,26 @@
#define HB_DEBUG_BUFFER (HB_DEBUG+0)
#endif
+/**
+ * SECTION: hb-buffer
+ * @title: Buffers
+ * @short_description: Input and output buffers
+ * @include: hb.h
+ *
+ * Buffers serve dual role in HarfBuzz; they hold the input characters that are
+ * passed hb_shape(), and after shaping they hold the output glyphs.
+ **/
/**
+ * hb_segment_properties_equal:
+ * @a: first #hb_segment_properties_t to compare.
+ * @b: second #hb_segment_properties_t to compare.
+ *
+ * Checks the equality of two #hb_segment_properties_t's.
+ *
+ * Return value:
+ * %true if all properties of @a equal those of @b, false otherwise.
+ *
* Since: 0.9.7
**/
hb_bool_t
@@ -52,6 +70,14 @@ hb_segment_properties_equal (const hb_segment_properties_t *a,
}
/**
+ * hb_segment_properties_hash:
+ * @p: #hb_segment_properties_t to hash.
+ *
+ * Creates a hash representing @p.
+ *
+ * Return value:
+ * A hash of @p.
+ *
* Since: 0.9.7
**/
unsigned int
@@ -91,6 +117,11 @@ hb_buffer_t::enlarge (unsigned int size)
{
if (unlikely (in_error))
return false;
+ if (unlikely (size > max_len))
+ {
+ in_error = true;
+ return false;
+ }
unsigned int new_allocated = allocated;
hb_glyph_position_t *new_pos = NULL;
@@ -152,6 +183,12 @@ hb_buffer_t::shift_forward (unsigned int count)
if (unlikely (!ensure (len + count))) return false;
memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
+ if (idx + count > len)
+ {
+ /* Under memory failure we might expose this area. At least
+ * clean it up. Oh well... */
+ memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
+ }
len += count;
idx += count;
@@ -198,6 +235,7 @@ hb_buffer_t::clear (void)
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
props = default_props;
+ scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
in_error = false;
@@ -210,11 +248,11 @@ hb_buffer_t::clear (void)
out_info = info;
serial = 0;
- memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
- memset (allocated_var_owner, 0, sizeof allocated_var_owner);
memset (context, 0, sizeof context);
memset (context_len, 0, sizeof context_len);
+
+ deallocate_var_all ();
}
void
@@ -375,6 +413,8 @@ hb_buffer_t::move_to (unsigned int i)
idx = i;
return true;
}
+ if (unlikely (in_error))
+ return false;
assert (i <= out_len + (len - idx));
@@ -392,6 +432,8 @@ hb_buffer_t::move_to (unsigned int i)
/* Tricky part: rewinding... */
unsigned int count = out_len - i;
+ /* This will blow in our face if memory allocation fails later
+ * in this same lookup... */
if (unlikely (idx < count && !shift_forward (count + 32))) return false;
assert (idx >= count);
@@ -627,82 +669,19 @@ hb_buffer_t::guess_segment_properties (void)
}
-static inline void
-dump_var_allocation (const hb_buffer_t *buffer)
-{
- char buf[80];
- for (unsigned int i = 0; i < 8; i++)
- buf[i] = '0' + buffer->allocated_var_bytes[7 - i];
- buf[8] = '\0';
- DEBUG_MSG (BUFFER, buffer,
- "Current var allocation: %s",
- buf);
-}
-
-void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner)
-{
- assert (byte_i < 8 && byte_i + count <= 8);
-
- if (DEBUG_ENABLED (BUFFER))
- dump_var_allocation (this);
- DEBUG_MSG (BUFFER, this,
- "Allocating var bytes %d..%d for %s",
- byte_i, byte_i + count - 1, owner);
-
- for (unsigned int i = byte_i; i < byte_i + count; i++) {
- assert (!allocated_var_bytes[i]);
- allocated_var_bytes[i]++;
- allocated_var_owner[i] = owner;
- }
-}
-
-void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
-{
- if (DEBUG_ENABLED (BUFFER))
- dump_var_allocation (this);
-
- DEBUG_MSG (BUFFER, this,
- "Deallocating var bytes %d..%d for %s",
- byte_i, byte_i + count - 1, owner);
-
- assert (byte_i < 8 && byte_i + count <= 8);
- for (unsigned int i = byte_i; i < byte_i + count; i++) {
- assert (allocated_var_bytes[i]);
- assert (0 == strcmp (allocated_var_owner[i], owner));
- allocated_var_bytes[i]--;
- }
-}
-
-void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
-{
- if (DEBUG_ENABLED (BUFFER))
- dump_var_allocation (this);
-
- DEBUG_MSG (BUFFER, this,
- "Asserting var bytes %d..%d for %s",
- byte_i, byte_i + count - 1, owner);
-
- assert (byte_i < 8 && byte_i + count <= 8);
- for (unsigned int i = byte_i; i < byte_i + count; i++) {
- assert (allocated_var_bytes[i]);
- assert (0 == strcmp (allocated_var_owner[i], owner));
- }
-}
-
-void hb_buffer_t::deallocate_var_all (void)
-{
- memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
- memset (allocated_var_owner, 0, sizeof (allocated_var_owner));
-}
-
/* Public API */
/**
* hb_buffer_create: (Xconstructor)
*
- *
+ * Creates a new #hb_buffer_t with all properties to defaults.
*
- * Return value: (transfer full)
+ * Return value: (transfer full):
+ * A newly allocated #hb_buffer_t with a reference count of 1. The initial
+ * reference count should be released with hb_buffer_destroy() when you are done
+ * using the #hb_buffer_t. This function never returns %NULL. If memory cannot
+ * be allocated, a special #hb_buffer_t object will be returned on which
+ * hb_buffer_allocation_successful() returns %false.
*
* Since: 0.9.2
**/
@@ -714,6 +693,8 @@ hb_buffer_create (void)
if (!(buffer = hb_object_create<hb_buffer_t> ()))
return hb_buffer_get_empty ();
+ buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
+
buffer->reset ();
return buffer;
@@ -738,6 +719,8 @@ hb_buffer_get_empty (void)
HB_BUFFER_FLAG_DEFAULT,
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
+ HB_BUFFER_SCRATCH_FLAG_DEFAULT,
+ HB_BUFFER_MAX_LEN_DEFAULT,
HB_BUFFER_CONTENT_TYPE_INVALID,
HB_SEGMENT_PROPERTIES_DEFAULT,
@@ -753,11 +736,13 @@ hb_buffer_get_empty (void)
/**
* hb_buffer_reference: (skip)
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * Increases the reference count on @buffer by one. This prevents @buffer from
+ * being destroyed until a matching call to hb_buffer_destroy() is made.
*
* Return value: (transfer full):
+ * The referenced #hb_buffer_t.
*
* Since: 0.9.2
**/
@@ -769,9 +754,11 @@ hb_buffer_reference (hb_buffer_t *buffer)
/**
* hb_buffer_destroy: (skip)
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * Deallocate the @buffer.
+ * Decreases the reference count on @buffer by one. If the result is zero, then
+ * @buffer and all associated resources are freed. See hb_buffer_reference().
*
* Since: 0.9.2
**/
@@ -784,13 +771,15 @@ hb_buffer_destroy (hb_buffer_t *buffer)
free (buffer->info);
free (buffer->pos);
+ if (buffer->message_destroy)
+ buffer->message_destroy (buffer->message_data);
free (buffer);
}
/**
* hb_buffer_set_user_data: (skip)
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
* @key:
* @data:
* @destroy:
@@ -814,7 +803,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
/**
* hb_buffer_get_user_data: (skip)
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
* @key:
*
*
@@ -833,10 +822,11 @@ hb_buffer_get_user_data (hb_buffer_t *buffer,
/**
* hb_buffer_set_content_type:
- * @buffer: a buffer.
- * @content_type:
+ * @buffer: an #hb_buffer_t.
+ * @content_type: the type of buffer contents to set
*
- *
+ * Sets the type of @buffer contents, buffers are either empty, contain
+ * characters (before shaping) or glyphs (the result of shaping).
*
* Since: 0.9.5
**/
@@ -849,11 +839,12 @@ hb_buffer_set_content_type (hb_buffer_t *buffer,
/**
* hb_buffer_get_content_type:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * see hb_buffer_set_content_type().
*
- * Return value:
+ * Return value:
+ * The type of @buffer contents.
*
* Since: 0.9.5
**/
@@ -866,7 +857,7 @@ hb_buffer_get_content_type (hb_buffer_t *buffer)
/**
* hb_buffer_set_unicode_funcs:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
* @unicode_funcs:
*
*
@@ -891,7 +882,7 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
/**
* hb_buffer_get_unicode_funcs:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
*
*
@@ -907,10 +898,16 @@ hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
/**
* hb_buffer_set_direction:
- * @buffer: a buffer.
- * @direction:
+ * @buffer: an #hb_buffer_t.
+ * @direction: the #hb_direction_t of the @buffer
*
- *
+ * Set the text flow direction of the buffer. No shaping can happen without
+ * setting @buffer direction, and it controls the visual direction for the
+ * output glyphs; for RTL direction the glyphs will be reversed. Many layout
+ * features depend on the proper setting of the direction, for example,
+ * reversing RTL text before shaping, then shaping with LTR direction is not
+ * the same as keeping the text in logical order and shaping with RTL
+ * direction.
*
* Since: 0.9.2
**/
@@ -927,11 +924,12 @@ hb_buffer_set_direction (hb_buffer_t *buffer,
/**
* hb_buffer_get_direction:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * See hb_buffer_set_direction()
*
- * Return value:
+ * Return value:
+ * The direction of the @buffer.
*
* Since: 0.9.2
**/
@@ -943,10 +941,18 @@ hb_buffer_get_direction (hb_buffer_t *buffer)
/**
* hb_buffer_set_script:
- * @buffer: a buffer.
- * @script:
+ * @buffer: an #hb_buffer_t.
+ * @script: an #hb_script_t to set.
*
- *
+ * Sets the script of @buffer to @script.
+ *
+ * Script is crucial for choosing the proper shaping behaviour for scripts that
+ * require it (e.g. Arabic) and the which OpenType features defined in the font
+ * to be applied.
+ *
+ * You can pass one of the predefined #hb_script_t values, or use
+ * hb_script_from_string() or hb_script_from_iso15924_tag() to get the
+ * corresponding script from an ISO 15924 script tag.
*
* Since: 0.9.2
**/
@@ -962,11 +968,12 @@ hb_buffer_set_script (hb_buffer_t *buffer,
/**
* hb_buffer_get_script:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * See hb_buffer_set_script().
*
- * Return value:
+ * Return value:
+ * The #hb_script_t of the @buffer.
*
* Since: 0.9.2
**/
@@ -978,10 +985,18 @@ hb_buffer_get_script (hb_buffer_t *buffer)
/**
* hb_buffer_set_language:
- * @buffer: a buffer.
- * @language:
+ * @buffer: an #hb_buffer_t.
+ * @language: an hb_language_t to set.
*
- *
+ * Sets the language of @buffer to @language.
+ *
+ * Languages are crucial for selecting which OpenType feature to apply to the
+ * buffer which can result in applying language-specific behaviour. Languages
+ * are orthogonal to the scripts, and though they are related, they are
+ * different concepts and should not be confused with each other.
+ *
+ * Use hb_language_from_string() to convert from ISO 639 language codes to
+ * #hb_language_t.
*
* Since: 0.9.2
**/
@@ -997,11 +1012,12 @@ hb_buffer_set_language (hb_buffer_t *buffer,
/**
* hb_buffer_get_language:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * See hb_buffer_set_language().
*
* Return value: (transfer none):
+ * The #hb_language_t of the buffer. Must not be freed by the caller.
*
* Since: 0.9.2
**/
@@ -1013,10 +1029,12 @@ hb_buffer_get_language (hb_buffer_t *buffer)
/**
* hb_buffer_set_segment_properties:
- * @buffer: a buffer.
- * @props:
+ * @buffer: an #hb_buffer_t.
+ * @props: an #hb_segment_properties_t to use.
*
- *
+ * Sets the segment properties of the buffer, a shortcut for calling
+ * hb_buffer_set_direction(), hb_buffer_set_script() and
+ * hb_buffer_set_language() individually.
*
* Since: 0.9.7
**/
@@ -1032,10 +1050,10 @@ hb_buffer_set_segment_properties (hb_buffer_t *buffer,
/**
* hb_buffer_get_segment_properties:
- * @buffer: a buffer.
- * @props: (out):
+ * @buffer: an #hb_buffer_t.
+ * @props: (out): the output #hb_segment_properties_t.
*
- *
+ * Sets @props to the #hb_segment_properties_t of @buffer.
*
* Since: 0.9.7
**/
@@ -1049,10 +1067,10 @@ hb_buffer_get_segment_properties (hb_buffer_t *buffer,
/**
* hb_buffer_set_flags:
- * @buffer: a buffer.
- * @flags:
+ * @buffer: an #hb_buffer_t.
+ * @flags: the buffer flags to set.
*
- *
+ * Sets @buffer flags to @flags. See #hb_buffer_flags_t.
*
* Since: 0.9.7
**/
@@ -1068,11 +1086,12 @@ hb_buffer_set_flags (hb_buffer_t *buffer,
/**
* hb_buffer_get_flags:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * See hb_buffer_set_flags().
*
* Return value:
+ * The @buffer flags.
*
* Since: 0.9.7
**/
@@ -1084,7 +1103,7 @@ hb_buffer_get_flags (hb_buffer_t *buffer)
/**
* hb_buffer_set_cluster_level:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
* @cluster_level:
*
*
@@ -1103,7 +1122,7 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer,
/**
* hb_buffer_get_cluster_level:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
*
*
@@ -1120,10 +1139,13 @@ hb_buffer_get_cluster_level (hb_buffer_t *buffer)
/**
* hb_buffer_set_replacement_codepoint:
- * @buffer: a buffer.
- * @replacement:
+ * @buffer: an #hb_buffer_t.
+ * @replacement: the replacement #hb_codepoint_t
*
- *
+ * Sets the #hb_codepoint_t that replaces invalid entries for a given encoding
+ * when adding text to @buffer.
+ *
+ * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT.
*
* Since: 0.9.31
**/
@@ -1139,11 +1161,12 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
/**
* hb_buffer_get_replacement_codepoint:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * See hb_buffer_set_replacement_codepoint().
*
* Return value:
+ * The @buffer replacement #hb_codepoint_t.
*
* Since: 0.9.31
**/
@@ -1156,9 +1179,10 @@ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
/**
* hb_buffer_reset:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * Resets the buffer to its initial status, as if it was just newly created
+ * with hb_buffer_create().
*
* Since: 0.9.2
**/
@@ -1170,9 +1194,10 @@ hb_buffer_reset (hb_buffer_t *buffer)
/**
* hb_buffer_clear_contents:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * Similar to hb_buffer_reset(), but does not clear the Unicode functions and
+ * the replacement code point.
*
* Since: 0.9.11
**/
@@ -1184,12 +1209,13 @@ hb_buffer_clear_contents (hb_buffer_t *buffer)
/**
* hb_buffer_pre_allocate:
- * @buffer: a buffer.
- * @size:
+ * @buffer: an #hb_buffer_t.
+ * @size: number of items to pre allocate.
*
- *
+ * Pre allocates memory for @buffer to fit at least @size number of items.
*
- * Return value:
+ * Return value:
+ * %true if @buffer memory allocation succeeded, %false otherwise.
*
* Since: 0.9.2
**/
@@ -1201,11 +1227,12 @@ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
/**
* hb_buffer_allocation_successful:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * Check if allocating memory for the buffer succeeded.
*
- * Return value:
+ * Return value:
+ * %true if @buffer memory allocation succeeded, %false otherwise.
*
* Since: 0.9.2
**/
@@ -1217,11 +1244,18 @@ hb_buffer_allocation_successful (hb_buffer_t *buffer)
/**
* hb_buffer_add:
- * @buffer: a buffer.
- * @codepoint:
- * @cluster:
+ * @buffer: an #hb_buffer_t.
+ * @codepoint: a Unicode code point.
+ * @cluster: the cluster value of @codepoint.
*
- *
+ * Appends a character with the Unicode value of @codepoint to @buffer, and
+ * gives it the initial cluster value of @cluster. Clusters can be any thing
+ * the client wants, they are usually used to refer to the index of the
+ * character in the input text stream and are output in
+ * #hb_glyph_info_t.cluster field.
+ *
+ * This function does not check the validity of @codepoint, it is up to the
+ * caller to ensure it is a valid Unicode code point.
*
* Since: 0.9.7
**/
@@ -1236,12 +1270,14 @@ hb_buffer_add (hb_buffer_t *buffer,
/**
* hb_buffer_set_length:
- * @buffer: a buffer.
- * @length:
+ * @buffer: an #hb_buffer_t.
+ * @length: the new length of @buffer.
*
- *
+ * Similar to hb_buffer_pre_allocate(), but clears any new items added at the
+ * end.
*
* Return value:
+ * %true if @buffer memory allocation succeeded, %false otherwise.
*
* Since: 0.9.2
**/
@@ -1276,11 +1312,13 @@ hb_buffer_set_length (hb_buffer_t *buffer,
/**
* hb_buffer_get_length:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
* Returns the number of items in the buffer.
*
- * Return value: buffer length.
+ * Return value:
+ * The @buffer length.
+ * The value valid as long as buffer has not been modified.
*
* Since: 0.9.2
**/
@@ -1292,13 +1330,15 @@ hb_buffer_get_length (hb_buffer_t *buffer)
/**
* hb_buffer_get_glyph_infos:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
* @length: (out): output array length.
*
- * Returns buffer glyph information array. Returned pointer
- * is valid as long as buffer contents are not modified.
+ * Returns @buffer glyph information array. Returned pointer
+ * is valid as long as @buffer contents are not modified.
*
- * Return value: (transfer none) (array length=length): buffer glyph information array.
+ * Return value: (transfer none) (array length=length):
+ * The @buffer glyph information array.
+ * The value valid as long as buffer has not been modified.
*
* Since: 0.9.2
**/
@@ -1314,13 +1354,15 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
/**
* hb_buffer_get_glyph_positions:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
* @length: (out): output length.
*
- * Returns buffer glyph position array. Returned pointer
- * is valid as long as buffer contents are not modified.
+ * Returns @buffer glyph position array. Returned pointer
+ * is valid as long as @buffer contents are not modified.
*
- * Return value: (transfer none) (array length=length): buffer glyph position array.
+ * Return value: (transfer none) (array length=length):
+ * The @buffer glyph position array.
+ * The value valid as long as buffer has not been modified.
*
* Since: 0.9.2
**/
@@ -1339,7 +1381,7 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
/**
* hb_buffer_reverse:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
* Reverses buffer contents.
*
@@ -1353,7 +1395,7 @@ hb_buffer_reverse (hb_buffer_t *buffer)
/**
* hb_buffer_reverse_range:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
* @start: start index.
* @end: end index.
*
@@ -1370,7 +1412,7 @@ hb_buffer_reverse_range (hb_buffer_t *buffer,
/**
* hb_buffer_reverse_clusters:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
* Reverses buffer clusters. That is, the buffer contents are
* reversed, then each cluster (consecutive items having the
@@ -1386,7 +1428,7 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
/**
* hb_buffer_guess_segment_properties:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
* Sets unset buffer segment properties based on buffer Unicode
* contents. If buffer is not empty, it must have content type
@@ -1485,13 +1527,18 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
/**
* hb_buffer_add_utf8:
- * @buffer: a buffer.
- * @text: (array length=text_length) (element-type uint8_t):
- * @text_length:
- * @item_offset:
- * @item_length:
+ * @buffer: an #hb_buffer_t.
+ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
+ * characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ * end of @text (assuming it is %NULL terminated).
*
- *
+ * See hb_buffer_add_codepoints().
+ *
+ * Replaces invalid UTF-8 characters with the @buffer replacement code point,
+ * see hb_buffer_set_replacement_codepoint().
*
* Since: 0.9.2
**/
@@ -1507,13 +1554,17 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer,
/**
* hb_buffer_add_utf16:
- * @buffer: a buffer.
- * @text: (array length=text_length):
- * @text_length:
- * @item_offset:
- * @item_length:
+ * @buffer: an #hb_buffer_t.
+ * @text: (array length=text_length): an array of UTF-16 characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ * end of @text (assuming it is %NULL terminated).
*
- *
+ * See hb_buffer_add_codepoints().
+ *
+ * Replaces invalid UTF-16 characters with the @buffer replacement code point,
+ * see hb_buffer_set_replacement_codepoint().
*
* Since: 0.9.2
**/
@@ -1529,13 +1580,17 @@ hb_buffer_add_utf16 (hb_buffer_t *buffer,
/**
* hb_buffer_add_utf32:
- * @buffer: a buffer.
- * @text: (array length=text_length):
- * @text_length:
- * @item_offset:
- * @item_length:
+ * @buffer: an #hb_buffer_t.
+ * @text: (array length=text_length): an array of UTF-32 characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ * end of @text (assuming it is %NULL terminated).
*
- *
+ * See hb_buffer_add_codepoints().
+ *
+ * Replaces invalid UTF-32 characters with the @buffer replacement code point,
+ * see hb_buffer_set_replacement_codepoint().
*
* Since: 0.9.2
**/
@@ -1551,13 +1606,18 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
/**
* hb_buffer_add_latin1:
- * @buffer: a buffer.
- * @text: (array length=text_length) (element-type uint8_t):
- * @text_length:
- * @item_offset:
- * @item_length:
+ * @buffer: an #hb_buffer_t.
+ * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8
+ * characters to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first character to add to the @buffer.
+ * @item_length: the number of characters to add to the @buffer, or -1 for the
+ * end of @text (assuming it is %NULL terminated).
*
- *
+ * Similar to hb_buffer_add_codepoints(), but allows only access to first 256
+ * Unicode code points that can fit in 8-bit strings.
+ *
+ * <note>Has nothing to do with non-Unicode Latin-1 encoding.</note>
*
* Since: 0.9.39
**/
@@ -1573,13 +1633,25 @@ hb_buffer_add_latin1 (hb_buffer_t *buffer,
/**
* hb_buffer_add_codepoints:
- * @buffer: a buffer.
- * @text: (array length=text_length):
- * @text_length:
- * @item_offset:
- * @item_length:
- *
- *
+ * @buffer: a #hb_buffer_t to append characters to.
+ * @text: (array length=text_length): an array of Unicode code points to append.
+ * @text_length: the length of the @text, or -1 if it is %NULL terminated.
+ * @item_offset: the offset of the first code point to add to the @buffer.
+ * @item_length: the number of code points to add to the @buffer, or -1 for the
+ * end of @text (assuming it is %NULL terminated).
+ *
+ * Appends characters from @text array to @buffer. The @item_offset is the
+ * position of the first character from @text that will be appended, and
+ * @item_length is the number of character. When shaping part of a larger text
+ * (e.g. a run of text from a paragraph), instead of passing just the substring
+ * corresponding to the run, it is preferable to pass the whole
+ * paragraph and specify the run start and length as @item_offset and
+ * @item_length, respectively, to give HarfBuzz the full context to be able,
+ * for example, to do cross-run Arabic shaping or properly handle combining
+ * marks at stat of run.
+ *
+ * This function does not check the validity of @text, it is up to the caller
+ * to ensure it contains a valid Unicode code points.
*
* Since: 0.9.31
**/
@@ -1651,9 +1723,12 @@ normalize_glyphs_cluster (hb_buffer_t *buffer,
/**
* hb_buffer_normalize_glyphs:
- * @buffer: a buffer.
+ * @buffer: an #hb_buffer_t.
*
- *
+ * Reorders a glyph buffer to have canonical in-cluster glyph order / position.
+ * The resulting clusters should behave identical to pre-reordering clusters.
+ *
+ * <note>This has nothing to do with Unicode normalization.</note>
*
* Since: 0.9.2
**/
@@ -1699,3 +1774,45 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
}
}
}
+
+/*
+ * Debugging.
+ */
+
+/**
+ * hb_buffer_set_message_func:
+ * @buffer: an #hb_buffer_t.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.3
+ **/
+void
+hb_buffer_set_message_func (hb_buffer_t *buffer,
+ hb_buffer_message_func_t func,
+ void *user_data, hb_destroy_func_t destroy)
+{
+ if (buffer->message_destroy)
+ buffer->message_destroy (buffer->message_data);
+
+ if (func) {
+ buffer->message_func = func;
+ buffer->message_data = user_data;
+ buffer->message_destroy = destroy;
+ } else {
+ buffer->message_func = NULL;
+ buffer->message_data = NULL;
+ buffer->message_destroy = NULL;
+ }
+}
+
+bool
+hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
+{
+ char buf[100];
+ vsnprintf (buf, sizeof (buf), fmt, ap);
+ return (bool) this->message_func (this, font, buf, this->message_data);
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.h b/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
index bb89dc3de7..bf289c19b3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
@@ -40,7 +40,27 @@
HB_BEGIN_DECLS
-
+/**
+ * hb_glyph_info_t:
+ * @codepoint: either a Unicode code point (before shaping) or a glyph index
+ * (after shaping).
+ * @mask:
+ * @cluster: the index of the character in the original text that corresponds
+ * to this #hb_glyph_info_t, or whatever the client passes to
+ * hb_buffer_add(). More than one #hb_glyph_info_t can have the same
+ * @cluster value, if they resulted from the same character (e.g. one
+ * to many glyph substitution), and when more than one character gets
+ * merged in the same glyph (e.g. many to one glyph substitution) the
+ * #hb_glyph_info_t will have the smallest cluster value of them.
+ * By default some characters are merged into the same cluster
+ * (e.g. combining marks have the same cluster as their bases)
+ * even if they are separate glyphs, hb_buffer_set_cluster_level()
+ * allow selecting more fine-grained cluster handling.
+ *
+ * The #hb_glyph_info_t is the structure that holds information about the
+ * glyphs and their relation to input text.
+ *
+ */
typedef struct hb_glyph_info_t {
hb_codepoint_t codepoint;
hb_mask_t mask;
@@ -51,6 +71,22 @@ typedef struct hb_glyph_info_t {
hb_var_int_t var2;
} hb_glyph_info_t;
+/**
+ * hb_glyph_position_t:
+ * @x_advance: how much the line advances after drawing this glyph when setting
+ * text in horizontal direction.
+ * @y_advance: how much the line advances after drawing this glyph when setting
+ * text in vertical direction.
+ * @x_offset: how much the glyph moves on the X-axis before drawing it, this
+ * should not affect how much the line advances.
+ * @y_offset: how much the glyph moves on the Y-axis before drawing it, this
+ * should not affect how much the line advances.
+ *
+ * The #hb_glyph_position_t is the structure that holds the positions of the
+ * glyph in both horizontal and vertical directions. All positions in
+ * #hb_glyph_position_t are relative to the current point.
+ *
+ */
typedef struct hb_glyph_position_t {
hb_position_t x_advance;
hb_position_t y_advance;
@@ -61,7 +97,16 @@ typedef struct hb_glyph_position_t {
hb_var_int_t var;
} hb_glyph_position_t;
-
+/**
+ * hb_segment_properties_t:
+ * @direction: the #hb_direction_t of the buffer, see hb_buffer_set_direction().
+ * @script: the #hb_script_t of the buffer, see hb_buffer_set_script().
+ * @language: the #hb_language_t of the buffer, see hb_buffer_set_language().
+ *
+ * The structure that holds various text properties of an #hb_buffer_t. Can be
+ * set and retrieved using hb_buffer_set_segment_properties() and
+ * hb_buffer_get_segment_properties(), respectively.
+ */
typedef struct hb_segment_properties_t {
hb_direction_t direction;
hb_script_t script;
@@ -77,101 +122,125 @@ typedef struct hb_segment_properties_t {
NULL, \
NULL}
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_segment_properties_equal (const hb_segment_properties_t *a,
const hb_segment_properties_t *b);
-unsigned int
+HB_EXTERN unsigned int
hb_segment_properties_hash (const hb_segment_properties_t *p);
-/*
- * hb_buffer_t
+/**
+ * hb_buffer_t:
+ *
+ * The main structure holding the input text and its properties before shaping,
+ * and output glyphs and their information after shaping.
*/
typedef struct hb_buffer_t hb_buffer_t;
-hb_buffer_t *
+HB_EXTERN hb_buffer_t *
hb_buffer_create (void);
-hb_buffer_t *
+HB_EXTERN hb_buffer_t *
hb_buffer_get_empty (void);
-hb_buffer_t *
+HB_EXTERN hb_buffer_t *
hb_buffer_reference (hb_buffer_t *buffer);
-void
+HB_EXTERN void
hb_buffer_destroy (hb_buffer_t *buffer);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_buffer_set_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
-void *
+HB_EXTERN void *
hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key);
-
+/**
+ * hb_buffer_content_type_t:
+ * @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
+ * @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping).
+ * @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping).
+ */
typedef enum {
HB_BUFFER_CONTENT_TYPE_INVALID = 0,
HB_BUFFER_CONTENT_TYPE_UNICODE,
HB_BUFFER_CONTENT_TYPE_GLYPHS
} hb_buffer_content_type_t;
-void
+HB_EXTERN void
hb_buffer_set_content_type (hb_buffer_t *buffer,
hb_buffer_content_type_t content_type);
-hb_buffer_content_type_t
+HB_EXTERN hb_buffer_content_type_t
hb_buffer_get_content_type (hb_buffer_t *buffer);
-void
+HB_EXTERN void
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
hb_unicode_funcs_t *unicode_funcs);
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
hb_buffer_get_unicode_funcs (hb_buffer_t *buffer);
-void
+HB_EXTERN void
hb_buffer_set_direction (hb_buffer_t *buffer,
hb_direction_t direction);
-hb_direction_t
+HB_EXTERN hb_direction_t
hb_buffer_get_direction (hb_buffer_t *buffer);
-void
+HB_EXTERN void
hb_buffer_set_script (hb_buffer_t *buffer,
hb_script_t script);
-hb_script_t
+HB_EXTERN hb_script_t
hb_buffer_get_script (hb_buffer_t *buffer);
-void
+HB_EXTERN void
hb_buffer_set_language (hb_buffer_t *buffer,
hb_language_t language);
-hb_language_t
+HB_EXTERN hb_language_t
hb_buffer_get_language (hb_buffer_t *buffer);
-void
+HB_EXTERN void
hb_buffer_set_segment_properties (hb_buffer_t *buffer,
const hb_segment_properties_t *props);
-void
+HB_EXTERN void
hb_buffer_get_segment_properties (hb_buffer_t *buffer,
hb_segment_properties_t *props);
-void
+HB_EXTERN void
hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
-/*
+/**
+ * hb_buffer_flags_t:
+ * @HB_BUFFER_FLAG_DEFAULT: the default buffer flag.
+ * @HB_BUFFER_FLAG_BOT: flag indicating that special handling of the beginning
+ * of text paragraph can be applied to this buffer. Should usually
+ * be set, unless you are passing to the buffer only part
+ * of the text without the full context.
+ * @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text
+ * paragraph can be applied to this buffer, similar to
+ * @HB_BUFFER_FLAG_EOT.
+ * @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES:
+ * flag indication that character with Default_Ignorable
+ * Unicode property should use the corresponding glyph
+ * from the font, instead of hiding them (currently done
+ * by replacing them with the space glyph and zeroing the
+ * advance width.)
+ *
* Since: 0.9.20
*/
typedef enum { /*< flags >*/
@@ -181,11 +250,11 @@ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u
} hb_buffer_flags_t;
-void
+HB_EXTERN void
hb_buffer_set_flags (hb_buffer_t *buffer,
hb_buffer_flags_t flags);
-hb_buffer_flags_t
+HB_EXTERN hb_buffer_flags_t
hb_buffer_get_flags (hb_buffer_t *buffer);
/*
@@ -198,93 +267,92 @@ typedef enum {
HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
} hb_buffer_cluster_level_t;
-void
+HB_EXTERN void
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
hb_buffer_cluster_level_t cluster_level);
-hb_buffer_cluster_level_t
+HB_EXTERN hb_buffer_cluster_level_t
hb_buffer_get_cluster_level (hb_buffer_t *buffer);
+/**
+ * HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT:
+ *
+ * The default code point for replacing invalid characters in a given encoding.
+ * Set to U+FFFD REPLACEMENT CHARACTER.
+ *
+ * Since: 0.9.31
+ */
#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
-/* Sets codepoint used to replace invalid UTF-8/16/32 entries.
- * Default is 0xFFFDu. */
-void
+HB_EXTERN void
hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
hb_codepoint_t replacement);
-hb_codepoint_t
+HB_EXTERN hb_codepoint_t
hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
-/* Resets the buffer. Afterwards it's as if it was just created,
- * except that it has a larger buffer allocated perhaps... */
-void
+HB_EXTERN void
hb_buffer_reset (hb_buffer_t *buffer);
-/* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */
-void
+HB_EXTERN void
hb_buffer_clear_contents (hb_buffer_t *buffer);
-/* Returns false if allocation failed */
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_buffer_pre_allocate (hb_buffer_t *buffer,
unsigned int size);
-/* Returns false if allocation has failed before */
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_buffer_allocation_successful (hb_buffer_t *buffer);
-void
+HB_EXTERN void
hb_buffer_reverse (hb_buffer_t *buffer);
-void
+HB_EXTERN void
hb_buffer_reverse_range (hb_buffer_t *buffer,
unsigned int start, unsigned int end);
-void
+HB_EXTERN void
hb_buffer_reverse_clusters (hb_buffer_t *buffer);
/* Filling the buffer in */
-void
+HB_EXTERN void
hb_buffer_add (hb_buffer_t *buffer,
hb_codepoint_t codepoint,
unsigned int cluster);
-void
+HB_EXTERN void
hb_buffer_add_utf8 (hb_buffer_t *buffer,
const char *text,
int text_length,
unsigned int item_offset,
int item_length);
-void
+HB_EXTERN void
hb_buffer_add_utf16 (hb_buffer_t *buffer,
const uint16_t *text,
int text_length,
unsigned int item_offset,
int item_length);
-void
+HB_EXTERN void
hb_buffer_add_utf32 (hb_buffer_t *buffer,
const uint32_t *text,
int text_length,
unsigned int item_offset,
int item_length);
-/* Allows only access to first 256 Unicode codepoints. */
-void
+HB_EXTERN void
hb_buffer_add_latin1 (hb_buffer_t *buffer,
const uint8_t *text,
int text_length,
unsigned int item_offset,
int item_length);
-/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */
-void
+HB_EXTERN void
hb_buffer_add_codepoints (hb_buffer_t *buffer,
const hb_codepoint_t *text,
int text_length,
@@ -292,32 +360,25 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
int item_length);
-/* Clears any new items added at the end */
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_buffer_set_length (hb_buffer_t *buffer,
unsigned int length);
-/* Return value valid as long as buffer not modified */
-unsigned int
+HB_EXTERN unsigned int
hb_buffer_get_length (hb_buffer_t *buffer);
/* Getting glyphs out of the buffer */
-/* Return value valid as long as buffer not modified */
-hb_glyph_info_t *
+HB_EXTERN hb_glyph_info_t *
hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
unsigned int *length);
-/* Return value valid as long as buffer not modified */
-hb_glyph_position_t *
+HB_EXTERN hb_glyph_position_t *
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
unsigned int *length);
-/* Reorders a glyph buffer to have canonical in-cluster glyph order / position.
- * The resulting clusters should behave identical to pre-reordering clusters.
- * NOTE: This has nothing to do with Unicode normalization. */
-void
+HB_EXTERN void
hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
@@ -325,7 +386,16 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
* Serialize
*/
-/*
+/**
+ * hb_buffer_serialize_flags_t:
+ * @HB_BUFFER_SERIALIZE_FLAG_DEFAULT: serialize glyph names, clusters and positions.
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS: do not serialize glyph cluster.
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information.
+ * @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name.
+ * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents.
+ *
+ * Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
+ *
* Since: 0.9.20
*/
typedef enum { /*< flags >*/
@@ -336,43 +406,67 @@ typedef enum { /*< flags >*/
HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u
} hb_buffer_serialize_flags_t;
+/**
+ * hb_buffer_serialize_format_t:
+ * @HB_BUFFER_SERIALIZE_FORMAT_TEXT: a human-readable, plain text format.
+ * @HB_BUFFER_SERIALIZE_FORMAT_JSON: a machine-readable JSON format.
+ * @HB_BUFFER_SERIALIZE_FORMAT_INVALID: invalid format.
+ *
+ * The buffer serialization and de-serialization format used in
+ * hb_buffer_serialize_glyphs() and hb_buffer_deserialize_glyphs().
+ *
+ * Since: 0.9.2
+ */
typedef enum {
HB_BUFFER_SERIALIZE_FORMAT_TEXT = HB_TAG('T','E','X','T'),
HB_BUFFER_SERIALIZE_FORMAT_JSON = HB_TAG('J','S','O','N'),
HB_BUFFER_SERIALIZE_FORMAT_INVALID = HB_TAG_NONE
} hb_buffer_serialize_format_t;
-/* len=-1 means str is NUL-terminated. */
-hb_buffer_serialize_format_t
+HB_EXTERN hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len);
-const char *
+HB_EXTERN const char *
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
-const char **
+HB_EXTERN const char **
hb_buffer_serialize_list_formats (void);
-/* Returns number of items, starting at start, that were serialized. */
-unsigned int
+HB_EXTERN unsigned int
hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
unsigned int start,
unsigned int end,
char *buf,
unsigned int buf_size,
- unsigned int *buf_consumed, /* May be NULL */
- hb_font_t *font, /* May be NULL */
+ unsigned int *buf_consumed,
+ hb_font_t *font,
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
const char *buf,
- int buf_len, /* -1 means nul-terminated */
- const char **end_ptr, /* May be NULL */
- hb_font_t *font, /* May be NULL */
+ int buf_len,
+ const char **end_ptr,
+ hb_font_t *font,
hb_buffer_serialize_format_t format);
+/*
+ * Debugging.
+ */
+
+typedef hb_bool_t (*hb_buffer_message_func_t) (hb_buffer_t *buffer,
+ hb_font_t *font,
+ const char *message,
+ void *user_data);
+
+HB_EXTERN void
+hb_buffer_set_message_func (hb_buffer_t *buffer,
+ hb_buffer_message_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+
HB_END_DECLS
#endif /* HB_BUFFER_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cache-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-cache-private.hh
index 19b70b7e39..24957e1e96 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cache-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cache-private.hh
@@ -45,11 +45,11 @@ struct hb_cache_t
inline bool get (unsigned int key, unsigned int *value)
{
- unsigned int k = key & ((1<<cache_bits)-1);
+ unsigned int k = key & ((1u<<cache_bits)-1);
unsigned int v = values[k];
if ((v >> value_bits) != (key >> cache_bits))
return false;
- *value = v & ((1<<value_bits)-1);
+ *value = v & ((1u<<value_bits)-1);
return true;
}
@@ -57,14 +57,14 @@ struct hb_cache_t
{
if (unlikely ((key >> key_bits) || (value >> value_bits)))
return false; /* Overflows */
- unsigned int k = key & ((1<<cache_bits)-1);
+ unsigned int k = key & ((1u<<cache_bits)-1);
unsigned int v = ((key>>cache_bits)<<value_bits) | value;
values[k] = v;
return true;
}
private:
- unsigned int values[1<<cache_bits];
+ unsigned int values[1u<<cache_bits];
};
typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.cc b/src/3rdparty/harfbuzz-ng/src/hb-common.cc
index e67059d10b..3564e43557 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-common.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-common.cc
@@ -88,7 +88,7 @@ hb_tag_from_string (const char *str, int len)
/**
* hb_tag_to_string:
* @tag:
- * @buf: (array fixed-size=4):
+ * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
*
*
*
@@ -281,12 +281,15 @@ retry:
/**
* hb_language_from_string:
- * @str: (array length=len) (element-type uint8_t):
- * @len:
+ * @str: (array length=len) (element-type uint8_t): a string representing
+ * ISO 639 language code
+ * @len: length of the @str, or -1 if it is %NULL-terminated.
*
- *
+ * Converts @str representing an ISO 639 language code to the corresponding
+ * #hb_language_t.
*
* Return value: (transfer none):
+ * The #hb_language_t corresponding to the ISO 639 language code.
*
* Since: 0.9.2
**/
@@ -314,11 +317,13 @@ hb_language_from_string (const char *str, int len)
/**
* hb_language_to_string:
- * @language:
+ * @language: an #hb_language_t to convert.
*
- *
+ * See hb_language_from_string().
*
- * Return value: (transfer none):
+ * Return value: (transfer none):
+ * A %NULL-terminated string representing the @language. Must not be freed by
+ * the caller.
*
* Since: 0.9.2
**/
@@ -357,11 +362,12 @@ hb_language_get_default (void)
/**
* hb_script_from_iso15924_tag:
- * @tag:
+ * @tag: an #hb_tag_t representing an ISO 15924 tag.
*
- *
+ * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
*
* Return value:
+ * An #hb_script_t corresponding to the ISO 15924 tag.
*
* Since: 0.9.2
**/
@@ -401,28 +407,33 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
/**
* hb_script_from_string:
- * @s: (array length=len) (element-type uint8_t):
- * @len:
+ * @str: (array length=len) (element-type uint8_t): a string representing an
+ * ISO 15924 tag.
+ * @len: length of the @str, or -1 if it is %NULL-terminated.
*
- *
+ * Converts a string @str representing an ISO 15924 script tag to a
+ * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
+ * hb_script_from_iso15924_tag().
*
* Return value:
+ * An #hb_script_t corresponding to the ISO 15924 tag.
*
* Since: 0.9.2
**/
hb_script_t
-hb_script_from_string (const char *s, int len)
+hb_script_from_string (const char *str, int len)
{
- return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
+ return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
}
/**
* hb_script_to_iso15924_tag:
- * @script:
+ * @script: an #hb_script_ to convert.
*
- *
+ * See hb_script_from_iso15924_tag().
*
- * Return value:
+ * Return value:
+ * An #hb_tag_t representing an ISO 15924 script tag.
*
* Since: 0.9.2
**/
@@ -496,6 +507,9 @@ hb_script_get_horizontal_direction (hb_script_t script)
/* Unicode-8.0 additions */
case HB_SCRIPT_OLD_HUNGARIAN:
+ /* Unicode-9.0 additions */
+ case HB_SCRIPT_ADLAM:
+
return HB_DIRECTION_RTL;
}
@@ -521,7 +535,7 @@ hb_user_data_array_t::set (hb_user_data_key_t *key,
}
}
hb_user_data_item_t item = {key, data, destroy};
- bool ret = !!items.replace_or_insert (item, lock, replace);
+ bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
return ret;
}
@@ -529,7 +543,7 @@ hb_user_data_array_t::set (hb_user_data_key_t *key,
void *
hb_user_data_array_t::get (hb_user_data_key_t *key)
{
- hb_user_data_item_t item = {NULL };
+ hb_user_data_item_t item = {NULL, NULL, NULL};
return items.find (key, &item, lock) ? item.data : NULL;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.h b/src/3rdparty/harfbuzz-ng/src/hb-common.h
index c291dbbe94..2cbee76a8f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-common.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-common.h
@@ -98,16 +98,22 @@ typedef uint32_t hb_tag_t;
#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
/* len=-1 means str is NUL-terminated. */
-hb_tag_t
+HB_EXTERN hb_tag_t
hb_tag_from_string (const char *str, int len);
/* buf should have 4 bytes. */
-void
+HB_EXTERN void
hb_tag_to_string (hb_tag_t tag, char *buf);
-/* hb_direction_t */
-
+/**
+ * hb_direction_t:
+ * @HB_DIRECTION_INVALID: Initial, unset direction.
+ * @HB_DIRECTION_LTR: Text is set horizontally from left to right.
+ * @HB_DIRECTION_RTL: Text is set horizontally from right to left.
+ * @HB_DIRECTION_TTB: Text is set vertically from top to bottom.
+ * @HB_DIRECTION_BTT: Text is set vertically from bottom to top.
+ */
typedef enum {
HB_DIRECTION_INVALID = 0,
HB_DIRECTION_LTR = 4,
@@ -117,10 +123,10 @@ typedef enum {
} hb_direction_t;
/* len=-1 means str is NUL-terminated */
-hb_direction_t
+HB_EXTERN hb_direction_t
hb_direction_from_string (const char *str, int len);
-const char *
+HB_EXTERN const char *
hb_direction_to_string (hb_direction_t direction);
#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4)
@@ -136,16 +142,15 @@ hb_direction_to_string (hb_direction_t direction);
typedef const struct hb_language_impl_t *hb_language_t;
-/* len=-1 means str is NUL-terminated */
-hb_language_t
+HB_EXTERN hb_language_t
hb_language_from_string (const char *str, int len);
-const char *
+HB_EXTERN const char *
hb_language_to_string (hb_language_t language);
#define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
-hb_language_t
+HB_EXTERN hb_language_t
hb_language_get_default (void);
@@ -299,12 +304,22 @@ typedef enum
/*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'),
/*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'),
- /*8.0*/ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'),
- /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'),
- /*8.0*/ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'),
- /*8.0*/ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'),
- /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'),
- /*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'),
+ /*8.0*/ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'),
+ /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'),
+ /*8.0*/ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'),
+ /*8.0*/ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'),
+ /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'),
+ /*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'),
+
+ /*
+ * Since 1.3.0
+ */
+ /*9.0*/ HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'),
+ /*9.0*/ HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'),
+ /*9.0*/ HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'),
+ /*9.0*/ HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'),
+ /*9.0*/ HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'),
+ /*9.0*/ HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'),
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
@@ -324,18 +339,16 @@ typedef enum
/* Script functions */
-hb_script_t
+HB_EXTERN hb_script_t
hb_script_from_iso15924_tag (hb_tag_t tag);
-/* sugar for tag_from_string() then script_from_iso15924_tag */
-/* len=-1 means s is NUL-terminated */
-hb_script_t
-hb_script_from_string (const char *s, int len);
+HB_EXTERN hb_script_t
+hb_script_from_string (const char *str, int len);
-hb_tag_t
+HB_EXTERN hb_tag_t
hb_script_to_iso15924_tag (hb_script_t script);
-hb_direction_t
+HB_EXTERN hb_direction_t
hb_script_get_horizontal_direction (hb_script_t script);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc b/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc
index 76c81e48f4..9865bbba41 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc
@@ -27,7 +27,6 @@
*/
#define HB_SHAPER coretext
-#define hb_coretext_shaper_face_data_t CGFont
#include "hb-shaper-impl-private.hh"
#include "hb-coretext.h"
@@ -91,6 +90,29 @@ HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
* shaper face data
*/
+static CTFontDescriptorRef
+get_last_resort_font_desc (void)
+{
+ // TODO Handle allocation failures?
+ CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
+ CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
+ (const void **) &last_resort,
+ 1,
+ &kCFTypeArrayCallBacks);
+ CFRelease (last_resort);
+ CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+ (const void **) &kCTFontCascadeListAttribute,
+ (const void **) &cascade_list,
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFRelease (cascade_list);
+
+ CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+ CFRelease (attributes);
+ return font_desc;
+}
+
static void
release_data (void *info, const void *data, size_t size)
{
@@ -100,15 +122,14 @@ release_data (void *info, const void *data, size_t size)
hb_blob_destroy ((hb_blob_t *) info);
}
-hb_coretext_shaper_face_data_t *
-_hb_coretext_shaper_face_data_create (hb_face_t *face)
+static CGFontRef
+create_cg_font (hb_face_t *face)
{
- hb_coretext_shaper_face_data_t *data = NULL;
-
+ CGFontRef cg_font = NULL;
#if 0
if (face->destroy == (hb_destroy_func_t) CGFontRelease)
{
- data = CGFontRetain ((CGFontRef) face->user_data);
+ cg_font = CGFontRetain ((CGFontRef) face->user_data);
}
else
{
@@ -121,18 +142,119 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
if (likely (provider))
{
- data = CGFontCreateWithDataProvider (provider);
+ cg_font = CGFontCreateWithDataProvider (provider);
+ if (unlikely (!cg_font))
+ DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
CGDataProviderRelease (provider);
}
}
#else
FontEngineFaceData *fontEngineFaceData = (FontEngineFaceData *) face->user_data;
CoreTextFontEngineData *coreTextFontEngineData = (CoreTextFontEngineData *) fontEngineFaceData->user_data;
- data = CGFontRetain (coreTextFontEngineData->cgFont);
+ cg_font = CGFontRetain (coreTextFontEngineData->cgFont);
#endif
+ return cg_font;
+}
+
+static CTFontRef
+create_ct_font (CGFontRef cg_font, CGFloat font_size)
+{
+ CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
+ if (unlikely (!ct_font)) {
+ DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
+ return NULL;
+ }
+
+ /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
+ * bug indicate that the cascade list reconfiguration occasionally causes
+ * crashes in CoreText on OS X 10.9, thus let's skip this step on older
+ * operating system versions. Except for the emoji font, where _not_
+ * reconfiguring the cascade list causes CoreText crashes. For details, see
+ * crbug.com/549610 */
+ // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
+ if (&CTGetCoreTextVersion != NULL && CTGetCoreTextVersion() < 0x00070000) {
+ CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
+ bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
+ CFRelease (fontName);
+ if (!isEmojiFont)
+ return ct_font;
+ }
+
+ CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute);
+
+ /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
+ * font fallback which we don't need anyway. */
+ {
+ CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
+ CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, last_resort_font_desc);
+ CFRelease (last_resort_font_desc);
+ if (new_ct_font)
+ {
+ /* The CTFontCreateCopyWithAttributes call fails to stay on the same font
+ * when reconfiguring the cascade list and may switch to a different font
+ * when there are fonts that go by the same name, since the descriptor is
+ * just name and size.
+ *
+ * Avoid reconfiguring the cascade lists if the new font is outside the
+ * system locations that we cannot access from the sandboxed renderer
+ * process in Blink. This can be detected by the new file URL location
+ * that the newly found font points to. */
+ CFURLRef new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
+ // Keep reconfigured font if URL cannot be retrieved (seems to be the case
+ // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
+ if (!original_url || !new_url || CFEqual (original_url, new_url)) {
+ CFRelease (ct_font);
+ ct_font = new_ct_font;
+ } else {
+ CFRelease (new_ct_font);
+ DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
+ }
+ if (new_url)
+ CFRelease (new_url);
+ }
+ else
+ DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
+ }
+
+ if (original_url)
+ CFRelease (original_url);
+ return ct_font;
+}
+
+struct hb_coretext_shaper_face_data_t {
+ CGFontRef cg_font;
+ CTFontRef ct_font;
+};
+
+hb_coretext_shaper_face_data_t *
+_hb_coretext_shaper_face_data_create (hb_face_t *face)
+{
+ hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
+ if (unlikely (!data))
+ return NULL;
+
+ data->cg_font = create_cg_font (face);
+ if (unlikely (!data->cg_font))
+ {
+ DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
+ free (data);
+ return NULL;
+ }
- if (unlikely (!data)) {
- DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
+ /* We use 36pt size instead of UPEM, because CoreText implements the 'trak' table,
+ * which can make the font too tight at large sizes. 36pt should be a good semi-neutral
+ * size.
+ *
+ * Since we always create CTFont at a fixed size, our CTFont lives in face_data
+ * instead of font_data. Which is good, because when people change scale on
+ * hb_font_t, we won't need to update our CTFont. */
+ data->ct_font = create_ct_font (data->cg_font, 36.);
+ if (unlikely (!data->ct_font))
+ {
+ DEBUG_MSG (CORETEXT, face, "CTFont creation failed.");
+ CFRelease (data->cg_font);
+ free (data);
+ return NULL;
}
return data;
@@ -141,7 +263,9 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
void
_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
{
- CFRelease (data);
+ CFRelease (data->ct_font);
+ CFRelease (data->cg_font);
+ free (data);
}
/*
@@ -152,7 +276,7 @@ hb_coretext_face_get_cg_font (hb_face_t *face)
{
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
- return face_data;
+ return face_data->cg_font;
}
@@ -160,56 +284,17 @@ hb_coretext_face_get_cg_font (hb_face_t *face)
* shaper font data
*/
-struct hb_coretext_shaper_font_data_t {
- CTFontRef ct_font;
- CGFloat x_mult, y_mult; /* From CT space to HB space. */
-};
+struct hb_coretext_shaper_font_data_t {};
hb_coretext_shaper_font_data_t *
-_hb_coretext_shaper_font_data_create (hb_font_t *font)
+_hb_coretext_shaper_font_data_create (hb_font_t *font HB_UNUSED)
{
- if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
-
- hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
- if (unlikely (!data))
- return NULL;
-
- hb_face_t *face = font->face;
-#if 0
- hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-
- /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */
- /* TODO: use upem instead of 36? */
- CGFloat font_size = 36.; /* Default... */
- /* No idea if the following is even a good idea. */
- if (font->y_ppem)
- font_size = font->y_ppem;
-
- if (font_size < 0)
- font_size = -font_size;
- data->x_mult = (CGFloat) font->x_scale / font_size;
- data->y_mult = (CGFloat) font->y_scale / font_size;
- data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL);
-#else
- data->x_mult = data->y_mult = (CGFloat) 64.0f;
- FontEngineFaceData *fontEngineFaceData = (FontEngineFaceData *) face->user_data;
- CoreTextFontEngineData *coreTextFontEngineData = (CoreTextFontEngineData *) fontEngineFaceData->user_data;
- data->ct_font = (CTFontRef) CFRetain (coreTextFontEngineData->ctFont);
-#endif
- if (unlikely (!data->ct_font)) {
- DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
- free (data);
- return NULL;
- }
-
- return data;
+ return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
{
- CFRelease (data->ct_font);
- free (data);
}
@@ -222,7 +307,9 @@ struct hb_coretext_shaper_shape_plan_data_t {};
hb_coretext_shaper_shape_plan_data_t *
_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
- unsigned int num_user_features HB_UNUSED)
+ unsigned int num_user_features HB_UNUSED,
+ const int *coords HB_UNUSED,
+ unsigned int num_coords HB_UNUSED)
{
return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
@@ -235,9 +322,10 @@ _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
- if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
- hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
- return font_data->ct_font;
+ hb_face_t *face = font->face;
+ if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
+ hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+ return face_data->ct_font;
}
@@ -470,7 +558,10 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
{
hb_face_t *face = font->face;
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
- hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+ CGFloat ct_font_size = CTFontGetSize (face_data->ct_font);
+ CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
+ CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
/* Attach marks to their bases, to match the 'ot' shaper.
* Adapted from hb-ot-shape:hb_form_clusters().
@@ -479,6 +570,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
* B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
* continue pointing to B2 even though B2 was merged into B1's
* cluster... */
+ if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
{
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int count = buffer->len;
@@ -601,7 +693,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
CFRelease (attributes);
- range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
+ range->font = CTFontCreateCopyWithAttributes (face_data->ct_font, 0.0, NULL, font_desc);
CFRelease (font_desc);
}
else
@@ -662,7 +754,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
pchars[chars_len++] = 0xFFFDu;
else {
pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
- pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
+ pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
}
}
@@ -719,7 +811,6 @@ resize_and_retry:
scratch += old_scratch_used;
scratch_size -= old_scratch_used;
}
-retry:
{
string_ref = CFStringCreateWithCharactersNoCopy (NULL,
pchars, chars_len,
@@ -759,7 +850,7 @@ retry:
CFRelease (lang);
}
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
- kCTFontAttributeName, font_data->ct_font);
+ kCTFontAttributeName, face_data->ct_font);
if (num_features)
{
@@ -844,8 +935,6 @@ retry:
run_advance = -run_advance;
DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
- CFRange range = CTRunGetStringRange (run);
-
/* CoreText does automatic font fallback (AKA "cascading") for characters
* not supported by the requested font, and provides no way to turn it off,
* so we must detect if the returned run uses a font other than the requested
@@ -854,7 +943,7 @@ retry:
*/
CFDictionaryRef attributes = CTRunGetAttributes (run);
CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
- if (!CFEqual (run_ct_font, font_data->ct_font))
+ if (!CFEqual (run_ct_font, face_data->ct_font))
{
/* The run doesn't use our main font instance. We have to figure out
* whether font fallback happened, or this is just CoreText giving us
@@ -874,15 +963,11 @@ retry:
* backend.
*
* However, even that wouldn't work if we were passed in the CGFont to
- * begin with.
- *
- * Webkit uses a slightly different approach: it installs LastResort
- * as fallback chain, and then checks PS name of used font against
- * LastResort. That one is safe for any font except for LastResort,
- * as opposed to ours, which can fail if we are using any uninstalled
- * font that has the same name as an installed font.
+ * construct a hb_face to begin with.
*
* See: http://github.com/behdad/harfbuzz/pull/36
+ *
+ * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
*/
bool matched = false;
for (unsigned int i = 0; i < range_records.len; i++)
@@ -896,13 +981,13 @@ retry:
CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
if (run_cg_font)
{
- matched = CFEqual (run_cg_font, face_data);
+ matched = CFEqual (run_cg_font, face_data->cg_font);
CFRelease (run_cg_font);
}
}
if (!matched)
{
- CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
+ CFStringRef font_ps_name = CTFontCopyName (face_data->ct_font, kCTFontPostScriptNameKey);
CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
CFRelease (run_ps_name);
@@ -912,6 +997,7 @@ retry:
}
if (!matched)
{
+ CFRange range = CTRunGetStringRange (run);
DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
range.location, range.location + range.length);
if (!buffer->ensure_inplace (buffer->len + range.length))
@@ -963,13 +1049,7 @@ retry:
if (num_glyphs == 0)
continue;
- /* ### temporary fix for QTBUG-38113 */
- /* CoreText throws away the PDF token, while the OpenType backend will add a zero-advance
- * glyph for this. We need to make sure the two produce the same output. */
- UniChar endGlyph = CFStringGetCharacterAtIndex (string_ref, range.location + range.length - 1);
- bool endsWithPDF = endGlyph == 0x202c;
-
- if (!buffer->ensure_inplace (buffer->len + num_glyphs + (endsWithPDF ? 1 : 0)))
+ if (!buffer->ensure_inplace (buffer->len + num_glyphs))
goto resize_and_retry;
hb_glyph_info_t *run_info = buffer->info + buffer->len;
@@ -1027,7 +1107,6 @@ retry:
positions = position_buf;
}
hb_glyph_info_t *info = run_info;
- CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
@@ -1060,20 +1139,6 @@ retry:
info++;
}
}
- if (endsWithPDF) {
- /* Ensure a zero-advance glyph the PDF token */
- if (unlikely (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))) {
- memmove (run_info + 1, run_info, num_glyphs * sizeof (hb_glyph_info_t));
- info = run_info;
- }
- info->codepoint = 0xffff;
- info->cluster = log_clusters[range.location + range.length - 1];
- info->mask = 0;
- info->var1.u32 = 0;
- info->var2.u32 = 0;
-
- buffer->len++;
- }
SCRATCH_RESTORE();
advances_so_far += run_advance;
}
@@ -1176,10 +1241,6 @@ fail:
* AAT shaper
*/
-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
-HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
-
-
/*
* shaper face data
*/
@@ -1240,7 +1301,9 @@ struct hb_coretext_aat_shaper_shape_plan_data_t {};
hb_coretext_aat_shaper_shape_plan_data_t *
_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
- unsigned int num_user_features HB_UNUSED)
+ unsigned int num_user_features HB_UNUSED,
+ const int *coords HB_UNUSED,
+ unsigned int num_coords HB_UNUSED)
{
return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-coretext.h b/src/3rdparty/harfbuzz-ng/src/hb-coretext.h
index 25267bc978..82066e4e0d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-coretext.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-coretext.h
@@ -44,14 +44,14 @@ HB_BEGIN_DECLS
#define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
-hb_face_t *
+HB_EXTERN hb_face_t *
hb_coretext_face_create (CGFontRef cg_font);
-CGFontRef
+HB_EXTERN CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face);
-CTFontRef
+HB_EXTERN CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h b/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h
index 30ae4b1caf..0398dfae60 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h
@@ -44,6 +44,16 @@ HB_BEGIN_DECLS
#define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT
#define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT HB_BUFFER_SERIALIZE_FLAG_DEFAULT
+typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph,
+ void *user_data);
+
+HB_EXTERN void
+hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
#endif
HB_END_DECLS
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-face.cc b/src/3rdparty/harfbuzz-ng/src/hb-face.cc
index 9effc41c88..6b563bc8f1 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-face.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-face.cc
@@ -35,8 +35,6 @@
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
-#include "hb-cache-private.hh"
-
#include <string.h>
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-face.h b/src/3rdparty/harfbuzz-ng/src/hb-face.h
index f682c468de..91237b7085 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-face.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-face.h
@@ -43,28 +43,28 @@ HB_BEGIN_DECLS
typedef struct hb_face_t hb_face_t;
-hb_face_t *
+HB_EXTERN hb_face_t *
hb_face_create (hb_blob_t *blob,
unsigned int index);
typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data);
/* calls destroy() when not needing user_data anymore */
-hb_face_t *
+HB_EXTERN hb_face_t *
hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
void *user_data,
hb_destroy_func_t destroy);
-hb_face_t *
+HB_EXTERN hb_face_t *
hb_face_get_empty (void);
-hb_face_t *
+HB_EXTERN hb_face_t *
hb_face_reference (hb_face_t *face);
-void
+HB_EXTERN void
hb_face_destroy (hb_face_t *face);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_face_set_user_data (hb_face_t *face,
hb_user_data_key_t *key,
void * data,
@@ -72,43 +72,43 @@ hb_face_set_user_data (hb_face_t *face,
hb_bool_t replace);
-void *
+HB_EXTERN void *
hb_face_get_user_data (hb_face_t *face,
hb_user_data_key_t *key);
-void
+HB_EXTERN void
hb_face_make_immutable (hb_face_t *face);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_face_is_immutable (hb_face_t *face);
-hb_blob_t *
+HB_EXTERN hb_blob_t *
hb_face_reference_table (hb_face_t *face,
hb_tag_t tag);
-hb_blob_t *
+HB_EXTERN hb_blob_t *
hb_face_reference_blob (hb_face_t *face);
-void
+HB_EXTERN void
hb_face_set_index (hb_face_t *face,
unsigned int index);
-unsigned int
+HB_EXTERN unsigned int
hb_face_get_index (hb_face_t *face);
-void
+HB_EXTERN void
hb_face_set_upem (hb_face_t *face,
unsigned int upem);
-unsigned int
+HB_EXTERN unsigned int
hb_face_get_upem (hb_face_t *face);
-void
+HB_EXTERN void
hb_face_set_glyph_count (hb_face_t *face,
unsigned int glyph_count);
-unsigned int
+HB_EXTERN unsigned int
hb_face_get_glyph_count (hb_face_t *face);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-fallback-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-fallback-shape.cc
new file mode 100644
index 0000000000..ac6d4b00f5
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-fallback-shape.cc
@@ -0,0 +1,143 @@
+/*
+ * Copyright © 2011 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#define HB_SHAPER fallback
+#include "hb-shaper-impl-private.hh"
+
+
+/*
+ * shaper face data
+ */
+
+struct hb_fallback_shaper_face_data_t {};
+
+hb_fallback_shaper_face_data_t *
+_hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED)
+{
+ return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_fallback_shaper_font_data_t {};
+
+hb_fallback_shaper_font_data_t *
+_hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+{
+ return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_fallback_shaper_shape_plan_data_t {};
+
+hb_fallback_shaper_shape_plan_data_t *
+_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
+ const hb_feature_t *user_features HB_UNUSED,
+ unsigned int num_user_features HB_UNUSED,
+ const int *coords HB_UNUSED,
+ unsigned int num_coords HB_UNUSED)
+{
+ return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features HB_UNUSED,
+ unsigned int num_features HB_UNUSED)
+{
+ /* TODO
+ *
+ * - Apply fallback kern.
+ * - Handle Variation Selectors?
+ * - Apply normalization?
+ *
+ * This will make the fallback shaper into a dumb "TrueType"
+ * shaper which many people unfortunately still request.
+ */
+
+ hb_codepoint_t space;
+ bool has_space = (bool) font->get_nominal_glyph (' ', &space);
+
+ buffer->clear_positions ();
+
+ hb_direction_t direction = buffer->props.direction;
+ hb_unicode_funcs_t *unicode = buffer->unicode;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pos = buffer->pos;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (has_space && unicode->is_default_ignorable (info[i].codepoint)) {
+ info[i].codepoint = space;
+ pos[i].x_advance = 0;
+ pos[i].y_advance = 0;
+ continue;
+ }
+ font->get_nominal_glyph (info[i].codepoint, &info[i].codepoint);
+ font->get_glyph_advance_for_direction (info[i].codepoint,
+ direction,
+ &pos[i].x_advance,
+ &pos[i].y_advance);
+ font->subtract_glyph_origin_for_direction (info[i].codepoint,
+ direction,
+ &pos[i].x_offset,
+ &pos[i].y_offset);
+ }
+
+ if (HB_DIRECTION_IS_BACKWARD (direction))
+ hb_buffer_reverse (buffer);
+
+ return true;
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-font-private.hh
index c05499d4c2..53671d78d2 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-font-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-font-private.hh
@@ -42,7 +42,10 @@
*/
#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
- HB_FONT_FUNC_IMPLEMENT (glyph) \
+ HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
+ HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
+ HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
+ HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
@@ -61,14 +64,6 @@ struct hb_font_funcs_t {
hb_bool_t immutable;
- /* Don't access these directly. Call hb_font_get_*() instead. */
-
- struct {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
- } get;
-
struct {
#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
@@ -80,6 +75,16 @@ struct hb_font_funcs_t {
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} destroy;
+
+ /* Don't access these directly. Call font->get_*() instead. */
+ union get_t {
+ struct get_funcs_t {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+ } f;
+ void (*array[VAR]) (void);
+ } get;
};
@@ -103,6 +108,10 @@ struct hb_font_t {
unsigned int x_ppem;
unsigned int y_ppem;
+ /* Font variation coordinates. */
+ unsigned int num_coords;
+ int *coords;
+
hb_font_funcs_t *klass;
void *user_data;
hb_destroy_func_t destroy;
@@ -111,8 +120,14 @@ struct hb_font_t {
/* Convert from font-space to user-space */
- inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
- inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, this->y_scale); }
+ inline int dir_scale (hb_direction_t direction)
+ { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
+ inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
+ inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
+ inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
+ inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
+ inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
+ { return em_scale (v, dir_scale (direction)); }
/* Convert from parent-font user-space to our user-space */
inline hb_position_t parent_scale_x_distance (hb_position_t v) {
@@ -144,95 +159,133 @@ struct hb_font_t {
/* Public getters */
- inline hb_bool_t has_glyph (hb_codepoint_t unicode)
+ HB_INTERNAL bool has_func (unsigned int i);
+
+ /* has_* ... */
+#define HB_FONT_FUNC_IMPLEMENT(name) \
+ bool \
+ has_##name##_func (void) \
+ { \
+ hb_font_funcs_t *funcs = this->klass; \
+ unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
+ return has_func (i); \
+ }
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+
+ inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
+ {
+ memset (extents, 0, sizeof (*extents));
+ return klass->get.f.font_h_extents (this, user_data,
+ extents,
+ klass->user_data.font_h_extents);
+ }
+ inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
+ {
+ memset (extents, 0, sizeof (*extents));
+ return klass->get.f.font_v_extents (this, user_data,
+ extents,
+ klass->user_data.font_v_extents);
+ }
+
+ inline bool has_glyph (hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
- return get_glyph (unicode, 0, &glyph);
+ return get_nominal_glyph (unicode, &glyph);
}
- inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
- hb_codepoint_t *glyph)
+ inline hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
+ hb_codepoint_t *glyph)
{
*glyph = 0;
- return klass->get.glyph (this, user_data,
- unicode, variation_selector, glyph,
- klass->user_data.glyph);
+ return klass->get.f.nominal_glyph (this, user_data,
+ unicode, glyph,
+ klass->user_data.nominal_glyph);
+ }
+
+ inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph)
+ {
+ *glyph = 0;
+ return klass->get.f.variation_glyph (this, user_data,
+ unicode, variation_selector, glyph,
+ klass->user_data.variation_glyph);
}
inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
{
- return klass->get.glyph_h_advance (this, user_data,
- glyph,
- klass->user_data.glyph_h_advance);
+ return klass->get.f.glyph_h_advance (this, user_data,
+ glyph,
+ klass->user_data.glyph_h_advance);
}
inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
{
- return klass->get.glyph_v_advance (this, user_data,
- glyph,
- klass->user_data.glyph_v_advance);
+ return klass->get.f.glyph_v_advance (this, user_data,
+ glyph,
+ klass->user_data.glyph_v_advance);
}
inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
- return klass->get.glyph_h_origin (this, user_data,
- glyph, x, y,
- klass->user_data.glyph_h_origin);
+ return klass->get.f.glyph_h_origin (this, user_data,
+ glyph, x, y,
+ klass->user_data.glyph_h_origin);
}
inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
- return klass->get.glyph_v_origin (this, user_data,
- glyph, x, y,
- klass->user_data.glyph_v_origin);
+ return klass->get.f.glyph_v_origin (this, user_data,
+ glyph, x, y,
+ klass->user_data.glyph_v_origin);
}
inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
{
- return klass->get.glyph_h_kerning (this, user_data,
- left_glyph, right_glyph,
- klass->user_data.glyph_h_kerning);
+ return klass->get.f.glyph_h_kerning (this, user_data,
+ left_glyph, right_glyph,
+ klass->user_data.glyph_h_kerning);
}
inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
{
- return klass->get.glyph_v_kerning (this, user_data,
- top_glyph, bottom_glyph,
- klass->user_data.glyph_v_kerning);
+ return klass->get.f.glyph_v_kerning (this, user_data,
+ top_glyph, bottom_glyph,
+ klass->user_data.glyph_v_kerning);
}
inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
hb_glyph_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
- return klass->get.glyph_extents (this, user_data,
- glyph,
- extents,
- klass->user_data.glyph_extents);
+ return klass->get.f.glyph_extents (this, user_data,
+ glyph,
+ extents,
+ klass->user_data.glyph_extents);
}
inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
- return klass->get.glyph_contour_point (this, user_data,
- glyph, point_index,
- x, y,
- klass->user_data.glyph_contour_point);
+ return klass->get.f.glyph_contour_point (this, user_data,
+ glyph, point_index,
+ x, y,
+ klass->user_data.glyph_contour_point);
}
inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
char *name, unsigned int size)
{
if (size) *name = '\0';
- return klass->get.glyph_name (this, user_data,
- glyph,
- name, size,
- klass->user_data.glyph_name);
+ return klass->get.f.glyph_name (this, user_data,
+ glyph,
+ name, size,
+ klass->user_data.glyph_name);
}
inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
@@ -240,15 +293,43 @@ struct hb_font_t {
{
*glyph = 0;
if (len == -1) len = strlen (name);
- return klass->get.glyph_from_name (this, user_data,
- name, len,
- glyph,
- klass->user_data.glyph_from_name);
+ return klass->get.f.glyph_from_name (this, user_data,
+ name, len,
+ glyph,
+ klass->user_data.glyph_from_name);
}
/* A bit higher-level, and with fallback */
+ inline void get_h_extents_with_fallback (hb_font_extents_t *extents)
+ {
+ if (!get_font_h_extents (extents))
+ {
+ extents->ascender = y_scale * .8;
+ extents->descender = extents->ascender - y_scale;
+ extents->line_gap = 0;
+ }
+ }
+ inline void get_v_extents_with_fallback (hb_font_extents_t *extents)
+ {
+ if (!get_font_v_extents (extents))
+ {
+ extents->ascender = x_scale / 2;
+ extents->descender = extents->ascender - x_scale;
+ extents->line_gap = 0;
+ }
+ }
+
+ inline void get_extents_for_direction (hb_direction_t direction,
+ hb_font_extents_t *extents)
+ {
+ if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+ get_h_extents_with_fallback (extents);
+ else
+ get_v_extents_with_fallback (extents);
+ }
+
inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
@@ -262,14 +343,38 @@ struct hb_font_t {
}
}
- /* Internal only */
inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = get_glyph_h_advance (glyph) / 2;
- /* TODO use font_metrics.ascent */
- *y = y_scale;
+ /* TODO cache this somehow?! */
+ hb_font_extents_t extents;
+ get_h_extents_with_fallback (&extents);
+ *y = extents.ascender;
+ }
+
+ inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ if (!get_glyph_h_origin (glyph, x, y) &&
+ get_glyph_v_origin (glyph, x, y))
+ {
+ hb_position_t dx, dy;
+ guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+ *x -= dx; *y -= dy;
+ }
+ }
+ inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ if (!get_glyph_v_origin (glyph, x, y) &&
+ get_glyph_h_origin (glyph, x, y))
+ {
+ hb_position_t dx, dy;
+ guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+ *x += dx; *y += dy;
+ }
}
inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
@@ -277,27 +382,31 @@ struct hb_font_t {
hb_position_t *x, hb_position_t *y)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
- {
- if (!get_glyph_h_origin (glyph, x, y) &&
- get_glyph_v_origin (glyph, x, y))
- {
- hb_position_t dx, dy;
- guess_v_origin_minus_h_origin (glyph, &dx, &dy);
- *x -= dx; *y -= dy;
- }
- }
+ get_glyph_h_origin_with_fallback (glyph, x, y);
else
- {
- if (!get_glyph_v_origin (glyph, x, y) &&
- get_glyph_h_origin (glyph, x, y))
- {
- hb_position_t dx, dy;
- guess_v_origin_minus_h_origin (glyph, &dx, &dy);
- *x += dx; *y += dy;
- }
- }
+ get_glyph_v_origin_with_fallback (glyph, x, y);
}
+ inline void add_glyph_h_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ hb_position_t origin_x, origin_y;
+
+ get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
+
+ *x += origin_x;
+ *y += origin_y;
+ }
+ inline void add_glyph_v_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ hb_position_t origin_x, origin_y;
+
+ get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
+
+ *x += origin_x;
+ *y += origin_y;
+ }
inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
@@ -310,6 +419,26 @@ struct hb_font_t {
*y += origin_y;
}
+ inline void subtract_glyph_h_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ hb_position_t origin_x, origin_y;
+
+ get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
+
+ *x -= origin_x;
+ *y -= origin_y;
+ }
+ inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ hb_position_t origin_x, origin_y;
+
+ get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
+
+ *x -= origin_x;
+ *y -= origin_y;
+ }
inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
@@ -394,15 +523,24 @@ struct hb_font_t {
hb_codepoint_t unichar;
if (0 == strncmp (s, "uni", 3) &&
hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
- get_glyph (unichar, 0, glyph))
+ get_nominal_glyph (unichar, glyph))
return true;
}
return false;
}
- private:
- inline hb_position_t em_scale (int16_t v, int scale) { return (hb_position_t) (v * (int64_t) scale / face->get_upem ()); }
+ inline hb_position_t em_scale (int16_t v, int scale)
+ {
+ int upem = face->get_upem ();
+ int64_t scaled = v * (int64_t) scale;
+ scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
+ return (hb_position_t) (scaled / upem);
+ }
+ inline hb_position_t em_scalef (float v, int scale)
+ {
+ return (hb_position_t) (v * scale / face->get_upem ());
+ }
};
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-font.cc
index 6a69cae313..2935c4b4fd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-font.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-font.cc
@@ -35,8 +35,6 @@
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
-#include "hb-cache-private.hh"
-
#include <string.h>
@@ -45,130 +43,246 @@
*/
static hb_bool_t
-hb_font_get_glyph_nil (hb_font_t *font,
- void *font_data HB_UNUSED,
- hb_codepoint_t unicode,
- hb_codepoint_t variation_selector,
- hb_codepoint_t *glyph,
- void *user_data HB_UNUSED)
+hb_font_get_font_h_extents_nil (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_font_extents_t *metrics,
+ void *user_data HB_UNUSED)
{
- if (font->parent)
- return font->parent->get_glyph (unicode, variation_selector, glyph);
+ memset (metrics, 0, sizeof (*metrics));
+ return false;
+}
+static hb_bool_t
+hb_font_get_font_h_extents_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_font_extents_t *metrics,
+ void *user_data HB_UNUSED)
+{
+ hb_bool_t ret = font->parent->get_font_h_extents (metrics);
+ if (ret) {
+ metrics->ascender = font->parent_scale_y_distance (metrics->ascender);
+ metrics->descender = font->parent_scale_y_distance (metrics->descender);
+ metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap);
+ }
+ return ret;
+}
+static hb_bool_t
+hb_font_get_font_v_extents_nil (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_font_extents_t *metrics,
+ void *user_data HB_UNUSED)
+{
+ memset (metrics, 0, sizeof (*metrics));
+ return false;
+}
+static hb_bool_t
+hb_font_get_font_v_extents_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_font_extents_t *metrics,
+ void *user_data HB_UNUSED)
+{
+ hb_bool_t ret = font->parent->get_font_v_extents (metrics);
+ if (ret) {
+ metrics->ascender = font->parent_scale_x_distance (metrics->ascender);
+ metrics->descender = font->parent_scale_x_distance (metrics->descender);
+ metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap);
+ }
+ return ret;
+}
+
+static hb_bool_t
+hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+{
*glyph = 0;
return false;
}
+static hb_bool_t
+hb_font_get_nominal_glyph_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+{
+ return font->parent->get_nominal_glyph (unicode, glyph);
+}
+
+static hb_bool_t
+hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+{
+ *glyph = 0;
+ return false;
+}
+static hb_bool_t
+hb_font_get_variation_glyph_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+{
+ return font->parent->get_variation_glyph (unicode, variation_selector, glyph);
+}
+
static hb_position_t
-hb_font_get_glyph_h_advance_nil (hb_font_t *font,
+hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
- if (font->parent)
- return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
-
return font->x_scale;
}
+static hb_position_t
+hb_font_get_glyph_h_advance_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ void *user_data HB_UNUSED)
+{
+ return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
+}
static hb_position_t
-hb_font_get_glyph_v_advance_nil (hb_font_t *font,
+hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
- if (font->parent)
- return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
-
+ /* TODO use font_extents.ascender+descender */
return font->y_scale;
}
+static hb_position_t
+hb_font_get_glyph_v_advance_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ void *user_data HB_UNUSED)
+{
+ return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
+}
static hb_bool_t
-hb_font_get_glyph_h_origin_nil (hb_font_t *font,
+hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
- if (font->parent) {
- hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
- if (ret)
- font->parent_scale_position (x, y);
- return ret;
- }
-
*x = *y = 0;
- return false;
+ return true;
+}
+static hb_bool_t
+hb_font_get_glyph_h_origin_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_position_t *x,
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+{
+ hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
+ if (ret)
+ font->parent_scale_position (x, y);
+ return ret;
}
static hb_bool_t
-hb_font_get_glyph_v_origin_nil (hb_font_t *font,
+hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
- if (font->parent) {
- hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
- if (ret)
- font->parent_scale_position (x, y);
- return ret;
- }
-
*x = *y = 0;
return false;
}
+static hb_bool_t
+hb_font_get_glyph_v_origin_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_position_t *x,
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+{
+ hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
+ if (ret)
+ font->parent_scale_position (x, y);
+ return ret;
+}
static hb_position_t
-hb_font_get_glyph_h_kerning_nil (hb_font_t *font,
+hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
- if (font->parent)
- return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
-
return 0;
}
+static hb_position_t
+hb_font_get_glyph_h_kerning_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t left_glyph,
+ hb_codepoint_t right_glyph,
+ void *user_data HB_UNUSED)
+{
+ return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
+}
static hb_position_t
-hb_font_get_glyph_v_kerning_nil (hb_font_t *font,
+hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t top_glyph,
hb_codepoint_t bottom_glyph,
void *user_data HB_UNUSED)
{
- if (font->parent)
- return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
-
return 0;
}
+static hb_position_t
+hb_font_get_glyph_v_kerning_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t top_glyph,
+ hb_codepoint_t bottom_glyph,
+ void *user_data HB_UNUSED)
+{
+ return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
+}
static hb_bool_t
-hb_font_get_glyph_extents_nil (hb_font_t *font,
+hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
- if (font->parent) {
- hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
- if (ret) {
- font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
- font->parent_scale_distance (&extents->width, &extents->height);
- }
- return ret;
- }
-
memset (extents, 0, sizeof (*extents));
return false;
}
+static hb_bool_t
+hb_font_get_glyph_extents_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ hb_glyph_extents_t *extents,
+ void *user_data HB_UNUSED)
+{
+ hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
+ if (ret) {
+ font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
+ font->parent_scale_distance (&extents->width, &extents->height);
+ }
+ return ret;
+}
static hb_bool_t
-hb_font_get_glyph_contour_point_nil (hb_font_t *font,
+hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
unsigned int point_index,
@@ -176,45 +290,63 @@ hb_font_get_glyph_contour_point_nil (hb_font_t *font,
hb_position_t *y,
void *user_data HB_UNUSED)
{
- if (font->parent) {
- hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
- if (ret)
- font->parent_scale_position (x, y);
- return ret;
- }
-
*x = *y = 0;
return false;
}
+static hb_bool_t
+hb_font_get_glyph_contour_point_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ unsigned int point_index,
+ hb_position_t *x,
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+{
+ hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
+ if (ret)
+ font->parent_scale_position (x, y);
+ return ret;
+}
static hb_bool_t
-hb_font_get_glyph_name_nil (hb_font_t *font,
+hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
- if (font->parent)
- return font->parent->get_glyph_name (glyph, name, size);
-
if (size) *name = '\0';
return false;
}
+static hb_bool_t
+hb_font_get_glyph_name_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph,
+ char *name, unsigned int size,
+ void *user_data HB_UNUSED)
+{
+ return font->parent->get_glyph_name (glyph, name, size);
+}
static hb_bool_t
-hb_font_get_glyph_from_name_nil (hb_font_t *font,
+hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
- if (font->parent)
- return font->parent->get_glyph_from_name (name, len, glyph);
-
*glyph = 0;
return false;
}
-
+static hb_bool_t
+hb_font_get_glyph_from_name_parent (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ const char *name, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+{
+ return font->parent->get_glyph_from_name (name, len, glyph);
+}
static const hb_font_funcs_t _hb_font_funcs_nil = {
HB_OBJECT_HEADER_STATIC,
@@ -222,9 +354,44 @@ static const hb_font_funcs_t _hb_font_funcs_nil = {
true, /* immutable */
{
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+ },
+ {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+ },
+ {
+ {
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+ }
+ }
+};
+static const hb_font_funcs_t _hb_font_funcs_parent = {
+ HB_OBJECT_HEADER_STATIC,
+
+ true, /* immutable */
+
+ {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+ },
+ {
+#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
+ },
+ {
+ {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent,
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+ }
}
};
@@ -246,7 +413,7 @@ hb_font_funcs_create (void)
if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
return hb_font_funcs_get_empty ();
- ffuncs->get = _hb_font_funcs_nil.get;
+ ffuncs->get = _hb_font_funcs_parent.get;
return ffuncs;
}
@@ -263,7 +430,7 @@ hb_font_funcs_create (void)
hb_font_funcs_t *
hb_font_funcs_get_empty (void)
{
- return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
+ return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_parent);
}
/**
@@ -398,11 +565,11 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
ffuncs->destroy.name (ffuncs->user_data.name); \
\
if (func) { \
- ffuncs->get.name = func; \
+ ffuncs->get.f.name = func; \
ffuncs->user_data.name = user_data; \
ffuncs->destroy.name = destroy; \
} else { \
- ffuncs->get.name = hb_font_get_##name##_nil; \
+ ffuncs->get.f.name = hb_font_get_##name##_parent; \
ffuncs->user_data.name = NULL; \
ffuncs->destroy.name = NULL; \
} \
@@ -411,10 +578,53 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
+bool
+hb_font_t::has_func (unsigned int i)
+{
+ if (parent && parent != hb_font_get_empty () && parent->has_func (i))
+ return true;
+ return this->klass->get.array[i] != _hb_font_funcs_parent.get.array[i];
+}
/* Public getters */
/**
+ * hb_font_get_h_extents:
+ * @font: a font.
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.1.3
+ **/
+hb_bool_t
+hb_font_get_h_extents (hb_font_t *font,
+ hb_font_extents_t *extents)
+{
+ return font->get_font_h_extents (extents);
+}
+
+/**
+ * hb_font_get_v_extents:
+ * @font: a font.
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.1.3
+ **/
+hb_bool_t
+hb_font_get_v_extents (hb_font_t *font,
+ hb_font_extents_t *extents)
+{
+ return font->get_font_v_extents (extents);
+}
+
+/**
* hb_font_get_glyph:
* @font: a font.
* @unicode:
@@ -432,7 +642,50 @@ hb_font_get_glyph (hb_font_t *font,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph)
{
- return font->get_glyph (unicode, variation_selector, glyph);
+ if (unlikely (variation_selector))
+ return font->get_variation_glyph (unicode, variation_selector, glyph);
+ return font->get_nominal_glyph (unicode, glyph);
+}
+
+/**
+ * hb_font_get_nominal_glyph:
+ * @font: a font.
+ * @unicode:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.2.3
+ **/
+hb_bool_t
+hb_font_get_nominal_glyph (hb_font_t *font,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph)
+{
+ return font->get_nominal_glyph (unicode, glyph);
+}
+
+/**
+ * hb_font_get_variation_glyph:
+ * @font: a font.
+ * @unicode:
+ * @variation_selector:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.2.3
+ **/
+hb_bool_t
+hb_font_get_variation_glyph (hb_font_t *font,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph)
+{
+ return font->get_variation_glyph (unicode, variation_selector, glyph);
}
/**
@@ -639,6 +892,23 @@ hb_font_get_glyph_from_name (hb_font_t *font,
/* A bit higher-level, and with fallback */
/**
+ * hb_font_get_extents_for_direction:
+ * @font: a font.
+ * @direction:
+ * @extents:
+ *
+ *
+ *
+ * Since: 1.1.3
+ **/
+void
+hb_font_get_extents_for_direction (hb_font_t *font,
+ hb_direction_t direction,
+ hb_font_extents_t *extents)
+{
+ return font->get_extents_for_direction (direction, extents);
+}
+/**
* hb_font_get_glyph_advance_for_direction:
* @font: a font.
* @glyph:
@@ -858,6 +1128,7 @@ hb_font_create (hb_face_t *face)
return hb_font_get_empty ();
hb_face_make_immutable (face);
+ font->parent = hb_font_get_empty ();
font->face = hb_face_reference (face);
font->klass = hb_font_funcs_get_empty ();
@@ -894,6 +1165,8 @@ hb_font_create_sub_font (hb_font_t *parent)
font->x_ppem = parent->x_ppem;
font->y_ppem = parent->y_ppem;
+ /* TODO: copy variation coordinates. */
+
return font;
}
@@ -917,12 +1190,15 @@ hb_font_get_empty (void)
NULL, /* parent */
const_cast<hb_face_t *> (&_hb_face_nil),
- 0, /* x_scale */
- 0, /* y_scale */
+ 1000, /* x_scale */
+ 1000, /* y_scale */
0, /* x_ppem */
0, /* y_ppem */
+ 0, /* num_coords */
+ NULL, /* coords */
+
const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
NULL, /* user_data */
NULL, /* destroy */
@@ -977,6 +1253,8 @@ hb_font_destroy (hb_font_t *font)
hb_face_destroy (font->face);
hb_font_funcs_destroy (font->klass);
+ free (font->coords);
+
free (font);
}
@@ -1264,3 +1542,157 @@ hb_font_get_ppem (hb_font_t *font,
if (x_ppem) *x_ppem = font->x_ppem;
if (y_ppem) *y_ppem = font->y_ppem;
}
+
+
+void
+hb_font_set_var_coords_normalized (hb_font_t *font,
+ int *coords, /* XXX 2.14 normalized */
+ unsigned int coords_length)
+{
+ if (font->immutable)
+ return;
+
+ /* Skip tail zero entries. */
+ while (coords_length && !coords[coords_length - 1])
+ coords_length--;
+
+ int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : NULL;
+ if (unlikely (coords_length && !copy))
+ return;
+
+ free (font->coords);
+
+ if (coords_length)
+ memcpy (copy, coords, coords_length * sizeof (coords[0]));
+
+ font->coords = copy;
+ font->num_coords = coords_length;
+}
+
+
+#ifndef HB_DISABLE_DEPRECATED
+
+/*
+ * Deprecated get_glyph_func():
+ */
+
+struct hb_trampoline_closure_t
+{
+ void *user_data;
+ hb_destroy_func_t destroy;
+ unsigned int ref_count;
+};
+
+template <typename FuncType>
+struct hb_trampoline_t
+{
+ hb_trampoline_closure_t closure; /* Must be first. */
+ FuncType func;
+};
+
+template <typename FuncType>
+static hb_trampoline_t<FuncType> *
+trampoline_create (FuncType func,
+ void *user_data,
+ hb_destroy_func_t destroy)
+{
+ typedef hb_trampoline_t<FuncType> trampoline_t;
+
+ trampoline_t *trampoline = (trampoline_t *) calloc (1, sizeof (trampoline_t));
+
+ if (unlikely (!trampoline))
+ return NULL;
+
+ trampoline->closure.user_data = user_data;
+ trampoline->closure.destroy = destroy;
+ trampoline->closure.ref_count = 1;
+ trampoline->func = func;
+
+ return trampoline;
+}
+
+static void
+trampoline_reference (hb_trampoline_closure_t *closure)
+{
+ closure->ref_count++;
+}
+
+static void
+trampoline_destroy (void *user_data)
+{
+ hb_trampoline_closure_t *closure = (hb_trampoline_closure_t *) user_data;
+
+ if (--closure->ref_count)
+ return;
+
+ if (closure->destroy)
+ closure->destroy (closure->user_data);
+ free (closure);
+}
+
+typedef hb_trampoline_t<hb_font_get_glyph_func_t> hb_font_get_glyph_trampoline_t;
+
+static hb_bool_t
+hb_font_get_nominal_glyph_trampoline (hb_font_t *font,
+ void *font_data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph,
+ void *user_data)
+{
+ hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data;
+ return trampoline->func (font, font_data, unicode, 0, glyph, trampoline->closure.user_data);
+}
+
+static hb_bool_t
+hb_font_get_variation_glyph_trampoline (hb_font_t *font,
+ void *font_data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph,
+ void *user_data)
+{
+ hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data;
+ return trampoline->func (font, font_data, unicode, variation_selector, glyph, trampoline->closure.user_data);
+}
+
+/**
+ * hb_font_funcs_set_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * Deprecated. Use hb_font_funcs_set_nominal_glyph_func() and
+ * hb_font_funcs_set_variation_glyph_func() instead.
+ *
+ * Since: 0.9.2
+ * Deprecated: 1.2.3
+ **/
+void
+hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_func_t func,
+ void *user_data, hb_destroy_func_t destroy)
+{
+ hb_font_get_glyph_trampoline_t *trampoline;
+
+ trampoline = trampoline_create (func, user_data, destroy);
+ if (unlikely (!trampoline))
+ {
+ if (destroy)
+ destroy (user_data);
+ return;
+ }
+
+ hb_font_funcs_set_nominal_glyph_func (ffuncs,
+ hb_font_get_nominal_glyph_trampoline,
+ trampoline,
+ trampoline_destroy);
+
+ trampoline_reference (&trampoline->closure);
+ hb_font_funcs_set_variation_glyph_func (ffuncs,
+ hb_font_get_variation_glyph_trampoline,
+ trampoline,
+ trampoline_destroy);
+}
+
+#endif /* HB_DISABLE_DEPRECATED */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.h b/src/3rdparty/harfbuzz-ng/src/hb-font.h
index fb4a0eab5a..8813286726 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-font.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-font.h
@@ -46,19 +46,19 @@ typedef struct hb_font_t hb_font_t;
typedef struct hb_font_funcs_t hb_font_funcs_t;
-hb_font_funcs_t *
+HB_EXTERN hb_font_funcs_t *
hb_font_funcs_create (void);
-hb_font_funcs_t *
+HB_EXTERN hb_font_funcs_t *
hb_font_funcs_get_empty (void);
-hb_font_funcs_t *
+HB_EXTERN hb_font_funcs_t *
hb_font_funcs_reference (hb_font_funcs_t *ffuncs);
-void
+HB_EXTERN void
hb_font_funcs_destroy (hb_font_funcs_t *ffuncs);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key,
void * data,
@@ -66,19 +66,37 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
hb_bool_t replace);
-void *
+HB_EXTERN void *
hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key);
-void
+HB_EXTERN void
hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
-/* glyph extents */
+/* font and glyph extents */
+
+/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */
+typedef struct hb_font_extents_t
+{
+ hb_position_t ascender; /* typographic ascender. */
+ hb_position_t descender; /* typographic descender. */
+ hb_position_t line_gap; /* suggested line spacing gap. */
+ /*< private >*/
+ hb_position_t reserved9;
+ hb_position_t reserved8;
+ hb_position_t reserved7;
+ hb_position_t reserved6;
+ hb_position_t reserved5;
+ hb_position_t reserved4;
+ hb_position_t reserved3;
+ hb_position_t reserved2;
+ hb_position_t reserved1;
+} hb_font_extents_t;
/* Note that height is negative in coordinate systems that grow up. */
typedef struct hb_glyph_extents_t
@@ -89,13 +107,23 @@ typedef struct hb_glyph_extents_t
hb_position_t height; /* distance from top to bottom side. */
} hb_glyph_extents_t;
-
/* func types */
-typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
- hb_codepoint_t unicode, hb_codepoint_t variation_selector,
- hb_codepoint_t *glyph,
- void *user_data);
+typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
+ hb_font_extents_t *metrics,
+ void *user_data);
+typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
+typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
+
+
+typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph,
+ void *user_data);
+typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph,
+ void *user_data);
typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
@@ -141,7 +169,39 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
/* func setters */
/**
- * hb_font_funcs_set_glyph_func:
+ * hb_font_funcs_set_font_h_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_font_h_extents_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_font_v_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.1.2
+ **/
+HB_EXTERN void
+hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_font_v_extents_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_nominal_glyph_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
@@ -149,12 +209,28 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
*
*
*
- * Since: 0.9.2
+ * Since: 1.2.3
+ **/
+HB_EXTERN void
+hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_nominal_glyph_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_variation_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.2.3
**/
-void
-hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
- hb_font_get_glyph_func_t func,
- void *user_data, hb_destroy_func_t destroy);
+HB_EXTERN void
+hb_font_funcs_set_variation_glyph_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_variation_glyph_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_advance_func:
@@ -167,7 +243,7 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_advance_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -183,7 +259,7 @@ hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_advance_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -199,7 +275,7 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_origin_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -215,7 +291,7 @@ hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_origin_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -231,7 +307,7 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -247,7 +323,7 @@ hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -263,7 +339,7 @@ hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_extents_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -279,7 +355,7 @@ hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_contour_point_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -295,7 +371,7 @@ hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_name_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -311,57 +387,67 @@ hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_from_name_func_t func,
void *user_data, hb_destroy_func_t destroy);
-
/* func dispatch */
-hb_bool_t
-hb_font_get_glyph (hb_font_t *font,
- hb_codepoint_t unicode, hb_codepoint_t variation_selector,
- hb_codepoint_t *glyph);
+HB_EXTERN hb_bool_t
+hb_font_get_h_extents (hb_font_t *font,
+ hb_font_extents_t *extents);
+HB_EXTERN hb_bool_t
+hb_font_get_v_extents (hb_font_t *font,
+ hb_font_extents_t *extents);
+
+HB_EXTERN hb_bool_t
+hb_font_get_nominal_glyph (hb_font_t *font,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph);
+HB_EXTERN hb_bool_t
+hb_font_get_variation_glyph (hb_font_t *font,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph);
-hb_position_t
+HB_EXTERN hb_position_t
hb_font_get_glyph_h_advance (hb_font_t *font,
hb_codepoint_t glyph);
-hb_position_t
+HB_EXTERN hb_position_t
hb_font_get_glyph_v_advance (hb_font_t *font,
hb_codepoint_t glyph);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_get_glyph_h_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_get_glyph_v_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y);
-hb_position_t
+HB_EXTERN hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
-hb_position_t
+HB_EXTERN hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_get_glyph_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_get_glyph_contour_point (hb_font_t *font,
hb_codepoint_t glyph, unsigned int point_index,
hb_position_t *x, hb_position_t *y);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_get_glyph_name (hb_font_t *font,
hb_codepoint_t glyph,
char *name, unsigned int size);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_get_glyph_from_name (hb_font_t *font,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph);
@@ -369,52 +455,63 @@ hb_font_get_glyph_from_name (hb_font_t *font,
/* high-level funcs, with fallback */
-void
+/* Calls either hb_font_get_nominal_glyph() if variation_selector is 0,
+ * otherwise callse hb_font_get_variation_glyph(). */
+HB_EXTERN hb_bool_t
+hb_font_get_glyph (hb_font_t *font,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph);
+
+HB_EXTERN void
+hb_font_get_extents_for_direction (hb_font_t *font,
+ hb_direction_t direction,
+ hb_font_extents_t *extents);
+HB_EXTERN void
hb_font_get_glyph_advance_for_direction (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
-void
+HB_EXTERN void
hb_font_get_glyph_origin_for_direction (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
-void
+HB_EXTERN void
hb_font_add_glyph_origin_for_direction (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
-void
+HB_EXTERN void
hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
-void
+HB_EXTERN void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_get_glyph_extents_for_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_glyph_extents_t *extents);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
hb_codepoint_t glyph, unsigned int point_index,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
/* Generates gidDDD if glyph has no name. */
-void
+HB_EXTERN void
hb_font_glyph_to_string (hb_font_t *font,
hb_codepoint_t glyph,
char *s, unsigned int size);
/* Parses gidDDD and uniUUUU strings automatically. */
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_glyph_from_string (hb_font_t *font,
const char *s, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph);
@@ -426,22 +523,22 @@ hb_font_glyph_from_string (hb_font_t *font,
/* Fonts are very light-weight objects */
-hb_font_t *
+HB_EXTERN hb_font_t *
hb_font_create (hb_face_t *face);
-hb_font_t *
+HB_EXTERN hb_font_t *
hb_font_create_sub_font (hb_font_t *parent);
-hb_font_t *
+HB_EXTERN hb_font_t *
hb_font_get_empty (void);
-hb_font_t *
+HB_EXTERN hb_font_t *
hb_font_reference (hb_font_t *font);
-void
+HB_EXTERN void
hb_font_destroy (hb_font_t *font);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_set_user_data (hb_font_t *font,
hb_user_data_key_t *key,
void * data,
@@ -449,46 +546,46 @@ hb_font_set_user_data (hb_font_t *font,
hb_bool_t replace);
-void *
+HB_EXTERN void *
hb_font_get_user_data (hb_font_t *font,
hb_user_data_key_t *key);
-void
+HB_EXTERN void
hb_font_make_immutable (hb_font_t *font);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_font_is_immutable (hb_font_t *font);
-void
+HB_EXTERN void
hb_font_set_parent (hb_font_t *font,
hb_font_t *parent);
-hb_font_t *
+HB_EXTERN hb_font_t *
hb_font_get_parent (hb_font_t *font);
-hb_face_t *
+HB_EXTERN hb_face_t *
hb_font_get_face (hb_font_t *font);
-void
+HB_EXTERN void
hb_font_set_funcs (hb_font_t *font,
hb_font_funcs_t *klass,
void *font_data,
hb_destroy_func_t destroy);
/* Be *very* careful with this function! */
-void
+HB_EXTERN void
hb_font_set_funcs_data (hb_font_t *font,
void *font_data,
hb_destroy_func_t destroy);
-void
+HB_EXTERN void
hb_font_set_scale (hb_font_t *font,
int x_scale,
int y_scale);
-void
+HB_EXTERN void
hb_font_get_scale (hb_font_t *font,
int *x_scale,
int *y_scale);
@@ -496,17 +593,22 @@ hb_font_get_scale (hb_font_t *font,
/*
* A zero value means "no hinting in that direction"
*/
-void
+HB_EXTERN void
hb_font_set_ppem (hb_font_t *font,
unsigned int x_ppem,
unsigned int y_ppem);
-void
+HB_EXTERN void
hb_font_get_ppem (hb_font_t *font,
unsigned int *x_ppem,
unsigned int *y_ppem);
+HB_EXTERN void
+hb_font_set_var_coords_normalized (hb_font_t *font,
+ int *coords, /* XXX 2.14 normalized */
+ unsigned int coords_length);
+
HB_END_DECLS
#endif /* HB_FONT_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-file-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-file-private.hh
index 152230a0e5..5357ddcf5b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-open-file-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-open-file-private.hh
@@ -140,7 +140,7 @@ struct TTCHeaderVersion1
protected:
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
- FixedVersion version; /* Version of the TTC Header (1.0),
+ FixedVersion<>version; /* Version of the TTC Header (1.0),
* 0x00010000u */
ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
table; /* Array of offsets to the OffsetTable for each font
@@ -187,7 +187,7 @@ struct TTCHeader
union {
struct {
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
- FixedVersion version; /* Version of the TTC Header (1.0 or 2.0),
+ FixedVersion<>version; /* Version of the TTC Header (1.0 or 2.0),
* 0x00010000u or 0x00020000u */
} header;
TTCHeaderVersion1 version1;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-type-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-type-private.hh
index f053502ded..2cc1fb20d2 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-open-type-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-open-type-private.hh
@@ -101,13 +101,11 @@ static inline Type& StructAfter(TObject &X)
#define DEFINE_SIZE_STATIC(size) \
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
static const unsigned int static_size = (size); \
- static const unsigned int min_size = (size)
-
-/* Size signifying variable-sized array */
-#define VAR 1
+ static const unsigned int min_size = (size); \
+ inline unsigned int get_size (void) const { return (size); }
#define DEFINE_SIZE_UNION(size, _member) \
- DEFINE_INSTANCE_ASSERTION (this->u._member.static_size == (size)); \
+ DEFINE_INSTANCE_ASSERTION (0*sizeof(this->u._member.static_size) + sizeof(this->u._member) == (size)); \
static const unsigned int min_size = (size)
#define DEFINE_SIZE_MIN(size) \
@@ -185,7 +183,7 @@ struct hb_dispatch_context_t
/* This limits sanitizing time on really broken fonts. */
#ifndef HB_SANITIZE_MAX_EDITS
-#define HB_SANITIZE_MAX_EDITS 100
+#define HB_SANITIZE_MAX_EDITS 32
#endif
struct hb_sanitize_context_t :
@@ -652,7 +650,9 @@ struct IntType
DEFINE_SIZE_STATIC (Size);
};
+typedef IntType<int8_t , 1> CHAR; /* 8-bit signed integer. */
typedef IntType<uint8_t , 1> BYTE; /* 8-bit unsigned integer. */
+typedef IntType<int8_t , 1> INT8; /* 8-bit signed integer. */
typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */
typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */
typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */
@@ -665,6 +665,24 @@ typedef SHORT FWORD;
/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */
typedef USHORT UFWORD;
+/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
+struct F2DOT14 : SHORT
+{
+ //inline float to_float (void) const { return ???; }
+ //inline void set_float (float f) { v.set (f * ???); }
+ public:
+ DEFINE_SIZE_STATIC (2);
+};
+
+/* 32-bit signed fixed-point number (16.16). */
+struct Fixed: LONG
+{
+ //inline float to_float (void) const { return ???; }
+ //inline void set_float (float f) { v.set (f * ???); }
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
/* Date represented in number of seconds since 12:00 midnight, January 1,
* 1904. The value is represented as a signed 64-bit integer. */
struct LONGDATETIME
@@ -742,9 +760,10 @@ struct CheckSum : ULONG
* Version Numbers
*/
+template <typename FixedType=USHORT>
struct FixedVersion
{
- inline uint32_t to_int (void) const { return (major << 16) + minor; }
+ inline uint32_t to_int (void) const { return (major << (sizeof(FixedType) * 8)) + minor; }
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -752,10 +771,10 @@ struct FixedVersion
return_trace (c->check_struct (this));
}
- USHORT major;
- USHORT minor;
+ FixedType major;
+ FixedType minor;
public:
- DEFINE_SIZE_STATIC (4);
+ DEFINE_SIZE_STATIC (2 * sizeof(FixedType));
};
@@ -788,6 +807,7 @@ struct OffsetTo : Offset<OffsetType>
if (unlikely (!c->check_struct (this))) return_trace (false);
unsigned int offset = *this;
if (unlikely (!offset)) return_trace (true);
+ if (unlikely (!c->check_range (base, offset))) return_trace (false);
const Type &obj = StructAtOffset<Type> (base, offset);
return_trace (likely (obj.sanitize (c)) || neuter (c));
}
@@ -798,6 +818,7 @@ struct OffsetTo : Offset<OffsetType>
if (unlikely (!c->check_struct (this))) return_trace (false);
unsigned int offset = *this;
if (unlikely (!offset)) return_trace (true);
+ if (unlikely (!c->check_range (base, offset))) return_trace (false);
const Type &obj = StructAtOffset<Type> (base, offset);
return_trace (likely (obj.sanitize (c, user_data)) || neuter (c));
}
@@ -931,8 +952,8 @@ struct ArrayOf
};
/* Array of Offset's */
-template <typename Type>
-struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
+template <typename Type, typename OffsetType=USHORT>
+struct OffsetArrayOf : ArrayOf<OffsetTo<Type, OffsetType> > {};
/* Array of offsets relative to the beginning of the array itself. */
template <typename Type>
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cbdt-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cbdt-table.hh
new file mode 100644
index 0000000000..52897abd3a
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cbdt-table.hh
@@ -0,0 +1,384 @@
+/*
+ * Copyright © 2016 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Seigo Nonaka
+ */
+
+#ifndef HB_OT_CBDT_TABLE_HH
+#define HB_OT_CBDT_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+namespace OT {
+
+struct SmallGlyphMetrics
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ inline void get_extents (hb_glyph_extents_t *extents) const
+ {
+ extents->x_bearing = bearingX;
+ extents->y_bearing = bearingY;
+ extents->width = width;
+ extents->height = -height;
+ }
+
+ BYTE height;
+ BYTE width;
+ CHAR bearingX;
+ CHAR bearingY;
+ BYTE advance;
+
+ DEFINE_SIZE_STATIC(5);
+};
+
+struct BigGlyphMetrics : SmallGlyphMetrics
+{
+ CHAR vertBearingX;
+ CHAR vertBearingY;
+ BYTE vertAdvance;
+
+ DEFINE_SIZE_STATIC(8);
+};
+
+struct SBitLineMetrics
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ CHAR ascender;
+ CHAR decender;
+ BYTE widthMax;
+ CHAR caretSlopeNumerator;
+ CHAR caretSlopeDenominator;
+ CHAR caretOffset;
+ CHAR minOriginSB;
+ CHAR minAdvanceSB;
+ CHAR maxBeforeBL;
+ CHAR minAfterBL;
+ CHAR padding1;
+ CHAR padding2;
+
+ DEFINE_SIZE_STATIC(12);
+};
+
+
+/*
+ * Index Subtables.
+ */
+
+struct IndexSubtableHeader
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ USHORT indexFormat;
+ USHORT imageFormat;
+ ULONG imageDataOffset;
+
+ DEFINE_SIZE_STATIC(8);
+};
+
+template <typename OffsetType>
+struct IndexSubtableFormat1Or3
+{
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1));
+ }
+
+ bool get_image_data (unsigned int idx,
+ unsigned int *offset,
+ unsigned int *length) const
+ {
+ if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
+ return false;
+
+ *offset = header.imageDataOffset + offsetArrayZ[idx];
+ *length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
+ return true;
+ }
+
+ IndexSubtableHeader header;
+ Offset<OffsetType> offsetArrayZ[VAR];
+
+ DEFINE_SIZE_ARRAY(8, offsetArrayZ);
+};
+
+struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<ULONG> {};
+struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<USHORT> {};
+
+struct IndexSubtable
+{
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
+ {
+ TRACE_SANITIZE (this);
+ if (!u.header.sanitize (c)) return_trace (false);
+ switch (u.header.indexFormat) {
+ case 1: return_trace (u.format1.sanitize (c, glyph_count));
+ case 3: return_trace (u.format3.sanitize (c, glyph_count));
+ default:return_trace (true);
+ }
+ }
+
+ inline bool get_extents (hb_glyph_extents_t *extents) const
+ {
+ switch (u.header.indexFormat) {
+ case 2: case 5: /* TODO */
+ case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
+ default:return (false);
+ }
+ }
+
+ bool get_image_data (unsigned int idx,
+ unsigned int *offset,
+ unsigned int *length,
+ unsigned int *format) const
+ {
+ *format = u.header.imageFormat;
+ switch (u.header.indexFormat) {
+ case 1: return u.format1.get_image_data (idx, offset, length);
+ case 3: return u.format3.get_image_data (idx, offset, length);
+ default: return false;
+ }
+ }
+
+ protected:
+ union {
+ IndexSubtableHeader header;
+ IndexSubtableFormat1 format1;
+ IndexSubtableFormat3 format3;
+ /* TODO: Format 2, 4, 5. */
+ } u;
+ public:
+ DEFINE_SIZE_UNION (8, header);
+};
+
+struct IndexSubtableRecord
+{
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ firstGlyphIndex <= lastGlyphIndex &&
+ offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1));
+ }
+
+ inline bool get_extents (hb_glyph_extents_t *extents) const
+ {
+ return (this+offsetToSubtable).get_extents (extents);
+ }
+
+ bool get_image_data (unsigned int gid,
+ unsigned int *offset,
+ unsigned int *length,
+ unsigned int *format) const
+ {
+ if (gid < firstGlyphIndex || gid > lastGlyphIndex)
+ {
+ return false;
+ }
+ return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
+ offset, length, format);
+ }
+
+ USHORT firstGlyphIndex;
+ USHORT lastGlyphIndex;
+ OffsetTo<IndexSubtable, ULONG> offsetToSubtable;
+
+ DEFINE_SIZE_STATIC(8);
+};
+
+struct IndexSubtableArray
+{
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count)))
+ return_trace (false);
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!indexSubtablesZ[i].sanitize (c, this)))
+ return_trace (false);
+ return_trace (true);
+ }
+
+ public:
+ const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
+ {
+ for (unsigned int i = 0; i < numTables; ++i)
+ {
+ unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
+ unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
+ if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) {
+ return &indexSubtablesZ[i];
+ }
+ }
+ return NULL;
+ }
+
+ protected:
+ IndexSubtableRecord indexSubtablesZ[VAR];
+
+ public:
+ DEFINE_SIZE_ARRAY(0, indexSubtablesZ);
+};
+
+struct BitmapSizeTable
+{
+ friend struct CBLC;
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
+ c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) &&
+ horizontal.sanitize (c) &&
+ vertical.sanitize (c));
+ }
+
+ const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const
+ {
+ return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
+ }
+
+ protected:
+ OffsetTo<IndexSubtableArray, ULONG> indexSubtableArrayOffset;
+ ULONG indexTablesSize;
+ ULONG numberOfIndexSubtables;
+ ULONG colorRef;
+ SBitLineMetrics horizontal;
+ SBitLineMetrics vertical;
+ USHORT startGlyphIndex;
+ USHORT endGlyphIndex;
+ BYTE ppemX;
+ BYTE ppemY;
+ BYTE bitDepth;
+ CHAR flags;
+
+public:
+ DEFINE_SIZE_STATIC(48);
+};
+
+
+/*
+ * Glyph Bitmap Data Formats.
+ */
+
+struct GlyphBitmapDataFormat17
+{
+ SmallGlyphMetrics glyphMetrics;
+ ULONG dataLen;
+ BYTE dataZ[VAR];
+
+ DEFINE_SIZE_ARRAY(9, dataZ);
+};
+
+
+/*
+ * CBLC -- Color Bitmap Location Table
+ */
+
+#define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
+
+struct CBLC
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ likely (version.major == 2 || version.major == 3) &&
+ sizeTables.sanitize (c, this));
+ }
+
+ public:
+ const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
+ unsigned int *x_ppem, unsigned int *y_ppem) const
+ {
+ /* TODO: Make it possible to select strike. */
+
+ unsigned int count = sizeTables.len;
+ for (uint32_t i = 0; i < count; ++i)
+ {
+ unsigned int startGlyphIndex = sizeTables.array[i].startGlyphIndex;
+ unsigned int endGlyphIndex = sizeTables.array[i].endGlyphIndex;
+ if (startGlyphIndex <= glyph && glyph <= endGlyphIndex)
+ {
+ *x_ppem = sizeTables[i].ppemX;
+ *y_ppem = sizeTables[i].ppemY;
+ return sizeTables[i].find_table (glyph, this);
+ }
+ }
+
+ return NULL;
+ }
+
+ protected:
+ FixedVersion<>version;
+ ArrayOf<BitmapSizeTable, ULONG> sizeTables;
+
+ public:
+ DEFINE_SIZE_ARRAY(8, sizeTables);
+};
+
+/*
+ * CBDT -- Color Bitmap Data Table
+ */
+#define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
+
+struct CBDT
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ likely (version.major == 2 || version.major == 3));
+ }
+
+ protected:
+ FixedVersion<>version;
+ BYTE dataZ[VAR];
+
+ public:
+ DEFINE_SIZE_ARRAY(4, dataZ);
+};
+
+} /* namespace OT */
+
+#endif /* HB_OT_CBDT_TABLE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
index c9161f0ef4..d7a94a1ef0 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
@@ -69,61 +69,78 @@ struct CmapSubtableFormat0
struct CmapSubtableFormat4
{
- inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+ struct accelerator_t
{
- unsigned int segCount;
- const USHORT *endCount;
- const USHORT *startCount;
- const USHORT *idDelta;
- const USHORT *idRangeOffset;
- const USHORT *glyphIdArray;
- unsigned int glyphIdArrayLength;
+ inline void init (const CmapSubtableFormat4 *subtable)
+ {
+ segCount = subtable->segCountX2 / 2;
+ endCount = subtable->values;
+ startCount = endCount + segCount + 1;
+ idDelta = startCount + segCount;
+ idRangeOffset = idDelta + segCount;
+ glyphIdArray = idRangeOffset + segCount;
+ glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
+ }
- segCount = this->segCountX2 / 2;
- endCount = this->values;
- startCount = endCount + segCount + 1;
- idDelta = startCount + segCount;
- idRangeOffset = idDelta + segCount;
- glyphIdArray = idRangeOffset + segCount;
- glyphIdArrayLength = (this->length - 16 - 8 * segCount) / 2;
-
- /* Custom two-array bsearch. */
- int min = 0, max = (int) segCount - 1;
- unsigned int i;
- while (min <= max)
+ static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
{
- int mid = (min + max) / 2;
- if (codepoint < startCount[mid])
- max = mid - 1;
- else if (codepoint > endCount[mid])
- min = mid + 1;
+ const accelerator_t *thiz = (const accelerator_t *) obj;
+
+ /* Custom two-array bsearch. */
+ int min = 0, max = (int) thiz->segCount - 1;
+ const USHORT *startCount = thiz->startCount;
+ const USHORT *endCount = thiz->endCount;
+ unsigned int i;
+ while (min <= max)
+ {
+ int mid = (min + max) / 2;
+ if (codepoint < startCount[mid])
+ max = mid - 1;
+ else if (codepoint > endCount[mid])
+ min = mid + 1;
+ else
+ {
+ i = mid;
+ goto found;
+ }
+ }
+ return false;
+
+ found:
+ hb_codepoint_t gid;
+ unsigned int rangeOffset = thiz->idRangeOffset[i];
+ if (rangeOffset == 0)
+ gid = codepoint + thiz->idDelta[i];
else
{
- i = mid;
- goto found;
+ /* Somebody has been smoking... */
+ unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
+ if (unlikely (index >= thiz->glyphIdArrayLength))
+ return false;
+ gid = thiz->glyphIdArray[index];
+ if (unlikely (!gid))
+ return false;
+ gid += thiz->idDelta[i];
}
- }
- return false;
-
- found:
- hb_codepoint_t gid;
- unsigned int rangeOffset = idRangeOffset[i];
- if (rangeOffset == 0)
- gid = codepoint + idDelta[i];
- else
- {
- /* Somebody has been smoking... */
- unsigned int index = rangeOffset / 2 + (codepoint - startCount[i]) + i - segCount;
- if (unlikely (index >= glyphIdArrayLength))
- return false;
- gid = glyphIdArray[index];
- if (unlikely (!gid))
- return false;
- gid += idDelta[i];
+
+ *glyph = gid & 0xFFFFu;
+ return true;
}
- *glyph = gid & 0xFFFFu;
- return true;
+ const USHORT *endCount;
+ const USHORT *startCount;
+ const USHORT *idDelta;
+ const USHORT *idRangeOffset;
+ const USHORT *glyphIdArray;
+ unsigned int segCount;
+ unsigned int glyphIdArrayLength;
+ };
+
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+ {
+ accelerator_t accel;
+ accel.init (this);
+ return accel.get_glyph_func (&accel, codepoint, glyph);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -388,7 +405,7 @@ struct CmapSubtableFormat14
}
protected:
- USHORT format; /* Format number is set to 0. */
+ USHORT format; /* Format number is set to 14. */
ULONG lengthZ; /* Byte length of this subtable. */
SortedArrayOf<VariationSelectorRecord, ULONG>
record; /* Variation selector records; sorted
@@ -416,16 +433,6 @@ struct CmapSubtable
}
}
- inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
- hb_codepoint_t variation_selector,
- hb_codepoint_t *glyph) const
- {
- switch (u.format) {
- case 14: return u.format14.get_glyph_variant(codepoint, variation_selector, glyph);
- default: return GLYPH_VARIANT_NOT_FOUND;
- }
- }
-
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -442,7 +449,7 @@ struct CmapSubtable
}
}
- protected:
+ public:
union {
USHORT format; /* Format identifier */
CmapSubtableFormat0 format0;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
index 69d2503abb..5be055d344 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
@@ -31,10 +31,13 @@
#include "hb-font-private.hh"
#include "hb-ot-cmap-table.hh"
+#include "hb-ot-cbdt-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-hmtx-table.hh"
+#include "hb-ot-os2-table.hh"
+//#include "hb-ot-post-table.hh"
struct hb_ot_face_metrics_accelerator_t
@@ -42,24 +45,63 @@ struct hb_ot_face_metrics_accelerator_t
unsigned int num_metrics;
unsigned int num_advances;
unsigned int default_advance;
+ unsigned short ascender;
+ unsigned short descender;
+ unsigned short line_gap;
+ bool has_font_extents;
+
const OT::_mtx *table;
hb_blob_t *blob;
inline void init (hb_face_t *face,
- hb_tag_t _hea_tag, hb_tag_t _mtx_tag,
- unsigned int default_advance_)
+ hb_tag_t _hea_tag,
+ hb_tag_t _mtx_tag,
+ hb_tag_t os2_tag,
+ unsigned int default_advance = 0)
{
- this->default_advance = default_advance_;
- this->num_metrics = face->get_num_glyphs ();
+ this->default_advance = default_advance ? default_advance : face->get_upem ();
+
+ bool got_font_extents = false;
+ if (os2_tag)
+ {
+ hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
+ const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
+#define USE_TYPO_METRICS (1u<<7)
+ if (0 != (os2->fsSelection & USE_TYPO_METRICS))
+ {
+ this->ascender = os2->sTypoAscender;
+ this->descender = os2->sTypoDescender;
+ this->line_gap = os2->sTypoLineGap;
+ got_font_extents = (this->ascender | this->descender) != 0;
+ }
+ hb_blob_destroy (os2_blob);
+ }
hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
this->num_advances = _hea->numberOfLongMetrics;
+ if (!got_font_extents)
+ {
+ this->ascender = _hea->ascender;
+ this->descender = _hea->descender;
+ this->line_gap = _hea->lineGap;
+ got_font_extents = (this->ascender | this->descender) != 0;
+ }
hb_blob_destroy (_hea_blob);
+ this->has_font_extents = got_font_extents;
+
this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
- if (unlikely (!this->num_advances ||
- 2 * (this->num_advances + this->num_metrics) > hb_blob_get_length (this->blob)))
+
+ /* Cap num_metrics() and num_advances() based on table length. */
+ unsigned int len = hb_blob_get_length (this->blob);
+ if (unlikely (this->num_advances * 4 > len))
+ this->num_advances = len / 4;
+ this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
+
+ /* We MUST set num_metrics to zero if num_advances is zero.
+ * Our get_advance() depends on that. */
+ if (unlikely (!this->num_advances))
{
this->num_metrics = this->num_advances = 0;
hb_blob_destroy (this->blob);
@@ -166,10 +208,133 @@ struct hb_ot_face_glyf_accelerator_t
}
};
+struct hb_ot_face_cbdt_accelerator_t
+{
+ hb_blob_t *cblc_blob;
+ hb_blob_t *cbdt_blob;
+ const OT::CBLC *cblc;
+ const OT::CBDT *cbdt;
+
+ unsigned int cbdt_len;
+ float upem;
+
+ inline void init (hb_face_t *face)
+ {
+ upem = face->get_upem();
+
+ cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
+ cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
+ cbdt_len = hb_blob_get_length (cbdt_blob);
+
+ if (hb_blob_get_length (cblc_blob) == 0) {
+ cblc = NULL;
+ cbdt = NULL;
+ return; /* Not a bitmap font. */
+ }
+ cblc = OT::Sanitizer<OT::CBLC>::lock_instance (cblc_blob);
+ cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (cbdt_blob);
+
+ }
+
+ inline void fini (void)
+ {
+ hb_blob_destroy (this->cblc_blob);
+ hb_blob_destroy (this->cbdt_blob);
+ }
+
+ inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+ {
+ unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
+
+ if (cblc == NULL)
+ return false; // Not a color bitmap font.
+
+ const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
+ if (subtable_record == NULL)
+ return false;
+
+ if (subtable_record->get_extents (extents))
+ return true;
+
+ unsigned int image_offset = 0, image_length = 0, image_format = 0;
+ if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
+ return false;
+
+ {
+ /* TODO Move the following into CBDT struct when adding more formats. */
+
+ if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
+ return false;
+
+ switch (image_format)
+ {
+ case 17: {
+ if (unlikely (image_length < OT::GlyphBitmapDataFormat17::min_size))
+ return false;
+
+ const OT::GlyphBitmapDataFormat17& glyphFormat17 =
+ OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, image_offset);
+ glyphFormat17.glyphMetrics.get_extents (extents);
+ }
+ break;
+ default:
+ // TODO: Support other image formats.
+ return false;
+ }
+ }
+
+ /* Convert to the font units. */
+ extents->x_bearing *= upem / (float) x_ppem;
+ extents->y_bearing *= upem / (float) y_ppem;
+ extents->width *= upem / (float) x_ppem;
+ extents->height *= upem / (float) y_ppem;
+
+ return true;
+ }
+};
+
+typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph);
+
+template <typename Type>
+static inline bool get_glyph_from (const void *obj,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph)
+{
+ const Type *typed_obj = (const Type *) obj;
+ return typed_obj->get_glyph (codepoint, glyph);
+}
+
+template <typename Type>
+static inline bool get_glyph_from_symbol (const void *obj,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph)
+{
+ const Type *typed_obj = (const Type *) obj;
+ if (likely (typed_obj->get_glyph (codepoint, glyph)))
+ return true;
+
+ if (codepoint <= 0x00FFu)
+ {
+ /* For symbol-encoded OpenType fonts, we duplicate the
+ * U+F000..F0FF range at U+0000..U+00FF. That's what
+ * Windows seems to do, and that's hinted about at:
+ * http://www.microsoft.com/typography/otspec/recom.htm
+ * under "Non-Standard (Symbol) Fonts". */
+ return typed_obj->get_glyph (0xF000u + codepoint, glyph);
+ }
+
+ return false;
+}
+
struct hb_ot_face_cmap_accelerator_t
{
- const OT::CmapSubtable *table;
- const OT::CmapSubtable *uvs_table;
+ hb_cmap_get_glyph_func_t get_glyph_func;
+ const void *get_glyph_data;
+ OT::CmapSubtableFormat4::accelerator_t format4_accel;
+
+ const OT::CmapSubtableFormat14 *uvs_table;
hb_blob_t *blob;
inline void init (hb_face_t *face)
@@ -177,8 +342,9 @@ struct hb_ot_face_cmap_accelerator_t
this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
const OT::CmapSubtable *subtable = NULL;
- const OT::CmapSubtable *subtable_uvs = NULL;
+ const OT::CmapSubtableFormat14 *subtable_uvs = NULL;
+ bool symbol = false;
/* 32-bit subtables. */
if (!subtable) subtable = cmap->find_subtable (3, 10);
if (!subtable) subtable = cmap->find_subtable (0, 6);
@@ -189,17 +355,42 @@ struct hb_ot_face_cmap_accelerator_t
if (!subtable) subtable = cmap->find_subtable (0, 2);
if (!subtable) subtable = cmap->find_subtable (0, 1);
if (!subtable) subtable = cmap->find_subtable (0, 0);
- if (!subtable) subtable = cmap->find_subtable (3, 0);
+ if (!subtable)
+ {
+ subtable = cmap->find_subtable (3, 0);
+ if (subtable) symbol = true;
+ }
/* Meh. */
if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
/* UVS subtable. */
- if (!subtable_uvs) subtable_uvs = cmap->find_subtable (0, 5);
+ if (!subtable_uvs)
+ {
+ const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
+ if (st && st->u.format == 14)
+ subtable_uvs = &st->u.format14;
+ }
/* Meh. */
- if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtable);
+ if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
- this->table = subtable;
this->uvs_table = subtable_uvs;
+
+ this->get_glyph_data = subtable;
+ if (unlikely (symbol))
+ this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
+ else
+ switch (subtable->u.format) {
+ /* Accelerate format 4 and format 12. */
+ default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>; break;
+ case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; break;
+ case 4:
+ {
+ this->format4_accel.init (&subtable->u.format4);
+ this->get_glyph_data = &this->format4_accel;
+ this->get_glyph_func = this->format4_accel.get_glyph_func;
+ }
+ break;
+ }
}
inline void fini (void)
@@ -207,33 +398,78 @@ struct hb_ot_face_cmap_accelerator_t
hb_blob_destroy (this->blob);
}
- inline bool get_glyph (hb_codepoint_t unicode,
- hb_codepoint_t variation_selector,
- hb_codepoint_t *glyph) const
+ inline bool get_nominal_glyph (hb_codepoint_t unicode,
+ hb_codepoint_t *glyph) const
{
- if (unlikely (variation_selector))
+ return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
+ }
+
+ inline bool get_variation_glyph (hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph) const
+ {
+ switch (this->uvs_table->get_glyph_variant (unicode,
+ variation_selector,
+ glyph))
{
- switch (this->uvs_table->get_glyph_variant (unicode,
- variation_selector,
- glyph))
- {
- case OT::GLYPH_VARIANT_NOT_FOUND: return false;
- case OT::GLYPH_VARIANT_FOUND: return true;
- case OT::GLYPH_VARIANT_USE_DEFAULT: break;
- }
+ case OT::GLYPH_VARIANT_NOT_FOUND: return false;
+ case OT::GLYPH_VARIANT_FOUND: return true;
+ case OT::GLYPH_VARIANT_USE_DEFAULT: break;
}
- return this->table->get_glyph (unicode, glyph);
+ return get_nominal_glyph (unicode, glyph);
}
};
+template <typename T>
+struct hb_lazy_loader_t
+{
+ inline void init (hb_face_t *face_)
+ {
+ face = face_;
+ instance = NULL;
+ }
+
+ inline void fini (void)
+ {
+ if (instance && instance != &OT::Null(T))
+ {
+ instance->fini();
+ free (instance);
+ }
+ }
+
+ inline const T* operator-> (void) const
+ {
+ retry:
+ T *p = (T *) hb_atomic_ptr_get (&instance);
+ if (unlikely (!p))
+ {
+ p = (T *) calloc (1, sizeof (T));
+ if (unlikely (!p))
+ return &OT::Null(T);
+ p->init (face);
+ if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
+ {
+ p->fini ();
+ goto retry;
+ }
+ }
+ return p;
+ }
+
+ private:
+ hb_face_t *face;
+ T *instance;
+};
struct hb_ot_font_t
{
hb_ot_face_cmap_accelerator_t cmap;
hb_ot_face_metrics_accelerator_t h_metrics;
hb_ot_face_metrics_accelerator_t v_metrics;
- hb_ot_face_glyf_accelerator_t glyf;
+ hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
+ hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
};
@@ -245,12 +481,12 @@ _hb_ot_font_create (hb_face_t *face)
if (unlikely (!ot_font))
return NULL;
- unsigned int upem = face->get_upem ();
-
ot_font->cmap.init (face);
- ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1);
- ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */
+ ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
+ ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE,
+ ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
ot_font->glyf.init (face);
+ ot_font->cbdt.init (face);
return ot_font;
}
@@ -262,88 +498,54 @@ _hb_ot_font_destroy (hb_ot_font_t *ot_font)
ot_font->h_metrics.fini ();
ot_font->v_metrics.fini ();
ot_font->glyf.fini ();
+ ot_font->cbdt.fini ();
free (ot_font);
}
static hb_bool_t
-hb_ot_get_glyph (hb_font_t *font HB_UNUSED,
- void *font_data,
- hb_codepoint_t unicode,
- hb_codepoint_t variation_selector,
- hb_codepoint_t *glyph,
- void *user_data HB_UNUSED)
+hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- return ot_font->cmap.get_glyph (unicode, variation_selector, glyph);
+ return ot_font->cmap.get_nominal_glyph (unicode, glyph);
}
-static hb_position_t
-hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
+static hb_bool_t
+hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
- hb_codepoint_t glyph,
+ hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- return font->em_scale_x (ot_font->h_metrics.get_advance (glyph));
+ return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph);
}
static hb_position_t
-hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
+hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
-}
-
-static hb_bool_t
-hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t glyph HB_UNUSED,
- hb_position_t *x HB_UNUSED,
- hb_position_t *y HB_UNUSED,
- void *user_data HB_UNUSED)
-{
- /* We always work in the horizontal coordinates. */
- return true;
-}
-
-static hb_bool_t
-hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
- void *font_data,
- hb_codepoint_t glyph,
- hb_position_t *x,
- hb_position_t *y,
- void *user_data HB_UNUSED)
-{
- /* TODO */
- return false;
+ return font->em_scale_x (ot_font->h_metrics.get_advance (glyph));
}
static hb_position_t
-hb_ot_get_glyph_h_kerning (hb_font_t *font,
+hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
void *font_data,
- hb_codepoint_t left_glyph,
- hb_codepoint_t right_glyph,
- void *user_data HB_UNUSED)
-{
- /* TODO */
- return 0;
-}
-
-static hb_position_t
-hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t top_glyph HB_UNUSED,
- hb_codepoint_t bottom_glyph HB_UNUSED,
+ hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
- /* OpenType doesn't have vertical-kerning other than GPOS. */
- return 0;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph));
}
static hb_bool_t
@@ -354,7 +556,9 @@ hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- bool ret = ot_font->glyf.get_extents (glyph, extents);
+ bool ret = ot_font->glyf->get_extents (glyph, extents);
+ if (!ret)
+ ret = ot_font->cbdt->get_extents (glyph, extents);
extents->x_bearing = font->em_scale_x (extents->x_bearing);
extents->y_bearing = font->em_scale_y (extents->y_bearing);
extents->width = font->em_scale_x (extents->width);
@@ -363,61 +567,85 @@ hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
}
static hb_bool_t
-hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
- void *font_data,
- hb_codepoint_t glyph,
- unsigned int point_index,
- hb_position_t *x,
- hb_position_t *y,
- void *user_data HB_UNUSED)
+hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_font_extents_t *metrics,
+ void *user_data HB_UNUSED)
{
- /* TODO */
- return false;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
+ metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
+ metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
+ return ot_font->h_metrics.has_font_extents;
}
static hb_bool_t
-hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
- void *font_data,
- hb_codepoint_t glyph,
- char *name, unsigned int size,
- void *user_data HB_UNUSED)
+hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_font_extents_t *metrics,
+ void *user_data HB_UNUSED)
{
- /* TODO */
- return false;
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
+ metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
+ metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
+ return ot_font->v_metrics.has_font_extents;
}
-static hb_bool_t
-hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
- void *font_data,
- const char *name, int len, /* -1 means nul-terminated */
- hb_codepoint_t *glyph,
- void *user_data HB_UNUSED)
+static hb_font_funcs_t *static_ot_funcs = NULL;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_ot_funcs (void)
{
- /* TODO */
- return false;
+ hb_font_funcs_destroy (static_ot_funcs);
}
-
+#endif
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
- static const hb_font_funcs_t ot_ffuncs = {
- HB_OBJECT_HEADER_STATIC,
-
- true, /* immutable */
+retry:
+ hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
- {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name,
- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
+ if (unlikely (!funcs))
+ {
+ funcs = hb_font_funcs_create ();
+
+ hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
+ hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
+ hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL);
+ hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL);
+ hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
+ hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
+ //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
+ //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
+ //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
+ //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
+ hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
+ //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
+ //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
+ //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
+
+ hb_font_funcs_make_immutable (funcs);
+
+ if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
+ hb_font_funcs_destroy (funcs);
+ goto retry;
}
+
+#ifdef HB_USE_ATEXIT
+ atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
+#endif
};
- return const_cast<hb_font_funcs_t *> (&ot_ffuncs);
+ return funcs;
}
/**
+ * hb_ot_font_set_funcs:
+ *
* Since: 0.9.28
**/
void
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.h b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.h
index b9947a16bc..80eaa54b1a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.h
@@ -36,7 +36,7 @@
HB_BEGIN_DECLS
-void
+HB_EXTERN void
hb_ot_font_set_funcs (hb_font_t *font);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-glyf-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-glyf-table.hh
index 9e5af6d10d..dc7aa8469a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-glyf-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-glyf-table.hh
@@ -90,10 +90,10 @@ struct glyfGlyphHeader
* greater than or equal to zero,
* this is a simple glyph; if negative,
* this is a composite glyph. */
- SHORT xMin; /* Minimum x for coordinate data. */
- SHORT yMin; /* Minimum y for coordinate data. */
- SHORT xMax; /* Maximum x for coordinate data. */
- SHORT yMax; /* Maximum y for coordinate data. */
+ FWORD xMin; /* Minimum x for coordinate data. */
+ FWORD yMin; /* Minimum y for coordinate data. */
+ FWORD xMax; /* Maximum x for coordinate data. */
+ FWORD yMax; /* Maximum y for coordinate data. */
DEFINE_SIZE_STATIC (10);
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-head-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-head-table.hh
index fc351cfb48..9c3e51eb08 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-head-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-head-table.hh
@@ -55,13 +55,15 @@ struct head
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && likely (version.major == 1));
+ return_trace (c->check_struct (this) &&
+ version.major == 1 &&
+ magicNumber == 0x5F0F3CF5u);
}
protected:
- FixedVersion version; /* Version of the head table--currently
+ FixedVersion<>version; /* Version of the head table--currently
* 0x00010000u for version 1.0. */
- FixedVersion fontRevision; /* Set by font manufacturer. */
+ FixedVersion<>fontRevision; /* Set by font manufacturer. */
ULONG checkSumAdjustment; /* To compute: set it to 0, sum the
* entire font as ULONG, then store
* 0xB1B0AFBAu - sum. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh
index 24114534a7..c8e9536cf1 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh
@@ -56,7 +56,7 @@ struct _hea
}
public:
- FixedVersion version; /* 0x00010000u for version 1.0. */
+ FixedVersion<>version; /* 0x00010000u for version 1.0. */
FWORD ascender; /* Typographic ascent. */
FWORD descender; /* Typographic descent. */
FWORD lineGap; /* Typographic line gap. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
index 49056e6769..a9606b3d27 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
@@ -44,8 +44,8 @@ namespace OT {
struct LongMetric
{
- USHORT advance; /* Advance width/height. */
- SHORT lsb; /* Leading (left/top) side bearing. */
+ UFWORD advance; /* Advance width/height. */
+ FWORD lsb; /* Leading (left/top) side bearing. */
public:
DEFINE_SIZE_STATIC (4);
};
@@ -74,7 +74,7 @@ struct _mtx
* be in the array, but that entry is
* required. The last entry applies to
* all subsequent glyphs. */
- SHORT leadingBearingX[VAR]; /* Here the advance is assumed
+ FWORD leadingBearingX[VAR]; /* Here the advance is assumed
* to be the same as the advance
* for the last entry above. The
* number of entries in this array is
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common-private.hh
index ea61f5c1bd..62ca7a348e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common-private.hh
@@ -34,6 +34,14 @@
#include "hb-set-private.hh"
+#ifndef HB_MAX_NESTING_LEVEL
+#define HB_MAX_NESTING_LEVEL 6
+#endif
+#ifndef HB_MAX_CONTEXT_LENGTH
+#define HB_MAX_CONTEXT_LENGTH 64
+#endif
+
+
namespace OT {
@@ -44,8 +52,6 @@ namespace OT {
#define NOT_COVERED ((unsigned int) -1)
-#define MAX_NESTING_LEVEL 6
-#define MAX_CONTEXT_LENGTH 64
@@ -501,7 +507,7 @@ struct Feature
{ return this+featureParams; }
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<Feature>::sanitize_closure_t *closure) const
+ const Record<Feature>::sanitize_closure_t *closure = NULL) const
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
@@ -539,6 +545,9 @@ struct Feature
c->try_set (&featureParams, new_offset) &&
!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
return_trace (false);
+
+ if (c->edit_count > 1)
+ c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
}
return_trace (true);
@@ -573,6 +582,11 @@ struct LookupFlag : USHORT
DEFINE_SIZE_STATIC (2);
};
+} /* namespace OT */
+/* This has to be outside the namespace. */
+HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
+namespace OT {
+
struct Lookup
{
inline unsigned int get_subtable_count (void) const { return subTable.len; }
@@ -717,8 +731,8 @@ struct CoverageFormat1
inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
inline bool more (void) { return i < c->glyphArray.len; }
inline void next (void) { i++; }
- inline uint16_t get_glyph (void) { return c->glyphArray[i]; }
- inline uint16_t get_coverage (void) { return i; }
+ inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
+ inline unsigned int get_coverage (void) { return i; }
private:
const struct CoverageFormat1 *c;
@@ -756,7 +770,11 @@ struct CoverageFormat2
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
- if (unlikely (!num_glyphs)) return_trace (true);
+ if (unlikely (!num_glyphs))
+ {
+ rangeRecord.len.set (0);
+ return_trace (true);
+ }
unsigned int num_ranges = 1;
for (unsigned int i = 1; i < num_glyphs; i++)
@@ -811,26 +829,33 @@ struct CoverageFormat2
public:
/* Older compilers need this to be public. */
- struct Iter {
- inline void init (const CoverageFormat2 &c_) {
+ struct Iter
+ {
+ inline void init (const CoverageFormat2 &c_)
+ {
c = &c_;
coverage = 0;
i = 0;
j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
}
inline bool more (void) { return i < c->rangeRecord.len; }
- inline void next (void) {
- coverage++;
- if (j == c->rangeRecord[i].end) {
+ inline void next (void)
+ {
+ if (j >= c->rangeRecord[i].end)
+ {
i++;
if (more ())
+ {
j = c->rangeRecord[i].start;
+ coverage = c->rangeRecord[i].value;
+ }
return;
}
+ coverage++;
j++;
}
- inline uint16_t get_glyph (void) { return j; }
- inline uint16_t get_coverage (void) { return coverage; }
+ inline hb_codepoint_t get_glyph (void) { return j; }
+ inline unsigned int get_coverage (void) { return coverage; }
private:
const struct CoverageFormat2 *c;
@@ -939,14 +964,14 @@ struct Coverage
default: break;
}
}
- inline uint16_t get_glyph (void) {
+ inline hb_codepoint_t get_glyph (void) {
switch (format) {
case 1: return u.format1.get_glyph ();
case 2: return u.format2.get_glyph ();
default:return 0;
}
}
- inline uint16_t get_coverage (void) {
+ inline unsigned int get_coverage (void) {
switch (format) {
case 1: return u.format1.get_coverage ();
case 2: return u.format2.get_coverage ();
@@ -1144,11 +1169,380 @@ struct ClassDef
/*
+ * Item Variation Store
+ */
+
+struct VarRegionAxis
+{
+ inline float evaluate (int coord) const
+ {
+ int start = startCoord, peak = peakCoord, end = endCoord;
+
+ /* TODO Move these to sanitize(). */
+ if (unlikely (start > peak || peak > end))
+ return 1.;
+ if (unlikely (start < 0 && end > 0 && peak != 0))
+ return 1.;
+
+ if (peak == 0 || coord == peak)
+ return 1.;
+
+ if (coord <= start || end <= coord)
+ return 0.;
+
+ /* Interpolate */
+ if (coord < peak)
+ return float (coord - start) / (peak - start);
+ else
+ return float (end - coord) / (end - peak);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ /* TODO Handle invalid start/peak/end configs, so we don't
+ * have to do that at runtime. */
+ }
+
+ public:
+ F2DOT14 startCoord;
+ F2DOT14 peakCoord;
+ F2DOT14 endCoord;
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct VarRegionList
+{
+ inline float evaluate (unsigned int region_index,
+ int *coords, unsigned int coord_len) const
+ {
+ if (unlikely (region_index >= regionCount))
+ return 0.;
+
+ const VarRegionAxis *axes = axesZ + (region_index * axisCount);
+
+ float v = 1.;
+ unsigned int count = MIN (coord_len, (unsigned int) axisCount);
+ for (unsigned int i = 0; i < count; i++)
+ {
+ float factor = axes[i].evaluate (coords[i]);
+ if (factor == 0.)
+ return 0.;
+ v *= factor;
+ }
+ return v;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ c->check_array (axesZ, axesZ[0].static_size,
+ (unsigned int) axisCount * (unsigned int) regionCount));
+ }
+
+ protected:
+ USHORT axisCount;
+ USHORT regionCount;
+ VarRegionAxis axesZ[VAR];
+ public:
+ DEFINE_SIZE_ARRAY (4, axesZ);
+};
+
+struct VarData
+{
+ inline unsigned int get_row_size (void) const
+ { return shortCount + regionIndices.len; }
+
+ inline unsigned int get_size (void) const
+ { return itemCount * get_row_size (); }
+
+ inline float get_delta (unsigned int inner,
+ int *coords, unsigned int coord_count,
+ const VarRegionList &regions) const
+ {
+ if (unlikely (inner >= itemCount))
+ return 0.;
+
+ unsigned int count = regionIndices.len;
+ unsigned int scount = shortCount;
+
+ const BYTE *bytes = &StructAfter<BYTE> (regionIndices);
+ const BYTE *row = bytes + inner * (scount + count);
+
+ float delta = 0.;
+ unsigned int i = 0;
+
+ const SHORT *scursor = reinterpret_cast<const SHORT *> (row);
+ for (; i < scount; i++)
+ {
+ float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
+ delta += scalar * *scursor++;
+ }
+ const INT8 *bcursor = reinterpret_cast<const INT8 *> (scursor);
+ for (; i < count; i++)
+ {
+ float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
+ delta += scalar * *bcursor++;
+ }
+
+ return delta;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ regionIndices.sanitize(c) &&
+ shortCount <= regionIndices.len &&
+ c->check_array (&StructAfter<BYTE> (regionIndices),
+ get_row_size (), itemCount));
+ }
+
+ protected:
+ USHORT itemCount;
+ USHORT shortCount;
+ ArrayOf<USHORT> regionIndices;
+ BYTE bytesX[VAR];
+ public:
+ DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
+};
+
+struct VariationStore
+{
+ inline float get_delta (unsigned int outer, unsigned int inner,
+ int *coords, unsigned int coord_count) const
+ {
+ if (unlikely (outer >= dataSets.len))
+ return 0.;
+
+ return (this+dataSets[outer]).get_delta (inner,
+ coords, coord_count,
+ this+regions);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ format == 1 &&
+ regions.sanitize (c, this) &&
+ dataSets.sanitize (c, this));
+ }
+
+ protected:
+ USHORT format;
+ OffsetTo<VarRegionList, ULONG> regions;
+ OffsetArrayOf<VarData, ULONG> dataSets;
+ public:
+ DEFINE_SIZE_ARRAY (8, dataSets);
+};
+
+/*
+ * Feature Variations
+ */
+
+struct ConditionFormat1
+{
+ friend struct Condition;
+
+ private:
+ inline bool evaluate (const int *coords, unsigned int coord_len) const
+ {
+ int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
+ return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ protected:
+ USHORT format; /* Format identifier--format = 1 */
+ USHORT axisIndex;
+ F2DOT14 filterRangeMinValue;
+ F2DOT14 filterRangeMaxValue;
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct Condition
+{
+ inline bool evaluate (const int *coords, unsigned int coord_len) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.evaluate (coords, coord_len);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (!u.format.sanitize (c)) return_trace (false);
+ switch (u.format) {
+ case 1: return_trace (u.format1.sanitize (c));
+ default:return_trace (true);
+ }
+ }
+
+ protected:
+ union {
+ USHORT format; /* Format identifier */
+ ConditionFormat1 format1;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, format);
+};
+
+struct ConditionSet
+{
+ inline bool evaluate (const int *coords, unsigned int coord_len) const
+ {
+ unsigned int count = conditions.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (!(this+conditions.array[i]).evaluate (coords, coord_len))
+ return false;
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (conditions.sanitize (c, this));
+ }
+
+ protected:
+ OffsetArrayOf<Condition, ULONG> conditions;
+ public:
+ DEFINE_SIZE_ARRAY (2, conditions);
+};
+
+struct FeatureTableSubstitutionRecord
+{
+ friend struct FeatureTableSubstitution;
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && feature.sanitize (c, base));
+ }
+
+ protected:
+ USHORT featureIndex;
+ OffsetTo<Feature, ULONG> feature;
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct FeatureTableSubstitution
+{
+ inline const Feature *find_substitute (unsigned int feature_index) const
+ {
+ unsigned int count = substitutions.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ const FeatureTableSubstitutionRecord &record = substitutions.array[i];
+ if (record.featureIndex == feature_index)
+ return &(this+record.feature);
+ }
+ return NULL;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (version.sanitize (c) &&
+ likely (version.major == 1) &&
+ substitutions.sanitize (c, this));
+ }
+
+ protected:
+ FixedVersion<> version; /* Version--0x00010000u */
+ ArrayOf<FeatureTableSubstitutionRecord>
+ substitutions;
+ public:
+ DEFINE_SIZE_ARRAY (6, substitutions);
+};
+
+struct FeatureVariationRecord
+{
+ friend struct FeatureVariations;
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (conditions.sanitize (c, base) &&
+ substitutions.sanitize (c, base));
+ }
+
+ protected:
+ OffsetTo<ConditionSet, ULONG>
+ conditions;
+ OffsetTo<FeatureTableSubstitution, ULONG>
+ substitutions;
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct FeatureVariations
+{
+ static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;
+
+ inline bool find_index (const int *coords, unsigned int coord_len,
+ unsigned int *index) const
+ {
+ unsigned int count = varRecords.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ const FeatureVariationRecord &record = varRecords.array[i];
+ if ((this+record.conditions).evaluate (coords, coord_len))
+ {
+ *index = i;
+ return true;
+ }
+ }
+ *index = NOT_FOUND_INDEX;
+ return false;
+ }
+
+ inline const Feature *find_substitute (unsigned int variations_index,
+ unsigned int feature_index) const
+ {
+ const FeatureVariationRecord &record = varRecords[variations_index];
+ return (this+record.substitutions).find_substitute (feature_index);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (version.sanitize (c) &&
+ likely (version.major == 1) &&
+ varRecords.sanitize (c, this));
+ }
+
+ protected:
+ FixedVersion<> version; /* Version--0x00010000u */
+ ArrayOf<FeatureVariationRecord, ULONG>
+ varRecords;
+ public:
+ DEFINE_SIZE_ARRAY (8, varRecords);
+};
+
+
+/*
* Device Tables
*/
-struct Device
+struct HintingDevice
{
+ friend struct Device;
+
+ private:
inline hb_position_t get_x_delta (hb_font_t *font) const
{ return get_delta (font->x_ppem, font->x_scale); }
@@ -1156,6 +1550,21 @@ struct Device
inline hb_position_t get_y_delta (hb_font_t *font) const
{ return get_delta (font->y_ppem, font->y_scale); }
+ inline unsigned int get_size (void) const
+ {
+ unsigned int f = deltaFormat;
+ if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
+ return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
+ }
+
+ private:
+
inline int get_delta (unsigned int ppem, int scale) const
{
if (!ppem) return 0;
@@ -1166,8 +1575,6 @@ struct Device
return (int) (pixels * (int64_t) scale / ppem);
}
-
-
inline int get_delta_pixels (unsigned int ppem_size) const
{
unsigned int f = deltaFormat;
@@ -1191,19 +1598,6 @@ struct Device
return delta;
}
- inline unsigned int get_size (void) const
- {
- unsigned int f = deltaFormat;
- if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
- return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
- }
-
- inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
- }
-
protected:
USHORT startSize; /* Smallest size to correct--in ppem */
USHORT endSize; /* Largest size to correct--in ppem */
@@ -1217,6 +1611,101 @@ struct Device
DEFINE_SIZE_ARRAY (6, deltaValue);
};
+struct VariationDevice
+{
+ friend struct Device;
+
+ private:
+
+ inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
+ { return font->em_scalef_x (get_delta (font, store)); }
+
+ inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
+ { return font->em_scalef_y (get_delta (font, store)); }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ private:
+
+ inline float get_delta (hb_font_t *font, const VariationStore &store) const
+ {
+ return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
+ }
+
+ protected:
+ USHORT outerIndex;
+ USHORT innerIndex;
+ USHORT deltaFormat; /* Format identifier for this table: 0x0x8000 */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct DeviceHeader
+{
+ protected:
+ USHORT reserved1;
+ USHORT reserved2;
+ public:
+ USHORT format; /* Format identifier */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct Device
+{
+ inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
+ {
+ switch (u.b.format)
+ {
+ case 1: case 2: case 3:
+ return u.hinting.get_x_delta (font);
+ case 0x8000:
+ return u.variation.get_x_delta (font, store);
+ default:
+ return 0;
+ }
+ }
+ inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
+ {
+ switch (u.b.format)
+ {
+ case 1: case 2: case 3:
+ return u.hinting.get_y_delta (font);
+ case 0x8000:
+ return u.variation.get_y_delta (font, store);
+ default:
+ return 0;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (!u.b.format.sanitize (c)) return_trace (false);
+ switch (u.b.format) {
+ case 1: case 2: case 3:
+ return_trace (u.hinting.sanitize (c));
+ case 0x8000:
+ return_trace (u.variation.sanitize (c));
+ default:
+ return_trace (true);
+ }
+ }
+
+ protected:
+ union {
+ DeviceHeader b;
+ HintingDevice hinting;
+ VariationDevice variation;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (6, b);
+};
+
} /* namespace OT */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
index bc36436be7..b70cbb7a38 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
@@ -97,7 +97,7 @@ struct CaretValueFormat1
friend struct CaretValue;
private:
- inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
+ inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
}
@@ -146,11 +146,11 @@ struct CaretValueFormat3
{
friend struct CaretValue;
- inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const
+ inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, const VariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
- font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font) :
- font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
+ font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
+ font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -172,12 +172,15 @@ struct CaretValueFormat3
struct CaretValue
{
- inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
+ inline hb_position_t get_caret_value (hb_font_t *font,
+ hb_direction_t direction,
+ hb_codepoint_t glyph_id,
+ const VariationStore &var_store) const
{
switch (u.format) {
- case 1: return u.format1.get_caret_value (font, direction, glyph_id);
+ case 1: return u.format1.get_caret_value (font, direction);
case 2: return u.format2.get_caret_value (font, direction, glyph_id);
- case 3: return u.format3.get_caret_value (font, direction, glyph_id);
+ case 3: return u.format3.get_caret_value (font, direction, var_store);
default:return 0;
}
}
@@ -210,6 +213,7 @@ struct LigGlyph
inline unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
+ const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -218,7 +222,7 @@ struct LigGlyph
const OffsetTo<CaretValue> *array = carets.sub_array (start_offset, caret_count);
unsigned int count = *caret_count;
for (unsigned int i = 0; i < count; i++)
- caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id);
+ caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
}
return carets.len;
@@ -244,6 +248,7 @@ struct LigCaretList
inline unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
+ const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -256,7 +261,7 @@ struct LigCaretList
return 0;
}
const LigGlyph &lig_glyph = this+ligGlyph[index];
- return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
+ return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -367,11 +372,17 @@ struct GDEF
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
- { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
+ { return (this+ligCaretList).get_lig_carets (font,
+ direction, glyph_id, get_var_store(),
+ start_offset, caret_count, caret_array); }
- inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef[0] != 0; }
+ inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
- { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
+ { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
+
+ inline bool has_var_store (void) const { return version.to_int () >= 0x00010003u && varStore != 0; }
+ inline const VariationStore &get_var_store (void) const
+ { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -382,10 +393,10 @@ struct GDEF
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
- (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
+ (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+ (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
-
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */
@@ -409,8 +420,8 @@ struct GDEF
protected:
- FixedVersion version; /* Version of the GDEF table--currently
- * 0x00010002u */
+ FixedVersion<>version; /* Version of the GDEF table--currently
+ * 0x00010003u */
OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of
@@ -428,12 +439,17 @@ struct GDEF
* mark attachment type--from beginning
* of GDEF header (may be Null) */
OffsetTo<MarkGlyphSets>
- markGlyphSetsDef[VAR]; /* Offset to the table of mark set
+ markGlyphSetsDef; /* Offset to the table of mark set
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
- * in version 00010002. */
+ * in version 0x00010002. */
+ OffsetTo<VariationStore, ULONG>
+ varStore; /* Offset to the table of Item Variation
+ * Store--from beginning of GDEF
+ * header (may be NULL). Introduced
+ * in version 0x00010003. */
public:
- DEFINE_SIZE_ARRAY (12, markGlyphSetsDef);
+ DEFINE_SIZE_MIN (12);
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
index 568b5f63a9..952fd60fec 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
@@ -36,8 +36,17 @@ namespace OT {
/* buffer **position** var allocations */
-#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
-#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
+#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
+#define attach_type() var.u8[2] /* attachment type */
+/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
+
+enum attach_type_t {
+ ATTACH_TYPE_NONE = 0X00,
+
+ /* Each attachment should be either a mark or a cursive; can't be both. */
+ ATTACH_TYPE_MARK = 0X01,
+ ATTACH_TYPE_CURSIVE = 0X02,
+};
/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
@@ -94,18 +103,17 @@ struct ValueFormat : USHORT
inline unsigned int get_size (void) const
{ return get_len () * Value::static_size; }
- void apply_value (hb_font_t *font,
- hb_direction_t direction,
+ void apply_value (hb_apply_context_t *c,
const void *base,
const Value *values,
hb_glyph_position_t &glyph_pos) const
{
- unsigned int x_ppem, y_ppem;
unsigned int format = *this;
- hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
-
if (!format) return;
+ hb_font_t *font = c->font;
+ hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction);
+
if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
if (format & xAdvance) {
@@ -120,27 +128,29 @@ struct ValueFormat : USHORT
if (!has_device ()) return;
- x_ppem = font->x_ppem;
- y_ppem = font->y_ppem;
+ bool use_x_device = font->x_ppem || font->num_coords;
+ bool use_y_device = font->y_ppem || font->num_coords;
+
+ if (!use_x_device && !use_y_device) return;
- if (!x_ppem && !y_ppem) return;
+ const VariationStore &store = c->var_store;
/* pixel -> fractional pixel */
if (format & xPlaDevice) {
- if (x_ppem) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font);
+ if (use_x_device) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font, store);
values++;
}
if (format & yPlaDevice) {
- if (y_ppem) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font);
+ if (use_y_device) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font, store);
values++;
}
if (format & xAdvDevice) {
- if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
+ if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font, store);
values++;
}
if (format & yAdvDevice) {
/* y_advance values grow downward but font-space grows upward, hence negation */
- if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
+ if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font, store);
values++;
}
}
@@ -222,11 +232,12 @@ struct ValueFormat : USHORT
struct AnchorFormat1
{
- inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
+ inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
hb_position_t *x, hb_position_t *y) const
{
- *x = font->em_scale_x (xCoordinate);
- *y = font->em_scale_y (yCoordinate);
+ hb_font_t *font = c->font;
+ *x = font->em_scale_x (xCoordinate);
+ *y = font->em_scale_y (yCoordinate);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -245,18 +256,19 @@ struct AnchorFormat1
struct AnchorFormat2
{
- inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
+ inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id,
hb_position_t *x, hb_position_t *y) const
{
- unsigned int x_ppem = font->x_ppem;
- unsigned int y_ppem = font->y_ppem;
- hb_position_t cx, cy;
- hb_bool_t ret;
+ hb_font_t *font = c->font;
+ unsigned int x_ppem = font->x_ppem;
+ unsigned int y_ppem = font->y_ppem;
+ hb_position_t cx, cy;
+ hb_bool_t ret;
- ret = (x_ppem || y_ppem) &&
- font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
- *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
- *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
+ ret = (x_ppem || y_ppem) &&
+ font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
+ *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
+ *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -276,16 +288,17 @@ struct AnchorFormat2
struct AnchorFormat3
{
- inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
+ inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
hb_position_t *x, hb_position_t *y) const
{
- *x = font->em_scale_x (xCoordinate);
- *y = font->em_scale_y (yCoordinate);
+ hb_font_t *font = c->font;
+ *x = font->em_scale_x (xCoordinate);
+ *y = font->em_scale_y (yCoordinate);
- if (font->x_ppem)
- *x += (this+xDeviceTable).get_x_delta (font);
- if (font->y_ppem)
- *y += (this+yDeviceTable).get_x_delta (font);
+ if (font->x_ppem || font->num_coords)
+ *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
+ if (font->y_ppem || font->num_coords)
+ *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -312,14 +325,14 @@ struct AnchorFormat3
struct Anchor
{
- inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
+ inline void get_anchor (hb_apply_context_t *c, hb_codepoint_t glyph_id,
hb_position_t *x, hb_position_t *y) const
{
*x = *y = 0;
switch (u.format) {
- case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
- case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
- case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
+ case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
+ case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
+ case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
default: return;
}
}
@@ -361,7 +374,7 @@ struct AnchorMatrix
{
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false);
- if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
+ if (unlikely (_hb_unsigned_int_mul_overflows (rows, cols))) return_trace (false);
unsigned int count = rows * cols;
if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
for (unsigned int i = 0; i < count; i++)
@@ -419,13 +432,15 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
hb_position_t mark_x, mark_y, base_x, base_y;
- mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
- glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+ mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
+ glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
hb_glyph_position_t &o = buffer->cur_pos();
o.x_offset = base_x - mark_x;
o.y_offset = base_y - mark_y;
- o.attach_lookback() = buffer->idx - glyph_pos;
+ o.attach_type() = ATTACH_TYPE_MARK;
+ o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
buffer->idx++;
return_trace (true);
@@ -461,8 +476,7 @@ struct SinglePosFormat1
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
- valueFormat.apply_value (c->font, c->direction, this,
- values, buffer->cur_pos());
+ valueFormat.apply_value (c, this, values, buffer->cur_pos());
buffer->idx++;
return_trace (true);
@@ -512,7 +526,7 @@ struct SinglePosFormat2
if (likely (index >= valueCount)) return_trace (false);
- valueFormat.apply_value (c->font, c->direction, this,
+ valueFormat.apply_value (c, this,
&values[index * valueFormat.get_len ()],
buffer->cur_pos());
@@ -629,10 +643,8 @@ struct PairSet
min = mid + 1;
else
{
- valueFormats[0].apply_value (c->font, c->direction, this,
- &record->values[0], buffer->cur_pos());
- valueFormats[1].apply_value (c->font, c->direction, this,
- &record->values[len1], buffer->pos[pos]);
+ valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+ valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
if (len2)
pos++;
buffer->idx = pos;
@@ -678,7 +690,7 @@ struct PairPosFormat1
(this+coverage).add_coverage (c->input);
unsigned int count = pairSet.len;
for (unsigned int i = 0; i < count; i++)
- (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
+ (this+pairSet[i]).collect_glyphs (c, valueFormat);
}
inline const Coverage &get_coverage (void) const
@@ -697,7 +709,7 @@ struct PairPosFormat1
skippy_iter.reset (buffer->idx, 1);
if (!skippy_iter.next ()) return_trace (false);
- return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
+ return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -706,11 +718,11 @@ struct PairPosFormat1
if (!c->check_struct (this)) return_trace (false);
- unsigned int len1 = valueFormat1.get_len ();
- unsigned int len2 = valueFormat2.get_len ();
+ unsigned int len1 = valueFormat[0].get_len ();
+ unsigned int len2 = valueFormat[1].get_len ();
PairSet::sanitize_closure_t closure = {
this,
- &valueFormat1,
+ valueFormat,
len1,
1 + len1 + len2
};
@@ -723,10 +735,10 @@ struct PairPosFormat1
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
- ValueFormat valueFormat1; /* Defines the types of data in
+ ValueFormat valueFormat[2]; /* [0] Defines the types of data in
* ValueRecord1--for the first glyph
* in the pair--may be zero (0) */
- ValueFormat valueFormat2; /* Defines the types of data in
+ /* [1] Defines the types of data in
* ValueRecord2--for the second glyph
* in the pair--may be zero (0) */
OffsetArrayOf<PairSet>
@@ -741,7 +753,7 @@ struct PairPosFormat2
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
- /* (this+coverage).add_coverage (c->input); // Don't need this. */
+ (this+coverage).add_coverage (c->input);
unsigned int count1 = class1Count;
const ClassDef &klass1 = this+classDef1;
@@ -779,10 +791,8 @@ struct PairPosFormat2
if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
- valueFormat1.apply_value (c->font, c->direction, this,
- v, buffer->cur_pos());
- valueFormat2.apply_value (c->font, c->direction, this,
- v + len1, buffer->pos[skippy_iter.idx]);
+ valueFormat1.apply_value (c, this, v, buffer->cur_pos());
+ valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
buffer->idx = skippy_iter.idx;
if (len2)
@@ -906,9 +916,6 @@ struct CursivePosFormat1
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
- /* We don't handle mark glyphs here. */
- if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return_trace (false);
-
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
if (!this_record.exitAnchor) return_trace (false);
@@ -923,8 +930,8 @@ struct CursivePosFormat1
unsigned int j = skippy_iter.idx;
hb_position_t entry_x, entry_y, exit_x, exit_y;
- (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
- (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
+ (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
+ (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
hb_glyph_position_t *pos = buffer->pos;
@@ -992,7 +999,9 @@ struct CursivePosFormat1
*/
reverse_cursive_minor_offset (pos, child, c->direction, parent);
- pos[child].cursive_chain() = parent - child;
+ pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
+ pos[child].attach_chain() = (int) parent - (int) child;
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
pos[child].y_offset = y_offset;
else
@@ -1067,7 +1076,7 @@ struct MarkBasePosFormat1
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return_trace (false);
- /* now we search backwards for a non-mark glyph */
+ /* Now we search backwards for a non-mark glyph */
hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
@@ -1079,7 +1088,7 @@ struct MarkBasePosFormat1
} while (1);
/* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
- if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
+ //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
if (base_index == NOT_COVERED) return_trace (false);
@@ -1168,14 +1177,14 @@ struct MarkLigPosFormat1
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return_trace (false);
- /* now we search backwards for a non-mark glyph */
+ /* Now we search backwards for a non-mark glyph */
hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
if (!skippy_iter.prev ()) return_trace (false);
/* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
- if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
+ //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
unsigned int j = skippy_iter.idx;
unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
@@ -1499,7 +1508,8 @@ struct GPOS : GSUBGPOS
{ return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
- static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
+ static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
+ static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -1508,21 +1518,19 @@ struct GPOS : GSUBGPOS
const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
return_trace (list.sanitize (c, this));
}
- public:
- DEFINE_SIZE_STATIC (10);
};
static void
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
{
- unsigned int j = pos[i].cursive_chain();
- if (likely (!j))
+ int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+ if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
return;
- j += i;
+ pos[i].attach_chain() = 0;
- pos[i].cursive_chain() = 0;
+ unsigned int j = (int) i + chain;
/* Stop if we see new parent in the chain. */
if (j == new_parent)
@@ -1535,62 +1543,68 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc
else
pos[j].x_offset = -pos[i].x_offset;
- pos[j].cursive_chain() = i - j;
+ pos[j].attach_chain() = -chain;
+ pos[j].attach_type() = type;
}
static void
-fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
+propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
{
- unsigned int j = pos[i].cursive_chain();
- if (likely (!j))
+ /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
+ * offset of glyph they are attached to. */
+ int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+ if (likely (!chain))
return;
- j += i;
-
- pos[i].cursive_chain() = 0;
+ unsigned int j = (int) i + chain;
- fix_cursive_minor_offset (pos, j, direction);
+ pos[i].attach_chain() = 0;
- if (HB_DIRECTION_IS_HORIZONTAL (direction))
- pos[i].y_offset += pos[j].y_offset;
- else
- pos[i].x_offset += pos[j].x_offset;
-}
+ propagate_attachment_offsets (pos, j, direction);
-static void
-fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
-{
- if (likely (!(pos[i].attach_lookback())))
- return;
+ assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
- unsigned int j = i - pos[i].attach_lookback();
-
- pos[i].x_offset += pos[j].x_offset;
- pos[i].y_offset += pos[j].y_offset;
+ if (type & ATTACH_TYPE_CURSIVE)
+ {
+ if (HB_DIRECTION_IS_HORIZONTAL (direction))
+ pos[i].y_offset += pos[j].y_offset;
+ else
+ pos[i].x_offset += pos[j].x_offset;
+ }
+ else /*if (type & ATTACH_TYPE_MARK)*/
+ {
+ pos[i].x_offset += pos[j].x_offset;
+ pos[i].y_offset += pos[j].y_offset;
- if (HB_DIRECTION_IS_FORWARD (direction))
- for (unsigned int k = j; k < i; k++) {
- pos[i].x_offset -= pos[k].x_advance;
- pos[i].y_offset -= pos[k].y_advance;
- }
- else
- for (unsigned int k = j + 1; k < i + 1; k++) {
- pos[i].x_offset += pos[k].x_advance;
- pos[i].y_offset += pos[k].y_advance;
- }
+ assert (j < i);
+ if (HB_DIRECTION_IS_FORWARD (direction))
+ for (unsigned int k = j; k < i; k++) {
+ pos[i].x_offset -= pos[k].x_advance;
+ pos[i].y_offset -= pos[k].y_advance;
+ }
+ else
+ for (unsigned int k = j + 1; k < i + 1; k++) {
+ pos[i].x_offset += pos[k].x_advance;
+ pos[i].y_offset += pos[k].y_advance;
+ }
+ }
}
void
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
- buffer->clear_positions ();
-
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
- buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
+ buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
}
void
-GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+{
+ //_hb_buffer_assert_gsubgpos_vars (buffer);
+}
+
+void
+GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
_hb_buffer_assert_gsubgpos_vars (buffer);
@@ -1598,13 +1612,10 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
hb_direction_t direction = buffer->props.direction;
- /* Handle cursive connections */
- for (unsigned int i = 0; i < len; i++)
- fix_cursive_minor_offset (pos, i, direction);
-
/* Handle attachments */
- for (unsigned int i = 0; i < len; i++)
- fix_mark_attachment (pos, i, direction);
+ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
+ for (unsigned int i = 0; i < len; i++)
+ propagate_attachment_offsets (pos, i, direction);
}
@@ -1633,8 +1644,8 @@ template <typename context_t>
}
-#undef attach_lookback
-#undef cursive_chain
+#undef attach_chain
+#undef attach_type
} /* namespace OT */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
index eebc87b4c5..66fcb3f3af 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
@@ -41,7 +41,10 @@ struct SingleSubstFormat1
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ /* TODO Switch to range-based API to work around malicious fonts.
+ * https://github.com/behdad/harfbuzz/issues/363 */
hb_codepoint_t glyph_id = iter.get_glyph ();
if (c->glyphs->has (glyph_id))
c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
@@ -52,7 +55,10 @@ struct SingleSubstFormat1
{
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ /* TODO Switch to range-based API to work around malicious fonts.
+ * https://github.com/behdad/harfbuzz/issues/363 */
hb_codepoint_t glyph_id = iter.get_glyph ();
c->input->add (glyph_id);
c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
@@ -120,7 +126,11 @@ struct SingleSubstFormat2
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = substitute.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ()))
c->glyphs->add (substitute[iter.get_coverage ()]);
}
@@ -130,7 +140,11 @@ struct SingleSubstFormat2
{
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = substitute.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
c->input->add (iter.get_glyph ());
c->output->add (substitute[iter.get_coverage ()]);
}
@@ -265,16 +279,6 @@ struct Sequence
TRACE_APPLY (this);
unsigned int count = substitute.len;
- /* TODO:
- * Testing shows that Uniscribe actually allows zero-len susbstitute,
- * which essentially deletes a glyph. We don't allow for now. It
- * can be confusing to the client since the cluster from the deleted
- * glyph won't be merged with any output cluster... Also, currently
- * buffer->move_to() makes assumptions about this too. Perhaps fix
- * in the future after figuring out what to do with the clusters.
- */
- if (unlikely (!count)) return_trace (false);
-
/* Special-case to make it in-place and not consider this
* as a "multiplied" substitution. */
if (unlikely (count == 1))
@@ -282,6 +286,13 @@ struct Sequence
c->replace_glyph (substitute.array[0]);
return_trace (true);
}
+ /* Spec disallows this, but Uniscribe allows it.
+ * https://github.com/behdad/harfbuzz/issues/253 */
+ else if (unlikely (count == 0))
+ {
+ c->buffer->delete_glyph ();
+ return_trace (true);
+ }
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
@@ -324,7 +335,11 @@ struct MultipleSubstFormat1
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = sequence.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ()))
(this+sequence[iter.get_coverage ()]).closure (c);
}
@@ -442,7 +457,11 @@ struct AlternateSubstFormat1
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = alternateSet.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ())) {
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
unsigned int count = alt_set.len;
@@ -456,7 +475,11 @@ struct AlternateSubstFormat1
{
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = alternateSet.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
c->input->add (iter.get_glyph ());
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
unsigned int count = alt_set.len;
@@ -630,7 +653,7 @@ struct Ligature
unsigned int total_component_count = 0;
unsigned int match_length = 0;
- unsigned int match_positions[MAX_CONTEXT_LENGTH];
+ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
if (likely (!match_input (c, count,
&component[1],
@@ -765,7 +788,11 @@ struct LigatureSubstFormat1
{
TRACE_CLOSURE (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = ligatureSet.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ()))
(this+ligatureSet[iter.get_coverage ()]).closure (c);
}
@@ -775,7 +802,11 @@ struct LigatureSubstFormat1
{
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ unsigned int count = ligatureSet.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
c->input->add (iter.get_glyph ());
(this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
}
@@ -926,7 +957,11 @@ struct ReverseChainSingleSubstFormat1
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ count = substitute.len;
+ for (iter.init (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
if (c->glyphs->has (iter.get_glyph ()))
c->glyphs->add (substitute[iter.get_coverage ()]);
}
@@ -970,7 +1005,7 @@ struct ReverseChainSingleSubstFormat1
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY (this);
- if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
+ if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
return_trace (false); /* No chaining to this type */
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@@ -1268,7 +1303,6 @@ struct GSUB : GSUBGPOS
{ return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
- static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -1277,8 +1311,6 @@ struct GSUB : GSUBGPOS
const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
return_trace (list.sanitize (c, this));
}
- public:
- DEFINE_SIZE_STATIC (10);
};
@@ -1297,11 +1329,6 @@ GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
}
}
-void
-GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
-{
-}
-
/* Out-of-class implementation for methods recursing */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh
index 230b3b6851..fd75c5425a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh
@@ -74,7 +74,7 @@ struct hb_closure_context_t :
hb_closure_context_t (hb_face_t *face_,
hb_set_t *glyphs_,
- unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+ unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
face (face_),
glyphs (glyphs_),
recurse_func (NULL),
@@ -196,7 +196,7 @@ struct hb_collect_glyphs_context_t :
hb_set_t *glyphs_input, /* OUT. May be NULL */
hb_set_t *glyphs_after, /* OUT. May be NULL */
hb_set_t *glyphs_output, /* OUT. May be NULL */
- unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+ unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
face (face_),
before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
@@ -319,7 +319,7 @@ struct hb_apply_context_t :
if (!c->check_glyph_property (&info, lookup_props))
return SKIP_YES;
- if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
+ if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_fvs (&info) &&
(ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
(ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
return SKIP_MAYBE;
@@ -469,6 +469,7 @@ struct hb_apply_context_t :
unsigned int lookup_props;
const GDEF &gdef;
bool has_glyph_classes;
+ const VariationStore &var_store;
skipping_iterator_t iter_input, iter_context;
unsigned int lookup_index;
unsigned int debug_depth;
@@ -483,10 +484,11 @@ struct hb_apply_context_t :
lookup_mask (1),
auto_zwj (true),
recurse_func (NULL),
- nesting_level_left (MAX_NESTING_LEVEL),
+ nesting_level_left (HB_MAX_NESTING_LEVEL),
lookup_props (0),
gdef (*hb_ot_layout_from_face (face)->gdef),
has_glyph_classes (gdef.has_glyph_classes ()),
+ var_store (gdef.get_var_store ()),
iter_input (),
iter_context (),
lookup_index ((unsigned int) -1),
@@ -704,13 +706,13 @@ static inline bool match_input (hb_apply_context_t *c,
match_func_t match_func,
const void *match_data,
unsigned int *end_offset,
- unsigned int match_positions[MAX_CONTEXT_LENGTH],
+ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
bool *p_is_mark_ligature = NULL,
unsigned int *p_total_component_count = NULL)
{
TRACE_APPLY (NULL);
- if (unlikely (count > MAX_CONTEXT_LENGTH)) return_trace (false);
+ if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
hb_buffer_t *buffer = c->buffer;
@@ -784,7 +786,7 @@ static inline bool match_input (hb_apply_context_t *c,
}
static inline bool ligate_input (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph */
- unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
+ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
unsigned int match_length,
hb_codepoint_t lig_glyph,
bool is_mark_ligature,
@@ -836,19 +838,21 @@ static inline bool ligate_input (hb_apply_context_t *c,
if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
{
_hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
- _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
}
}
c->replace_glyph_with_ligature (lig_glyph, klass);
for (unsigned int i = 1; i < count; i++)
{
- while (buffer->idx < match_positions[i])
+ while (buffer->idx < match_positions[i] && !buffer->in_error)
{
if (!is_mark_ligature) {
+ unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+ if (this_comp == 0)
+ this_comp = last_num_components;
unsigned int new_lig_comp = components_so_far - last_num_components +
- MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
- _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
+ MIN (this_comp, last_num_components);
+ _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
}
buffer->next_glyph ();
}
@@ -865,8 +869,11 @@ static inline bool ligate_input (hb_apply_context_t *c,
/* Re-adjust components for any marks following. */
for (unsigned int i = buffer->idx; i < buffer->len; i++) {
if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
+ unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
+ if (!this_comp)
+ break;
unsigned int new_lig_comp = components_so_far - last_num_components +
- MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
+ MIN (this_comp, last_num_components);
_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
} else
break;
@@ -944,7 +951,7 @@ static inline void recurse_lookups (context_t *c,
static inline bool apply_lookup (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph */
- unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
+ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
unsigned int match_length)
@@ -966,12 +973,17 @@ static inline bool apply_lookup (hb_apply_context_t *c,
match_positions[j] += delta;
}
- for (unsigned int i = 0; i < lookupCount; i++)
+ for (unsigned int i = 0; i < lookupCount && !buffer->in_error; i++)
{
unsigned int idx = lookupRecord[i].sequenceIndex;
if (idx >= count)
continue;
+ /* Don't recurse to ourself at same position.
+ * Note that this test is too naive, it doesn't catch longer loops. */
+ if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
+ continue;
+
buffer->move_to (match_positions[idx]);
unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
@@ -986,16 +998,23 @@ static inline bool apply_lookup (hb_apply_context_t *c,
/* Recursed lookup changed buffer len. Adjust. */
- /* end can't go back past the current match position.
- * Note: this is only true because we do NOT allow MultipleSubst
- * with zero sequence len. */
- end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
+ end = int (end) + delta;
+ if (end <= match_positions[idx])
+ {
+ /* End might end up being smaller than match_positions[idx] if the recursed
+ * lookup ended up removing many items, more than we have had matched.
+ * Just never rewind end back and get out of here.
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
+ end = match_positions[idx];
+ /* There can't be any further changes. */
+ break;
+ }
unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
if (delta > 0)
{
- if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
+ if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
break;
}
else
@@ -1094,7 +1113,7 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
ContextApplyLookupContext &lookup_context)
{
unsigned int match_length = 0;
- unsigned int match_positions[MAX_CONTEXT_LENGTH];
+ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
return match_input (c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data,
@@ -1621,7 +1640,7 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
ChainContextApplyLookupContext &lookup_context)
{
unsigned int match_length = 0;
- unsigned int match_positions[MAX_CONTEXT_LENGTH];
+ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
return match_input (c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data[1],
@@ -2256,6 +2275,24 @@ struct GSUBGPOS
inline const Lookup& get_lookup (unsigned int i) const
{ return (this+lookupList)[i]; }
+ inline bool find_variations_index (const int *coords, unsigned int num_coords,
+ unsigned int *index) const
+ { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
+ .find_index (coords, num_coords, index); }
+ inline const Feature& get_feature_variation (unsigned int feature_index,
+ unsigned int variations_index) const
+ {
+ if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
+ version.to_int () >= 0x00010001u)
+ {
+ const Feature *feature = (this+featureVars).find_substitute (variations_index,
+ feature_index);
+ if (feature)
+ return *feature;
+ }
+ return get_feature (feature_index);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -2263,11 +2300,12 @@ struct GSUBGPOS
likely (version.major == 1) &&
scriptList.sanitize (c, this) &&
featureList.sanitize (c, this) &&
- lookupList.sanitize (c, this));
+ lookupList.sanitize (c, this) &&
+ (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
}
protected:
- FixedVersion version; /* Version of the GSUB/GPOS table--initially set
+ FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
* to 0x00010000u */
OffsetTo<ScriptList>
scriptList; /* ScriptList table */
@@ -2275,8 +2313,13 @@ struct GSUBGPOS
featureList; /* FeatureList table */
OffsetTo<LookupList>
lookupList; /* LookupList table */
+ OffsetTo<FeatureVariations, ULONG>
+ featureVars; /* Offset to Feature Variations
+ table--from beginning of table
+ * (may be NULL). Introduced
+ * in version 0x00010001. */
public:
- DEFINE_SIZE_STATIC (10);
+ DEFINE_SIZE_MIN (10);
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
index 7e199c2e14..c3068491be 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
@@ -218,7 +218,7 @@ struct JSTF
}
protected:
- FixedVersion version; /* Version of the JSTF table--initially set
+ FixedVersion<>version; /* Version of the JSTF table--initially set
* to 0x00010000u */
RecordArrayOf<JstfScript>
scriptList; /* Array of JstfScripts--listed
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-math-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-math-table.hh
new file mode 100644
index 0000000000..b52b1215d2
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-math-table.hh
@@ -0,0 +1,722 @@
+/*
+ * Copyright © 2016 Igalia S.L.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Igalia Author(s): Frédéric Wang
+ */
+
+#ifndef HB_OT_LAYOUT_MATH_TABLE_HH
+#define HB_OT_LAYOUT_MATH_TABLE_HH
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-layout-common-private.hh"
+#include "hb-ot-math.h"
+
+namespace OT {
+
+
+struct MathValueRecord
+{
+ inline hb_position_t get_x_value (hb_font_t *font, const void *base) const
+ { return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); }
+ inline hb_position_t get_y_value (hb_font_t *font, const void *base) const
+ { return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
+ }
+
+ protected:
+ SHORT value; /* The X or Y value in design units */
+ OffsetTo<Device> deviceTable; /* Offset to the device table - from the
+ * beginning of parent table. May be NULL.
+ * Suggested format for device table is 1. */
+
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+struct MathConstants
+{
+ inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+
+ unsigned int count = ARRAY_LENGTH (mathValueRecords);
+ for (unsigned int i = 0; i < count; i++)
+ if (!mathValueRecords[i].sanitize (c, this))
+ return_trace (false);
+
+ return_trace (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && sanitize_math_value_records(c));
+ }
+
+ inline hb_position_t get_value (hb_ot_math_constant_t constant,
+ hb_font_t *font) const
+ {
+ switch (constant) {
+
+ case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
+ case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
+ return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
+
+ case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
+ case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
+ return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
+
+ case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
+ case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
+ case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
+ case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
+ return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value(font, this);
+
+ case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
+ case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
+ case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
+ case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
+ case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
+ case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_MATH_LEADING:
+ case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
+ case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
+ case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
+ case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
+ case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
+ case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
+ case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
+ case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
+ case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
+ case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
+ case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
+ case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
+ case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
+ case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
+ case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
+ case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
+ return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value(font, this);
+
+ case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
+ return radicalDegreeBottomRaisePercent;
+
+ default:
+ return 0;
+ }
+ }
+
+ protected:
+ SHORT percentScaleDown[2];
+ USHORT minHeight[2];
+ MathValueRecord mathValueRecords[51];
+ SHORT radicalDegreeBottomRaisePercent;
+
+ public:
+ DEFINE_SIZE_STATIC (214);
+};
+
+struct MathItalicsCorrectionInfo
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ coverage.sanitize (c, this) &&
+ italicsCorrection.sanitize (c, this));
+ }
+
+ inline hb_position_t get_value (hb_codepoint_t glyph,
+ hb_font_t *font) const
+ {
+ unsigned int index = (this+coverage).get_coverage (glyph);
+ return italicsCorrection[index].get_x_value (font, this);
+ }
+
+ protected:
+ OffsetTo<Coverage> coverage; /* Offset to Coverage table -
+ * from the beginning of
+ * MathItalicsCorrectionInfo
+ * table. */
+ ArrayOf<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
+ * defining italics correction
+ * values for each
+ * covered glyph. */
+
+ public:
+ DEFINE_SIZE_ARRAY (4, italicsCorrection);
+};
+
+struct MathTopAccentAttachment
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ topAccentCoverage.sanitize (c, this) &&
+ topAccentAttachment.sanitize (c, this));
+ }
+
+ inline hb_position_t get_value (hb_codepoint_t glyph,
+ hb_font_t *font) const
+ {
+ unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
+ if (index == NOT_COVERED)
+ return font->get_glyph_h_advance (glyph) / 2;
+ return topAccentAttachment[index].get_x_value(font, this);
+ }
+
+ protected:
+ OffsetTo<Coverage> topAccentCoverage; /* Offset to Coverage table -
+ * from the beginning of
+ * MathTopAccentAttachment
+ * table. */
+ ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
+ * defining top accent
+ * attachment points for each
+ * covered glyph. */
+
+ public:
+ DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
+};
+
+struct MathKern
+{
+ inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ unsigned int count = 2 * heightCount + 1;
+ for (unsigned int i = 0; i < count; i++)
+ if (!mathValueRecords[i].sanitize (c, this)) return_trace (false);
+ return_trace (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ c->check_array (mathValueRecords,
+ mathValueRecords[0].static_size,
+ 2 * heightCount + 1) &&
+ sanitize_math_value_records (c));
+ }
+
+ inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
+ {
+ const MathValueRecord* correctionHeight = mathValueRecords;
+ const MathValueRecord* kernValue = mathValueRecords + heightCount;
+ int sign = font->y_scale < 0 ? -1 : +1;
+
+ /* The description of the MathKern table is a ambiguous, but interpreting
+ * "between the two heights found at those indexes" for 0 < i < len as
+ *
+ * correctionHeight[i-1] < correction_height <= correctionHeight[i]
+ *
+ * makes the result consistent with the limit cases and we can just use the
+ * binary search algorithm of std::upper_bound:
+ */
+ unsigned int i = 0;
+ unsigned int count = heightCount;
+ while (count > 0)
+ {
+ unsigned int half = count / 2;
+ hb_position_t height = correctionHeight[i + half].get_y_value(font, this);
+ if (sign * height < sign * correction_height)
+ {
+ i += half + 1;
+ count -= half + 1;
+ } else
+ count = half;
+ }
+ return kernValue[i].get_x_value(font, this);
+ }
+
+ protected:
+ USHORT heightCount;
+ MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
+ * which the kern value changes.
+ * Sorted by the height value in
+ * design units (heightCount entries),
+ * Followed by:
+ * Array of kern values corresponding
+ * to heights. (heightCount+1 entries).
+ */
+
+ public:
+ DEFINE_SIZE_ARRAY (2, mathValueRecords);
+};
+
+struct MathKernInfoRecord
+{
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+
+ unsigned int count = ARRAY_LENGTH (mathKern);
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!mathKern[i].sanitize (c, base)))
+ return_trace (false);
+
+ return_trace (true);
+ }
+
+ inline hb_position_t get_kerning (hb_ot_math_kern_t kern,
+ hb_position_t correction_height,
+ hb_font_t *font,
+ const void *base) const
+ {
+ unsigned int idx = kern;
+ if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
+ return (base+mathKern[idx]).get_value (correction_height, font);
+ }
+
+ protected:
+ /* Offset to MathKern table for each corner -
+ * from the beginning of MathKernInfo table. May be NULL. */
+ OffsetTo<MathKern> mathKern[4];
+
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct MathKernInfo
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ mathKernCoverage.sanitize (c, this) &&
+ mathKernInfoRecords.sanitize (c, this));
+ }
+
+ inline hb_position_t get_kerning (hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height,
+ hb_font_t *font) const
+ {
+ unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
+ return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
+ }
+
+ protected:
+ OffsetTo<Coverage> mathKernCoverage; /* Offset to Coverage table -
+ * from the beginning of the
+ * MathKernInfo table. */
+ ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of
+ * MathKernInfoRecords,
+ * per-glyph information for
+ * mathematical positioning
+ * of subscripts and
+ * superscripts. */
+
+ public:
+ DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
+};
+
+struct MathGlyphInfo
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ mathItalicsCorrectionInfo.sanitize (c, this) &&
+ mathTopAccentAttachment.sanitize (c, this) &&
+ extendedShapeCoverage.sanitize (c, this) &&
+ mathKernInfo.sanitize(c, this));
+ }
+
+ inline hb_position_t
+ get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const
+ { return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
+
+ inline hb_position_t
+ get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const
+ { return (this+mathTopAccentAttachment).get_value (glyph, font); }
+
+ inline bool is_extended_shape (hb_codepoint_t glyph) const
+ { return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
+
+ inline hb_position_t get_kerning (hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height,
+ hb_font_t *font) const
+ { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
+
+ protected:
+ /* Offset to MathItalicsCorrectionInfo table -
+ * from the beginning of MathGlyphInfo table. */
+ OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
+
+ /* Offset to MathTopAccentAttachment table -
+ * from the beginning of MathGlyphInfo table. */
+ OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
+
+ /* Offset to coverage table for Extended Shape glyphs -
+ * from the beginning of MathGlyphInfo table. When the left or right glyph of
+ * a box is an extended shape variant, the (ink) box (and not the default
+ * position defined by values in MathConstants table) should be used for
+ * vertical positioning purposes. May be NULL.. */
+ OffsetTo<Coverage> extendedShapeCoverage;
+
+ /* Offset to MathKernInfo table -
+ * from the beginning of MathGlyphInfo table. */
+ OffsetTo<MathKernInfo> mathKernInfo;
+
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct MathGlyphVariantRecord
+{
+ friend struct MathGlyphConstruction;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ protected:
+ GlyphID variantGlyph; /* Glyph ID for the variant. */
+ USHORT advanceMeasurement; /* Advance width/height, in design units, of the
+ * variant, in the direction of requested
+ * glyph extension. */
+
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+struct PartFlags : USHORT
+{
+ enum Flags {
+ Extender = 0x0001u, /* If set, the part can be skipped or repeated. */
+
+ Defined = 0x0001u, /* All defined flags. */
+ };
+
+ public:
+ DEFINE_SIZE_STATIC (2);
+};
+
+struct MathGlyphPartRecord
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ inline void extract (hb_ot_math_glyph_part_t &out,
+ int scale,
+ hb_font_t *font) const
+ {
+ out.glyph = glyph;
+
+ out.start_connector_length = font->em_scale (startConnectorLength, scale);
+ out.end_connector_length = font->em_scale (endConnectorLength, scale);
+ out.full_advance = font->em_scale (fullAdvance, scale);
+
+ ASSERT_STATIC ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
+ (unsigned int) PartFlags::Extender);
+
+ out.flags = (hb_ot_math_glyph_part_flags_t)
+ (unsigned int)
+ (partFlags & PartFlags::Defined);
+ }
+
+ protected:
+ GlyphID glyph; /* Glyph ID for the part. */
+ USHORT startConnectorLength; /* Advance width/ height of the straight bar
+ * connector material, in design units, is at
+ * the beginning of the glyph, in the
+ * direction of the extension. */
+ USHORT endConnectorLength; /* Advance width/ height of the straight bar
+ * connector material, in design units, is at
+ * the end of the glyph, in the direction of
+ * the extension. */
+ USHORT fullAdvance; /* Full advance width/height for this part,
+ * in the direction of the extension.
+ * In design units. */
+ PartFlags partFlags; /* Part qualifiers. */
+
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
+struct MathGlyphAssembly
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ italicsCorrection.sanitize(c, this) &&
+ partRecords.sanitize(c));
+ }
+
+ inline unsigned int get_parts (hb_direction_t direction,
+ hb_font_t *font,
+ unsigned int start_offset,
+ unsigned int *parts_count, /* IN/OUT */
+ hb_ot_math_glyph_part_t *parts /* OUT */,
+ hb_position_t *italics_correction /* OUT */) const
+ {
+ if (parts_count)
+ {
+ int scale = font->dir_scale (direction);
+ const MathGlyphPartRecord *arr =
+ partRecords.sub_array (start_offset, parts_count);
+ unsigned int count = *parts_count;
+ for (unsigned int i = 0; i < count; i++)
+ arr[i].extract (parts[i], scale, font);
+ }
+
+ if (italics_correction)
+ *italics_correction = italicsCorrection.get_x_value (font, this);
+
+ return partRecords.len;
+ }
+
+ protected:
+ MathValueRecord italicsCorrection; /* Italics correction of this
+ * MathGlyphAssembly. Should not
+ * depend on the assembly size. */
+ ArrayOf<MathGlyphPartRecord> partRecords; /* Array of part records, from
+ * left to right and bottom to
+ * top. */
+
+ public:
+ DEFINE_SIZE_ARRAY (6, partRecords);
+};
+
+struct MathGlyphConstruction
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ glyphAssembly.sanitize(c, this) &&
+ mathGlyphVariantRecord.sanitize(c));
+ }
+
+ inline const MathGlyphAssembly &get_assembly (void) const
+ { return this+glyphAssembly; }
+
+ inline unsigned int get_variants (hb_direction_t direction,
+ hb_font_t *font,
+ unsigned int start_offset,
+ unsigned int *variants_count, /* IN/OUT */
+ hb_ot_math_glyph_variant_t *variants /* OUT */) const
+ {
+ if (variants_count)
+ {
+ int scale = font->dir_scale (direction);
+ const MathGlyphVariantRecord *arr =
+ mathGlyphVariantRecord.sub_array (start_offset, variants_count);
+ unsigned int count = *variants_count;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ variants[i].glyph = arr[i].variantGlyph;
+ variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale);
+ }
+ }
+ return mathGlyphVariantRecord.len;
+ }
+
+ protected:
+ /* Offset to MathGlyphAssembly table for this shape - from the beginning of
+ MathGlyphConstruction table. May be NULL. */
+ OffsetTo<MathGlyphAssembly> glyphAssembly;
+
+ /* MathGlyphVariantRecords for alternative variants of the glyphs. */
+ ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
+
+ public:
+ DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
+};
+
+struct MathVariants
+{
+ inline bool sanitize_offsets (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ unsigned int count = vertGlyphCount + horizGlyphCount;
+ for (unsigned int i = 0; i < count; i++)
+ if (!glyphConstruction[i].sanitize (c, this)) return_trace (false);
+ return_trace (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ vertGlyphCoverage.sanitize (c, this) &&
+ horizGlyphCoverage.sanitize (c, this) &&
+ c->check_array (glyphConstruction,
+ glyphConstruction[0].static_size,
+ vertGlyphCount + horizGlyphCount) &&
+ sanitize_offsets (c));
+ }
+
+ inline hb_position_t get_min_connector_overlap (hb_direction_t direction,
+ hb_font_t *font) const
+ { return font->em_scale_dir (minConnectorOverlap, direction); }
+
+ inline unsigned int get_glyph_variants (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_font_t *font,
+ unsigned int start_offset,
+ unsigned int *variants_count, /* IN/OUT */
+ hb_ot_math_glyph_variant_t *variants /* OUT */) const
+ { return get_glyph_construction (glyph, direction, font)
+ .get_variants (direction, font, start_offset, variants_count, variants); }
+
+ inline unsigned int get_glyph_parts (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_font_t *font,
+ unsigned int start_offset,
+ unsigned int *parts_count, /* IN/OUT */
+ hb_ot_math_glyph_part_t *parts /* OUT */,
+ hb_position_t *italics_correction /* OUT */) const
+ { return get_glyph_construction (glyph, direction, font)
+ .get_assembly ()
+ .get_parts (direction, font,
+ start_offset, parts_count, parts,
+ italics_correction); }
+
+ private:
+ inline const MathGlyphConstruction &
+ get_glyph_construction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_font_t *font) const
+ {
+ bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
+ unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
+ const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage
+ : horizGlyphCoverage;
+
+ unsigned int index = (this+coverage).get_coverage (glyph);
+ if (unlikely (index >= count)) return Null(MathGlyphConstruction);
+
+ if (!vertical)
+ index += vertGlyphCount;
+
+ return this+glyphConstruction[index];
+ }
+
+ protected:
+ USHORT minConnectorOverlap; /* Minimum overlap of connecting
+ * glyphs during glyph construction,
+ * in design units. */
+ OffsetTo<Coverage> vertGlyphCoverage; /* Offset to Coverage table -
+ * from the beginning of MathVariants
+ * table. */
+ OffsetTo<Coverage> horizGlyphCoverage; /* Offset to Coverage table -
+ * from the beginning of MathVariants
+ * table. */
+ USHORT vertGlyphCount; /* Number of glyphs for which
+ * information is provided for
+ * vertically growing variants. */
+ USHORT horizGlyphCount; /* Number of glyphs for which
+ * information is provided for
+ * horizontally growing variants. */
+
+ /* Array of offsets to MathGlyphConstruction tables - from the beginning of
+ the MathVariants table, for shapes growing in vertical/horizontal
+ direction. */
+ OffsetTo<MathGlyphConstruction> glyphConstruction[VAR];
+
+ public:
+ DEFINE_SIZE_ARRAY (10, glyphConstruction);
+};
+
+
+/*
+ * MATH -- The MATH Table
+ */
+
+struct MATH
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_MATH;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (version.sanitize (c) &&
+ likely (version.major == 1) &&
+ mathConstants.sanitize (c, this) &&
+ mathGlyphInfo.sanitize (c, this) &&
+ mathVariants.sanitize (c, this));
+ }
+
+ inline hb_position_t get_constant (hb_ot_math_constant_t constant,
+ hb_font_t *font) const
+ { return (this+mathConstants).get_value (constant, font); }
+
+ inline const MathGlyphInfo &get_math_glyph_info (void) const
+ { return this+mathGlyphInfo; }
+
+ inline const MathVariants &get_math_variants (void) const
+ { return this+mathVariants; }
+
+ protected:
+ FixedVersion<>version; /* Version of the MATH table
+ * initially set to 0x00010000u */
+ OffsetTo<MathConstants> mathConstants;/* MathConstants table */
+ OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */
+ OffsetTo<MathVariants> mathVariants; /* MathVariants table */
+
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
+} /* mathspace OT */
+
+
+#endif /* HB_OT_LAYOUT_MATH_TABLE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-private.hh
index d168e27f53..a4272de631 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-private.hh
@@ -49,7 +49,7 @@ hb_ot_layout_table_find_feature (hb_face_t *face,
* GDEF
*/
-typedef enum
+enum hb_ot_layout_glyph_props_flags_t
{
/* The following three match LookupFlags::Ignore* numbers. */
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 0x02u,
@@ -64,7 +64,8 @@ typedef enum
HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
-} hb_ot_layout_glyph_class_mask_t;
+};
+HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);
/*
@@ -98,21 +99,20 @@ hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
const hb_ot_layout_lookup_accelerator_t &accel);
-/* Should be called after all the substitute_lookup's are done */
-HB_INTERNAL void
-hb_ot_layout_substitute_finish (hb_font_t *font,
- hb_buffer_t *buffer);
-
-
-/* Should be called before all the position_lookup's are done. Resets positions to zero. */
+/* Should be called before all the position_lookup's are done. */
HB_INTERNAL void
hb_ot_layout_position_start (hb_font_t *font,
hb_buffer_t *buffer);
-/* Should be called after all the position_lookup's are done */
+/* Should be called after all the position_lookup's are done, to finish advances. */
+HB_INTERNAL void
+hb_ot_layout_position_finish_advances (hb_font_t *font,
+ hb_buffer_t *buffer);
+
+/* Should be called after hb_ot_layout_position_finish_advances, to finish offsets. */
HB_INTERNAL void
-hb_ot_layout_position_finish (hb_font_t *font,
- hb_buffer_t *buffer);
+hb_ot_layout_position_finish_offsets (hb_font_t *font,
+ hb_buffer_t *buffer);
@@ -124,6 +124,7 @@ namespace OT {
struct GDEF;
struct GSUB;
struct GPOS;
+ struct MATH;
}
struct hb_ot_layout_lookup_accelerator_t
@@ -152,10 +153,12 @@ struct hb_ot_layout_t
hb_blob_t *gdef_blob;
hb_blob_t *gsub_blob;
hb_blob_t *gpos_blob;
+ hb_blob_t *math_blob;
const struct OT::GDEF *gdef;
const struct OT::GSUB *gsub;
const struct OT::GPOS *gpos;
+ const struct OT::MATH *math;
unsigned int gsub_lookup_count;
unsigned int gpos_lookup_count;
@@ -180,8 +183,7 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout);
*/
/* buffer var allocations, used during the entire shaping process */
-#define unicode_props0() var2.u8[0]
-#define unicode_props1() var2.u8[1]
+#define unicode_props() var2.u16[0]
/* buffer var allocations, used during the GSUB/GPOS processing */
#define glyph_props() var1.u16[0] /* GDEF glyph properties */
@@ -214,48 +216,146 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start)
/* unicode_props */
-enum {
- MASK0_ZWJ = 0x20u,
- MASK0_ZWNJ = 0x40u,
- MASK0_IGNORABLE = 0x80u,
- MASK0_GEN_CAT = 0x1Fu
+/* Design:
+ * unicode_props() is a two-byte number. The low byte includes:
+ * - General_Category: 5 bits.
+ * - A bit each for:
+ * * Is it Default_Ignorable(); we have a modified Default_Ignorable().
+ * * Whether it's one of the three Mongolian Free Variation Selectors.
+ * * One free bit right now.
+ *
+ * The high-byte has different meanings, switched by the Gen-Cat:
+ * - For Mn,Mc,Me: the modified Combining_Class.
+ * - For Cf: whether it's ZWJ, ZWNJ, or something else.
+ * - For Ws: index of which space character this is, if space fallback
+ * is needed, ie. we don't set this by default, only if asked to.
+ */
+
+enum hb_unicode_props_flags_t {
+ UPROPS_MASK_GEN_CAT = 0x001Fu,
+ UPROPS_MASK_IGNORABLE = 0x0020u,
+ UPROPS_MASK_FVS = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3 */
+
+ /* If GEN_CAT=FORMAT, top byte masks: */
+ UPROPS_MASK_Cf_ZWJ = 0x0100u,
+ UPROPS_MASK_Cf_ZWNJ = 0x0200u
};
+HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
static inline void
-_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
+_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
{
- /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
- info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
- (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
- (info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
- (info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
- info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
+ hb_unicode_funcs_t *unicode = buffer->unicode;
+ unsigned int u = info->codepoint;
+ unsigned int gen_cat = (unsigned int) unicode->general_category (u);
+ unsigned int props = gen_cat;
+
+ if (u >= 0x80)
+ {
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
+ if (unlikely (unicode->is_default_ignorable (u)))
+ {
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
+ props |= UPROPS_MASK_IGNORABLE;
+ if (u == 0x200Cu) props |= UPROPS_MASK_Cf_ZWNJ;
+ if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
+ /* Mongolian Free Variation Selectors need to be remembered
+ * because although we need to hide them like default-ignorables,
+ * they need to non-ignorable during shaping. This is similar to
+ * what we do for joiners in Indic-like shapers, but since the
+ * FVSes are GC=Mn, we have use a separate bit to remember them.
+ * Fixes:
+ * https://github.com/behdad/harfbuzz/issues/234
+ */
+ if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_FVS;
+ }
+ else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
+ {
+ /* The above check is just an optimization to let in only things we need further
+ * processing on. */
+
+ /* Only Mn and Mc can have non-zero ccc:
+ * http://www.unicode.org/policies/stability_policy.html#Property_Value
+ * """
+ * Canonical_Combining_Class, General_Category
+ * All characters other than those with General_Category property values
+ * Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class
+ * property value 0.
+ * 1.1.5+
+ * """
+ *
+ * Also, all Mn's that are Default_Ignorable, have ccc=0, hence
+ * the "else if".
+ */
+ props |= unicode->modified_combining_class (info->codepoint)<<8;
+
+ /* Recategorize emoji skin-tone modifiers as Unicode mark, so they
+ * behave correctly in non-native directionality. They originally
+ * are MODIFIER_SYMBOL. Fixes:
+ * https://github.com/behdad/harfbuzz/issues/169
+ */
+ if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
+ {
+ props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
+ }
+ }
+ }
+
+ info->unicode_props() = props;
}
static inline void
_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
hb_unicode_general_category_t gen_cat)
{
- info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
+ /* Clears top-byte. */
+ info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
}
static inline hb_unicode_general_category_t
_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
{
- return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
+ return (hb_unicode_general_category_t) (info->unicode_props() & UPROPS_MASK_GEN_CAT);
}
+static inline bool
+_hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
+{
+ return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
+}
static inline void
_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
unsigned int modified_class)
{
- info->unicode_props1() = modified_class;
+ if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
+ return;
+ info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
}
-
static inline unsigned int
_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{
- return info->unicode_props1();
+ return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
+}
+
+static inline bool
+_hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
+{
+ return _hb_glyph_info_get_general_category (info) ==
+ HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
+}
+static inline void
+_hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
+{
+ if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
+ return;
+ info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
+}
+static inline hb_unicode_funcs_t::space_t
+_hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
+{
+ return _hb_glyph_info_is_unicode_space (info) ?
+ (hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
+ hb_unicode_funcs_t::NOT_SPACE;
}
static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
@@ -263,25 +363,44 @@ static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
static inline hb_bool_t
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
- return (info->unicode_props0() & MASK0_IGNORABLE) && !_hb_glyph_info_ligated (info);
+ return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
+ !_hb_glyph_info_ligated (info);
+}
+static inline hb_bool_t
+_hb_glyph_info_is_default_ignorable_and_not_fvs (const hb_glyph_info_t *info)
+{
+ return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_FVS))
+ == UPROPS_MASK_IGNORABLE) &&
+ !_hb_glyph_info_ligated (info);
}
+static inline bool
+_hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info)
+{
+ return _hb_glyph_info_get_general_category (info) ==
+ HB_UNICODE_GENERAL_CATEGORY_FORMAT;
+}
static inline hb_bool_t
_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
{
- return !!(info->unicode_props0() & MASK0_ZWNJ);
+ return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWNJ);
}
-
static inline hb_bool_t
_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
{
- return !!(info->unicode_props0() & MASK0_ZWJ);
+ return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ);
+}
+static inline hb_bool_t
+_hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
+{
+ return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ));
}
-
static inline void
_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
{
- info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
+ if (!_hb_glyph_info_is_unicode_format (info))
+ return;
+ info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ;
}
/* lig_props: aka lig_id / lig_comp
@@ -442,11 +561,9 @@ _hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
}
static inline void
-_hb_glyph_info_clear_substituted_and_ligated_and_multiplied (hb_glyph_info_t *info)
+_hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
{
- info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
- HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
- HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+ info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
}
@@ -455,22 +572,19 @@ _hb_glyph_info_clear_substituted_and_ligated_and_multiplied (hb_glyph_info_t *in
static inline void
_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
{
- HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
- HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
+ HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
}
static inline void
_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
{
- HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
- HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
+ HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
}
static inline void
_hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
{
- HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
- HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
+ HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
}
static inline void
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
index 275a960d58..145ec76389 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
@@ -60,6 +60,92 @@ _hb_ot_layout_create (hb_face_t *face)
layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
+ /* The MATH table is rarely used, so only try and load it in _get_math. */
+ layout->math_blob = NULL;
+ layout->math = NULL;
+
+ {
+ /*
+ * The ugly business of blacklisting individual fonts' tables happen here!
+ * See this thread for why we finally had to bend in and do this:
+ * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
+ */
+ unsigned int gdef_len = hb_blob_get_length (layout->gdef_blob);
+ unsigned int gsub_len = hb_blob_get_length (layout->gsub_blob);
+ unsigned int gpos_len = hb_blob_get_length (layout->gpos_blob);
+ if (0
+ /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
+ || (442 == gdef_len && 42038 == gpos_len && 2874 == gsub_len)
+ /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
+ || (430 == gdef_len && 40662 == gpos_len && 2874 == gsub_len)
+ /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
+ || (442 == gdef_len && 39116 == gpos_len && 2874 == gsub_len)
+ /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
+ || (430 == gdef_len && 39374 == gpos_len && 2874 == gsub_len)
+ /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
+ || (490 == gdef_len && 41638 == gpos_len && 3046 == gsub_len)
+ /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
+ || (478 == gdef_len && 41902 == gpos_len && 3046 == gsub_len)
+ )
+ {
+ /* In certain versions of Times New Roman Italic and Bold Italic,
+ * ASCII double quotation mark U+0022, mapped to glyph 5, has wrong
+ * glyph class 3 (mark) in GDEF. Nuke the GDEF to avoid zero-width
+ * double-quote. See:
+ * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
+ */
+ if (3 == layout->gdef->get_glyph_class (5))
+ layout->gdef = &OT::Null(OT::GDEF);
+ }
+ else if (0
+ /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */
+ || (898 == gdef_len && 46470 == gpos_len && 12554 == gsub_len)
+ /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */
+ || (910 == gdef_len && 47732 == gpos_len && 12566 == gsub_len)
+ /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */
+ || (928 == gdef_len && 59332 == gpos_len && 23298 == gsub_len)
+ /* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */
+ || (940 == gdef_len && 60732 == gpos_len && 23310 == gsub_len)
+ /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */
+ || (994 == gdef_len && 60336 == gpos_len && 24474 == gsub_len)
+ /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */
+ || (1006 == gdef_len && 61740 == gpos_len && 24470 == gsub_len)
+ /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */
+ || (832 == gdef_len && 47162 == gpos_len && 7324 == gsub_len)
+ /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */
+ || (844 == gdef_len && 45474 == gpos_len && 7302 == gsub_len)
+ /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */
+ || (192 == gdef_len && 7254 == gpos_len && 12638 == gsub_len)
+ /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */
+ || (192 == gdef_len && 7254 == gpos_len && 12690 == gsub_len)
+ /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */
+ /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */
+ || (188 == gdef_len && 3852 == gpos_len && 248 == gsub_len)
+ /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
+ /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
+ || (188 == gdef_len && 3426 == gpos_len && 264 == gsub_len)
+ /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
+ || (1046 == gdef_len && 17112 == gpos_len && 71788 == gsub_len)
+ /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
+ || (1058 == gdef_len && 17514 == gpos_len && 71794 == gsub_len)
+ /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */
+ || (1330 == gdef_len && 57938 == gpos_len && 109904 == gsub_len)
+ /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
+ || (1330 == gdef_len && 58972 == gpos_len && 109904 == gsub_len)
+ )
+ {
+ /* Many versions of Tahoma have bad GDEF tables that incorrectly classify some spacing marks
+ * such as certain IPA symbols as glyph class 3. So do older versions of Microsoft Himalaya,
+ * and the version of Cantarell shipped by Ubuntu 16.04.
+ * Nuke the GDEF tables of these fonts to avoid unwanted width-zeroing.
+ * See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=1279693
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=1279875
+ */
+ layout->gdef = &OT::Null(OT::GDEF);
+ }
+ }
+
layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
@@ -95,6 +181,7 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
hb_blob_destroy (layout->gdef_blob);
hb_blob_destroy (layout->gsub_blob);
hb_blob_destroy (layout->gpos_blob);
+ hb_blob_destroy (layout->math_blob);
free (layout);
}
@@ -118,7 +205,6 @@ _get_gpos (hb_face_t *face)
return *hb_ot_layout_from_face (face)->gpos;
}
-
/*
* GDEF
*/
@@ -130,6 +216,8 @@ hb_ot_layout_has_glyph_classes (hb_face_t *face)
}
/**
+ * hb_ot_layout_get_glyph_class:
+ *
* Since: 0.9.7
**/
hb_ot_layout_glyph_class_t
@@ -140,6 +228,8 @@ hb_ot_layout_get_glyph_class (hb_face_t *face,
}
/**
+ * hb_ot_layout_get_glyphs_in_class:
+ *
* Since: 0.9.7
**/
void
@@ -365,6 +455,8 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
}
/**
+ * hb_ot_layout_language_get_required_feature:
+ *
* Since: 0.9.30
**/
hb_bool_t
@@ -452,6 +544,8 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
}
/**
+ * hb_ot_layout_feature_get_lookups:
+ *
* Since: 0.9.7
**/
unsigned int
@@ -462,13 +556,18 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */)
{
- const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
- const OT::Feature &f = g.get_feature (feature_index);
-
- return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
+ return hb_ot_layout_feature_with_variations_get_lookups (face,
+ table_tag,
+ feature_index,
+ HB_OT_LAYOUT_NO_VARIATIONS_INDEX,
+ start_offset,
+ lookup_count,
+ lookup_indexes);
}
/**
+ * hb_ot_layout_table_get_lookup_count:
+ *
* Since: 0.9.22
**/
unsigned int
@@ -629,6 +728,8 @@ _hb_ot_layout_collect_lookups_languages (hb_face_t *face,
}
/**
+ * hb_ot_layout_collect_lookups:
+ *
* Since: 0.9.8
**/
void
@@ -673,6 +774,8 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
}
/**
+ * hb_ot_layout_lookup_collect_glyphs:
+ *
* Since: 0.9.7
**/
void
@@ -710,6 +813,38 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
}
+/* Variations support */
+
+hb_bool_t
+hb_ot_layout_table_find_feature_variations (hb_face_t *face,
+ hb_tag_t table_tag,
+ const int *coords,
+ unsigned int num_coords,
+ unsigned int *variations_index /* out */)
+{
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+ return g.find_variations_index (coords, num_coords, variations_index);
+}
+
+unsigned int
+hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ unsigned int variations_index,
+ unsigned int start_offset,
+ unsigned int *lookup_count /* IN/OUT */,
+ unsigned int *lookup_indexes /* OUT */)
+{
+ ASSERT_STATIC (OT::FeatureVariations::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+ const OT::Feature &f = g.get_feature_variation (feature_index, variations_index);
+
+ return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
+}
+
+
/*
* OT::GSUB
*/
@@ -721,6 +856,8 @@ hb_ot_layout_has_substitution (hb_face_t *face)
}
/**
+ * hb_ot_layout_lookup_would_substitute:
+ *
* Since: 0.9.7
**/
hb_bool_t
@@ -742,7 +879,7 @@ hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
hb_bool_t zero_context)
{
if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
- OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
+ OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
@@ -755,13 +892,9 @@ hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
OT::GSUB::substitute_start (font, buffer);
}
-void
-hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
-{
- OT::GSUB::substitute_finish (font, buffer);
-}
-
/**
+ * hb_ot_layout_lookup_substitute_closure:
+ *
* Since: 0.9.7
**/
void
@@ -793,12 +926,20 @@ hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
}
void
-hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
+hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
+{
+ OT::GPOS::position_finish_advances (font, buffer);
+}
+
+void
+hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
{
- OT::GPOS::position_finish (font, buffer);
+ OT::GPOS::position_finish_offsets (font, buffer);
}
/**
+ * hb_ot_layout_get_size_params:
+ *
* Since: 0.9.10
**/
hb_bool_t
@@ -882,20 +1023,79 @@ struct GPOSProxy
};
-template <typename Obj>
+struct hb_get_subtables_context_t :
+ OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
+{
+ template <typename Type>
+ static inline bool apply_to (const void *obj, OT::hb_apply_context_t *c)
+ {
+ const Type *typed_obj = (const Type *) obj;
+ return typed_obj->apply (c);
+ }
+
+ typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_apply_context_t *c);
+
+ struct hb_applicable_t
+ {
+ inline void init (const void *obj_, hb_apply_func_t apply_func_)
+ {
+ obj = obj_;
+ apply_func = apply_func_;
+ }
+
+ inline bool apply (OT::hb_apply_context_t *c) const { return apply_func (obj, c); }
+
+ private:
+ const void *obj;
+ hb_apply_func_t apply_func;
+ };
+
+ typedef hb_auto_array_t<hb_applicable_t> array_t;
+
+ /* Dispatch interface. */
+ inline const char *get_name (void) { return "GET_SUBTABLES"; }
+ template <typename T>
+ inline return_t dispatch (const T &obj)
+ {
+ hb_applicable_t *entry = array.push();
+ if (likely (entry))
+ entry->init (&obj, apply_to<T>);
+ return HB_VOID;
+ }
+ static return_t default_return_value (void) { return HB_VOID; }
+ bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+
+ hb_get_subtables_context_t (array_t &array_) :
+ array (array_),
+ debug_depth (0) {}
+
+ array_t &array;
+ unsigned int debug_depth;
+};
+
static inline bool
apply_forward (OT::hb_apply_context_t *c,
- const Obj &obj,
- const hb_ot_layout_lookup_accelerator_t &accel)
+ const hb_ot_layout_lookup_accelerator_t &accel,
+ const hb_get_subtables_context_t::array_t &subtables)
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
- while (buffer->idx < buffer->len)
+ while (buffer->idx < buffer->len && !buffer->in_error)
{
+ bool applied = false;
if (accel.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
- c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
- obj.apply (c))
+ c->check_glyph_property (&buffer->cur(), c->lookup_props))
+ {
+ for (unsigned int i = 0; i < subtables.len; i++)
+ if (subtables[i].apply (c))
+ {
+ applied = true;
+ break;
+ }
+ }
+
+ if (applied)
ret = true;
else
buffer->next_glyph ();
@@ -903,11 +1103,10 @@ apply_forward (OT::hb_apply_context_t *c,
return ret;
}
-template <typename Obj>
static inline bool
apply_backward (OT::hb_apply_context_t *c,
- const Obj &obj,
- const hb_ot_layout_lookup_accelerator_t &accel)
+ const hb_ot_layout_lookup_accelerator_t &accel,
+ const hb_get_subtables_context_t::array_t &subtables)
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
@@ -915,9 +1114,15 @@ apply_backward (OT::hb_apply_context_t *c,
{
if (accel.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
- c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
- obj.apply (c))
- ret = true;
+ c->check_glyph_property (&buffer->cur(), c->lookup_props))
+ {
+ for (unsigned int i = 0; i < subtables.len; i++)
+ if (subtables[i].apply (c))
+ {
+ ret = true;
+ break;
+ }
+ }
/* The reverse lookup doesn't "advance" cursor (for good reason). */
buffer->idx--;
@@ -926,26 +1131,6 @@ apply_backward (OT::hb_apply_context_t *c,
return ret;
}
-struct hb_apply_forward_context_t :
- OT::hb_dispatch_context_t<hb_apply_forward_context_t, bool, HB_DEBUG_APPLY>
-{
- inline const char *get_name (void) { return "APPLY_FWD"; }
- template <typename T>
- inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
- static return_t default_return_value (void) { return false; }
- bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }
-
- hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
- const hb_ot_layout_lookup_accelerator_t &accel_) :
- c (c_),
- accel (accel_),
- debug_depth (0) {}
-
- OT::hb_apply_context_t *c;
- const hb_ot_layout_lookup_accelerator_t &accel;
- unsigned int debug_depth;
-};
-
template <typename Proxy>
static inline void
apply_string (OT::hb_apply_context_t *c,
@@ -959,6 +1144,10 @@ apply_string (OT::hb_apply_context_t *c,
c->set_lookup_props (lookup.get_props ());
+ hb_get_subtables_context_t::array_t subtables;
+ hb_get_subtables_context_t c_get_subtables (subtables);
+ lookup.dispatch (&c_get_subtables);
+
if (likely (!lookup.is_reverse ()))
{
/* in/out forward substitution/positioning */
@@ -967,13 +1156,7 @@ apply_string (OT::hb_apply_context_t *c,
buffer->idx = 0;
bool ret;
- if (lookup.get_subtable_count () == 1)
- {
- hb_apply_forward_context_t c_forward (c, accel);
- ret = lookup.dispatch (&c_forward);
- }
- else
- ret = apply_forward (c, lookup, accel);
+ ret = apply_forward (c, accel, subtables);
if (ret)
{
if (!Proxy::inplace)
@@ -989,7 +1172,7 @@ apply_string (OT::hb_apply_context_t *c,
buffer->remove_output ();
buffer->idx = buffer->len - 1;
- apply_backward (c, lookup, accel);
+ apply_backward (c, accel, subtables);
}
}
@@ -1008,25 +1191,15 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
const stage_map_t *stage = &stages[table_index][stage_index];
for (; i < stage->last_lookup; i++)
{
-#if 0
- char buf[4096];
- hb_buffer_serialize_glyphs (buffer, 0, buffer->len,
- buf, sizeof (buf), NULL,
- font,
- HB_BUFFER_SERIALIZE_FORMAT_TEXT,
- Proxy::table_index == 0 ?
- HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS :
- HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
- printf ("buf: [%s]\n", buf);
-#endif
-
unsigned int lookup_index = lookups[table_index][i].index;
+ if (!buffer->message (font, "start lookup %d", lookup_index)) continue;
c.set_lookup_index (lookup_index);
c.set_lookup_mask (lookups[table_index][i].mask);
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
apply_string<Proxy> (&c,
proxy.table.get_lookup (lookup_index),
proxy.accels[lookup_index]);
+ (void) buffer->message (font, "end lookup %d", lookup_index);
}
if (stage->pause_func)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h
index 949678ac42..9861f0fc7b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h
@@ -48,7 +48,7 @@ HB_BEGIN_DECLS
* GDEF
*/
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_has_glyph_classes (hb_face_t *face);
typedef enum {
@@ -59,11 +59,11 @@ typedef enum {
HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 4
} hb_ot_layout_glyph_class_t;
-hb_ot_layout_glyph_class_t
+HB_EXTERN hb_ot_layout_glyph_class_t
hb_ot_layout_get_glyph_class (hb_face_t *face,
hb_codepoint_t glyph);
-void
+HB_EXTERN void
hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
hb_ot_layout_glyph_class_t klass,
hb_set_t *glyphs /* OUT */);
@@ -71,7 +71,7 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
/* Not that useful. Provides list of attach points for a glyph that a
* client may want to cache */
-unsigned int
+HB_EXTERN unsigned int
hb_ot_layout_get_attach_points (hb_face_t *face,
hb_codepoint_t glyph,
unsigned int start_offset,
@@ -79,7 +79,7 @@ hb_ot_layout_get_attach_points (hb_face_t *face,
unsigned int *point_array /* OUT */);
/* Ligature caret positions */
-unsigned int
+HB_EXTERN unsigned int
hb_ot_layout_get_ligature_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph,
@@ -95,36 +95,37 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
#define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
+#define HB_OT_LAYOUT_NO_VARIATIONS_INDEX 0xFFFFFFFFu
-unsigned int
+HB_EXTERN unsigned int
hb_ot_layout_table_get_script_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *script_count /* IN/OUT */,
hb_tag_t *script_tags /* OUT */);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_table_find_script (hb_face_t *face,
hb_tag_t table_tag,
hb_tag_t script_tag,
unsigned int *script_index);
/* Like find_script, but takes zero-terminated array of scripts to test */
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_table_choose_script (hb_face_t *face,
hb_tag_t table_tag,
const hb_tag_t *script_tags,
unsigned int *script_index,
hb_tag_t *chosen_script);
-unsigned int
+HB_EXTERN unsigned int
hb_ot_layout_table_get_feature_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */);
-unsigned int
+HB_EXTERN unsigned int
hb_ot_layout_script_get_language_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
@@ -132,21 +133,21 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
unsigned int *language_count /* IN/OUT */,
hb_tag_t *language_tags /* OUT */);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_script_find_language (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
hb_tag_t language_tag,
unsigned int *language_index);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int *feature_index);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_language_get_required_feature (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
@@ -154,7 +155,7 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face,
unsigned int *feature_index,
hb_tag_t *feature_tag);
-unsigned int
+HB_EXTERN unsigned int
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
@@ -163,7 +164,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
unsigned int *feature_count /* IN/OUT */,
unsigned int *feature_indexes /* OUT */);
-unsigned int
+HB_EXTERN unsigned int
hb_ot_layout_language_get_feature_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
@@ -172,7 +173,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_language_find_feature (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
@@ -180,7 +181,7 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
hb_tag_t feature_tag,
unsigned int *feature_index);
-unsigned int
+HB_EXTERN unsigned int
hb_ot_layout_feature_get_lookups (hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
@@ -188,12 +189,12 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */);
-unsigned int
+HB_EXTERN unsigned int
hb_ot_layout_table_get_lookup_count (hb_face_t *face,
hb_tag_t table_tag);
-void
+HB_EXTERN void
hb_ot_layout_collect_lookups (hb_face_t *face,
hb_tag_t table_tag,
const hb_tag_t *scripts,
@@ -201,7 +202,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
const hb_tag_t *features,
hb_set_t *lookup_indexes /* OUT */);
-void
+HB_EXTERN void
hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
hb_tag_t table_tag,
unsigned int lookup_index,
@@ -228,7 +229,7 @@ typedef hb_bool_t
const hb_ot_layout_glyph_sequence_t *sequence,
void *user_data);
-void
+HB_EXTERN void
Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
hb_tag_t table_tag,
unsigned int lookup_index,
@@ -236,22 +237,40 @@ Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
void *user_data);
#endif
+/* Variations support */
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_table_find_feature_variations (hb_face_t *face,
+ hb_tag_t table_tag,
+ const int *coords,
+ unsigned int num_coords,
+ unsigned int *variations_index /* out */);
+
+HB_EXTERN unsigned int
+hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ unsigned int variations_index,
+ unsigned int start_offset,
+ unsigned int *lookup_count /* IN/OUT */,
+ unsigned int *lookup_indexes /* OUT */);
+
/*
* GSUB
*/
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_has_substitution (hb_face_t *face);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_lookup_would_substitute (hb_face_t *face,
unsigned int lookup_index,
const hb_codepoint_t *glyphs,
unsigned int glyphs_length,
hb_bool_t zero_context);
-void
+HB_EXTERN void
hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
unsigned int lookup_index,
hb_set_t *glyphs
@@ -259,7 +278,7 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
#ifdef HB_NOT_IMPLEMENTED
/* Note: You better have GDEF when using this API, or marks won't do much. */
-hb_bool_t
+HB_EXTERN hb_bool_t
Xhb_ot_layout_lookup_substitute (hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
@@ -274,12 +293,12 @@ Xhb_ot_layout_lookup_substitute (hb_font_t *font,
* GPOS
*/
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_has_positioning (hb_face_t *face);
#ifdef HB_NOT_IMPLEMENTED
/* Note: You better have GDEF when using this API, or marks won't do much. */
-hb_bool_t
+HB_EXTERN hb_bool_t
Xhb_ot_layout_lookup_position (hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
@@ -288,7 +307,7 @@ Xhb_ot_layout_lookup_position (hb_font_t *font,
/* Optical 'size' feature info. Returns true if found.
* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_ot_layout_get_size_params (hb_face_t *face,
unsigned int *design_size, /* OUT. May be NULL */
unsigned int *subfamily_id, /* OUT. May be NULL */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-map-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-map-private.hh
index f9538af183..0395c9c22f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-map-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-map-private.hh
@@ -139,12 +139,6 @@ struct hb_ot_map_t
private:
- HB_INTERNAL void add_lookups (hb_face_t *face,
- unsigned int table_index,
- unsigned int feature_index,
- hb_mask_t mask,
- bool auto_zwj);
-
hb_mask_t global_mask;
hb_prealloced_array_t<feature_map_t, 8> features;
@@ -159,23 +153,9 @@ enum hb_ot_map_feature_flags_t {
F_MANUAL_ZWJ = 0x0004u, /* Don't skip over ZWJ when matching. */
F_GLOBAL_SEARCH = 0x0008u /* If feature not found in LangSys, look for it in global feature list and pick one. */
};
+HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
/* Macro version for where const is desired. */
#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
-static inline hb_ot_map_feature_flags_t
-operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
-{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
-static inline hb_ot_map_feature_flags_t
-operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
-{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
-static inline hb_ot_map_feature_flags_t
-operator ~ (hb_ot_map_feature_flags_t r)
-{ return hb_ot_map_feature_flags_t (~(unsigned int) r); }
-static inline hb_ot_map_feature_flags_t&
-operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
-{ l = l | r; return l; }
-static inline hb_ot_map_feature_flags_t&
-operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
-{ l = l & r; return l; }
struct hb_ot_map_builder_t
@@ -196,7 +176,9 @@ struct hb_ot_map_builder_t
inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
{ add_pause (1, pause_func); }
- HB_INTERNAL void compile (struct hb_ot_map_t &m);
+ HB_INTERNAL void compile (hb_ot_map_t &m,
+ const int *coords,
+ unsigned int num_coords);
inline void finish (void) {
feature_infos.finish ();
@@ -208,6 +190,14 @@ struct hb_ot_map_builder_t
private:
+ HB_INTERNAL void add_lookups (hb_ot_map_t &m,
+ hb_face_t *face,
+ unsigned int table_index,
+ unsigned int feature_index,
+ unsigned int variations_index,
+ hb_mask_t mask,
+ bool auto_zwj);
+
struct feature_info_t {
hb_tag_t tag;
unsigned int seq; /* sequence#, used for stable sorting only */
@@ -217,7 +207,8 @@ struct hb_ot_map_builder_t
unsigned int stage[2]; /* GSUB/GPOS */
static int cmp (const feature_info_t *a, const feature_info_t *b)
- { return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : 1); }
+ { return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) :
+ (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); }
};
struct stage_info_t {
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc
index 95bd04ee8e..9b331d5210 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc
@@ -31,44 +31,13 @@
#include "hb-ot-layout-private.hh"
-void
-hb_ot_map_t::add_lookups (hb_face_t *face,
- unsigned int table_index,
- unsigned int feature_index,
- hb_mask_t mask,
- bool auto_zwj)
+void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
{
- unsigned int lookup_indices[32];
- unsigned int offset, len;
- unsigned int table_lookup_count;
-
- table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
-
- offset = 0;
- do {
- len = ARRAY_LENGTH (lookup_indices);
- hb_ot_layout_feature_get_lookups (face,
- table_tags[table_index],
- feature_index,
- offset, &len,
- lookup_indices);
-
- for (unsigned int i = 0; i < len; i++)
- {
- if (lookup_indices[i] >= table_lookup_count)
- continue;
- hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
- if (unlikely (!lookup))
- return;
- lookup->mask = mask;
- lookup->index = lookup_indices[i];
- lookup->auto_zwj = auto_zwj;
- }
-
- offset += len;
- } while (len == ARRAY_LENGTH (lookup_indices));
+ for (unsigned int i = 0; i < lookups[table_index].len; i++)
+ hb_set_add (lookups_out, lookups[table_index][i].index);
}
+
hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
const hb_segment_properties_t *props_)
{
@@ -89,7 +58,7 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
for (unsigned int table_index = 0; table_index < 2; table_index++) {
hb_tag_t table_tag = table_tags[table_index];
- found_script[table_index] = hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
+ found_script[table_index] = (bool) hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
}
}
@@ -109,13 +78,48 @@ void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
info->stage[1] = current_stage[1];
}
-
-void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
+void
+hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
+ hb_face_t *face,
+ unsigned int table_index,
+ unsigned int feature_index,
+ unsigned int variations_index,
+ hb_mask_t mask,
+ bool auto_zwj)
{
- for (unsigned int i = 0; i < lookups[table_index].len; i++)
- hb_set_add (lookups_out, lookups[table_index][i].index);
+ unsigned int lookup_indices[32];
+ unsigned int offset, len;
+ unsigned int table_lookup_count;
+
+ table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
+
+ offset = 0;
+ do {
+ len = ARRAY_LENGTH (lookup_indices);
+ hb_ot_layout_feature_with_variations_get_lookups (face,
+ table_tags[table_index],
+ feature_index,
+ variations_index,
+ offset, &len,
+ lookup_indices);
+
+ for (unsigned int i = 0; i < len; i++)
+ {
+ if (lookup_indices[i] >= table_lookup_count)
+ continue;
+ hb_ot_map_t::lookup_map_t *lookup = m.lookups[table_index].push ();
+ if (unlikely (!lookup))
+ return;
+ lookup->mask = mask;
+ lookup->index = lookup_indices[i];
+ lookup->auto_zwj = auto_zwj;
+ }
+
+ offset += len;
+ } while (len == ARRAY_LENGTH (lookup_indices));
}
+
void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
{
stage_info_t *s = stages[table_index].push ();
@@ -128,7 +132,9 @@ void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::paus
}
void
-hb_ot_map_builder_t::compile (hb_ot_map_t &m)
+hb_ot_map_builder_t::compile (hb_ot_map_t &m,
+ const int *coords,
+ unsigned int num_coords)
{
m.global_mask = 1;
@@ -193,7 +199,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
/* Uses the global bit */
bits_needed = 0;
else
- bits_needed = _hb_bit_storage (info->max_value);
+ /* Limit to 8 bits per feature. */
+ bits_needed = MIN(8u, _hb_bit_storage (info->max_value));
if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
continue; /* Feature disabled, or not enough bits. */
@@ -204,11 +211,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
if (required_feature_tag[table_index] == info->tag)
- {
required_feature_stage[table_index] = info->stage[table_index];
- found = true;
- continue;
- }
+
found |= hb_ot_layout_language_find_feature (face,
table_tags[table_index],
script_index[table_index],
@@ -246,11 +250,11 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
map->mask = 1;
} else {
map->shift = next_bit;
- map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
+ map->mask = (1u << (next_bit + bits_needed)) - (1u << next_bit);
next_bit += bits_needed;
m.global_mask |= (info->default_value << map->shift) & map->mask;
}
- map->_1_mask = (1 << map->shift) & map->mask;
+ map->_1_mask = (1u << map->shift) & map->mask;
map->needs_fallback = !found;
}
@@ -264,23 +268,32 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m)
{
/* Collect lookup indices for features */
+ unsigned int variations_index;
+ hb_ot_layout_table_find_feature_variations (face,
+ table_tags[table_index],
+ coords,
+ num_coords,
+ &variations_index);
+
unsigned int stage_index = 0;
unsigned int last_num_lookups = 0;
for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
{
if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
required_feature_stage[table_index] == stage)
- m.add_lookups (face, table_index,
- required_feature_index[table_index],
- 1 /* mask */,
- true /* auto_zwj */);
+ add_lookups (m, face, table_index,
+ required_feature_index[table_index],
+ variations_index,
+ 1 /* mask */,
+ true /* auto_zwj */);
for (unsigned i = 0; i < m.features.len; i++)
if (m.features[i].stage[table_index] == stage)
- m.add_lookups (face, table_index,
- m.features[i].index[table_index],
- m.features[i].mask,
- m.features[i].auto_zwj);
+ add_lookups (m, face, table_index,
+ m.features[i].index[table_index],
+ variations_index,
+ m.features[i].mask,
+ m.features[i].auto_zwj);
/* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].len)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-math.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-math.cc
new file mode 100644
index 0000000000..9ef21d2995
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-math.cc
@@ -0,0 +1,272 @@
+/*
+ * Copyright © 2016 Igalia S.L.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Igalia Author(s): Frédéric Wang
+ */
+
+#include "hb-open-type-private.hh"
+
+#include "hb-ot-layout-math-table.hh"
+
+HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
+
+static inline const OT::MATH&
+_get_math (hb_face_t *face)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::MATH);
+
+ hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
+
+retry:
+ const OT::MATH *math = (const OT::MATH *) hb_atomic_ptr_get (&layout->math);
+
+ if (unlikely (!math))
+ {
+ hb_blob_t *blob = OT::Sanitizer<OT::MATH>::sanitize (face->reference_table (HB_OT_TAG_MATH));
+ math = OT::Sanitizer<OT::MATH>::lock_instance (blob);
+ if (!hb_atomic_ptr_cmpexch (&layout->math, NULL, math))
+ {
+ hb_blob_destroy (blob);
+ goto retry;
+ }
+ layout->math_blob = blob;
+ }
+
+ return *math;
+}
+
+/*
+ * OT::MATH
+ */
+
+/**
+ * hb_ot_math_has_data:
+ * @face: #hb_face_t to test
+ *
+ * This function allows to verify the presence of an OpenType MATH table on the
+ * face. If so, such a table will be loaded into memory and sanitized. You can
+ * then safely call other functions for math layout and shaping.
+ *
+ * Return value: #TRUE if face has a MATH table and #FALSE otherwise
+ *
+ * Since: 1.3.3
+ **/
+hb_bool_t
+hb_ot_math_has_data (hb_face_t *face)
+{
+ return &_get_math (face) != &OT::Null(OT::MATH);
+}
+
+/**
+ * hb_ot_math_get_constant:
+ * @font: #hb_font_t from which to retrieve the value
+ * @constant: #hb_ot_math_constant_t the constant to retrieve
+ *
+ * This function returns the requested math constants as a #hb_position_t.
+ * If the request constant is HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
+ * HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
+ * HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN then the return value is
+ * actually an integer between 0 and 100 representing that percentage.
+ *
+ * Return value: the requested constant or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_constant (hb_font_t *font,
+ hb_ot_math_constant_t constant)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_constant(constant, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_italics_correction:
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ *
+ * Return value: the italics correction of the glyph or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_glyph_italics_correction (hb_font_t *font,
+ hb_codepoint_t glyph)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_glyph_info().get_italics_correction (glyph, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_top_accent_attachment:
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ *
+ * Return value: the top accent attachment of the glyph or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
+ hb_codepoint_t glyph)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_glyph_info().get_top_accent_attachment (glyph, font);
+}
+
+/**
+ * hb_ot_math_is_glyph_extended_shape:
+ * @font: a #hb_font_t to test
+ * @glyph: a glyph index to test
+ *
+ * Return value: #TRUE if the glyph is an extended shape and #FALSE otherwise
+ *
+ * Since: 1.3.3
+ **/
+hb_bool_t
+hb_ot_math_is_glyph_extended_shape (hb_face_t *face,
+ hb_codepoint_t glyph)
+{
+ const OT::MATH &math = _get_math (face);
+ return math.get_math_glyph_info().is_extended_shape (glyph);
+}
+
+/**
+ * hb_ot_math_get_glyph_kerning:
+ * @font: #hb_font_t from which to retrieve the value
+ * @glyph: glyph index from which to retrieve the value
+ * @kern: the #hb_ot_math_kern_t from which to retrieve the value
+ * @correction_height: the correction height to use to determine the kerning.
+ *
+ * This function tries to retrieve the MathKern table for the specified font,
+ * glyph and #hb_ot_math_kern_t. Then it browses the list of heights from the
+ * MathKern table to find one value that is greater or equal to specified
+ * correction_height. If one is found the corresponding value from the list of
+ * kerns is returned and otherwise the last kern value is returned.
+ *
+ * Return value: requested kerning or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_glyph_kerning (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_glyph_info().get_kerning (glyph, kern, correction_height, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_variants:
+ * @font: #hb_font_t from which to retrieve the values
+ * @glyph: index of the glyph to stretch
+ * @direction: direction of the stretching
+ * @start_offset: offset of the first variant to retrieve
+ * @variants_count: maximum number of variants to retrieve after start_offset
+ * (IN) and actual number of variants retrieved (OUT)
+ * @variants: array of size at least @variants_count to store the result
+ *
+ * This function tries to retrieve the MathGlyphConstruction for the specified
+ * font, glyph and direction. Note that only the value of
+ * #HB_DIRECTION_IS_HORIZONTAL is considered. It provides the corresponding list
+ * of size variants as an array of hb_ot_math_glyph_variant_t structs.
+ *
+ * Return value: the total number of size variants available or 0
+ *
+ * Since: 1.3.3
+ **/
+unsigned int
+hb_ot_math_get_glyph_variants (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ unsigned int start_offset,
+ unsigned int *variants_count, /* IN/OUT */
+ hb_ot_math_glyph_variant_t *variants /* OUT */)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_variants().get_glyph_variants (glyph, direction, font,
+ start_offset,
+ variants_count,
+ variants);
+}
+
+/**
+ * hb_ot_math_get_min_connector_overlap:
+ * @font: #hb_font_t from which to retrieve the value
+ * @direction: direction of the stretching
+ *
+ * This function tries to retrieve the MathVariants table for the specified
+ * font and returns the minimum overlap of connecting glyphs to draw a glyph
+ * assembly in the specified direction. Note that only the value of
+ * #HB_DIRECTION_IS_HORIZONTAL is considered.
+ *
+ * Return value: requested min connector overlap or 0
+ *
+ * Since: 1.3.3
+ **/
+hb_position_t
+hb_ot_math_get_min_connector_overlap (hb_font_t *font,
+ hb_direction_t direction)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_variants().get_min_connector_overlap (direction, font);
+}
+
+/**
+ * hb_ot_math_get_glyph_assembly:
+ * @font: #hb_font_t from which to retrieve the values
+ * @glyph: index of the glyph to stretch
+ * @direction: direction of the stretching
+ * @start_offset: offset of the first glyph part to retrieve
+ * @parts_count: maximum number of glyph parts to retrieve after start_offset
+ * (IN) and actual number of parts retrieved (OUT)
+ * @parts: array of size at least @parts_count to store the result
+ * @italics_correction: italic correction of the glyph assembly
+ *
+ * This function tries to retrieve the GlyphAssembly for the specified font,
+ * glyph and direction. Note that only the value of #HB_DIRECTION_IS_HORIZONTAL
+ * is considered. It provides the information necessary to draw the glyph
+ * assembly as an array of #hb_ot_math_glyph_part_t.
+ *
+ * Return value: the total number of parts in the glyph assembly
+ *
+ * Since: 1.3.3
+ **/
+unsigned int
+hb_ot_math_get_glyph_assembly (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ unsigned int start_offset,
+ unsigned int *parts_count, /* IN/OUT */
+ hb_ot_math_glyph_part_t *parts, /* OUT */
+ hb_position_t *italics_correction /* OUT */)
+{
+ const OT::MATH &math = _get_math (font->face);
+ return math.get_math_variants().get_glyph_parts (glyph, direction, font,
+ start_offset,
+ parts_count,
+ parts,
+ italics_correction);
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-math.h b/src/3rdparty/harfbuzz-ng/src/hb-ot-math.h
new file mode 100644
index 0000000000..521a5ca037
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-math.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2016 Igalia S.L.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Igalia Author(s): Frédéric Wang
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_MATH_H
+#define HB_OT_MATH_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * MATH
+ */
+
+#define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
+
+/* Use with hb_buffer_set_script() for math shaping. */
+#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
+
+/* Types */
+
+/**
+ * hb_ot_math_constant_t:
+ *
+ * Since: 1.3.3
+ */
+typedef enum {
+ HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN = 0,
+ HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN = 1,
+ HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT = 2,
+ HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT = 3,
+ HB_OT_MATH_CONSTANT_MATH_LEADING = 4,
+ HB_OT_MATH_CONSTANT_AXIS_HEIGHT = 5,
+ HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT = 6,
+ HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT = 7,
+ HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN = 8,
+ HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX = 9,
+ HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN = 10,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP = 11,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED = 12,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN = 13,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX = 14,
+ HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN = 15,
+ HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT = 16,
+ HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT = 17,
+ HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN = 18,
+ HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN = 19,
+ HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN = 20,
+ HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN = 21,
+ HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP = 22,
+ HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP = 23,
+ HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN = 24,
+ HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN = 25,
+ HB_OT_MATH_CONSTANT_STACK_GAP_MIN = 26,
+ HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN = 27,
+ HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP = 28,
+ HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN = 29,
+ HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN = 30,
+ HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN = 31,
+ HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP = 32,
+ HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP = 33,
+ HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN = 34,
+ HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN = 35,
+ HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN = 36,
+ HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN = 37,
+ HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS = 38,
+ HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN = 39,
+ HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN = 40,
+ HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP = 41,
+ HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP = 42,
+ HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP = 43,
+ HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS = 44,
+ HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER = 45,
+ HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP = 46,
+ HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS = 47,
+ HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER = 48,
+ HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP = 49,
+ HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP = 50,
+ HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS = 51,
+ HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER = 52,
+ HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE = 53,
+ HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE = 54,
+ HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT = 55
+} hb_ot_math_constant_t;
+
+/**
+ * hb_ot_math_kern_t:
+ *
+ * Since: 1.3.3
+ */
+typedef enum {
+ HB_OT_MATH_KERN_TOP_RIGHT = 0,
+ HB_OT_MATH_KERN_TOP_LEFT = 1,
+ HB_OT_MATH_KERN_BOTTOM_RIGHT = 2,
+ HB_OT_MATH_KERN_BOTTOM_LEFT = 3
+} hb_ot_math_kern_t;
+
+/**
+ * hb_ot_math_glyph_variant_t:
+ *
+ * Since: 1.3.3
+ */
+typedef struct hb_ot_math_glyph_variant_t {
+ hb_codepoint_t glyph;
+ hb_position_t advance;
+} hb_ot_math_glyph_variant_t;
+
+/**
+ * hb_ot_math_glyph_part_flags_t:
+ *
+ * Since: 1.3.3
+ */
+typedef enum { /*< flags >*/
+ HB_MATH_GLYPH_PART_FLAG_EXTENDER = 0x00000001u /* Extender glyph */
+} hb_ot_math_glyph_part_flags_t;
+
+/**
+ * hb_ot_math_glyph_part_t:
+ *
+ * Since: 1.3.3
+ */
+typedef struct hb_ot_math_glyph_part_t {
+ hb_codepoint_t glyph;
+ hb_position_t start_connector_length;
+ hb_position_t end_connector_length;
+ hb_position_t full_advance;
+ hb_ot_math_glyph_part_flags_t flags;
+} hb_ot_math_glyph_part_t;
+
+/* Methods */
+
+HB_EXTERN hb_bool_t
+hb_ot_math_has_data (hb_face_t *face);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_constant (hb_font_t *font,
+ hb_ot_math_constant_t constant);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_glyph_italics_correction (hb_font_t *font,
+ hb_codepoint_t glyph);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
+ hb_codepoint_t glyph);
+
+HB_EXTERN hb_bool_t
+hb_ot_math_is_glyph_extended_shape (hb_face_t *face,
+ hb_codepoint_t glyph);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_glyph_kerning (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_ot_math_kern_t kern,
+ hb_position_t correction_height);
+
+HB_EXTERN unsigned int
+hb_ot_math_get_glyph_variants (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ unsigned int start_offset,
+ unsigned int *variants_count, /* IN/OUT */
+ hb_ot_math_glyph_variant_t *variants /* OUT */);
+
+HB_EXTERN hb_position_t
+hb_ot_math_get_min_connector_overlap (hb_font_t *font,
+ hb_direction_t direction);
+
+HB_EXTERN unsigned int
+hb_ot_math_get_glyph_assembly (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_direction_t direction,
+ unsigned int start_offset,
+ unsigned int *parts_count, /* IN/OUT */
+ hb_ot_math_glyph_part_t *parts, /* OUT */
+ hb_position_t *italics_correction /* OUT */);
+
+
+HB_END_DECLS
+
+#endif /* HB_OT_MATH_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh
index 27105af132..943e3908c7 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh
@@ -58,7 +58,7 @@ struct maxp
/* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
protected:
- FixedVersion version; /* Version of the maxp table (0.5 or 1.0),
+ FixedVersion<>version; /* Version of the maxp table (0.5 or 1.0),
* 0x00005000u or 0x00010000u. */
USHORT numGlyphs; /* The number of glyphs in the font. */
public:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
new file mode 100644
index 0000000000..4709cd6e87
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2011,2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_OS2_TABLE_HH
+#define HB_OT_OS2_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+/*
+ * OS/2 and Windows Metrics
+ * http://www.microsoft.com/typography/otspec/os2.htm
+ */
+
+#define HB_OT_TAG_os2 HB_TAG('O','S','/','2')
+
+struct os2
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_os2;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ public:
+ USHORT version;
+
+ /* Version 0 */
+ SHORT xAvgCharWidth;
+ USHORT usWeightClass;
+ USHORT usWidthClass;
+ USHORT fsType;
+ SHORT ySubscriptXSize;
+ SHORT ySubscriptYSize;
+ SHORT ySubscriptXOffset;
+ SHORT ySubscriptYOffset;
+ SHORT ySuperscriptXSize;
+ SHORT ySuperscriptYSize;
+ SHORT ySuperscriptXOffset;
+ SHORT ySuperscriptYOffset;
+ SHORT yStrikeoutSize;
+ SHORT yStrikeoutPosition;
+ SHORT sFamilyClass;
+ BYTE panose[10];
+ ULONG ulUnicodeRange[4];
+ Tag achVendID;
+ USHORT fsSelection;
+ USHORT usFirstCharIndex;
+ USHORT usLastCharIndex;
+ SHORT sTypoAscender;
+ SHORT sTypoDescender;
+ SHORT sTypoLineGap;
+ USHORT usWinAscent;
+ USHORT usWinDescent;
+
+ /* Version 1 */
+ //ULONG ulCodePageRange1;
+ //ULONG ulCodePageRange2;
+
+ /* Version 2 */
+ //SHORT sxHeight;
+ //SHORT sCapHeight;
+ //USHORT usDefaultChar;
+ //USHORT usBreakChar;
+ //USHORT usMaxContext;
+
+ /* Version 5 */
+ //USHORT usLowerOpticalPointSize;
+ //USHORT usUpperOpticalPointSize;
+
+ public:
+ DEFINE_SIZE_STATIC (78);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_OS2_TABLE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
new file mode 100644
index 0000000000..82ab3882a8
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2016 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_POST_TABLE_HH
+#define HB_OT_POST_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * post -- PostScript
+ */
+
+#define HB_OT_TAG_post HB_TAG('p','o','s','t')
+
+
+struct postV2Tail
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (numberOfGlyphs.sanitize (c) &&
+ c->check_array (glyphNameIndex, sizeof (USHORT), numberOfGlyphs));
+ }
+
+ USHORT numberOfGlyphs; /* Number of glyphs (this should be the
+ * same as numGlyphs in 'maxp' table). */
+ USHORT glyphNameIndex[VAR]; /* This is not an offset, but is the
+ * ordinal number of the glyph in 'post'
+ * string tables. */
+ BYTE namesX[VAR]; /* Glyph names with length bytes [variable]
+ * (a Pascal string). */
+
+ DEFINE_SIZE_ARRAY2 (2, glyphNameIndex, namesX);
+};
+
+struct post
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_post;
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!c->check_struct (this)))
+ return_trace (false);
+ if (version.to_int () == 0x00020000)
+ {
+ const postV2Tail &v2 = StructAfter<postV2Tail>(*this);
+ return_trace (v2.sanitize (c));
+ }
+ return_trace (true);
+ }
+
+ public:
+ FixedVersion<>version; /* 0x00010000 for version 1.0
+ * 0x00020000 for version 2.0
+ * 0x00025000 for version 2.5 (deprecated)
+ * 0x00030000 for version 3.0 */
+ Fixed italicAngle; /* Italic angle in counter-clockwise degrees
+ * from the vertical. Zero for upright text,
+ * negative for text that leans to the right
+ * (forward). */
+ FWORD underlinePosition; /* This is the suggested distance of the top
+ * of the underline from the baseline
+ * (negative values indicate below baseline).
+ * The PostScript definition of this FontInfo
+ * dictionary key (the y coordinate of the
+ * center of the stroke) is not used for
+ * historical reasons. The value of the
+ * PostScript key may be calculated by
+ * subtracting half the underlineThickness
+ * from the value of this field. */
+ FWORD underlineThickness; /* Suggested values for the underline
+ thickness. */
+ ULONG isFixedPitch; /* Set to 0 if the font is proportionally
+ * spaced, non-zero if the font is not
+ * proportionally spaced (i.e. monospaced). */
+ ULONG minMemType42; /* Minimum memory usage when an OpenType font
+ * is downloaded. */
+ ULONG maxMemType42; /* Maximum memory usage when an OpenType font
+ * is downloaded. */
+ ULONG minMemType1; /* Minimum memory usage when an OpenType font
+ * is downloaded as a Type 1 font. */
+ ULONG maxMemType1; /* Maximum memory usage when an OpenType font
+ * is downloaded as a Type 1 font. */
+/*postV2Tail v2[VAR];*/
+ DEFINE_SIZE_STATIC (32);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_POST_TABLE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.hh
index 80d5044354..736c7f76b3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.hh
@@ -6,10 +6,10 @@
*
* on files with these headers:
*
- * # ArabicShaping-8.0.0.txt
- * # Date: 2015-02-17, 23:33:00 GMT [RP]
- * # Blocks-8.0.0.txt
- * # Date: 2014-11-10, 23:04:00 GMT [KW]
+ * # ArabicShaping-9.0.0.txt
+ * # Date: 2016-02-24, 22:25:00 GMT [RP]
+ * # Blocks-9.0.0.txt
+ * # Date: 2016-02-05, 23:48:00 GMT [KW]
* UnicodeData.txt does not have a header.
*/
@@ -19,6 +19,7 @@
#define X JOINING_TYPE_X
#define R JOINING_TYPE_R
+#define T JOINING_TYPE_T
#define U JOINING_TYPE_U
#define A JOINING_GROUP_ALAPH
#define DR JOINING_GROUP_DALATH_RISH
@@ -76,9 +77,11 @@ static const uint8_t joining_table[] =
/* Arabic Extended-A */
- /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,
+ /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,X,D,D,D,R,D,D,D,D,X,X,
+ /* 08C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 08E0 */ X,X,U,
-#define joining_offset_0x1806u 693
+#define joining_offset_0x1806u 739
/* Mongolian */
@@ -86,43 +89,48 @@ static const uint8_t joining_table[] =
/* 1820 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
/* 1840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
/* 1860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,
- /* 1880 */ U,U,U,U,U,U,U,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 1880 */ U,U,U,U,U,T,T,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
/* 18A0 */ D,D,D,D,D,D,D,D,D,X,D,
-#define joining_offset_0x200cu 858
+#define joining_offset_0x200cu 904
/* General Punctuation */
- /* 2000 */ U,C,
+ /* 2000 */ U,C,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 2020 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 2040 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 2060 */ X,X,X,X,X,X,U,U,U,U,
-#define joining_offset_0x2066u 860
-
- /* General Punctuation */
-
- /* 2060 */ U,U,U,U,
-
-#define joining_offset_0xa840u 864
+#define joining_offset_0xa840u 998
/* Phags-pa */
/* A840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
/* A860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,L,U,
-#define joining_offset_0x10ac0u 916
+#define joining_offset_0x10ac0u 1050
/* Manichaean */
/* 10AC0 */ D,D,D,D,D,R,U,R,U,R,R,U,U,L,R,R,R,R,R,D,D,D,D,L,D,D,D,D,D,R,D,D,
/* 10AE0 */ D,R,U,U,R,X,X,X,X,X,X,D,D,D,D,R,
-#define joining_offset_0x10b80u 964
+#define joining_offset_0x10b80u 1098
/* Psalter Pahlavi */
/* 10B80 */ D,R,D,R,R,R,D,D,D,R,D,D,R,D,R,R,D,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 10BA0 */ X,X,X,X,X,X,X,X,X,R,R,R,R,D,D,U,
-}; /* Table items: 1012; occupancy: 57% */
+#define joining_offset_0x1e900u 1146
+
+ /* Adlam */
+
+ /* 1E900 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 1E940 */ D,D,D,D,
+
+}; /* Table items: 1214; occupancy: 54% */
static unsigned int
@@ -131,7 +139,7 @@ joining_type (hb_codepoint_t u)
switch (u >> 12)
{
case 0x0u:
- if (hb_in_range (u, 0x0600u, 0x08B4u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
+ if (hb_in_range (u, 0x0600u, 0x08E2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
break;
case 0x1u:
@@ -139,8 +147,7 @@ joining_type (hb_codepoint_t u)
break;
case 0x2u:
- if (hb_in_range (u, 0x200Cu, 0x200Du)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
- if (hb_in_range (u, 0x2066u, 0x2069u)) return joining_table[u - 0x2066u + joining_offset_0x2066u];
+ if (hb_in_range (u, 0x200Cu, 0x2069u)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
break;
case 0xAu:
@@ -152,6 +159,10 @@ joining_type (hb_codepoint_t u)
if (hb_in_range (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
break;
+ case 0x1Eu:
+ if (hb_in_range (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
+ break;
+
default:
break;
}
@@ -160,6 +171,7 @@ joining_type (hb_codepoint_t u)
#undef X
#undef R
+#undef T
#undef U
#undef A
#undef DR
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-win1256.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-win1256.hh
new file mode 100644
index 0000000000..e70c48f427
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -0,0 +1,323 @@
+/*
+ * Copyright © 2014 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+
+
+/*
+ * The macros in the first part of this file are generic macros that can
+ * be used to define the bytes for OpenType table data in code in a
+ * readable manner. We can move the macros to reside with their respective
+ * struct types, but since we only use these to define one data table, the
+ * Windows-1256 Arabic shaping table in this file, we keep them here.
+ */
+
+
+/* First we measure, then we cut. */
+#ifndef OT_MEASURE
+#define OT_MEASURE
+#define OT_TABLE_START static const struct TABLE_NAME {
+#define OT_TABLE_END }
+#define OT_LABEL_START(Name) unsigned char Name[
+#define OT_LABEL_END ];
+#define OT_BYTE(u8) +1/*byte*/
+#define OT_USHORT(u16) +2/*bytes*/
+#else
+#undef OT_MEASURE
+#define OT_TABLE_START TABLE_NAME = {
+#define OT_TABLE_END };
+#define OT_LABEL_START(Name) {
+#define OT_LABEL_END },
+#define OT_BYTE(u8) (u8),
+#define OT_USHORT(u16) (unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
+#define OT_COUNT(Name, ItemSize) ((unsigned int) sizeof(((struct TABLE_NAME*)0)->Name) \
+ / (unsigned int)(ItemSize) \
+ /* OT_ASSERT it's divisible (and positive). */)
+#define OT_DISTANCE(From,To) ((unsigned int) \
+ ((char*)(&((struct TABLE_NAME*)0)->To) - \
+ (char*)(&((struct TABLE_NAME*)0)->From)) \
+ /* OT_ASSERT it's positive. */)
+#endif
+
+
+#define OT_LABEL(Name) \
+ OT_LABEL_END \
+ OT_LABEL_START(Name)
+
+/* Whenever we receive an argument that is a list, it will expand to
+ * contain commas. That cannot be passed to another macro because the
+ * commas will throw off the preprocessor. The solution is to wrap
+ * the passed-in argument in OT_LIST() before passing to the next macro.
+ * Unfortunately this trick requires vararg macros. */
+#define OT_LIST(...) __VA_ARGS__
+
+
+/*
+ * Basic Types
+ */
+
+#define OT_TAG(a,b,c,d) \
+ OT_BYTE(a) OT_BYTE(b) OT_BYTE(c) OT_BYTE(d)
+
+#define OT_OFFSET(From, To) /* Offset from From to To in bytes */ \
+ OT_USHORT(OT_DISTANCE(From, To))
+
+#define OT_GLYPHID /* GlyphID */ \
+ OT_USHORT
+
+#define OT_UARRAY(Name, Items) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(OT_COUNT(Name##Data, 2)) \
+ OT_LABEL(Name##Data) \
+ Items \
+ OT_LABEL_END
+
+#define OT_UHEADLESSARRAY(Name, Items) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(OT_COUNT(Name##Data, 2) + 1) \
+ OT_LABEL(Name##Data) \
+ Items \
+ OT_LABEL_END
+
+
+/*
+ * Common Types
+ */
+
+#define OT_LOOKUP_FLAG_IGNORE_MARKS 0x08u
+
+#define OT_LOOKUP(Name, LookupType, LookupFlag, SubLookupOffsets) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(LookupType) \
+ OT_USHORT(LookupFlag) \
+ OT_LABEL_END \
+ OT_UARRAY(Name##SubLookupOffsetsArray, OT_LIST(SubLookupOffsets))
+
+#define OT_SUBLOOKUP(Name, SubFormat, Items) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(SubFormat) \
+ Items
+
+#define OT_COVERAGE1(Name, Items) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(1) \
+ OT_LABEL_END \
+ OT_UARRAY(Name##Glyphs, OT_LIST(Items))
+
+
+/*
+ * GSUB
+ */
+
+#define OT_LOOKUP_TYPE_SUBST_SINGLE 1u
+#define OT_LOOKUP_TYPE_SUBST_LIGATURE 4u
+
+#define OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(Name, FromGlyphs, ToGlyphs) \
+ OT_SUBLOOKUP(Name, 2, \
+ OT_OFFSET(Name, Name##Coverage) \
+ OT_LABEL_END \
+ OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
+ ) \
+ OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
+ /* ASSERT_STATIC_EXPR_ZERO (len(FromGlyphs) == len(ToGlyphs)) */
+
+#define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
+ OT_SUBLOOKUP(Name, 1, \
+ OT_OFFSET(Name, Name##Coverage) \
+ OT_LABEL_END \
+ OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
+ ) \
+ OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
+ /* ASSERT_STATIC_EXPR_ZERO (len(FirstGlyphs) == len(LigatureSetOffsets)) */
+
+#define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
+ OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
+
+#define OT_LIGATURE(Name, Components, LigGlyph) \
+ OT_LABEL_START(Name) \
+ LigGlyph \
+ OT_LABEL_END \
+ OT_UHEADLESSARRAY(Name##ComponentsArray, OT_LIST(Components))
+
+/*
+ *
+ * Start of Windows-1256 shaping table.
+ *
+ */
+
+/* Table name. */
+#define TABLE_NAME arabic_win1256_gsub_lookups
+
+/* Table manifest. */
+#define MANIFEST(Items) \
+ OT_LABEL_START(manifest) \
+ OT_USHORT(OT_COUNT(manifestData, 6)) \
+ OT_LABEL(manifestData) \
+ Items \
+ OT_LABEL_END
+
+#define MANIFEST_LOOKUP(Tag, Name) \
+ Tag \
+ OT_OFFSET(manifest, Name)
+
+/* Shorthand. */
+#define G OT_GLYPHID
+
+/*
+ * Table Start
+ */
+OT_TABLE_START
+
+
+/*
+ * Manifest
+ */
+MANIFEST(
+ MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligLookup)
+ MANIFEST_LOOKUP(OT_TAG('i','n','i','t'), initLookup)
+ MANIFEST_LOOKUP(OT_TAG('m','e','d','i'), mediLookup)
+ MANIFEST_LOOKUP(OT_TAG('f','i','n','a'), finaLookup)
+ MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligMarksLookup)
+)
+
+/*
+ * Lookups
+ */
+OT_LOOKUP(initLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+ OT_OFFSET(initLookup, initmediSubLookup)
+ OT_OFFSET(initLookup, initSubLookup)
+)
+OT_LOOKUP(mediLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+ OT_OFFSET(mediLookup, initmediSubLookup)
+ OT_OFFSET(mediLookup, mediSubLookup)
+ OT_OFFSET(mediLookup, medifinaLamAlefSubLookup)
+)
+OT_LOOKUP(finaLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+ OT_OFFSET(finaLookup, finaSubLookup)
+ /* We don't need this one currently as the sequence inherits masks
+ * from the first item. Just in case we change that in the future
+ * to be smart about Arabic masks when ligating... */
+ OT_OFFSET(finaLookup, medifinaLamAlefSubLookup)
+)
+OT_LOOKUP(rligLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+ OT_OFFSET(rligLookup, lamAlefLigaturesSubLookup)
+)
+OT_LOOKUP(rligMarksLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, 0,
+ OT_OFFSET(rligMarksLookup, shaddaLigaturesSubLookup)
+)
+
+/*
+ * init/medi/fina forms
+ */
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initmediSubLookup,
+ G(198) G(200) G(201) G(202) G(203) G(204) G(205) G(206) G(211)
+ G(212) G(213) G(214) G(223) G(225) G(227) G(228) G(236) G(237),
+ G(162) G(4) G(5) G(5) G(6) G(7) G(9) G(11) G(13)
+ G(14) G(15) G(26) G(140) G(141) G(142) G(143) G(154) G(154)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initSubLookup,
+ G(218) G(219) G(221) G(222) G(229),
+ G(27) G(30) G(128) G(131) G(144)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(mediSubLookup,
+ G(218) G(219) G(221) G(222) G(229),
+ G(28) G(31) G(129) G(138) G(149)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(finaSubLookup,
+ G(194) G(195) G(197) G(198) G(199) G(201) G(204) G(205) G(206)
+ G(218) G(219) G(229) G(236) G(237),
+ G(2) G(1) G(3) G(181) G(0) G(159) G(8) G(10) G(12)
+ G(29) G(127) G(152) G(160) G(156)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(medifinaLamAlefSubLookup,
+ G(165) G(178) G(180) G(252),
+ G(170) G(179) G(185) G(255)
+)
+
+/*
+ * Lam+Alef ligatures
+ */
+OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(lamAlefLigaturesSubLookup,
+ G(225),
+ OT_OFFSET(lamAlefLigaturesSubLookup, lamLigatureSet)
+)
+OT_LIGATURE_SET(lamLigatureSet,
+ OT_OFFSET(lamLigatureSet, lamInitLigature1)
+ OT_OFFSET(lamLigatureSet, lamInitLigature2)
+ OT_OFFSET(lamLigatureSet, lamInitLigature3)
+ OT_OFFSET(lamLigatureSet, lamInitLigature4)
+)
+OT_LIGATURE(lamInitLigature1, G(199), G(165))
+OT_LIGATURE(lamInitLigature2, G(195), G(178))
+OT_LIGATURE(lamInitLigature3, G(194), G(180))
+OT_LIGATURE(lamInitLigature4, G(197), G(252))
+
+/*
+ * Shadda ligatures
+ */
+OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(shaddaLigaturesSubLookup,
+ G(248),
+ OT_OFFSET(shaddaLigaturesSubLookup, shaddaLigatureSet)
+)
+OT_LIGATURE_SET(shaddaLigatureSet,
+ OT_OFFSET(shaddaLigatureSet, shaddaLigature1)
+ OT_OFFSET(shaddaLigatureSet, shaddaLigature2)
+ OT_OFFSET(shaddaLigatureSet, shaddaLigature3)
+)
+OT_LIGATURE(shaddaLigature1, G(243), G(172))
+OT_LIGATURE(shaddaLigature2, G(245), G(173))
+OT_LIGATURE(shaddaLigature3, G(246), G(175))
+
+/*
+ * Table end
+ */
+OT_TABLE_END
+
+
+/*
+ * Clean up
+ */
+#undef OT_TABLE_START
+#undef OT_TABLE_END
+#undef OT_LABEL_START
+#undef OT_LABEL_END
+#undef OT_BYTE
+#undef OT_USHORT
+#undef OT_DISTANCE
+#undef OT_COUNT
+
+/*
+ * Include a second time to get the table data...
+ */
+#if 0
+#include "hb-private.hh" /* Make check-includes.sh happy. */
+#endif
+#ifdef OT_MEASURE
+#include "hb-ot-shape-complex-arabic-win1256.hh"
+#endif
+
+#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc
index cde02e0a56..56ec5cd65c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc
@@ -28,9 +28,38 @@
#include "hb-ot-shape-private.hh"
+#ifndef HB_DEBUG_ARABIC
+#define HB_DEBUG_ARABIC (HB_DEBUG+0)
+#endif
+
+
/* buffer var allocations */
#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
+#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
+
+/* See:
+ * https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
+#define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
+ (FLAG_SAFE (gen_cat) & \
+ (FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
+ /*FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |*/ \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | \
+ /*FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |*/ \
+ /*FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |*/ \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL)))
+
/*
* Joining types:
@@ -84,7 +113,7 @@ static const hb_tag_t arabic_features[] =
/* Same order as the feature array */
-enum {
+enum arabic_action_t {
ISOL,
FINA,
FIN2,
@@ -95,7 +124,11 @@ enum {
NONE,
- ARABIC_NUM_FEATURES = NONE
+ ARABIC_NUM_FEATURES = NONE,
+
+ /* We abuse the same byte for other things... */
+ STCH_FIXED,
+ STCH_REPEATING,
};
static const struct arabic_state_table_entry {
@@ -140,6 +173,11 @@ arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer);
static void
+record_stch (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+static void
collect_features_arabic (hb_ot_shape_planner_t *plan)
{
hb_ot_map_builder_t *map = &plan->map;
@@ -165,6 +203,9 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (nuke_joiners);
+ map->add_global_bool_feature (HB_TAG('s','t','c','h'));
+ map->add_gsub_pause (record_stch);
+
map->add_global_bool_feature (HB_TAG('c','c','m','p'));
map->add_global_bool_feature (HB_TAG('l','o','c','l'));
@@ -182,7 +223,6 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (arabic_fallback_shape);
map->add_global_bool_feature (HB_TAG('c','a','l','t'));
- map->add_gsub_pause (NULL);
/* The spec includes 'cswh'. Earlier versions of Windows
* used to enable this by default, but testing suggests
@@ -192,6 +232,7 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
* Note that IranNastaliq uses this feature extensively
* to fixup broken glyph sequences. Oh well...
* Test case: U+0643,U+0640,U+0631. */
+ //map->add_gsub_pause (NULL);
//map->add_global_bool_feature (HB_TAG('c','s','w','h'));
map->add_global_bool_feature (HB_TAG('m','s','e','t'));
}
@@ -208,8 +249,10 @@ struct arabic_shape_plan_t
* mask_array[NONE] == 0. */
hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
- bool do_fallback;
arabic_fallback_plan_t *fallback_plan;
+
+ unsigned int do_fallback : 1;
+ unsigned int has_stch : 1;
};
void *
@@ -220,6 +263,7 @@ data_create_arabic (const hb_ot_shape_plan_t *plan)
return NULL;
arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
+ arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
arabic_plan->do_fallback = arabic_plan->do_fallback &&
@@ -320,8 +364,6 @@ setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
-
- HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
static void
@@ -371,6 +413,197 @@ retry:
arabic_fallback_plan_shape (fallback_plan, font, buffer);
}
+/*
+ * Stretch feature: "stch".
+ * See example here:
+ * https://www.microsoft.com/typography/OpenTypeDev/syriac/intro.htm
+ * We implement this in a generic way, such that the Arabic subtending
+ * marks can use it as well.
+ */
+
+static void
+record_stch (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+ if (!arabic_plan->has_stch)
+ return;
+
+ /* 'stch' feature was just applied. Look for anything that multiplied,
+ * and record it for stch treatment later. Note that rtlm, frac, etc
+ * are applied before stch, but we assume that they didn't result in
+ * anything multiplying into 5 pieces, so it's safe-ish... */
+
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (_hb_glyph_info_multiplied (&info[i])))
+ {
+ unsigned int comp = _hb_glyph_info_get_lig_comp (&info[i]);
+ info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
+ }
+}
+
+static void
+apply_stch (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font)
+{
+ if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
+ return;
+
+ /* The Arabic shaper currently always processes in RTL mode, so we should
+ * stretch / position the stretched pieces to the left / preceding glyphs. */
+
+ /* We do a two pass implementation:
+ * First pass calculates the exact number of extra glyphs we need,
+ * We then enlarge buffer to have that much room,
+ * Second pass applies the stretch, copying things to the end of buffer.
+ */
+
+ int sign = font->x_scale < 0 ? -1 : +1;
+ unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT
+ typedef enum { MEASURE, CUT } step_t;
+
+ for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1))
+ {
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pos = buffer->pos;
+ unsigned int new_len = count + extra_glyphs_needed; // write head during CUT
+ unsigned int j = new_len;
+ for (unsigned int i = count; i; i--)
+ {
+ if (!hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+ {
+ if (step == CUT)
+ {
+ --j;
+ info[j] = info[i - 1];
+ pos[j] = pos[i - 1];
+ }
+ continue;
+ }
+
+ /* Yay, justification! */
+
+ hb_position_t w_total = 0; // Total to be filled
+ hb_position_t w_fixed = 0; // Sum of fixed tiles
+ hb_position_t w_repeating = 0; // Sum of repeating tiles
+ int n_fixed = 0;
+ int n_repeating = 0;
+
+ unsigned int end = i;
+ while (i &&
+ hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
+ {
+ i--;
+ hb_position_t width = font->get_glyph_h_advance (info[i].codepoint);
+ if (info[i].arabic_shaping_action() == STCH_FIXED)
+ {
+ w_fixed += width;
+ n_fixed++;
+ }
+ else
+ {
+ w_repeating += width;
+ n_repeating++;
+ }
+ }
+ unsigned int start = i;
+ unsigned int context = i;
+ while (context &&
+ !hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
+ (_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
+ HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
+ {
+ context--;
+ w_total += pos[context].x_advance;
+ }
+ i++; // Don't touch i again.
+
+ DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)",
+ step == MEASURE ? "measuring" : "cutting", context, start, end);
+ DEBUG_MSG (ARABIC, NULL, "rest of word: count=%d width %d", start - context, w_total);
+ DEBUG_MSG (ARABIC, NULL, "fixed tiles: count=%d width=%d", n_fixed, w_fixed);
+ DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
+
+ /* Number of additional times to repeat each repeating tile. */
+ int n_copies = 0;
+
+ hb_position_t w_remaining = w_total - w_fixed;
+ if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0)
+ n_copies = (sign * w_remaining) / (sign * w_repeating) - 1;
+
+ /* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */
+ hb_position_t extra_repeat_overlap = 0;
+ hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
+ if (shortfall > 0)
+ {
+ ++n_copies;
+ hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
+ if (excess > 0)
+ extra_repeat_overlap = excess / (n_copies * n_repeating);
+ }
+
+ if (step == MEASURE)
+ {
+ extra_glyphs_needed += n_copies * n_repeating;
+ DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
+ }
+ else
+ {
+ hb_position_t x_offset = 0;
+ for (unsigned int k = end; k > start; k--)
+ {
+ hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
+
+ unsigned int repeat = 1;
+ if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
+ repeat += n_copies;
+
+ DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
+ repeat, info[k - 1].codepoint, j);
+ for (unsigned int n = 0; n < repeat; n++)
+ {
+ x_offset -= width;
+ if (n > 0)
+ x_offset += extra_repeat_overlap;
+ pos[k - 1].x_offset = x_offset;
+ /* Append copy. */
+ --j;
+ info[j] = info[k - 1];
+ pos[j] = pos[k - 1];
+ }
+ }
+ }
+ }
+
+ if (step == MEASURE)
+ {
+ if (unlikely (!buffer->ensure (count + extra_glyphs_needed)))
+ break;
+ }
+ else
+ {
+ assert (j == 0);
+ buffer->len = new_len;
+ }
+ }
+}
+
+
+static void
+postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font)
+{
+ apply_stch (plan, buffer, font);
+
+ HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
+}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
{
@@ -379,11 +612,13 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
NULL, /* override_features */
data_create_arabic,
data_destroy_arabic,
- NULL, /* preprocess_text_arabic */
+ NULL, /* preprocess_text */
+ postprocess_glyphs_arabic,
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
setup_masks_arabic,
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-default.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-default.cc
index f7f097eeda..42830ab618 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-default.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-default.cc
@@ -35,10 +35,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
+ NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+ NULL, /* disable_otl */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hangul.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hangul.cc
index 1fa79ce6d4..eb95a28c09 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hangul.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hangul.cc
@@ -188,7 +188,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
*/
unsigned int count = buffer->len;
- for (buffer->idx = 0; buffer->idx < count;)
+ for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
{
hb_codepoint_t u = buffer->cur().codepoint;
@@ -411,13 +411,15 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
"hangul",
collect_features_hangul,
override_features_hangul,
- data_create_hangul, /* data_create */
- data_destroy_hangul, /* data_destroy */
+ data_create_hangul,
+ data_destroy_hangul,
preprocess_text_hangul,
+ NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
NULL, /* decompose */
NULL, /* compose */
- setup_masks_hangul, /* setup_masks */
+ setup_masks_hangul,
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hebrew.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hebrew.cc
index c7b7a5eba6..96f2494616 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hebrew.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-hebrew.cc
@@ -68,7 +68,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
0xFB4Au /* TAV */
};
- bool found = c->unicode->compose (a, b, ab);
+ bool found = (bool) c->unicode->compose (a, b, ab);
if (!found && !c->plan->has_mark)
{
@@ -154,6 +154,18 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
return found;
}
+static bool
+disable_otl_hebrew (const hb_ot_shape_plan_t *plan)
+{
+ /* For Hebrew shaper, use fallback if GPOS does not have 'hebr'
+ * script. This matches Uniscribe better, and makes fonts like
+ * Arial that have GSUB/GPOS/GDEF but no data for Hebrew work.
+ * See:
+ * https://github.com/behdad/harfbuzz/issues/347#issuecomment-267838368
+ */
+ return plan->map.chosen_script[1] != HB_TAG ('h','e','b','r');
+}
+
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
{
@@ -163,10 +175,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
+ NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
compose_hebrew,
NULL, /* setup_masks */
+ disable_otl_hebrew,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh
index f652d4fda7..5a7a265c87 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh
@@ -56,52 +56,52 @@ static const unsigned char _indic_syllable_machine_trans_keys[] = {
5u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
5u, 7u, 7u, 7u, 8u, 8u, 1u, 16u, 8u, 13u, 4u, 8u, 6u, 6u, 16u, 16u,
4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
- 16u, 16u, 8u, 8u, 1u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
- 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
- 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u,
+ 16u, 16u, 8u, 8u, 1u, 18u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u,
+ 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u,
+ 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 14u, 5u, 14u,
5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u,
3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u,
- 5u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 3u, 31u, 3u, 31u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
- 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
- 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u,
- 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u,
- 3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
- 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u,
- 5u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
- 4u, 14u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u,
- 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u,
- 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u, 5u, 10u,
+ 5u, 14u, 3u, 14u, 1u, 16u, 4u, 14u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u,
+ 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u,
+ 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 14u, 5u, 14u, 5u, 10u,
9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 3u, 10u,
5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u,
4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
- 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
- 4u, 14u, 3u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
- 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u,
- 3u, 31u, 4u, 31u, 1u, 16u, 3u, 31u, 3u, 31u, 4u, 31u, 5u, 14u, 5u, 14u,
- 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u,
- 3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+ 3u, 14u, 1u, 16u, 4u, 14u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 14u, 1u, 16u,
+ 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+ 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+ 3u, 17u, 3u, 17u, 4u, 17u, 5u, 14u, 5u, 14u, 5u, 10u, 9u, 10u, 9u, 9u,
+ 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 3u, 10u, 5u, 10u, 3u, 10u,
+ 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+ 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 1u, 16u,
+ 4u, 14u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u,
+ 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 14u, 3u, 17u, 4u, 14u,
+ 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+ 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
+ 3u, 17u, 3u, 17u, 4u, 17u, 5u, 14u, 5u, 14u, 5u, 10u, 9u, 10u, 9u, 9u,
+ 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 3u, 13u, 3u, 10u, 5u, 10u, 3u, 10u,
+ 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
+ 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 1u, 16u,
+ 4u, 14u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u,
+ 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 1u, 17u, 3u, 17u,
+ 1u, 17u, 4u, 14u, 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u,
+ 5u, 10u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 3u, 17u, 3u, 17u, 1u, 16u,
3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u,
- 5u, 14u, 3u, 14u, 1u, 16u, 4u, 31u, 4u, 14u, 3u, 31u, 3u, 31u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 1u, 16u, 3u, 31u, 3u, 31u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 3u, 31u, 1u, 31u, 3u, 31u, 1u, 31u, 4u, 14u, 5u, 10u, 9u, 10u,
- 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 1u, 16u, 3u, 31u, 3u, 31u,
- 4u, 31u, 3u, 31u, 3u, 31u, 1u, 16u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u,
- 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u,
- 3u, 13u, 3u, 10u, 5u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 3u, 10u, 5u, 10u,
- 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u, 9u, 10u, 9u, 9u, 5u, 10u, 0
+ 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 13u, 3u, 10u, 5u, 10u, 3u, 10u,
+ 3u, 13u, 1u, 16u, 3u, 10u, 5u, 10u, 5u, 10u, 9u, 10u, 9u, 9u, 9u, 10u,
+ 9u, 10u, 9u, 9u, 5u, 10u, 0
};
static const char _indic_syllable_machine_key_spans[] = {
@@ -127,52 +127,52 @@ static const char _indic_syllable_machine_key_spans[] = {
3, 4, 3, 1, 4, 3, 1, 4,
3, 1, 1, 16, 6, 5, 1, 1,
5, 1, 1, 5, 1, 1, 5, 1,
- 1, 1, 31, 29, 29, 28, 16, 29,
- 29, 28, 16, 29, 29, 28, 16, 29,
- 29, 28, 16, 29, 29, 28, 10, 10,
+ 1, 1, 18, 15, 15, 14, 16, 15,
+ 15, 14, 16, 15, 15, 14, 16, 15,
+ 15, 14, 16, 15, 15, 14, 10, 10,
6, 2, 1, 2, 2, 1, 6, 11,
8, 6, 8, 11, 12, 12, 11, 10,
12, 11, 10, 12, 11, 10, 12, 11,
- 10, 12, 16, 28, 11, 29, 29, 16,
- 16, 16, 16, 16, 29, 29, 16, 16,
- 16, 16, 16, 29, 29, 16, 16, 16,
- 16, 16, 29, 29, 16, 16, 16, 16,
- 16, 29, 29, 29, 29, 28, 16, 29,
- 29, 28, 16, 29, 29, 28, 16, 29,
- 29, 28, 16, 29, 29, 28, 10, 10,
- 6, 2, 1, 2, 2, 1, 6, 11,
- 8, 6, 8, 11, 12, 12, 11, 10,
- 12, 11, 10, 12, 11, 10, 12, 11,
- 10, 12, 16, 28, 11, 29, 29, 16,
- 16, 16, 16, 16, 29, 29, 16, 16,
- 16, 16, 16, 29, 29, 16, 16, 16,
- 16, 16, 29, 29, 16, 16, 16, 16,
- 11, 16, 29, 29, 28, 16, 29, 29,
- 28, 16, 29, 29, 28, 16, 29, 29,
- 28, 16, 29, 29, 28, 10, 10, 6,
+ 10, 12, 16, 11, 15, 15, 16, 16,
+ 16, 16, 16, 15, 15, 16, 16, 16,
+ 16, 16, 15, 15, 16, 16, 16, 16,
+ 16, 15, 15, 16, 16, 16, 16, 16,
+ 15, 15, 15, 15, 14, 16, 15, 15,
+ 14, 16, 15, 15, 14, 16, 15, 15,
+ 14, 16, 15, 15, 14, 10, 10, 6,
2, 1, 2, 2, 1, 6, 11, 8,
6, 8, 11, 12, 12, 11, 10, 12,
11, 10, 12, 11, 10, 12, 11, 10,
- 12, 16, 28, 11, 29, 29, 16, 16,
- 16, 16, 16, 29, 29, 16, 16, 16,
- 16, 16, 29, 29, 16, 16, 16, 16,
- 16, 29, 29, 16, 16, 16, 16, 16,
- 11, 29, 11, 29, 29, 28, 16, 29,
- 29, 28, 16, 29, 29, 28, 16, 29,
- 29, 28, 16, 29, 29, 28, 10, 10,
- 6, 2, 1, 2, 2, 1, 6, 11,
- 8, 6, 8, 11, 12, 12, 11, 10,
+ 12, 16, 11, 15, 15, 16, 16, 16,
+ 16, 16, 15, 15, 16, 16, 16, 16,
+ 16, 15, 15, 16, 16, 16, 16, 16,
+ 15, 15, 16, 16, 16, 16, 11, 16,
+ 15, 15, 14, 16, 15, 15, 14, 16,
+ 15, 15, 14, 16, 15, 15, 14, 16,
+ 15, 15, 14, 10, 10, 6, 2, 1,
+ 2, 2, 1, 6, 11, 8, 6, 8,
+ 11, 12, 12, 11, 10, 12, 11, 10,
+ 12, 11, 10, 12, 11, 10, 12, 16,
+ 11, 15, 15, 16, 16, 16, 16, 16,
+ 15, 15, 16, 16, 16, 16, 16, 15,
+ 15, 16, 16, 16, 16, 16, 15, 15,
+ 16, 16, 16, 16, 16, 11, 15, 11,
+ 15, 15, 14, 16, 15, 15, 14, 16,
+ 15, 15, 14, 16, 15, 15, 14, 16,
+ 15, 15, 14, 10, 10, 6, 2, 1,
+ 2, 2, 1, 6, 11, 8, 6, 8,
+ 11, 12, 12, 11, 10, 12, 11, 10,
+ 12, 11, 10, 12, 11, 10, 12, 16,
+ 11, 15, 15, 16, 16, 16, 16, 16,
+ 15, 15, 16, 16, 16, 16, 16, 15,
+ 15, 16, 16, 16, 16, 16, 15, 15,
+ 16, 16, 16, 16, 16, 15, 17, 15,
+ 17, 11, 6, 2, 1, 2, 2, 1,
+ 6, 16, 15, 15, 14, 15, 15, 16,
12, 11, 10, 12, 11, 10, 12, 11,
- 10, 12, 16, 28, 11, 29, 29, 16,
- 16, 16, 16, 16, 29, 29, 16, 16,
- 16, 16, 16, 29, 29, 16, 16, 16,
- 16, 16, 29, 29, 16, 16, 16, 16,
- 16, 29, 31, 29, 31, 11, 6, 2,
- 1, 2, 2, 1, 6, 16, 29, 29,
- 28, 29, 29, 16, 12, 11, 10, 12,
- 11, 10, 12, 11, 10, 12, 11, 10,
- 11, 8, 6, 8, 11, 16, 8, 6,
- 6, 2, 1, 2, 2, 1, 6
+ 10, 12, 11, 10, 11, 8, 6, 8,
+ 11, 16, 8, 6, 6, 2, 1, 2,
+ 2, 1, 6
};
static const short _indic_syllable_machine_index_offsets[] = {
@@ -198,52 +198,52 @@ static const short _indic_syllable_machine_index_offsets[] = {
954, 958, 963, 967, 969, 974, 978, 980,
985, 989, 991, 993, 1010, 1017, 1023, 1025,
1027, 1033, 1035, 1037, 1043, 1045, 1047, 1053,
- 1055, 1057, 1059, 1091, 1121, 1151, 1180, 1197,
- 1227, 1257, 1286, 1303, 1333, 1363, 1392, 1409,
- 1439, 1469, 1498, 1515, 1545, 1575, 1604, 1615,
- 1626, 1633, 1636, 1638, 1641, 1644, 1646, 1653,
- 1665, 1674, 1681, 1690, 1702, 1715, 1728, 1740,
- 1751, 1764, 1776, 1787, 1800, 1812, 1823, 1836,
- 1848, 1859, 1872, 1889, 1918, 1930, 1960, 1990,
- 2007, 2024, 2041, 2058, 2075, 2105, 2135, 2152,
- 2169, 2186, 2203, 2220, 2250, 2280, 2297, 2314,
- 2331, 2348, 2365, 2395, 2425, 2442, 2459, 2476,
- 2493, 2510, 2540, 2570, 2600, 2630, 2659, 2676,
- 2706, 2736, 2765, 2782, 2812, 2842, 2871, 2888,
- 2918, 2948, 2977, 2994, 3024, 3054, 3083, 3094,
- 3105, 3112, 3115, 3117, 3120, 3123, 3125, 3132,
- 3144, 3153, 3160, 3169, 3181, 3194, 3207, 3219,
- 3230, 3243, 3255, 3266, 3279, 3291, 3302, 3315,
- 3327, 3338, 3351, 3368, 3397, 3409, 3439, 3469,
- 3486, 3503, 3520, 3537, 3554, 3584, 3614, 3631,
- 3648, 3665, 3682, 3699, 3729, 3759, 3776, 3793,
- 3810, 3827, 3844, 3874, 3904, 3921, 3938, 3955,
- 3972, 3984, 4001, 4031, 4061, 4090, 4107, 4137,
- 4167, 4196, 4213, 4243, 4273, 4302, 4319, 4349,
- 4379, 4408, 4425, 4455, 4485, 4514, 4525, 4536,
- 4543, 4546, 4548, 4551, 4554, 4556, 4563, 4575,
- 4584, 4591, 4600, 4612, 4625, 4638, 4650, 4661,
- 4674, 4686, 4697, 4710, 4722, 4733, 4746, 4758,
- 4769, 4782, 4799, 4828, 4840, 4870, 4900, 4917,
- 4934, 4951, 4968, 4985, 5015, 5045, 5062, 5079,
- 5096, 5113, 5130, 5160, 5190, 5207, 5224, 5241,
- 5258, 5275, 5305, 5335, 5352, 5369, 5386, 5403,
- 5420, 5432, 5462, 5474, 5504, 5534, 5563, 5580,
- 5610, 5640, 5669, 5686, 5716, 5746, 5775, 5792,
- 5822, 5852, 5881, 5898, 5928, 5958, 5987, 5998,
- 6009, 6016, 6019, 6021, 6024, 6027, 6029, 6036,
- 6048, 6057, 6064, 6073, 6085, 6098, 6111, 6123,
- 6134, 6147, 6159, 6170, 6183, 6195, 6206, 6219,
- 6231, 6242, 6255, 6272, 6301, 6313, 6343, 6373,
- 6390, 6407, 6424, 6441, 6458, 6488, 6518, 6535,
- 6552, 6569, 6586, 6603, 6633, 6663, 6680, 6697,
- 6714, 6731, 6748, 6778, 6808, 6825, 6842, 6859,
- 6876, 6893, 6923, 6955, 6985, 7017, 7029, 7036,
- 7039, 7041, 7044, 7047, 7049, 7056, 7073, 7103,
- 7133, 7162, 7192, 7222, 7239, 7252, 7264, 7275,
- 7288, 7300, 7311, 7324, 7336, 7347, 7360, 7372,
- 7383, 7395, 7404, 7411, 7420, 7432, 7449, 7458,
- 7465, 7472, 7475, 7477, 7480, 7483, 7485
+ 1055, 1057, 1059, 1078, 1094, 1110, 1125, 1142,
+ 1158, 1174, 1189, 1206, 1222, 1238, 1253, 1270,
+ 1286, 1302, 1317, 1334, 1350, 1366, 1381, 1392,
+ 1403, 1410, 1413, 1415, 1418, 1421, 1423, 1430,
+ 1442, 1451, 1458, 1467, 1479, 1492, 1505, 1517,
+ 1528, 1541, 1553, 1564, 1577, 1589, 1600, 1613,
+ 1625, 1636, 1649, 1666, 1678, 1694, 1710, 1727,
+ 1744, 1761, 1778, 1795, 1811, 1827, 1844, 1861,
+ 1878, 1895, 1912, 1928, 1944, 1961, 1978, 1995,
+ 2012, 2029, 2045, 2061, 2078, 2095, 2112, 2129,
+ 2146, 2162, 2178, 2194, 2210, 2225, 2242, 2258,
+ 2274, 2289, 2306, 2322, 2338, 2353, 2370, 2386,
+ 2402, 2417, 2434, 2450, 2466, 2481, 2492, 2503,
+ 2510, 2513, 2515, 2518, 2521, 2523, 2530, 2542,
+ 2551, 2558, 2567, 2579, 2592, 2605, 2617, 2628,
+ 2641, 2653, 2664, 2677, 2689, 2700, 2713, 2725,
+ 2736, 2749, 2766, 2778, 2794, 2810, 2827, 2844,
+ 2861, 2878, 2895, 2911, 2927, 2944, 2961, 2978,
+ 2995, 3012, 3028, 3044, 3061, 3078, 3095, 3112,
+ 3129, 3145, 3161, 3178, 3195, 3212, 3229, 3241,
+ 3258, 3274, 3290, 3305, 3322, 3338, 3354, 3369,
+ 3386, 3402, 3418, 3433, 3450, 3466, 3482, 3497,
+ 3514, 3530, 3546, 3561, 3572, 3583, 3590, 3593,
+ 3595, 3598, 3601, 3603, 3610, 3622, 3631, 3638,
+ 3647, 3659, 3672, 3685, 3697, 3708, 3721, 3733,
+ 3744, 3757, 3769, 3780, 3793, 3805, 3816, 3829,
+ 3846, 3858, 3874, 3890, 3907, 3924, 3941, 3958,
+ 3975, 3991, 4007, 4024, 4041, 4058, 4075, 4092,
+ 4108, 4124, 4141, 4158, 4175, 4192, 4209, 4225,
+ 4241, 4258, 4275, 4292, 4309, 4326, 4338, 4354,
+ 4366, 4382, 4398, 4413, 4430, 4446, 4462, 4477,
+ 4494, 4510, 4526, 4541, 4558, 4574, 4590, 4605,
+ 4622, 4638, 4654, 4669, 4680, 4691, 4698, 4701,
+ 4703, 4706, 4709, 4711, 4718, 4730, 4739, 4746,
+ 4755, 4767, 4780, 4793, 4805, 4816, 4829, 4841,
+ 4852, 4865, 4877, 4888, 4901, 4913, 4924, 4937,
+ 4954, 4966, 4982, 4998, 5015, 5032, 5049, 5066,
+ 5083, 5099, 5115, 5132, 5149, 5166, 5183, 5200,
+ 5216, 5232, 5249, 5266, 5283, 5300, 5317, 5333,
+ 5349, 5366, 5383, 5400, 5417, 5434, 5450, 5468,
+ 5484, 5502, 5514, 5521, 5524, 5526, 5529, 5532,
+ 5534, 5541, 5558, 5574, 5590, 5605, 5621, 5637,
+ 5654, 5667, 5679, 5690, 5703, 5715, 5726, 5739,
+ 5751, 5762, 5775, 5787, 5798, 5810, 5819, 5826,
+ 5835, 5847, 5864, 5873, 5880, 5887, 5890, 5892,
+ 5895, 5898, 5900
};
static const short _indic_syllable_machine_indicies[] = {
@@ -381,882 +381,684 @@ static const short _indic_syllable_machine_indicies[] = {
161, 161, 162, 157, 0, 183, 0, 184,
0, 186, 185, 188, 189, 190, 191, 192,
193, 84, 79, 194, 195, 196, 196, 156,
- 197, 198, 199, 200, 201, 187, 187, 187,
- 187, 187, 187, 187, 187, 187, 187, 187,
- 187, 202, 187, 204, 205, 206, 207, 6,
- 1, 208, 209, 203, 203, 38, 210, 203,
- 203, 211, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 212,
- 203, 213, 205, 214, 214, 6, 1, 208,
- 209, 203, 203, 203, 210, 203, 203, 211,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 212, 203, 205,
- 214, 214, 6, 1, 208, 209, 203, 203,
- 203, 210, 203, 203, 211, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 212, 203, 215, 203, 203, 203,
- 19, 216, 203, 1, 208, 209, 203, 203,
- 203, 217, 203, 215, 203, 218, 219, 220,
- 221, 6, 1, 208, 209, 203, 203, 36,
- 222, 203, 203, 211, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 212, 203, 223, 219, 224, 224, 6,
- 1, 208, 209, 203, 203, 203, 222, 203,
- 203, 211, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 212,
- 203, 219, 224, 224, 6, 1, 208, 209,
- 203, 203, 203, 222, 203, 203, 211, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 212, 203, 225, 203,
- 203, 203, 19, 226, 203, 1, 208, 209,
- 203, 203, 203, 217, 203, 225, 203, 227,
- 228, 229, 230, 6, 1, 208, 209, 203,
- 203, 34, 231, 203, 203, 211, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 212, 203, 232, 228, 233,
- 233, 6, 1, 208, 209, 203, 203, 203,
- 231, 203, 203, 211, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 212, 203, 228, 233, 233, 6, 1,
- 208, 209, 203, 203, 203, 231, 203, 203,
- 211, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 212, 203,
- 234, 203, 203, 203, 19, 235, 203, 1,
- 208, 209, 203, 203, 203, 217, 203, 234,
- 203, 236, 237, 238, 239, 6, 1, 208,
- 209, 203, 203, 32, 240, 203, 203, 211,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 212, 203, 241,
- 237, 242, 242, 6, 1, 208, 209, 203,
- 203, 203, 240, 203, 203, 211, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 212, 203, 237, 242, 242,
- 6, 1, 208, 209, 203, 203, 203, 240,
- 203, 203, 211, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 212, 203, 243, 203, 203, 203, 19, 244,
- 203, 1, 208, 209, 203, 203, 203, 217,
- 203, 243, 203, 245, 246, 247, 248, 6,
- 1, 208, 209, 203, 203, 30, 249, 203,
- 203, 211, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 212,
- 203, 250, 246, 251, 251, 6, 1, 208,
- 209, 203, 203, 203, 249, 203, 203, 211,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 212, 203, 246,
- 251, 251, 6, 1, 208, 209, 203, 203,
- 203, 249, 203, 203, 211, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 212, 203, 19, 252, 203, 1,
- 208, 209, 203, 203, 203, 217, 203, 253,
- 253, 203, 1, 208, 209, 203, 203, 203,
- 217, 203, 254, 203, 203, 255, 208, 209,
- 203, 208, 209, 203, 256, 203, 208, 257,
- 203, 208, 258, 203, 208, 203, 254, 203,
- 203, 203, 208, 209, 203, 259, 203, 260,
- 261, 203, 1, 208, 209, 203, 203, 4,
- 203, 3, 203, 253, 253, 203, 1, 208,
- 209, 203, 253, 253, 203, 1, 208, 209,
- 203, 259, 203, 253, 253, 203, 1, 208,
- 209, 203, 259, 203, 260, 253, 203, 1,
- 208, 209, 203, 203, 4, 203, 19, 203,
- 262, 262, 6, 1, 208, 209, 203, 203,
- 203, 217, 203, 263, 28, 264, 265, 9,
- 1, 208, 209, 203, 203, 203, 217, 203,
- 28, 264, 265, 9, 1, 208, 209, 203,
- 203, 203, 217, 203, 264, 264, 9, 1,
- 208, 209, 203, 203, 203, 217, 203, 266,
- 25, 267, 268, 12, 1, 208, 209, 203,
- 203, 203, 217, 203, 25, 267, 268, 12,
- 1, 208, 209, 203, 203, 203, 217, 203,
- 267, 267, 12, 1, 208, 209, 203, 203,
- 203, 217, 203, 269, 22, 270, 271, 15,
- 1, 208, 209, 203, 203, 203, 217, 203,
- 22, 270, 271, 15, 1, 208, 209, 203,
- 203, 203, 217, 203, 270, 270, 15, 1,
- 208, 209, 203, 203, 203, 217, 203, 272,
- 19, 253, 273, 203, 1, 208, 209, 203,
- 203, 203, 217, 203, 19, 253, 273, 203,
- 1, 208, 209, 203, 203, 203, 217, 203,
- 253, 274, 203, 1, 208, 209, 203, 203,
- 203, 217, 203, 19, 203, 253, 253, 203,
- 1, 208, 209, 203, 203, 203, 217, 203,
- 2, 3, 203, 203, 19, 252, 203, 1,
- 208, 209, 203, 203, 203, 217, 203, 2,
- 203, 246, 251, 251, 6, 1, 208, 209,
- 203, 203, 203, 249, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 212, 203, 246, 251,
- 251, 6, 1, 208, 209, 203, 203, 203,
- 249, 203, 245, 246, 251, 251, 6, 1,
- 208, 209, 203, 203, 203, 249, 203, 203,
- 211, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 212, 203,
- 245, 246, 247, 251, 6, 1, 208, 209,
- 203, 203, 30, 249, 203, 203, 211, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 212, 203, 243, 203,
- 275, 203, 262, 262, 6, 1, 208, 209,
- 203, 203, 203, 217, 203, 243, 203, 243,
- 203, 203, 203, 253, 253, 203, 1, 208,
- 209, 203, 203, 203, 217, 203, 243, 203,
- 243, 203, 203, 203, 253, 276, 203, 1,
- 208, 209, 203, 203, 203, 217, 203, 243,
- 203, 243, 203, 275, 203, 253, 253, 203,
- 1, 208, 209, 203, 203, 203, 217, 203,
- 243, 203, 243, 3, 203, 203, 19, 244,
- 203, 1, 208, 209, 203, 203, 203, 217,
- 203, 243, 203, 236, 237, 242, 242, 6,
- 1, 208, 209, 203, 203, 203, 240, 203,
- 203, 211, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 212,
- 203, 236, 237, 238, 242, 6, 1, 208,
- 209, 203, 203, 32, 240, 203, 203, 211,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 212, 203, 234,
- 203, 277, 203, 262, 262, 6, 1, 208,
- 209, 203, 203, 203, 217, 203, 234, 203,
- 234, 203, 203, 203, 253, 253, 203, 1,
- 208, 209, 203, 203, 203, 217, 203, 234,
- 203, 234, 203, 203, 203, 253, 278, 203,
- 1, 208, 209, 203, 203, 203, 217, 203,
- 234, 203, 234, 203, 277, 203, 253, 253,
- 203, 1, 208, 209, 203, 203, 203, 217,
- 203, 234, 203, 234, 3, 203, 203, 19,
- 235, 203, 1, 208, 209, 203, 203, 203,
- 217, 203, 234, 203, 227, 228, 233, 233,
- 6, 1, 208, 209, 203, 203, 203, 231,
- 203, 203, 211, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 212, 203, 227, 228, 229, 233, 6, 1,
- 208, 209, 203, 203, 34, 231, 203, 203,
- 211, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 212, 203,
- 225, 203, 279, 203, 262, 262, 6, 1,
- 208, 209, 203, 203, 203, 217, 203, 225,
- 203, 225, 203, 203, 203, 253, 253, 203,
- 1, 208, 209, 203, 203, 203, 217, 203,
- 225, 203, 225, 203, 203, 203, 253, 280,
- 203, 1, 208, 209, 203, 203, 203, 217,
- 203, 225, 203, 225, 203, 279, 203, 253,
- 253, 203, 1, 208, 209, 203, 203, 203,
- 217, 203, 225, 203, 225, 3, 203, 203,
- 19, 226, 203, 1, 208, 209, 203, 203,
- 203, 217, 203, 225, 203, 218, 219, 224,
- 224, 6, 1, 208, 209, 203, 203, 203,
- 222, 203, 203, 211, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 212, 203, 218, 219, 220, 224, 6,
- 1, 208, 209, 203, 203, 36, 222, 203,
- 203, 211, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 212,
- 203, 215, 203, 281, 203, 262, 262, 6,
- 1, 208, 209, 203, 203, 203, 217, 203,
- 215, 203, 215, 203, 203, 203, 253, 253,
- 203, 1, 208, 209, 203, 203, 203, 217,
- 203, 215, 203, 215, 203, 203, 203, 253,
- 282, 203, 1, 208, 209, 203, 203, 203,
- 217, 203, 215, 203, 215, 203, 281, 203,
- 253, 253, 203, 1, 208, 209, 203, 203,
- 203, 217, 203, 215, 203, 215, 3, 203,
- 203, 19, 216, 203, 1, 208, 209, 203,
- 203, 203, 217, 203, 215, 203, 204, 205,
- 214, 214, 6, 1, 208, 209, 203, 203,
- 203, 210, 203, 203, 211, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 212, 203, 204, 205, 206, 214,
- 6, 1, 208, 209, 203, 203, 38, 210,
- 203, 203, 211, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 212, 203, 284, 285, 286, 287, 45, 40,
- 288, 289, 283, 283, 77, 290, 283, 283,
- 291, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 292, 283,
- 293, 285, 294, 287, 45, 40, 288, 289,
- 283, 283, 283, 290, 283, 283, 291, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 292, 283, 285, 294,
- 287, 45, 40, 288, 289, 283, 283, 283,
- 290, 283, 283, 291, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 292, 283, 295, 283, 283, 283, 58,
- 296, 283, 40, 288, 289, 283, 283, 283,
- 297, 283, 295, 283, 298, 299, 300, 301,
- 45, 40, 288, 289, 283, 283, 75, 302,
- 283, 283, 291, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 292, 283, 303, 299, 304, 304, 45, 40,
- 288, 289, 283, 283, 283, 302, 283, 283,
- 291, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 292, 283,
- 299, 304, 304, 45, 40, 288, 289, 283,
- 283, 283, 302, 283, 283, 291, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 292, 283, 305, 283, 283,
- 283, 58, 306, 283, 40, 288, 289, 283,
- 283, 283, 297, 283, 305, 283, 307, 308,
- 309, 310, 45, 40, 288, 289, 283, 283,
- 73, 311, 283, 283, 291, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 292, 283, 312, 308, 313, 313,
- 45, 40, 288, 289, 283, 283, 283, 311,
- 283, 283, 291, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 292, 283, 308, 313, 313, 45, 40, 288,
- 289, 283, 283, 283, 311, 283, 283, 291,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 292, 283, 314,
- 283, 283, 283, 58, 315, 283, 40, 288,
- 289, 283, 283, 283, 297, 283, 314, 283,
- 316, 317, 318, 319, 45, 40, 288, 289,
- 283, 283, 71, 320, 283, 283, 291, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 292, 283, 321, 317,
- 322, 322, 45, 40, 288, 289, 283, 283,
- 283, 320, 283, 283, 291, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 292, 283, 317, 322, 322, 45,
- 40, 288, 289, 283, 283, 283, 320, 283,
- 283, 291, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 292,
- 283, 323, 283, 283, 283, 58, 324, 283,
- 40, 288, 289, 283, 283, 283, 297, 283,
- 323, 283, 325, 326, 327, 328, 45, 40,
- 288, 289, 283, 283, 69, 329, 283, 283,
- 291, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 292, 283,
- 330, 326, 331, 331, 45, 40, 288, 289,
- 283, 283, 283, 329, 283, 283, 291, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 292, 283, 326, 331,
- 331, 45, 40, 288, 289, 283, 283, 283,
- 329, 283, 283, 291, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 292, 283, 58, 332, 283, 40, 288,
- 289, 283, 283, 283, 297, 283, 333, 333,
- 283, 40, 288, 289, 283, 283, 283, 297,
- 283, 334, 283, 283, 335, 288, 289, 283,
- 288, 289, 283, 336, 283, 288, 337, 283,
- 288, 338, 283, 288, 283, 334, 283, 283,
- 283, 288, 289, 283, 339, 283, 340, 341,
- 283, 40, 288, 289, 283, 283, 43, 283,
- 42, 283, 333, 333, 283, 40, 288, 289,
- 283, 333, 333, 283, 40, 288, 289, 283,
- 339, 283, 333, 333, 283, 40, 288, 289,
- 283, 339, 283, 340, 333, 283, 40, 288,
- 289, 283, 283, 43, 283, 58, 283, 342,
- 342, 45, 40, 288, 289, 283, 283, 283,
- 297, 283, 343, 67, 344, 345, 48, 40,
- 288, 289, 283, 283, 283, 297, 283, 67,
- 344, 345, 48, 40, 288, 289, 283, 283,
- 283, 297, 283, 344, 344, 48, 40, 288,
- 289, 283, 283, 283, 297, 283, 346, 64,
- 347, 348, 51, 40, 288, 289, 283, 283,
- 283, 297, 283, 64, 347, 348, 51, 40,
- 288, 289, 283, 283, 283, 297, 283, 347,
- 347, 51, 40, 288, 289, 283, 283, 283,
- 297, 283, 349, 61, 350, 351, 54, 40,
- 288, 289, 283, 283, 283, 297, 283, 61,
- 350, 351, 54, 40, 288, 289, 283, 283,
- 283, 297, 283, 350, 350, 54, 40, 288,
- 289, 283, 283, 283, 297, 283, 352, 58,
- 333, 353, 283, 40, 288, 289, 283, 283,
- 283, 297, 283, 58, 333, 353, 283, 40,
- 288, 289, 283, 283, 283, 297, 283, 333,
- 354, 283, 40, 288, 289, 283, 283, 283,
- 297, 283, 58, 283, 333, 333, 283, 40,
- 288, 289, 283, 283, 283, 297, 283, 41,
- 42, 283, 283, 58, 332, 283, 40, 288,
- 289, 283, 283, 283, 297, 283, 41, 283,
- 326, 331, 331, 45, 40, 288, 289, 283,
- 283, 283, 329, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 292, 283, 326, 331, 331,
- 45, 40, 288, 289, 283, 283, 283, 329,
- 283, 325, 326, 331, 331, 45, 40, 288,
- 289, 283, 283, 283, 329, 283, 283, 291,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 292, 283, 325,
- 326, 327, 331, 45, 40, 288, 289, 283,
- 283, 69, 329, 283, 283, 291, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 292, 283, 323, 283, 355,
- 283, 342, 342, 45, 40, 288, 289, 283,
- 283, 283, 297, 283, 323, 283, 323, 283,
- 283, 283, 333, 333, 283, 40, 288, 289,
- 283, 283, 283, 297, 283, 323, 283, 323,
- 283, 283, 283, 333, 356, 283, 40, 288,
- 289, 283, 283, 283, 297, 283, 323, 283,
- 323, 283, 355, 283, 333, 333, 283, 40,
- 288, 289, 283, 283, 283, 297, 283, 323,
- 283, 323, 42, 283, 283, 58, 324, 283,
- 40, 288, 289, 283, 283, 283, 297, 283,
- 323, 283, 316, 317, 322, 322, 45, 40,
- 288, 289, 283, 283, 283, 320, 283, 283,
- 291, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 292, 283,
- 316, 317, 318, 322, 45, 40, 288, 289,
- 283, 283, 71, 320, 283, 283, 291, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 292, 283, 314, 283,
- 357, 283, 342, 342, 45, 40, 288, 289,
- 283, 283, 283, 297, 283, 314, 283, 314,
- 283, 283, 283, 333, 333, 283, 40, 288,
- 289, 283, 283, 283, 297, 283, 314, 283,
- 314, 283, 283, 283, 333, 358, 283, 40,
- 288, 289, 283, 283, 283, 297, 283, 314,
- 283, 314, 283, 357, 283, 333, 333, 283,
- 40, 288, 289, 283, 283, 283, 297, 283,
- 314, 283, 314, 42, 283, 283, 58, 315,
- 283, 40, 288, 289, 283, 283, 283, 297,
- 283, 314, 283, 307, 308, 313, 313, 45,
- 40, 288, 289, 283, 283, 283, 311, 283,
- 283, 291, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 292,
- 283, 307, 308, 309, 313, 45, 40, 288,
- 289, 283, 283, 73, 311, 283, 283, 291,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 292, 283, 305,
- 283, 359, 283, 342, 342, 45, 40, 288,
- 289, 283, 283, 283, 297, 283, 305, 283,
- 305, 283, 283, 283, 333, 333, 283, 40,
- 288, 289, 283, 283, 283, 297, 283, 305,
- 283, 305, 283, 283, 283, 333, 360, 283,
- 40, 288, 289, 283, 283, 283, 297, 283,
- 305, 283, 305, 283, 359, 283, 333, 333,
- 283, 40, 288, 289, 283, 283, 283, 297,
- 283, 305, 283, 305, 42, 283, 283, 58,
- 306, 283, 40, 288, 289, 283, 283, 283,
- 297, 283, 305, 283, 298, 299, 304, 304,
- 45, 40, 288, 289, 283, 283, 283, 302,
- 283, 283, 291, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 292, 283, 298, 299, 300, 304, 45, 40,
- 288, 289, 283, 283, 75, 302, 283, 283,
- 291, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 283, 292, 283,
- 295, 283, 361, 283, 342, 342, 45, 40,
- 288, 289, 283, 283, 283, 297, 283, 295,
- 283, 295, 283, 283, 283, 333, 333, 283,
- 40, 288, 289, 283, 283, 283, 297, 283,
- 295, 283, 295, 283, 283, 283, 333, 362,
- 283, 40, 288, 289, 283, 283, 283, 297,
- 283, 295, 283, 295, 283, 361, 283, 333,
- 333, 283, 40, 288, 289, 283, 283, 283,
- 297, 283, 295, 283, 76, 44, 44, 45,
- 40, 283, 283, 283, 283, 283, 76, 283,
- 295, 42, 283, 283, 58, 296, 283, 40,
- 288, 289, 283, 283, 283, 297, 283, 295,
- 283, 284, 285, 294, 287, 45, 40, 288,
- 289, 283, 283, 283, 290, 283, 283, 291,
- 283, 283, 283, 283, 283, 283, 283, 283,
- 283, 283, 283, 283, 283, 292, 283, 364,
- 191, 365, 365, 84, 79, 194, 195, 363,
- 363, 363, 197, 363, 363, 200, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 202, 363, 191, 365, 365,
- 84, 79, 194, 195, 363, 363, 363, 197,
- 363, 363, 200, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 202, 363, 366, 363, 363, 363, 98, 367,
- 363, 79, 194, 195, 363, 363, 363, 368,
- 363, 366, 363, 369, 370, 371, 372, 84,
- 79, 194, 195, 363, 363, 115, 373, 363,
- 363, 200, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 202,
- 363, 374, 370, 375, 375, 84, 79, 194,
- 195, 363, 363, 363, 373, 363, 363, 200,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 202, 363, 370,
- 375, 375, 84, 79, 194, 195, 363, 363,
- 363, 373, 363, 363, 200, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 202, 363, 376, 363, 363, 363,
- 98, 377, 363, 79, 194, 195, 363, 363,
- 363, 368, 363, 376, 363, 378, 379, 380,
- 381, 84, 79, 194, 195, 363, 363, 113,
- 382, 363, 363, 200, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 202, 363, 383, 379, 384, 384, 84,
- 79, 194, 195, 363, 363, 363, 382, 363,
- 363, 200, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 202,
- 363, 379, 384, 384, 84, 79, 194, 195,
- 363, 363, 363, 382, 363, 363, 200, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 202, 363, 385, 363,
- 363, 363, 98, 386, 363, 79, 194, 195,
- 363, 363, 363, 368, 363, 385, 363, 387,
- 388, 389, 390, 84, 79, 194, 195, 363,
- 363, 111, 391, 363, 363, 200, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 202, 363, 392, 388, 393,
- 393, 84, 79, 194, 195, 363, 363, 363,
- 391, 363, 363, 200, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 202, 363, 388, 393, 393, 84, 79,
- 194, 195, 363, 363, 363, 391, 363, 363,
- 200, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 202, 363,
- 394, 363, 363, 363, 98, 395, 363, 79,
- 194, 195, 363, 363, 363, 368, 363, 394,
- 363, 396, 397, 398, 399, 84, 79, 194,
- 195, 363, 363, 109, 400, 363, 363, 200,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 202, 363, 401,
- 397, 402, 402, 84, 79, 194, 195, 363,
- 363, 363, 400, 363, 363, 200, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 202, 363, 397, 402, 402,
- 84, 79, 194, 195, 363, 363, 363, 400,
- 363, 363, 200, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 202, 363, 98, 403, 363, 79, 194, 195,
- 363, 363, 363, 368, 363, 404, 404, 363,
- 79, 194, 195, 363, 363, 363, 368, 363,
- 405, 363, 363, 406, 194, 195, 363, 194,
- 195, 363, 407, 363, 194, 408, 363, 194,
- 409, 363, 194, 363, 405, 363, 363, 363,
- 194, 195, 363, 410, 363, 411, 412, 363,
- 79, 194, 195, 363, 363, 82, 363, 81,
- 363, 404, 404, 363, 79, 194, 195, 363,
- 404, 404, 363, 79, 194, 195, 363, 410,
- 363, 404, 404, 363, 79, 194, 195, 363,
- 410, 363, 411, 404, 363, 79, 194, 195,
- 363, 363, 82, 363, 98, 363, 413, 413,
- 84, 79, 194, 195, 363, 363, 363, 368,
- 363, 414, 107, 415, 416, 88, 79, 194,
- 195, 363, 363, 363, 368, 363, 107, 415,
- 416, 88, 79, 194, 195, 363, 363, 363,
- 368, 363, 415, 415, 88, 79, 194, 195,
- 363, 363, 363, 368, 363, 417, 104, 418,
- 419, 91, 79, 194, 195, 363, 363, 363,
- 368, 363, 104, 418, 419, 91, 79, 194,
- 195, 363, 363, 363, 368, 363, 418, 418,
- 91, 79, 194, 195, 363, 363, 363, 368,
- 363, 420, 101, 421, 422, 94, 79, 194,
- 195, 363, 363, 363, 368, 363, 101, 421,
- 422, 94, 79, 194, 195, 363, 363, 363,
- 368, 363, 421, 421, 94, 79, 194, 195,
- 363, 363, 363, 368, 363, 423, 98, 404,
- 424, 363, 79, 194, 195, 363, 363, 363,
- 368, 363, 98, 404, 424, 363, 79, 194,
- 195, 363, 363, 363, 368, 363, 404, 425,
- 363, 79, 194, 195, 363, 363, 363, 368,
- 363, 98, 363, 404, 404, 363, 79, 194,
- 195, 363, 363, 363, 368, 363, 80, 81,
- 363, 363, 98, 403, 363, 79, 194, 195,
- 363, 363, 363, 368, 363, 80, 363, 397,
- 402, 402, 84, 79, 194, 195, 363, 363,
- 363, 400, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 202, 363, 397, 402, 402, 84,
- 79, 194, 195, 363, 363, 363, 400, 363,
- 396, 397, 402, 402, 84, 79, 194, 195,
- 363, 363, 363, 400, 363, 363, 200, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 202, 363, 396, 397,
- 398, 402, 84, 79, 194, 195, 363, 363,
- 109, 400, 363, 363, 200, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 202, 363, 394, 363, 426, 363,
- 413, 413, 84, 79, 194, 195, 363, 363,
- 363, 368, 363, 394, 363, 394, 363, 363,
- 363, 404, 404, 363, 79, 194, 195, 363,
- 363, 363, 368, 363, 394, 363, 394, 363,
- 363, 363, 404, 427, 363, 79, 194, 195,
- 363, 363, 363, 368, 363, 394, 363, 394,
- 363, 426, 363, 404, 404, 363, 79, 194,
- 195, 363, 363, 363, 368, 363, 394, 363,
- 394, 81, 363, 363, 98, 395, 363, 79,
- 194, 195, 363, 363, 363, 368, 363, 394,
- 363, 387, 388, 393, 393, 84, 79, 194,
- 195, 363, 363, 363, 391, 363, 363, 200,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 202, 363, 387,
- 388, 389, 393, 84, 79, 194, 195, 363,
- 363, 111, 391, 363, 363, 200, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 202, 363, 385, 363, 428,
- 363, 413, 413, 84, 79, 194, 195, 363,
- 363, 363, 368, 363, 385, 363, 385, 363,
- 363, 363, 404, 404, 363, 79, 194, 195,
- 363, 363, 363, 368, 363, 385, 363, 385,
- 363, 363, 363, 404, 429, 363, 79, 194,
- 195, 363, 363, 363, 368, 363, 385, 363,
- 385, 363, 428, 363, 404, 404, 363, 79,
- 194, 195, 363, 363, 363, 368, 363, 385,
- 363, 385, 81, 363, 363, 98, 386, 363,
- 79, 194, 195, 363, 363, 363, 368, 363,
- 385, 363, 378, 379, 384, 384, 84, 79,
- 194, 195, 363, 363, 363, 382, 363, 363,
- 200, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 202, 363,
- 378, 379, 380, 384, 84, 79, 194, 195,
- 363, 363, 113, 382, 363, 363, 200, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 202, 363, 376, 363,
- 430, 363, 413, 413, 84, 79, 194, 195,
- 363, 363, 363, 368, 363, 376, 363, 376,
- 363, 363, 363, 404, 404, 363, 79, 194,
- 195, 363, 363, 363, 368, 363, 376, 363,
- 376, 363, 363, 363, 404, 431, 363, 79,
- 194, 195, 363, 363, 363, 368, 363, 376,
- 363, 376, 363, 430, 363, 404, 404, 363,
- 79, 194, 195, 363, 363, 363, 368, 363,
- 376, 363, 376, 81, 363, 363, 98, 377,
- 363, 79, 194, 195, 363, 363, 363, 368,
- 363, 376, 363, 369, 370, 375, 375, 84,
- 79, 194, 195, 363, 363, 363, 373, 363,
- 363, 200, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 202,
- 363, 369, 370, 371, 375, 84, 79, 194,
- 195, 363, 363, 115, 373, 363, 363, 200,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 202, 363, 366,
- 363, 432, 363, 413, 413, 84, 79, 194,
- 195, 363, 363, 363, 368, 363, 366, 363,
- 366, 363, 363, 363, 404, 404, 363, 79,
- 194, 195, 363, 363, 363, 368, 363, 366,
- 363, 366, 363, 363, 363, 404, 433, 363,
- 79, 194, 195, 363, 363, 363, 368, 363,
- 366, 363, 366, 363, 432, 363, 404, 404,
- 363, 79, 194, 195, 363, 363, 363, 368,
- 363, 366, 363, 366, 81, 363, 363, 98,
- 367, 363, 79, 194, 195, 363, 363, 363,
- 368, 363, 366, 363, 116, 83, 83, 84,
- 79, 434, 434, 434, 434, 156, 116, 434,
- 190, 191, 365, 365, 84, 79, 194, 195,
- 363, 363, 363, 197, 363, 363, 200, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 363, 363, 363, 202, 363, 116, 83,
- 83, 84, 79, 434, 434, 434, 434, 434,
- 116, 434, 436, 437, 438, 439, 123, 118,
- 440, 441, 435, 435, 155, 442, 435, 435,
- 443, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 444, 435,
- 445, 437, 439, 439, 123, 118, 440, 441,
- 435, 435, 435, 442, 435, 435, 443, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 444, 435, 437, 439,
- 439, 123, 118, 440, 441, 435, 435, 435,
- 442, 435, 435, 443, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 444, 435, 446, 435, 435, 435, 136,
- 447, 435, 118, 440, 441, 435, 435, 435,
- 448, 435, 446, 435, 449, 450, 451, 452,
- 123, 118, 440, 441, 435, 435, 153, 453,
- 435, 435, 443, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 444, 435, 454, 450, 455, 455, 123, 118,
- 440, 441, 435, 435, 435, 453, 435, 435,
- 443, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 444, 435,
- 450, 455, 455, 123, 118, 440, 441, 435,
- 435, 435, 453, 435, 435, 443, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 444, 435, 456, 435, 435,
- 435, 136, 457, 435, 118, 440, 441, 435,
- 435, 435, 448, 435, 456, 435, 458, 459,
- 460, 461, 123, 118, 440, 441, 435, 435,
- 151, 462, 435, 435, 443, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 444, 435, 463, 459, 464, 464,
- 123, 118, 440, 441, 435, 435, 435, 462,
- 435, 435, 443, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 444, 435, 459, 464, 464, 123, 118, 440,
- 441, 435, 435, 435, 462, 435, 435, 443,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 444, 435, 465,
- 435, 435, 435, 136, 466, 435, 118, 440,
- 441, 435, 435, 435, 448, 435, 465, 435,
- 467, 468, 469, 470, 123, 118, 440, 441,
- 435, 435, 149, 471, 435, 435, 443, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 444, 435, 472, 468,
- 473, 473, 123, 118, 440, 441, 435, 435,
- 435, 471, 435, 435, 443, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 444, 435, 468, 473, 473, 123,
- 118, 440, 441, 435, 435, 435, 471, 435,
- 435, 443, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 444,
- 435, 474, 435, 435, 435, 136, 475, 435,
- 118, 440, 441, 435, 435, 435, 448, 435,
- 474, 435, 476, 477, 478, 479, 123, 118,
- 440, 441, 435, 435, 147, 480, 435, 435,
- 443, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 444, 435,
- 481, 477, 482, 482, 123, 118, 440, 441,
- 435, 435, 435, 480, 435, 435, 443, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 444, 435, 477, 482,
- 482, 123, 118, 440, 441, 435, 435, 435,
- 480, 435, 435, 443, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 444, 435, 136, 483, 435, 118, 440,
- 441, 435, 435, 435, 448, 435, 484, 484,
- 435, 118, 440, 441, 435, 435, 435, 448,
- 435, 485, 435, 435, 486, 440, 441, 435,
- 440, 441, 435, 487, 435, 440, 488, 435,
- 440, 489, 435, 440, 435, 485, 435, 435,
- 435, 440, 441, 435, 490, 435, 491, 492,
- 435, 118, 440, 441, 435, 435, 121, 435,
- 120, 435, 484, 484, 435, 118, 440, 441,
- 435, 484, 484, 435, 118, 440, 441, 435,
- 490, 435, 484, 484, 435, 118, 440, 441,
- 435, 490, 435, 491, 484, 435, 118, 440,
- 441, 435, 435, 121, 435, 136, 435, 493,
- 493, 123, 118, 440, 441, 435, 435, 435,
- 448, 435, 494, 145, 495, 496, 126, 118,
- 440, 441, 435, 435, 435, 448, 435, 145,
- 495, 496, 126, 118, 440, 441, 435, 435,
- 435, 448, 435, 495, 495, 126, 118, 440,
- 441, 435, 435, 435, 448, 435, 497, 142,
- 498, 499, 129, 118, 440, 441, 435, 435,
- 435, 448, 435, 142, 498, 499, 129, 118,
- 440, 441, 435, 435, 435, 448, 435, 498,
- 498, 129, 118, 440, 441, 435, 435, 435,
- 448, 435, 500, 139, 501, 502, 132, 118,
- 440, 441, 435, 435, 435, 448, 435, 139,
- 501, 502, 132, 118, 440, 441, 435, 435,
- 435, 448, 435, 501, 501, 132, 118, 440,
- 441, 435, 435, 435, 448, 435, 503, 136,
- 484, 504, 435, 118, 440, 441, 435, 435,
- 435, 448, 435, 136, 484, 504, 435, 118,
- 440, 441, 435, 435, 435, 448, 435, 484,
- 505, 435, 118, 440, 441, 435, 435, 435,
- 448, 435, 136, 435, 484, 484, 435, 118,
- 440, 441, 435, 435, 435, 448, 435, 119,
- 120, 435, 435, 136, 483, 435, 118, 440,
- 441, 435, 435, 435, 448, 435, 119, 435,
- 477, 482, 482, 123, 118, 440, 441, 435,
- 435, 435, 480, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 444, 435, 477, 482, 482,
- 123, 118, 440, 441, 435, 435, 435, 480,
- 435, 476, 477, 482, 482, 123, 118, 440,
- 441, 435, 435, 435, 480, 435, 435, 443,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 444, 435, 476,
- 477, 478, 482, 123, 118, 440, 441, 435,
- 435, 147, 480, 435, 435, 443, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 444, 435, 474, 435, 506,
- 435, 493, 493, 123, 118, 440, 441, 435,
- 435, 435, 448, 435, 474, 435, 474, 435,
- 435, 435, 484, 484, 435, 118, 440, 441,
- 435, 435, 435, 448, 435, 474, 435, 474,
- 435, 435, 435, 484, 507, 435, 118, 440,
- 441, 435, 435, 435, 448, 435, 474, 435,
- 474, 435, 506, 435, 484, 484, 435, 118,
- 440, 441, 435, 435, 435, 448, 435, 474,
- 435, 474, 120, 435, 435, 136, 475, 435,
- 118, 440, 441, 435, 435, 435, 448, 435,
- 474, 435, 467, 468, 473, 473, 123, 118,
- 440, 441, 435, 435, 435, 471, 435, 435,
- 443, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 444, 435,
- 467, 468, 469, 473, 123, 118, 440, 441,
- 435, 435, 149, 471, 435, 435, 443, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 444, 435, 465, 435,
- 508, 435, 493, 493, 123, 118, 440, 441,
- 435, 435, 435, 448, 435, 465, 435, 465,
- 435, 435, 435, 484, 484, 435, 118, 440,
- 441, 435, 435, 435, 448, 435, 465, 435,
- 465, 435, 435, 435, 484, 509, 435, 118,
- 440, 441, 435, 435, 435, 448, 435, 465,
- 435, 465, 435, 508, 435, 484, 484, 435,
- 118, 440, 441, 435, 435, 435, 448, 435,
- 465, 435, 465, 120, 435, 435, 136, 466,
- 435, 118, 440, 441, 435, 435, 435, 448,
- 435, 465, 435, 458, 459, 464, 464, 123,
- 118, 440, 441, 435, 435, 435, 462, 435,
- 435, 443, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 444,
- 435, 458, 459, 460, 464, 123, 118, 440,
- 441, 435, 435, 151, 462, 435, 435, 443,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 444, 435, 456,
- 435, 510, 435, 493, 493, 123, 118, 440,
- 441, 435, 435, 435, 448, 435, 456, 435,
- 456, 435, 435, 435, 484, 484, 435, 118,
- 440, 441, 435, 435, 435, 448, 435, 456,
- 435, 456, 435, 435, 435, 484, 511, 435,
- 118, 440, 441, 435, 435, 435, 448, 435,
- 456, 435, 456, 435, 510, 435, 484, 484,
- 435, 118, 440, 441, 435, 435, 435, 448,
- 435, 456, 435, 456, 120, 435, 435, 136,
- 457, 435, 118, 440, 441, 435, 435, 435,
- 448, 435, 456, 435, 449, 450, 455, 455,
- 123, 118, 440, 441, 435, 435, 435, 453,
- 435, 435, 443, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 444, 435, 449, 450, 451, 455, 123, 118,
- 440, 441, 435, 435, 153, 453, 435, 435,
- 443, 435, 435, 435, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 444, 435,
- 446, 435, 512, 435, 493, 493, 123, 118,
- 440, 441, 435, 435, 435, 448, 435, 446,
- 435, 446, 435, 435, 435, 484, 484, 435,
- 118, 440, 441, 435, 435, 435, 448, 435,
- 446, 435, 446, 435, 435, 435, 484, 513,
- 435, 118, 440, 441, 435, 435, 435, 448,
- 435, 446, 435, 446, 435, 512, 435, 484,
- 484, 435, 118, 440, 441, 435, 435, 435,
- 448, 435, 446, 435, 446, 120, 435, 435,
- 136, 447, 435, 118, 440, 441, 435, 435,
- 435, 448, 435, 446, 435, 436, 437, 439,
- 439, 123, 118, 440, 441, 435, 435, 435,
- 442, 435, 435, 443, 435, 435, 435, 435,
- 435, 435, 435, 435, 435, 435, 435, 435,
- 435, 444, 435, 188, 189, 190, 191, 514,
- 365, 84, 79, 194, 195, 196, 196, 156,
- 197, 363, 188, 200, 363, 363, 363, 363,
- 363, 363, 363, 363, 363, 363, 363, 363,
- 363, 202, 363, 204, 515, 206, 207, 6,
- 1, 208, 209, 203, 203, 38, 210, 203,
- 203, 211, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 212,
- 203, 215, 189, 190, 191, 516, 517, 84,
- 157, 518, 519, 203, 196, 156, 520, 203,
- 215, 200, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 202,
- 203, 116, 521, 521, 84, 157, 208, 209,
- 203, 203, 156, 522, 203, 523, 203, 203,
- 524, 518, 519, 203, 518, 519, 203, 256,
- 203, 518, 525, 203, 518, 526, 203, 518,
- 203, 523, 203, 203, 203, 518, 519, 203,
- 527, 3, 363, 363, 404, 433, 363, 79,
- 194, 195, 363, 363, 363, 368, 363, 527,
- 363, 528, 370, 529, 530, 84, 157, 518,
- 519, 203, 203, 158, 373, 203, 203, 200,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 202, 203, 531,
- 370, 532, 532, 84, 157, 518, 519, 203,
- 203, 203, 373, 203, 203, 200, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 202, 203, 370, 532, 532,
- 84, 157, 518, 519, 203, 203, 203, 373,
- 203, 203, 200, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 202, 203, 528, 370, 532, 532, 84, 157,
- 518, 519, 203, 203, 203, 373, 203, 203,
- 200, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 203, 203, 202, 203,
- 528, 370, 529, 532, 84, 157, 518, 519,
- 203, 203, 158, 373, 203, 203, 200, 203,
- 203, 203, 203, 203, 203, 203, 203, 203,
- 203, 203, 203, 203, 202, 203, 215, 203,
- 281, 116, 533, 533, 160, 157, 208, 209,
- 203, 203, 203, 522, 203, 215, 203, 534,
- 184, 535, 536, 162, 157, 518, 519, 203,
- 203, 203, 537, 203, 184, 535, 536, 162,
- 157, 518, 519, 203, 203, 203, 537, 203,
- 535, 535, 162, 157, 518, 519, 203, 203,
- 203, 537, 203, 538, 181, 539, 540, 165,
- 157, 518, 519, 203, 203, 203, 537, 203,
- 181, 539, 540, 165, 157, 518, 519, 203,
- 203, 203, 537, 203, 539, 539, 165, 157,
- 518, 519, 203, 203, 203, 537, 203, 541,
- 178, 542, 543, 168, 157, 518, 519, 203,
- 203, 203, 537, 203, 178, 542, 543, 168,
- 157, 518, 519, 203, 203, 203, 537, 203,
- 542, 542, 168, 157, 518, 519, 203, 203,
- 203, 537, 203, 544, 175, 545, 546, 203,
- 157, 518, 519, 203, 203, 203, 537, 203,
- 175, 545, 546, 203, 157, 518, 519, 203,
- 203, 203, 537, 203, 545, 545, 203, 157,
- 518, 519, 203, 203, 203, 537, 203, 547,
- 203, 548, 549, 203, 157, 518, 519, 203,
- 203, 172, 203, 171, 203, 545, 545, 203,
- 157, 518, 519, 203, 545, 545, 203, 157,
- 518, 519, 203, 547, 203, 545, 545, 203,
- 157, 518, 519, 203, 547, 203, 548, 545,
- 203, 157, 518, 519, 203, 203, 172, 203,
- 527, 171, 363, 363, 98, 367, 363, 79,
- 194, 195, 363, 363, 363, 368, 363, 527,
- 363, 551, 550, 552, 552, 550, 186, 553,
- 554, 550, 552, 552, 550, 186, 553, 554,
- 550, 555, 550, 550, 556, 553, 554, 550,
- 553, 554, 550, 557, 550, 553, 558, 550,
- 553, 559, 550, 553, 550, 555, 550, 550,
- 550, 553, 554, 550, 0
+ 197, 198, 199, 200, 201, 187, 203, 204,
+ 205, 206, 6, 1, 207, 208, 202, 202,
+ 38, 209, 202, 202, 210, 202, 211, 204,
+ 212, 212, 6, 1, 207, 208, 202, 202,
+ 202, 209, 202, 202, 210, 202, 204, 212,
+ 212, 6, 1, 207, 208, 202, 202, 202,
+ 209, 202, 202, 210, 202, 213, 202, 202,
+ 202, 19, 214, 202, 1, 207, 208, 202,
+ 202, 202, 215, 202, 213, 202, 216, 217,
+ 218, 219, 6, 1, 207, 208, 202, 202,
+ 36, 220, 202, 202, 210, 202, 221, 217,
+ 222, 222, 6, 1, 207, 208, 202, 202,
+ 202, 220, 202, 202, 210, 202, 217, 222,
+ 222, 6, 1, 207, 208, 202, 202, 202,
+ 220, 202, 202, 210, 202, 223, 202, 202,
+ 202, 19, 224, 202, 1, 207, 208, 202,
+ 202, 202, 215, 202, 223, 202, 225, 226,
+ 227, 228, 6, 1, 207, 208, 202, 202,
+ 34, 229, 202, 202, 210, 202, 230, 226,
+ 231, 231, 6, 1, 207, 208, 202, 202,
+ 202, 229, 202, 202, 210, 202, 226, 231,
+ 231, 6, 1, 207, 208, 202, 202, 202,
+ 229, 202, 202, 210, 202, 232, 202, 202,
+ 202, 19, 233, 202, 1, 207, 208, 202,
+ 202, 202, 215, 202, 232, 202, 234, 235,
+ 236, 237, 6, 1, 207, 208, 202, 202,
+ 32, 238, 202, 202, 210, 202, 239, 235,
+ 240, 240, 6, 1, 207, 208, 202, 202,
+ 202, 238, 202, 202, 210, 202, 235, 240,
+ 240, 6, 1, 207, 208, 202, 202, 202,
+ 238, 202, 202, 210, 202, 241, 202, 202,
+ 202, 19, 242, 202, 1, 207, 208, 202,
+ 202, 202, 215, 202, 241, 202, 243, 244,
+ 245, 246, 6, 1, 207, 208, 202, 202,
+ 30, 247, 202, 202, 210, 202, 248, 244,
+ 249, 249, 6, 1, 207, 208, 202, 202,
+ 202, 247, 202, 202, 210, 202, 244, 249,
+ 249, 6, 1, 207, 208, 202, 202, 202,
+ 247, 202, 202, 210, 202, 19, 250, 202,
+ 1, 207, 208, 202, 202, 202, 215, 202,
+ 251, 251, 202, 1, 207, 208, 202, 202,
+ 202, 215, 202, 252, 202, 202, 253, 207,
+ 208, 202, 207, 208, 202, 254, 202, 207,
+ 255, 202, 207, 256, 202, 207, 202, 252,
+ 202, 202, 202, 207, 208, 202, 257, 202,
+ 258, 259, 202, 1, 207, 208, 202, 202,
+ 4, 202, 3, 202, 251, 251, 202, 1,
+ 207, 208, 202, 251, 251, 202, 1, 207,
+ 208, 202, 257, 202, 251, 251, 202, 1,
+ 207, 208, 202, 257, 202, 258, 251, 202,
+ 1, 207, 208, 202, 202, 4, 202, 19,
+ 202, 260, 260, 6, 1, 207, 208, 202,
+ 202, 202, 215, 202, 261, 28, 262, 263,
+ 9, 1, 207, 208, 202, 202, 202, 215,
+ 202, 28, 262, 263, 9, 1, 207, 208,
+ 202, 202, 202, 215, 202, 262, 262, 9,
+ 1, 207, 208, 202, 202, 202, 215, 202,
+ 264, 25, 265, 266, 12, 1, 207, 208,
+ 202, 202, 202, 215, 202, 25, 265, 266,
+ 12, 1, 207, 208, 202, 202, 202, 215,
+ 202, 265, 265, 12, 1, 207, 208, 202,
+ 202, 202, 215, 202, 267, 22, 268, 269,
+ 15, 1, 207, 208, 202, 202, 202, 215,
+ 202, 22, 268, 269, 15, 1, 207, 208,
+ 202, 202, 202, 215, 202, 268, 268, 15,
+ 1, 207, 208, 202, 202, 202, 215, 202,
+ 270, 19, 251, 271, 202, 1, 207, 208,
+ 202, 202, 202, 215, 202, 19, 251, 271,
+ 202, 1, 207, 208, 202, 202, 202, 215,
+ 202, 251, 272, 202, 1, 207, 208, 202,
+ 202, 202, 215, 202, 19, 202, 251, 251,
+ 202, 1, 207, 208, 202, 202, 202, 215,
+ 202, 2, 3, 202, 202, 19, 250, 202,
+ 1, 207, 208, 202, 202, 202, 215, 202,
+ 2, 202, 244, 249, 249, 6, 1, 207,
+ 208, 202, 202, 202, 247, 202, 243, 244,
+ 249, 249, 6, 1, 207, 208, 202, 202,
+ 202, 247, 202, 202, 210, 202, 243, 244,
+ 245, 249, 6, 1, 207, 208, 202, 202,
+ 30, 247, 202, 202, 210, 202, 241, 202,
+ 273, 202, 260, 260, 6, 1, 207, 208,
+ 202, 202, 202, 215, 202, 241, 202, 241,
+ 202, 202, 202, 251, 251, 202, 1, 207,
+ 208, 202, 202, 202, 215, 202, 241, 202,
+ 241, 202, 202, 202, 251, 274, 202, 1,
+ 207, 208, 202, 202, 202, 215, 202, 241,
+ 202, 241, 202, 273, 202, 251, 251, 202,
+ 1, 207, 208, 202, 202, 202, 215, 202,
+ 241, 202, 241, 3, 202, 202, 19, 242,
+ 202, 1, 207, 208, 202, 202, 202, 215,
+ 202, 241, 202, 234, 235, 240, 240, 6,
+ 1, 207, 208, 202, 202, 202, 238, 202,
+ 202, 210, 202, 234, 235, 236, 240, 6,
+ 1, 207, 208, 202, 202, 32, 238, 202,
+ 202, 210, 202, 232, 202, 275, 202, 260,
+ 260, 6, 1, 207, 208, 202, 202, 202,
+ 215, 202, 232, 202, 232, 202, 202, 202,
+ 251, 251, 202, 1, 207, 208, 202, 202,
+ 202, 215, 202, 232, 202, 232, 202, 202,
+ 202, 251, 276, 202, 1, 207, 208, 202,
+ 202, 202, 215, 202, 232, 202, 232, 202,
+ 275, 202, 251, 251, 202, 1, 207, 208,
+ 202, 202, 202, 215, 202, 232, 202, 232,
+ 3, 202, 202, 19, 233, 202, 1, 207,
+ 208, 202, 202, 202, 215, 202, 232, 202,
+ 225, 226, 231, 231, 6, 1, 207, 208,
+ 202, 202, 202, 229, 202, 202, 210, 202,
+ 225, 226, 227, 231, 6, 1, 207, 208,
+ 202, 202, 34, 229, 202, 202, 210, 202,
+ 223, 202, 277, 202, 260, 260, 6, 1,
+ 207, 208, 202, 202, 202, 215, 202, 223,
+ 202, 223, 202, 202, 202, 251, 251, 202,
+ 1, 207, 208, 202, 202, 202, 215, 202,
+ 223, 202, 223, 202, 202, 202, 251, 278,
+ 202, 1, 207, 208, 202, 202, 202, 215,
+ 202, 223, 202, 223, 202, 277, 202, 251,
+ 251, 202, 1, 207, 208, 202, 202, 202,
+ 215, 202, 223, 202, 223, 3, 202, 202,
+ 19, 224, 202, 1, 207, 208, 202, 202,
+ 202, 215, 202, 223, 202, 216, 217, 222,
+ 222, 6, 1, 207, 208, 202, 202, 202,
+ 220, 202, 202, 210, 202, 216, 217, 218,
+ 222, 6, 1, 207, 208, 202, 202, 36,
+ 220, 202, 202, 210, 202, 213, 202, 279,
+ 202, 260, 260, 6, 1, 207, 208, 202,
+ 202, 202, 215, 202, 213, 202, 213, 202,
+ 202, 202, 251, 251, 202, 1, 207, 208,
+ 202, 202, 202, 215, 202, 213, 202, 213,
+ 202, 202, 202, 251, 280, 202, 1, 207,
+ 208, 202, 202, 202, 215, 202, 213, 202,
+ 213, 202, 279, 202, 251, 251, 202, 1,
+ 207, 208, 202, 202, 202, 215, 202, 213,
+ 202, 213, 3, 202, 202, 19, 214, 202,
+ 1, 207, 208, 202, 202, 202, 215, 202,
+ 213, 202, 203, 204, 212, 212, 6, 1,
+ 207, 208, 202, 202, 202, 209, 202, 202,
+ 210, 202, 203, 204, 205, 212, 6, 1,
+ 207, 208, 202, 202, 38, 209, 202, 202,
+ 210, 202, 282, 283, 284, 285, 45, 40,
+ 286, 287, 281, 281, 77, 288, 281, 281,
+ 289, 281, 290, 283, 291, 285, 45, 40,
+ 286, 287, 281, 281, 281, 288, 281, 281,
+ 289, 281, 283, 291, 285, 45, 40, 286,
+ 287, 281, 281, 281, 288, 281, 281, 289,
+ 281, 292, 281, 281, 281, 58, 293, 281,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 292, 281, 295, 296, 297, 298, 45, 40,
+ 286, 287, 281, 281, 75, 299, 281, 281,
+ 289, 281, 300, 296, 301, 301, 45, 40,
+ 286, 287, 281, 281, 281, 299, 281, 281,
+ 289, 281, 296, 301, 301, 45, 40, 286,
+ 287, 281, 281, 281, 299, 281, 281, 289,
+ 281, 302, 281, 281, 281, 58, 303, 281,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 302, 281, 304, 305, 306, 307, 45, 40,
+ 286, 287, 281, 281, 73, 308, 281, 281,
+ 289, 281, 309, 305, 310, 310, 45, 40,
+ 286, 287, 281, 281, 281, 308, 281, 281,
+ 289, 281, 305, 310, 310, 45, 40, 286,
+ 287, 281, 281, 281, 308, 281, 281, 289,
+ 281, 311, 281, 281, 281, 58, 312, 281,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 311, 281, 313, 314, 315, 316, 45, 40,
+ 286, 287, 281, 281, 71, 317, 281, 281,
+ 289, 281, 318, 314, 319, 319, 45, 40,
+ 286, 287, 281, 281, 281, 317, 281, 281,
+ 289, 281, 314, 319, 319, 45, 40, 286,
+ 287, 281, 281, 281, 317, 281, 281, 289,
+ 281, 320, 281, 281, 281, 58, 321, 281,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 320, 281, 322, 323, 324, 325, 45, 40,
+ 286, 287, 281, 281, 69, 326, 281, 281,
+ 289, 281, 327, 323, 328, 328, 45, 40,
+ 286, 287, 281, 281, 281, 326, 281, 281,
+ 289, 281, 323, 328, 328, 45, 40, 286,
+ 287, 281, 281, 281, 326, 281, 281, 289,
+ 281, 58, 329, 281, 40, 286, 287, 281,
+ 281, 281, 294, 281, 330, 330, 281, 40,
+ 286, 287, 281, 281, 281, 294, 281, 331,
+ 281, 281, 332, 286, 287, 281, 286, 287,
+ 281, 333, 281, 286, 334, 281, 286, 335,
+ 281, 286, 281, 331, 281, 281, 281, 286,
+ 287, 281, 336, 281, 337, 338, 281, 40,
+ 286, 287, 281, 281, 43, 281, 42, 281,
+ 330, 330, 281, 40, 286, 287, 281, 330,
+ 330, 281, 40, 286, 287, 281, 336, 281,
+ 330, 330, 281, 40, 286, 287, 281, 336,
+ 281, 337, 330, 281, 40, 286, 287, 281,
+ 281, 43, 281, 58, 281, 339, 339, 45,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 340, 67, 341, 342, 48, 40, 286, 287,
+ 281, 281, 281, 294, 281, 67, 341, 342,
+ 48, 40, 286, 287, 281, 281, 281, 294,
+ 281, 341, 341, 48, 40, 286, 287, 281,
+ 281, 281, 294, 281, 343, 64, 344, 345,
+ 51, 40, 286, 287, 281, 281, 281, 294,
+ 281, 64, 344, 345, 51, 40, 286, 287,
+ 281, 281, 281, 294, 281, 344, 344, 51,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 346, 61, 347, 348, 54, 40, 286, 287,
+ 281, 281, 281, 294, 281, 61, 347, 348,
+ 54, 40, 286, 287, 281, 281, 281, 294,
+ 281, 347, 347, 54, 40, 286, 287, 281,
+ 281, 281, 294, 281, 349, 58, 330, 350,
+ 281, 40, 286, 287, 281, 281, 281, 294,
+ 281, 58, 330, 350, 281, 40, 286, 287,
+ 281, 281, 281, 294, 281, 330, 351, 281,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 58, 281, 330, 330, 281, 40, 286, 287,
+ 281, 281, 281, 294, 281, 41, 42, 281,
+ 281, 58, 329, 281, 40, 286, 287, 281,
+ 281, 281, 294, 281, 41, 281, 323, 328,
+ 328, 45, 40, 286, 287, 281, 281, 281,
+ 326, 281, 322, 323, 328, 328, 45, 40,
+ 286, 287, 281, 281, 281, 326, 281, 281,
+ 289, 281, 322, 323, 324, 328, 45, 40,
+ 286, 287, 281, 281, 69, 326, 281, 281,
+ 289, 281, 320, 281, 352, 281, 339, 339,
+ 45, 40, 286, 287, 281, 281, 281, 294,
+ 281, 320, 281, 320, 281, 281, 281, 330,
+ 330, 281, 40, 286, 287, 281, 281, 281,
+ 294, 281, 320, 281, 320, 281, 281, 281,
+ 330, 353, 281, 40, 286, 287, 281, 281,
+ 281, 294, 281, 320, 281, 320, 281, 352,
+ 281, 330, 330, 281, 40, 286, 287, 281,
+ 281, 281, 294, 281, 320, 281, 320, 42,
+ 281, 281, 58, 321, 281, 40, 286, 287,
+ 281, 281, 281, 294, 281, 320, 281, 313,
+ 314, 319, 319, 45, 40, 286, 287, 281,
+ 281, 281, 317, 281, 281, 289, 281, 313,
+ 314, 315, 319, 45, 40, 286, 287, 281,
+ 281, 71, 317, 281, 281, 289, 281, 311,
+ 281, 354, 281, 339, 339, 45, 40, 286,
+ 287, 281, 281, 281, 294, 281, 311, 281,
+ 311, 281, 281, 281, 330, 330, 281, 40,
+ 286, 287, 281, 281, 281, 294, 281, 311,
+ 281, 311, 281, 281, 281, 330, 355, 281,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 311, 281, 311, 281, 354, 281, 330, 330,
+ 281, 40, 286, 287, 281, 281, 281, 294,
+ 281, 311, 281, 311, 42, 281, 281, 58,
+ 312, 281, 40, 286, 287, 281, 281, 281,
+ 294, 281, 311, 281, 304, 305, 310, 310,
+ 45, 40, 286, 287, 281, 281, 281, 308,
+ 281, 281, 289, 281, 304, 305, 306, 310,
+ 45, 40, 286, 287, 281, 281, 73, 308,
+ 281, 281, 289, 281, 302, 281, 356, 281,
+ 339, 339, 45, 40, 286, 287, 281, 281,
+ 281, 294, 281, 302, 281, 302, 281, 281,
+ 281, 330, 330, 281, 40, 286, 287, 281,
+ 281, 281, 294, 281, 302, 281, 302, 281,
+ 281, 281, 330, 357, 281, 40, 286, 287,
+ 281, 281, 281, 294, 281, 302, 281, 302,
+ 281, 356, 281, 330, 330, 281, 40, 286,
+ 287, 281, 281, 281, 294, 281, 302, 281,
+ 302, 42, 281, 281, 58, 303, 281, 40,
+ 286, 287, 281, 281, 281, 294, 281, 302,
+ 281, 295, 296, 301, 301, 45, 40, 286,
+ 287, 281, 281, 281, 299, 281, 281, 289,
+ 281, 295, 296, 297, 301, 45, 40, 286,
+ 287, 281, 281, 75, 299, 281, 281, 289,
+ 281, 292, 281, 358, 281, 339, 339, 45,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 292, 281, 292, 281, 281, 281, 330, 330,
+ 281, 40, 286, 287, 281, 281, 281, 294,
+ 281, 292, 281, 292, 281, 281, 281, 330,
+ 359, 281, 40, 286, 287, 281, 281, 281,
+ 294, 281, 292, 281, 292, 281, 358, 281,
+ 330, 330, 281, 40, 286, 287, 281, 281,
+ 281, 294, 281, 292, 281, 76, 44, 44,
+ 45, 40, 281, 281, 281, 281, 281, 76,
+ 281, 292, 42, 281, 281, 58, 293, 281,
+ 40, 286, 287, 281, 281, 281, 294, 281,
+ 292, 281, 282, 283, 291, 285, 45, 40,
+ 286, 287, 281, 281, 281, 288, 281, 281,
+ 289, 281, 361, 191, 362, 362, 84, 79,
+ 194, 195, 360, 360, 360, 197, 360, 360,
+ 200, 360, 191, 362, 362, 84, 79, 194,
+ 195, 360, 360, 360, 197, 360, 360, 200,
+ 360, 363, 360, 360, 360, 98, 364, 360,
+ 79, 194, 195, 360, 360, 360, 365, 360,
+ 363, 360, 366, 367, 368, 369, 84, 79,
+ 194, 195, 360, 360, 115, 370, 360, 360,
+ 200, 360, 371, 367, 372, 372, 84, 79,
+ 194, 195, 360, 360, 360, 370, 360, 360,
+ 200, 360, 367, 372, 372, 84, 79, 194,
+ 195, 360, 360, 360, 370, 360, 360, 200,
+ 360, 373, 360, 360, 360, 98, 374, 360,
+ 79, 194, 195, 360, 360, 360, 365, 360,
+ 373, 360, 375, 376, 377, 378, 84, 79,
+ 194, 195, 360, 360, 113, 379, 360, 360,
+ 200, 360, 380, 376, 381, 381, 84, 79,
+ 194, 195, 360, 360, 360, 379, 360, 360,
+ 200, 360, 376, 381, 381, 84, 79, 194,
+ 195, 360, 360, 360, 379, 360, 360, 200,
+ 360, 382, 360, 360, 360, 98, 383, 360,
+ 79, 194, 195, 360, 360, 360, 365, 360,
+ 382, 360, 384, 385, 386, 387, 84, 79,
+ 194, 195, 360, 360, 111, 388, 360, 360,
+ 200, 360, 389, 385, 390, 390, 84, 79,
+ 194, 195, 360, 360, 360, 388, 360, 360,
+ 200, 360, 385, 390, 390, 84, 79, 194,
+ 195, 360, 360, 360, 388, 360, 360, 200,
+ 360, 391, 360, 360, 360, 98, 392, 360,
+ 79, 194, 195, 360, 360, 360, 365, 360,
+ 391, 360, 393, 394, 395, 396, 84, 79,
+ 194, 195, 360, 360, 109, 397, 360, 360,
+ 200, 360, 398, 394, 399, 399, 84, 79,
+ 194, 195, 360, 360, 360, 397, 360, 360,
+ 200, 360, 394, 399, 399, 84, 79, 194,
+ 195, 360, 360, 360, 397, 360, 360, 200,
+ 360, 98, 400, 360, 79, 194, 195, 360,
+ 360, 360, 365, 360, 401, 401, 360, 79,
+ 194, 195, 360, 360, 360, 365, 360, 402,
+ 360, 360, 403, 194, 195, 360, 194, 195,
+ 360, 404, 360, 194, 405, 360, 194, 406,
+ 360, 194, 360, 402, 360, 360, 360, 194,
+ 195, 360, 407, 360, 408, 409, 360, 79,
+ 194, 195, 360, 360, 82, 360, 81, 360,
+ 401, 401, 360, 79, 194, 195, 360, 401,
+ 401, 360, 79, 194, 195, 360, 407, 360,
+ 401, 401, 360, 79, 194, 195, 360, 407,
+ 360, 408, 401, 360, 79, 194, 195, 360,
+ 360, 82, 360, 98, 360, 410, 410, 84,
+ 79, 194, 195, 360, 360, 360, 365, 360,
+ 411, 107, 412, 413, 88, 79, 194, 195,
+ 360, 360, 360, 365, 360, 107, 412, 413,
+ 88, 79, 194, 195, 360, 360, 360, 365,
+ 360, 412, 412, 88, 79, 194, 195, 360,
+ 360, 360, 365, 360, 414, 104, 415, 416,
+ 91, 79, 194, 195, 360, 360, 360, 365,
+ 360, 104, 415, 416, 91, 79, 194, 195,
+ 360, 360, 360, 365, 360, 415, 415, 91,
+ 79, 194, 195, 360, 360, 360, 365, 360,
+ 417, 101, 418, 419, 94, 79, 194, 195,
+ 360, 360, 360, 365, 360, 101, 418, 419,
+ 94, 79, 194, 195, 360, 360, 360, 365,
+ 360, 418, 418, 94, 79, 194, 195, 360,
+ 360, 360, 365, 360, 420, 98, 401, 421,
+ 360, 79, 194, 195, 360, 360, 360, 365,
+ 360, 98, 401, 421, 360, 79, 194, 195,
+ 360, 360, 360, 365, 360, 401, 422, 360,
+ 79, 194, 195, 360, 360, 360, 365, 360,
+ 98, 360, 401, 401, 360, 79, 194, 195,
+ 360, 360, 360, 365, 360, 80, 81, 360,
+ 360, 98, 400, 360, 79, 194, 195, 360,
+ 360, 360, 365, 360, 80, 360, 394, 399,
+ 399, 84, 79, 194, 195, 360, 360, 360,
+ 397, 360, 393, 394, 399, 399, 84, 79,
+ 194, 195, 360, 360, 360, 397, 360, 360,
+ 200, 360, 393, 394, 395, 399, 84, 79,
+ 194, 195, 360, 360, 109, 397, 360, 360,
+ 200, 360, 391, 360, 423, 360, 410, 410,
+ 84, 79, 194, 195, 360, 360, 360, 365,
+ 360, 391, 360, 391, 360, 360, 360, 401,
+ 401, 360, 79, 194, 195, 360, 360, 360,
+ 365, 360, 391, 360, 391, 360, 360, 360,
+ 401, 424, 360, 79, 194, 195, 360, 360,
+ 360, 365, 360, 391, 360, 391, 360, 423,
+ 360, 401, 401, 360, 79, 194, 195, 360,
+ 360, 360, 365, 360, 391, 360, 391, 81,
+ 360, 360, 98, 392, 360, 79, 194, 195,
+ 360, 360, 360, 365, 360, 391, 360, 384,
+ 385, 390, 390, 84, 79, 194, 195, 360,
+ 360, 360, 388, 360, 360, 200, 360, 384,
+ 385, 386, 390, 84, 79, 194, 195, 360,
+ 360, 111, 388, 360, 360, 200, 360, 382,
+ 360, 425, 360, 410, 410, 84, 79, 194,
+ 195, 360, 360, 360, 365, 360, 382, 360,
+ 382, 360, 360, 360, 401, 401, 360, 79,
+ 194, 195, 360, 360, 360, 365, 360, 382,
+ 360, 382, 360, 360, 360, 401, 426, 360,
+ 79, 194, 195, 360, 360, 360, 365, 360,
+ 382, 360, 382, 360, 425, 360, 401, 401,
+ 360, 79, 194, 195, 360, 360, 360, 365,
+ 360, 382, 360, 382, 81, 360, 360, 98,
+ 383, 360, 79, 194, 195, 360, 360, 360,
+ 365, 360, 382, 360, 375, 376, 381, 381,
+ 84, 79, 194, 195, 360, 360, 360, 379,
+ 360, 360, 200, 360, 375, 376, 377, 381,
+ 84, 79, 194, 195, 360, 360, 113, 379,
+ 360, 360, 200, 360, 373, 360, 427, 360,
+ 410, 410, 84, 79, 194, 195, 360, 360,
+ 360, 365, 360, 373, 360, 373, 360, 360,
+ 360, 401, 401, 360, 79, 194, 195, 360,
+ 360, 360, 365, 360, 373, 360, 373, 360,
+ 360, 360, 401, 428, 360, 79, 194, 195,
+ 360, 360, 360, 365, 360, 373, 360, 373,
+ 360, 427, 360, 401, 401, 360, 79, 194,
+ 195, 360, 360, 360, 365, 360, 373, 360,
+ 373, 81, 360, 360, 98, 374, 360, 79,
+ 194, 195, 360, 360, 360, 365, 360, 373,
+ 360, 366, 367, 372, 372, 84, 79, 194,
+ 195, 360, 360, 360, 370, 360, 360, 200,
+ 360, 366, 367, 368, 372, 84, 79, 194,
+ 195, 360, 360, 115, 370, 360, 360, 200,
+ 360, 363, 360, 429, 360, 410, 410, 84,
+ 79, 194, 195, 360, 360, 360, 365, 360,
+ 363, 360, 363, 360, 360, 360, 401, 401,
+ 360, 79, 194, 195, 360, 360, 360, 365,
+ 360, 363, 360, 363, 360, 360, 360, 401,
+ 430, 360, 79, 194, 195, 360, 360, 360,
+ 365, 360, 363, 360, 363, 360, 429, 360,
+ 401, 401, 360, 79, 194, 195, 360, 360,
+ 360, 365, 360, 363, 360, 363, 81, 360,
+ 360, 98, 364, 360, 79, 194, 195, 360,
+ 360, 360, 365, 360, 363, 360, 116, 83,
+ 83, 84, 79, 431, 431, 431, 431, 156,
+ 116, 431, 190, 191, 362, 362, 84, 79,
+ 194, 195, 360, 360, 360, 197, 360, 360,
+ 200, 360, 116, 83, 83, 84, 79, 431,
+ 431, 431, 431, 431, 116, 431, 433, 434,
+ 435, 436, 123, 118, 437, 438, 432, 432,
+ 155, 439, 432, 432, 440, 432, 441, 434,
+ 436, 436, 123, 118, 437, 438, 432, 432,
+ 432, 439, 432, 432, 440, 432, 434, 436,
+ 436, 123, 118, 437, 438, 432, 432, 432,
+ 439, 432, 432, 440, 432, 442, 432, 432,
+ 432, 136, 443, 432, 118, 437, 438, 432,
+ 432, 432, 444, 432, 442, 432, 445, 446,
+ 447, 448, 123, 118, 437, 438, 432, 432,
+ 153, 449, 432, 432, 440, 432, 450, 446,
+ 451, 451, 123, 118, 437, 438, 432, 432,
+ 432, 449, 432, 432, 440, 432, 446, 451,
+ 451, 123, 118, 437, 438, 432, 432, 432,
+ 449, 432, 432, 440, 432, 452, 432, 432,
+ 432, 136, 453, 432, 118, 437, 438, 432,
+ 432, 432, 444, 432, 452, 432, 454, 455,
+ 456, 457, 123, 118, 437, 438, 432, 432,
+ 151, 458, 432, 432, 440, 432, 459, 455,
+ 460, 460, 123, 118, 437, 438, 432, 432,
+ 432, 458, 432, 432, 440, 432, 455, 460,
+ 460, 123, 118, 437, 438, 432, 432, 432,
+ 458, 432, 432, 440, 432, 461, 432, 432,
+ 432, 136, 462, 432, 118, 437, 438, 432,
+ 432, 432, 444, 432, 461, 432, 463, 464,
+ 465, 466, 123, 118, 437, 438, 432, 432,
+ 149, 467, 432, 432, 440, 432, 468, 464,
+ 469, 469, 123, 118, 437, 438, 432, 432,
+ 432, 467, 432, 432, 440, 432, 464, 469,
+ 469, 123, 118, 437, 438, 432, 432, 432,
+ 467, 432, 432, 440, 432, 470, 432, 432,
+ 432, 136, 471, 432, 118, 437, 438, 432,
+ 432, 432, 444, 432, 470, 432, 472, 473,
+ 474, 475, 123, 118, 437, 438, 432, 432,
+ 147, 476, 432, 432, 440, 432, 477, 473,
+ 478, 478, 123, 118, 437, 438, 432, 432,
+ 432, 476, 432, 432, 440, 432, 473, 478,
+ 478, 123, 118, 437, 438, 432, 432, 432,
+ 476, 432, 432, 440, 432, 136, 479, 432,
+ 118, 437, 438, 432, 432, 432, 444, 432,
+ 480, 480, 432, 118, 437, 438, 432, 432,
+ 432, 444, 432, 481, 432, 432, 482, 437,
+ 438, 432, 437, 438, 432, 483, 432, 437,
+ 484, 432, 437, 485, 432, 437, 432, 481,
+ 432, 432, 432, 437, 438, 432, 486, 432,
+ 487, 488, 432, 118, 437, 438, 432, 432,
+ 121, 432, 120, 432, 480, 480, 432, 118,
+ 437, 438, 432, 480, 480, 432, 118, 437,
+ 438, 432, 486, 432, 480, 480, 432, 118,
+ 437, 438, 432, 486, 432, 487, 480, 432,
+ 118, 437, 438, 432, 432, 121, 432, 136,
+ 432, 489, 489, 123, 118, 437, 438, 432,
+ 432, 432, 444, 432, 490, 145, 491, 492,
+ 126, 118, 437, 438, 432, 432, 432, 444,
+ 432, 145, 491, 492, 126, 118, 437, 438,
+ 432, 432, 432, 444, 432, 491, 491, 126,
+ 118, 437, 438, 432, 432, 432, 444, 432,
+ 493, 142, 494, 495, 129, 118, 437, 438,
+ 432, 432, 432, 444, 432, 142, 494, 495,
+ 129, 118, 437, 438, 432, 432, 432, 444,
+ 432, 494, 494, 129, 118, 437, 438, 432,
+ 432, 432, 444, 432, 496, 139, 497, 498,
+ 132, 118, 437, 438, 432, 432, 432, 444,
+ 432, 139, 497, 498, 132, 118, 437, 438,
+ 432, 432, 432, 444, 432, 497, 497, 132,
+ 118, 437, 438, 432, 432, 432, 444, 432,
+ 499, 136, 480, 500, 432, 118, 437, 438,
+ 432, 432, 432, 444, 432, 136, 480, 500,
+ 432, 118, 437, 438, 432, 432, 432, 444,
+ 432, 480, 501, 432, 118, 437, 438, 432,
+ 432, 432, 444, 432, 136, 432, 480, 480,
+ 432, 118, 437, 438, 432, 432, 432, 444,
+ 432, 119, 120, 432, 432, 136, 479, 432,
+ 118, 437, 438, 432, 432, 432, 444, 432,
+ 119, 432, 473, 478, 478, 123, 118, 437,
+ 438, 432, 432, 432, 476, 432, 472, 473,
+ 478, 478, 123, 118, 437, 438, 432, 432,
+ 432, 476, 432, 432, 440, 432, 472, 473,
+ 474, 478, 123, 118, 437, 438, 432, 432,
+ 147, 476, 432, 432, 440, 432, 470, 432,
+ 502, 432, 489, 489, 123, 118, 437, 438,
+ 432, 432, 432, 444, 432, 470, 432, 470,
+ 432, 432, 432, 480, 480, 432, 118, 437,
+ 438, 432, 432, 432, 444, 432, 470, 432,
+ 470, 432, 432, 432, 480, 503, 432, 118,
+ 437, 438, 432, 432, 432, 444, 432, 470,
+ 432, 470, 432, 502, 432, 480, 480, 432,
+ 118, 437, 438, 432, 432, 432, 444, 432,
+ 470, 432, 470, 120, 432, 432, 136, 471,
+ 432, 118, 437, 438, 432, 432, 432, 444,
+ 432, 470, 432, 463, 464, 469, 469, 123,
+ 118, 437, 438, 432, 432, 432, 467, 432,
+ 432, 440, 432, 463, 464, 465, 469, 123,
+ 118, 437, 438, 432, 432, 149, 467, 432,
+ 432, 440, 432, 461, 432, 504, 432, 489,
+ 489, 123, 118, 437, 438, 432, 432, 432,
+ 444, 432, 461, 432, 461, 432, 432, 432,
+ 480, 480, 432, 118, 437, 438, 432, 432,
+ 432, 444, 432, 461, 432, 461, 432, 432,
+ 432, 480, 505, 432, 118, 437, 438, 432,
+ 432, 432, 444, 432, 461, 432, 461, 432,
+ 504, 432, 480, 480, 432, 118, 437, 438,
+ 432, 432, 432, 444, 432, 461, 432, 461,
+ 120, 432, 432, 136, 462, 432, 118, 437,
+ 438, 432, 432, 432, 444, 432, 461, 432,
+ 454, 455, 460, 460, 123, 118, 437, 438,
+ 432, 432, 432, 458, 432, 432, 440, 432,
+ 454, 455, 456, 460, 123, 118, 437, 438,
+ 432, 432, 151, 458, 432, 432, 440, 432,
+ 452, 432, 506, 432, 489, 489, 123, 118,
+ 437, 438, 432, 432, 432, 444, 432, 452,
+ 432, 452, 432, 432, 432, 480, 480, 432,
+ 118, 437, 438, 432, 432, 432, 444, 432,
+ 452, 432, 452, 432, 432, 432, 480, 507,
+ 432, 118, 437, 438, 432, 432, 432, 444,
+ 432, 452, 432, 452, 432, 506, 432, 480,
+ 480, 432, 118, 437, 438, 432, 432, 432,
+ 444, 432, 452, 432, 452, 120, 432, 432,
+ 136, 453, 432, 118, 437, 438, 432, 432,
+ 432, 444, 432, 452, 432, 445, 446, 451,
+ 451, 123, 118, 437, 438, 432, 432, 432,
+ 449, 432, 432, 440, 432, 445, 446, 447,
+ 451, 123, 118, 437, 438, 432, 432, 153,
+ 449, 432, 432, 440, 432, 442, 432, 508,
+ 432, 489, 489, 123, 118, 437, 438, 432,
+ 432, 432, 444, 432, 442, 432, 442, 432,
+ 432, 432, 480, 480, 432, 118, 437, 438,
+ 432, 432, 432, 444, 432, 442, 432, 442,
+ 432, 432, 432, 480, 509, 432, 118, 437,
+ 438, 432, 432, 432, 444, 432, 442, 432,
+ 442, 432, 508, 432, 480, 480, 432, 118,
+ 437, 438, 432, 432, 432, 444, 432, 442,
+ 432, 442, 120, 432, 432, 136, 443, 432,
+ 118, 437, 438, 432, 432, 432, 444, 432,
+ 442, 432, 433, 434, 436, 436, 123, 118,
+ 437, 438, 432, 432, 432, 439, 432, 432,
+ 440, 432, 188, 189, 190, 191, 510, 362,
+ 84, 79, 194, 195, 196, 196, 156, 197,
+ 360, 188, 200, 360, 203, 511, 205, 206,
+ 6, 1, 207, 208, 202, 202, 38, 209,
+ 202, 202, 210, 202, 213, 189, 190, 191,
+ 512, 513, 84, 157, 514, 515, 202, 196,
+ 156, 516, 202, 213, 200, 202, 116, 517,
+ 517, 84, 157, 207, 208, 202, 202, 156,
+ 518, 202, 519, 202, 202, 520, 514, 515,
+ 202, 514, 515, 202, 254, 202, 514, 521,
+ 202, 514, 522, 202, 514, 202, 519, 202,
+ 202, 202, 514, 515, 202, 523, 3, 360,
+ 360, 401, 430, 360, 79, 194, 195, 360,
+ 360, 360, 365, 360, 523, 360, 524, 367,
+ 525, 526, 84, 157, 514, 515, 202, 202,
+ 158, 370, 202, 202, 200, 202, 527, 367,
+ 528, 528, 84, 157, 514, 515, 202, 202,
+ 202, 370, 202, 202, 200, 202, 367, 528,
+ 528, 84, 157, 514, 515, 202, 202, 202,
+ 370, 202, 202, 200, 202, 524, 367, 528,
+ 528, 84, 157, 514, 515, 202, 202, 202,
+ 370, 202, 202, 200, 202, 524, 367, 525,
+ 528, 84, 157, 514, 515, 202, 202, 158,
+ 370, 202, 202, 200, 202, 213, 202, 279,
+ 116, 529, 529, 160, 157, 207, 208, 202,
+ 202, 202, 518, 202, 213, 202, 530, 184,
+ 531, 532, 162, 157, 514, 515, 202, 202,
+ 202, 533, 202, 184, 531, 532, 162, 157,
+ 514, 515, 202, 202, 202, 533, 202, 531,
+ 531, 162, 157, 514, 515, 202, 202, 202,
+ 533, 202, 534, 181, 535, 536, 165, 157,
+ 514, 515, 202, 202, 202, 533, 202, 181,
+ 535, 536, 165, 157, 514, 515, 202, 202,
+ 202, 533, 202, 535, 535, 165, 157, 514,
+ 515, 202, 202, 202, 533, 202, 537, 178,
+ 538, 539, 168, 157, 514, 515, 202, 202,
+ 202, 533, 202, 178, 538, 539, 168, 157,
+ 514, 515, 202, 202, 202, 533, 202, 538,
+ 538, 168, 157, 514, 515, 202, 202, 202,
+ 533, 202, 540, 175, 541, 542, 202, 157,
+ 514, 515, 202, 202, 202, 533, 202, 175,
+ 541, 542, 202, 157, 514, 515, 202, 202,
+ 202, 533, 202, 541, 541, 202, 157, 514,
+ 515, 202, 202, 202, 533, 202, 543, 202,
+ 544, 545, 202, 157, 514, 515, 202, 202,
+ 172, 202, 171, 202, 541, 541, 202, 157,
+ 514, 515, 202, 541, 541, 202, 157, 514,
+ 515, 202, 543, 202, 541, 541, 202, 157,
+ 514, 515, 202, 543, 202, 544, 541, 202,
+ 157, 514, 515, 202, 202, 172, 202, 523,
+ 171, 360, 360, 98, 364, 360, 79, 194,
+ 195, 360, 360, 360, 365, 360, 523, 360,
+ 547, 546, 548, 548, 546, 186, 549, 550,
+ 546, 548, 548, 546, 186, 549, 550, 546,
+ 551, 546, 546, 552, 549, 550, 546, 549,
+ 550, 546, 553, 546, 549, 554, 546, 549,
+ 555, 546, 549, 546, 551, 546, 546, 546,
+ 549, 550, 546, 0
};
static const short _indic_syllable_machine_trans_targs[] = {
178, 200, 207, 209, 210, 4, 213, 5,
7, 216, 8, 10, 219, 11, 13, 222,
14, 16, 17, 199, 19, 20, 221, 22,
- 23, 218, 25, 26, 215, 224, 229, 233,
- 236, 240, 243, 247, 250, 254, 257, 178,
- 280, 287, 289, 290, 41, 293, 42, 44,
- 296, 45, 47, 299, 48, 50, 302, 51,
- 53, 54, 279, 56, 57, 301, 59, 60,
- 298, 62, 63, 295, 304, 309, 313, 316,
- 320, 323, 327, 330, 334, 338, 178, 359,
- 366, 368, 369, 78, 372, 178, 79, 81,
- 375, 82, 84, 378, 85, 87, 381, 88,
- 90, 91, 358, 93, 94, 380, 96, 97,
- 377, 99, 100, 374, 383, 388, 392, 395,
- 399, 402, 406, 409, 413, 178, 440, 447,
- 449, 450, 114, 453, 115, 117, 456, 118,
- 120, 459, 121, 123, 462, 124, 126, 127,
- 439, 129, 130, 461, 132, 133, 458, 135,
- 136, 455, 464, 469, 473, 476, 480, 483,
- 487, 490, 494, 497, 417, 502, 513, 152,
- 516, 154, 519, 155, 157, 522, 158, 160,
- 525, 161, 528, 530, 531, 166, 167, 527,
- 169, 170, 524, 172, 173, 521, 175, 176,
- 518, 178, 536, 178, 179, 259, 339, 341,
- 416, 418, 361, 362, 419, 415, 498, 499,
- 386, 534, 387, 178, 180, 182, 36, 258,
- 202, 203, 256, 227, 228, 181, 35, 183,
- 252, 1, 184, 186, 34, 251, 249, 185,
- 33, 187, 245, 188, 190, 32, 244, 242,
- 189, 31, 191, 238, 192, 194, 30, 237,
- 235, 193, 29, 195, 231, 196, 198, 28,
- 230, 226, 197, 27, 212, 0, 201, 206,
- 178, 204, 205, 208, 2, 211, 3, 214,
- 6, 24, 217, 9, 21, 220, 12, 18,
- 223, 15, 225, 232, 234, 239, 241, 246,
- 248, 253, 255, 178, 260, 262, 73, 336,
- 282, 283, 337, 307, 308, 261, 72, 263,
- 332, 38, 264, 266, 71, 331, 329, 265,
- 70, 267, 325, 268, 270, 69, 324, 322,
- 269, 68, 271, 318, 272, 274, 67, 317,
- 315, 273, 66, 275, 311, 276, 278, 65,
- 310, 306, 277, 64, 292, 37, 281, 286,
- 178, 284, 285, 288, 39, 291, 40, 294,
- 43, 61, 297, 46, 58, 300, 49, 55,
- 303, 52, 305, 312, 314, 319, 321, 326,
- 328, 333, 335, 178, 340, 109, 342, 411,
- 75, 343, 345, 108, 410, 408, 344, 107,
- 346, 404, 347, 349, 106, 403, 401, 348,
- 105, 350, 397, 351, 353, 104, 396, 394,
- 352, 103, 354, 390, 355, 357, 102, 389,
- 385, 356, 101, 371, 74, 360, 365, 178,
- 363, 364, 367, 76, 370, 77, 373, 80,
- 98, 376, 83, 95, 379, 86, 92, 382,
- 89, 384, 391, 393, 398, 400, 405, 407,
- 412, 414, 178, 178, 420, 422, 146, 145,
- 442, 443, 496, 467, 468, 421, 423, 492,
- 111, 424, 426, 144, 491, 489, 425, 143,
- 427, 485, 428, 430, 142, 484, 482, 429,
- 141, 431, 478, 432, 434, 140, 477, 475,
- 433, 139, 435, 471, 436, 438, 138, 470,
- 466, 437, 137, 452, 110, 441, 446, 178,
- 444, 445, 448, 112, 451, 113, 454, 116,
- 134, 457, 119, 131, 460, 122, 128, 463,
- 125, 465, 472, 474, 479, 481, 486, 488,
- 493, 495, 147, 500, 501, 515, 504, 505,
- 533, 148, 509, 503, 508, 506, 507, 510,
- 511, 150, 514, 512, 149, 151, 517, 153,
- 174, 163, 520, 156, 171, 523, 159, 168,
- 526, 162, 165, 529, 164, 532, 178, 535,
- 177, 538, 539, 537, 542, 178, 540, 541
+ 23, 218, 25, 26, 215, 224, 228, 232,
+ 235, 239, 242, 246, 249, 253, 256, 178,
+ 279, 286, 288, 289, 41, 292, 42, 44,
+ 295, 45, 47, 298, 48, 50, 301, 51,
+ 53, 54, 278, 56, 57, 300, 59, 60,
+ 297, 62, 63, 294, 303, 307, 311, 314,
+ 318, 321, 325, 328, 332, 336, 178, 357,
+ 364, 366, 367, 78, 370, 178, 79, 81,
+ 373, 82, 84, 376, 85, 87, 379, 88,
+ 90, 91, 356, 93, 94, 378, 96, 97,
+ 375, 99, 100, 372, 381, 385, 389, 392,
+ 396, 399, 403, 406, 410, 178, 437, 444,
+ 446, 447, 114, 450, 115, 117, 453, 118,
+ 120, 456, 121, 123, 459, 124, 126, 127,
+ 436, 129, 130, 458, 132, 133, 455, 135,
+ 136, 452, 461, 465, 469, 472, 476, 479,
+ 483, 486, 490, 493, 414, 498, 509, 152,
+ 512, 154, 515, 155, 157, 518, 158, 160,
+ 521, 161, 524, 526, 527, 166, 167, 523,
+ 169, 170, 520, 172, 173, 517, 175, 176,
+ 514, 178, 532, 178, 179, 258, 337, 339,
+ 413, 415, 359, 360, 416, 412, 494, 495,
+ 384, 530, 178, 180, 182, 36, 257, 202,
+ 203, 255, 227, 181, 35, 183, 251, 1,
+ 184, 186, 34, 250, 248, 185, 33, 187,
+ 244, 188, 190, 32, 243, 241, 189, 31,
+ 191, 237, 192, 194, 30, 236, 234, 193,
+ 29, 195, 230, 196, 198, 28, 229, 226,
+ 197, 27, 212, 0, 201, 206, 178, 204,
+ 205, 208, 2, 211, 3, 214, 6, 24,
+ 217, 9, 21, 220, 12, 18, 223, 15,
+ 225, 231, 233, 238, 240, 245, 247, 252,
+ 254, 178, 259, 261, 73, 334, 281, 282,
+ 335, 306, 260, 72, 262, 330, 38, 263,
+ 265, 71, 329, 327, 264, 70, 266, 323,
+ 267, 269, 69, 322, 320, 268, 68, 270,
+ 316, 271, 273, 67, 315, 313, 272, 66,
+ 274, 309, 275, 277, 65, 308, 305, 276,
+ 64, 291, 37, 280, 285, 178, 283, 284,
+ 287, 39, 290, 40, 293, 43, 61, 296,
+ 46, 58, 299, 49, 55, 302, 52, 304,
+ 310, 312, 317, 319, 324, 326, 331, 333,
+ 178, 338, 109, 340, 408, 75, 341, 343,
+ 108, 407, 405, 342, 107, 344, 401, 345,
+ 347, 106, 400, 398, 346, 105, 348, 394,
+ 349, 351, 104, 393, 391, 350, 103, 352,
+ 387, 353, 355, 102, 386, 383, 354, 101,
+ 369, 74, 358, 363, 178, 361, 362, 365,
+ 76, 368, 77, 371, 80, 98, 374, 83,
+ 95, 377, 86, 92, 380, 89, 382, 388,
+ 390, 395, 397, 402, 404, 409, 411, 178,
+ 178, 417, 419, 146, 145, 439, 440, 492,
+ 464, 418, 420, 488, 111, 421, 423, 144,
+ 487, 485, 422, 143, 424, 481, 425, 427,
+ 142, 480, 478, 426, 141, 428, 474, 429,
+ 431, 140, 473, 471, 430, 139, 432, 467,
+ 433, 435, 138, 466, 463, 434, 137, 449,
+ 110, 438, 443, 178, 441, 442, 445, 112,
+ 448, 113, 451, 116, 134, 454, 119, 131,
+ 457, 122, 128, 460, 125, 462, 468, 470,
+ 475, 477, 482, 484, 489, 491, 147, 496,
+ 497, 511, 500, 501, 529, 148, 505, 499,
+ 504, 502, 503, 506, 507, 150, 510, 508,
+ 149, 151, 513, 153, 174, 163, 516, 156,
+ 171, 519, 159, 168, 522, 162, 165, 525,
+ 164, 528, 178, 531, 177, 534, 535, 533,
+ 538, 178, 536, 537
};
static const char _indic_syllable_machine_trans_actions[] = {
@@ -1285,51 +1087,51 @@ static const char _indic_syllable_machine_trans_actions[] = {
0, 0, 2, 0, 0, 2, 0, 0,
2, 9, 0, 12, 2, 2, 6, 2,
13, 13, 0, 0, 2, 2, 6, 2,
- 6, 2, 6, 14, 2, 2, 0, 2,
- 0, 0, 2, 2, 2, 2, 0, 2,
- 2, 0, 2, 2, 0, 2, 2, 2,
- 0, 2, 2, 2, 2, 0, 2, 2,
- 2, 0, 2, 2, 2, 2, 0, 2,
- 2, 2, 0, 2, 2, 2, 2, 0,
- 2, 2, 2, 0, 2, 0, 0, 0,
- 15, 0, 0, 2, 0, 2, 0, 2,
- 0, 0, 2, 0, 0, 2, 0, 0,
- 2, 0, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 16, 2, 2, 0, 2,
- 0, 0, 2, 2, 2, 2, 0, 2,
- 2, 0, 2, 2, 0, 2, 2, 2,
- 0, 2, 2, 2, 2, 0, 2, 2,
- 2, 0, 2, 2, 2, 2, 0, 2,
- 2, 2, 0, 2, 2, 2, 2, 0,
- 2, 2, 2, 0, 2, 0, 0, 0,
- 17, 0, 0, 2, 0, 2, 0, 2,
- 0, 0, 2, 0, 0, 2, 0, 0,
- 2, 0, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 18, 6, 0, 6, 6,
- 0, 6, 2, 0, 6, 2, 6, 0,
- 6, 6, 6, 2, 0, 6, 2, 6,
- 0, 6, 6, 6, 2, 0, 6, 2,
- 6, 0, 6, 6, 6, 2, 0, 6,
- 2, 6, 0, 6, 0, 0, 0, 19,
- 0, 0, 2, 0, 2, 0, 2, 0,
- 0, 2, 0, 0, 2, 0, 0, 2,
- 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 20, 21, 2, 2, 0, 0,
- 0, 0, 2, 2, 2, 2, 2, 2,
- 0, 2, 2, 0, 2, 2, 2, 0,
+ 6, 2, 14, 2, 2, 0, 2, 0,
+ 0, 2, 2, 2, 0, 2, 2, 0,
+ 2, 2, 0, 2, 2, 2, 0, 2,
+ 2, 2, 2, 0, 2, 2, 2, 0,
2, 2, 2, 2, 0, 2, 2, 2,
0, 2, 2, 2, 2, 0, 2, 2,
- 2, 0, 2, 2, 2, 2, 0, 2,
- 2, 2, 0, 2, 0, 0, 0, 22,
- 0, 0, 2, 0, 2, 0, 2, 0,
+ 2, 0, 2, 0, 0, 0, 15, 0,
+ 0, 2, 0, 2, 0, 2, 0, 0,
+ 2, 0, 0, 2, 0, 0, 2, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 16, 2, 2, 0, 2, 0, 0,
+ 2, 2, 2, 0, 2, 2, 0, 2,
+ 2, 0, 2, 2, 2, 0, 2, 2,
+ 2, 2, 0, 2, 2, 2, 0, 2,
+ 2, 2, 2, 0, 2, 2, 2, 0,
+ 2, 2, 2, 2, 0, 2, 2, 2,
+ 0, 2, 0, 0, 0, 17, 0, 0,
+ 2, 0, 2, 0, 2, 0, 0, 2,
+ 0, 0, 2, 0, 0, 2, 0, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 18, 6, 0, 6, 6, 0, 6, 2,
+ 0, 6, 2, 6, 0, 6, 6, 6,
+ 2, 0, 6, 2, 6, 0, 6, 6,
+ 6, 2, 0, 6, 2, 6, 0, 6,
+ 6, 6, 2, 0, 6, 2, 6, 0,
+ 6, 0, 0, 0, 19, 0, 0, 2,
+ 0, 2, 0, 2, 0, 0, 2, 0,
+ 0, 2, 0, 0, 2, 0, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 20,
+ 21, 2, 2, 0, 0, 0, 0, 2,
+ 2, 2, 2, 2, 0, 2, 2, 0,
+ 2, 2, 2, 0, 2, 2, 2, 2,
+ 0, 2, 2, 2, 0, 2, 2, 2,
+ 2, 0, 2, 2, 2, 0, 2, 2,
+ 2, 2, 0, 2, 2, 2, 0, 2,
+ 0, 0, 0, 22, 0, 0, 2, 0,
+ 2, 0, 2, 0, 0, 2, 0, 0,
+ 2, 0, 0, 2, 0, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0,
+ 8, 2, 0, 0, 2, 0, 2, 0,
+ 0, 0, 0, 8, 8, 0, 8, 8,
+ 0, 0, 2, 0, 0, 0, 2, 0,
0, 2, 0, 0, 2, 0, 0, 2,
- 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 0, 0, 8, 2, 0, 0,
- 2, 0, 2, 0, 0, 0, 0, 8,
- 8, 0, 8, 8, 0, 0, 2, 0,
- 0, 0, 2, 0, 0, 2, 0, 0,
- 2, 0, 0, 2, 0, 2, 23, 2,
- 0, 0, 0, 0, 0, 24, 0, 0
+ 0, 2, 23, 2, 0, 0, 0, 0,
+ 0, 24, 0, 0
};
static const char _indic_syllable_machine_to_state_actions[] = {
@@ -1400,7 +1202,7 @@ static const char _indic_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0
};
static const char _indic_syllable_machine_from_state_actions[] = {
@@ -1471,7 +1273,7 @@ static const char _indic_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0
};
static const short _indic_syllable_machine_eof_trans[] = {
@@ -1497,52 +1299,52 @@ static const short _indic_syllable_machine_eof_trans[] = {
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, 186, 0, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 284, 284, 284, 284, 284,
- 284, 284, 284, 364, 364, 364, 364, 364,
- 364, 364, 364, 364, 364, 364, 364, 364,
- 364, 364, 364, 364, 364, 364, 364, 364,
- 364, 364, 364, 364, 364, 364, 364, 364,
- 364, 364, 364, 364, 364, 364, 364, 364,
- 364, 364, 364, 364, 364, 364, 364, 364,
- 364, 364, 364, 364, 364, 364, 364, 364,
- 364, 364, 364, 364, 364, 364, 364, 364,
- 364, 364, 364, 364, 364, 364, 364, 364,
- 364, 364, 364, 364, 364, 364, 364, 364,
- 435, 364, 435, 436, 436, 436, 436, 436,
- 436, 436, 436, 436, 436, 436, 436, 436,
- 436, 436, 436, 436, 436, 436, 436, 436,
- 436, 436, 436, 436, 436, 436, 436, 436,
- 436, 436, 436, 436, 436, 436, 436, 436,
- 436, 436, 436, 436, 436, 436, 436, 436,
- 436, 436, 436, 436, 436, 436, 436, 436,
- 436, 436, 436, 436, 436, 436, 436, 436,
- 436, 436, 436, 436, 436, 436, 436, 436,
- 436, 436, 436, 436, 436, 436, 436, 436,
- 436, 436, 364, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 364, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 204, 204, 204,
- 204, 204, 204, 204, 204, 364, 551, 551,
- 551, 551, 551, 551, 551, 551, 551
+ 1, 186, 0, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 282, 282, 282, 282, 282, 282,
+ 282, 282, 282, 282, 282, 282, 282, 282,
+ 282, 282, 282, 282, 282, 282, 282, 282,
+ 282, 282, 282, 282, 282, 282, 282, 282,
+ 282, 282, 282, 282, 282, 282, 282, 282,
+ 282, 282, 282, 282, 282, 282, 282, 282,
+ 282, 282, 282, 282, 282, 282, 282, 282,
+ 282, 282, 282, 282, 282, 282, 282, 282,
+ 282, 282, 282, 282, 282, 282, 282, 282,
+ 282, 282, 282, 282, 282, 282, 282, 282,
+ 282, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 432, 361, 432,
+ 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 361, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 361, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 361, 547, 547, 547, 547, 547, 547,
+ 547, 547, 547
};
static const int indic_syllable_machine_start = 178;
@@ -1556,7 +1358,7 @@ static const int indic_syllable_machine_en_main = 178;
-#line 97 "hb-ot-shape-complex-indic-machine.rl"
+#line 96 "hb-ot-shape-complex-indic-machine.rl"
#define found_syllable(syllable_type) \
@@ -1576,7 +1378,7 @@ find_syllables (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 1580 "hb-ot-shape-complex-indic-machine.hh"
+#line 1382 "hb-ot-shape-complex-indic-machine.hh"
{
cs = indic_syllable_machine_start;
ts = 0;
@@ -1584,7 +1386,7 @@ find_syllables (hb_buffer_t *buffer)
act = 0;
}
-#line 118 "hb-ot-shape-complex-indic-machine.rl"
+#line 117 "hb-ot-shape-complex-indic-machine.rl"
p = 0;
@@ -1593,7 +1395,7 @@ find_syllables (hb_buffer_t *buffer)
unsigned int last = 0;
unsigned int syllable_serial = 1;
-#line 1597 "hb-ot-shape-complex-indic-machine.hh"
+#line 1399 "hb-ot-shape-complex-indic-machine.hh"
{
int _slen;
int _trans;
@@ -1607,7 +1409,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 1611 "hb-ot-shape-complex-indic-machine.hh"
+#line 1413 "hb-ot-shape-complex-indic-machine.hh"
}
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -1630,71 +1432,71 @@ _eof_trans:
{te = p+1;}
break;
case 15:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
{te = p+1;{ found_syllable (consonant_syllable); }}
break;
case 17:
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
{te = p+1;{ found_syllable (vowel_syllable); }}
break;
case 22:
-#line 90 "hb-ot-shape-complex-indic-machine.rl"
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
{te = p+1;{ found_syllable (standalone_cluster); }}
break;
case 24:
-#line 91 "hb-ot-shape-complex-indic-machine.rl"
+#line 90 "hb-ot-shape-complex-indic-machine.rl"
{te = p+1;{ found_syllable (symbol_cluster); }}
break;
case 19:
-#line 92 "hb-ot-shape-complex-indic-machine.rl"
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
{te = p+1;{ found_syllable (broken_cluster); }}
break;
case 12:
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
{te = p+1;{ found_syllable (non_indic_cluster); }}
break;
case 14:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
{te = p;p--;{ found_syllable (consonant_syllable); }}
break;
case 16:
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
{te = p;p--;{ found_syllable (vowel_syllable); }}
break;
case 21:
-#line 90 "hb-ot-shape-complex-indic-machine.rl"
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
{te = p;p--;{ found_syllable (standalone_cluster); }}
break;
case 23:
-#line 91 "hb-ot-shape-complex-indic-machine.rl"
+#line 90 "hb-ot-shape-complex-indic-machine.rl"
{te = p;p--;{ found_syllable (symbol_cluster); }}
break;
case 18:
-#line 92 "hb-ot-shape-complex-indic-machine.rl"
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
{te = p;p--;{ found_syllable (broken_cluster); }}
break;
case 20:
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
{te = p;p--;{ found_syllable (non_indic_cluster); }}
break;
case 1:
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
break;
case 3:
-#line 89 "hb-ot-shape-complex-indic-machine.rl"
+#line 88 "hb-ot-shape-complex-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (vowel_syllable); }}
break;
case 7:
-#line 90 "hb-ot-shape-complex-indic-machine.rl"
+#line 89 "hb-ot-shape-complex-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (standalone_cluster); }}
break;
case 9:
-#line 91 "hb-ot-shape-complex-indic-machine.rl"
+#line 90 "hb-ot-shape-complex-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (symbol_cluster); }}
break;
case 4:
-#line 92 "hb-ot-shape-complex-indic-machine.rl"
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
break;
case 5:
@@ -1715,22 +1517,22 @@ _eof_trans:
case 8:
#line 1 "NONE"
{te = p+1;}
-#line 88 "hb-ot-shape-complex-indic-machine.rl"
+#line 87 "hb-ot-shape-complex-indic-machine.rl"
{act = 1;}
break;
case 6:
#line 1 "NONE"
{te = p+1;}
-#line 92 "hb-ot-shape-complex-indic-machine.rl"
+#line 91 "hb-ot-shape-complex-indic-machine.rl"
{act = 5;}
break;
case 13:
#line 1 "NONE"
{te = p+1;}
-#line 93 "hb-ot-shape-complex-indic-machine.rl"
+#line 92 "hb-ot-shape-complex-indic-machine.rl"
{act = 6;}
break;
-#line 1734 "hb-ot-shape-complex-indic-machine.hh"
+#line 1536 "hb-ot-shape-complex-indic-machine.hh"
}
_again:
@@ -1739,7 +1541,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 1743 "hb-ot-shape-complex-indic-machine.hh"
+#line 1545 "hb-ot-shape-complex-indic-machine.hh"
}
if ( ++p != pe )
@@ -1755,7 +1557,7 @@ _again:
}
-#line 127 "hb-ot-shape-complex-indic-machine.rl"
+#line 126 "hb-ot-shape-complex-indic-machine.rl"
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh
index 559ebe4986..5879c3e491 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh
@@ -60,11 +60,10 @@ enum indic_category_t {
OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
OT_Ra = 16,
OT_CM = 17, /* Consonant-Medial. */
- OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
- OT_CM2 = 31 /* Consonant-Medial, second slot. */
+ OT_Symbol = 18 /* Avagraha, etc that take marks (SM,A,VD). */
};
-#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2))
+#define MEDIAL_FLAGS (FLAG (OT_CM))
/* Note:
*
@@ -109,27 +108,31 @@ enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Symbol,
INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
- INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* TODO */
+ INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* Don't care. */
INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK = OT_A,
INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER = OT_M, /* U+17CD only. */
INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_PLACEHOLDER,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_Repha, /* TODO */
INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM,
- INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_H, /* TODO */
+ INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng,
INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ,
INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_NON_JOINER = OT_ZWNJ,
INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
INDIC_SYLLABIC_CATEGORY_NUMBER = OT_PLACEHOLDER,
- INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* TODO */
- INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_H, /* TODO */
+ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* Don't care. */
+ INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_M, /* Is like a vowel matra. */
INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
+ INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER = OT_M, /* Misc Khmer signs. */
INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,
@@ -162,17 +165,23 @@ enum indic_matra_category_t {
};
#define INDIC_COMBINE_CATEGORIES(S,M) \
- (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || \
- ( \
- S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
- S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
- S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
- S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
- S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
- S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
- false)) + \
- ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
- ((M << 8) | S))
+ ( \
+ ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+ ( S | \
+ ( \
+ ( \
+ S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
+ S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
+ S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
+ S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
+ S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
+ S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
+ false \
+ ? M : INDIC_MATRA_CATEGORY_NOT_APPLICABLE \
+ ) << 8 \
+ ) \
+ ) \
+ )
HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
hb_indic_get_categories (hb_codepoint_t u);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.cc
index 2e159a12b0..80a6b25e3b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.cc
@@ -2,67 +2,71 @@
/*
* The following table is generated by running:
*
- * ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
+ * ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
*
* on files with these headers:
*
- * # IndicSyllabicCategory-7.0.0.txt
- * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
- * # IndicMatraCategory-7.0.0.txt
- * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
- * # Blocks-7.0.0.txt
- * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
+ * # IndicSyllabicCategory-9.0.0.txt
+ * # Date: 2016-05-21, 02:46:00 GMT [RP]
+ * # IndicPositionalCategory-9.0.0.txt
+ * # Date: 2016-02-25, 00:48:00 GMT [RP]
+ * # Blocks-9.0.0.txt
+ * # Date: 2016-02-05, 23:48:00 GMT [KW]
*/
#include "hb-ot-shape-complex-indic-private.hh"
-#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 13 chars; Avagraha */
-#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 59 chars; Bindu */
+#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 15 chars; Avagraha */
+#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 67 chars; Bindu */
#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */
-#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 30 chars; Cantillation_Mark */
-#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 1744 chars; Consonant */
-#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 7 chars; Consonant_Dead */
-#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 61 chars; Consonant_Final */
+#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 53 chars; Cantillation_Mark */
+#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 1907 chars; Consonant */
+#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 10 chars; Consonant_Dead */
+#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 62 chars; Consonant_Final */
#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */
-#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 19 chars; Consonant_Medial */
-#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 11 chars; Consonant_Placeholder */
+#define ISC_CK INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER /* 2 chars; Consonant_Killer */
+#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 22 chars; Consonant_Medial */
+#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 16 chars; Consonant_Placeholder */
#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 1 chars; Consonant_Preceding_Repha */
-#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 61 chars; Consonant_Subjoined */
+#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED /* 2 chars; Consonant_Prefixed */
+#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 90 chars; Consonant_Subjoined */
#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 4 chars; Consonant_Succeeding_Repha */
+#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER /* 4 chars; Consonant_With_Stacker */
#define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK /* 2 chars; Gemination_Mark */
#define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER /* 7 chars; Invisible_Stacker */
#define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER /* 1 chars; Joiner */
#define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */
#define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */
-#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 18 chars; Nukta */
-#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 408 chars; Number */
+#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 24 chars; Nukta */
+#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 459 chars; Number */
#define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */
#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */
-#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 15 chars; Pure_Killer */
-#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 3 chars; Register_Shifter */
+#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 16 chars; Pure_Killer */
+#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 2 chars; Register_Shifter */
+#define ISC_SM INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER /* 22 chars; Syllable_Modifier */
#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */
-#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 62 chars; Tone_Mark */
-#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 22 chars; Virama */
-#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 29 chars; Visarga */
+#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 42 chars; Tone_Mark */
+#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 24 chars; Virama */
+#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 31 chars; Visarga */
#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */
-#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 553 chars; Vowel_Dependent */
-#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 395 chars; Vowel_Independent */
+#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 602 chars; Vowel_Dependent */
+#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 431 chars; Vowel_Independent */
-#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 142 chars; Bottom */
+#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 300 chars; Bottom */
#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 2 chars; Bottom_And_Right */
#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 57 chars; Left */
#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 21 chars; Left_And_Right */
#define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */
-#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 2 chars; Overstruck */
-#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 163 chars; Right */
-#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 169 chars; Top */
+#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 10 chars; Overstruck */
+#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 258 chars; Right */
+#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 342 chars; Top */
#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 10 chars; Top_And_Bottom */
#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */
#define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 6 chars; Top_And_Left */
#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */
#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */
-#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 15 chars; Visual_Order_Left */
+#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 19 chars; Visual_Order_Left */
#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
@@ -79,29 +83,33 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0038 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-#define indic_offset_0x00d0u 24
+#define indic_offset_0x00b0u 24
/* Latin-1 Supplement */
+ /* 00B0 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 00B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 00C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 00C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 00D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x),
-#define indic_offset_0x0900u 32
+#define indic_offset_0x0900u 64
/* Devanagari */
- /* 0900 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0900 */ _(Bi,T), _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0920 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0928 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,x), _(A,x), _(M,R), _(M,L),
+ /* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,B), _(A,x), _(M,R), _(M,L),
/* 0940 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
/* 0948 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(M,L), _(M,R),
- /* 0950 */ _(x,x), _(TM,x), _(TM,x), _(x,x), _(x,x), _(M,T), _(M,B), _(M,B),
+ /* 0950 */ _(x,x), _(Ca,T), _(Ca,B), _(x,T), _(x,T), _(M,T), _(M,B), _(M,B),
/* 0958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
@@ -110,14 +118,14 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* Bengali */
- /* 0980 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0980 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
/* 0990 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 09A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 09A8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 09B0 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
- /* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L),
+ /* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
/* 09C0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
/* 09C8 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,B), _(CD,x), _(x,x),
/* 09D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
@@ -129,33 +137,33 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* Gurmukhi */
- /* 0A00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0A00 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0A08 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
/* 0A10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0A18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0A28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0A30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x),
- /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(x,x), _(M,R), _(M,L),
+ /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(x,x), _(M,R), _(M,L),
/* 0A40 */ _(M,R), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T),
/* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x),
/* 0A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0A58 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x),
/* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0A70 */ _(Bi,x), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,x), _(x,x), _(x,x),
+ /* 0A70 */ _(Bi,T), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,B), _(x,x), _(x,x),
/* 0A78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Gujarati */
- /* 0A80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0A80 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x),
/* 0A90 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0A98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0AA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0AA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0AB0 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
- /* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L),
+ /* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
/* 0AC0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(x,x), _(M,T),
/* 0AC8 */ _(M,T), _(M,TR), _(x,x), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x),
/* 0AD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
@@ -163,18 +171,18 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0AF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0AF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0AF8 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Oriya */
- /* 0B00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0B00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
/* 0B10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0B28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0B30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
- /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T),
+ /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
/* 0B40 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
/* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x),
/* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,TR),
@@ -186,7 +194,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* Tamil */
- /* 0B80 */ _(x,x), _(x,x), _(Bi,x), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0B80 */ _(x,x), _(x,x), _(Bi,T), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0B88 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(VI,x),
/* 0B90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(x,x), _(x,x),
/* 0B98 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x), _(C,x),
@@ -194,7 +202,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0BA8 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
/* 0BB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0BB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R),
- /* 0BC0 */ _(M,T), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L),
+ /* 0BC0 */ _(M,T), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L),
/* 0BC8 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(x,x), _(x,x),
/* 0BD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 0BD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
@@ -205,7 +213,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* Telugu */
- /* 0C00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0C00 */ _(Bi,T), _(Bi,R), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0C10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -216,7 +224,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0C40 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,T),
/* 0C48 */ _(M,TB), _(x,x), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), _(x,x),
/* 0C50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(x,x),
- /* 0C58 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0C58 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0C70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
@@ -224,26 +232,26 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* Kannada */
- /* 0C80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0C80 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0CA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0CA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0CB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
- /* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T),
+ /* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
/* 0CC0 */ _(M,TR), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,TR),
/* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x),
/* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x),
/* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(x,x),
/* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 0CF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0CF0 */ _(x,x),_(CWS,x),_(CWS,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Malayalam */
- /* 0D00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0D00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0D10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0D18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -253,8 +261,8 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0D38 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(A,x), _(M,R), _(M,R),
/* 0D40 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(x,x), _(M,L), _(M,L),
/* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T),_(CPR,x), _(x,x),
- /* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
- /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(M,R),
+ /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
/* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0D70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
@@ -262,7 +270,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* Sinhala */
- /* 0D80 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0D80 */ _(x,x), _(x,x), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x),
/* 0D98 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -278,7 +286,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0DF0 */ _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(x,x),
-#define indic_offset_0x1000u 1304
+#define indic_offset_0x1000u 1336
/* Myanmar */
@@ -289,52 +297,24 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 1018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B),
- /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,x), _(TM,x),
- /* 1038 */ _(Vs,x), _(IS,x), _(PK,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(C,x),
+ /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,T), _(TM,B),
+ /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R), _(CM,x), _(CM,B), _(CM,B), _(C,x),
/* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 1048 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), _(x,x),
/* 1050 */ _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R),
- /* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,x), _(CM,x),
- /* 1060 */ _(CM,x), _(C,x), _(M,R), _(TM,x), _(TM,x), _(C,x), _(C,x), _(M,R),
- /* 1068 */ _(M,R), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(C,x),
+ /* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,B), _(CM,B),
+ /* 1060 */ _(CM,B), _(C,x), _(M,R), _(TM,R), _(TM,R), _(C,x), _(C,x), _(M,R),
+ /* 1068 */ _(M,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(C,x), _(C,x),
/* 1070 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(C,x), _(C,x), _(C,x),
/* 1078 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1080 */ _(C,x), _(C,x), _(CM,x), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,x),
- /* 1088 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(TM,x),
+ /* 1080 */ _(C,x), _(C,x), _(CM,B), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,R),
+ /* 1088 */ _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,B), _(C,x), _(TM,R),
/* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 1098 */ _(Nd,x), _(Nd,x), _(TM,x), _(TM,x), _(M,R), _(M,T), _(x,x), _(x,x),
+ /* 1098 */ _(Nd,x), _(Nd,x), _(TM,R), _(TM,R), _(M,R), _(M,T), _(x,x), _(x,x),
-#define indic_offset_0x1700u 1464
+#define indic_offset_0x1780u 1496
- /* Tagalog */
-
- /* 1700 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1708 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x),
- /* 1710 */ _(C,x), _(C,x), _(M,T), _(M,B), _(PK,B), _(x,x), _(x,x), _(x,x),
- /* 1718 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Hanunoo */
-
- /* 1720 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1728 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1730 */ _(C,x), _(C,x), _(M,T), _(M,B), _(PK,B), _(x,x), _(x,x), _(x,x),
- /* 1738 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Buhid */
-
- /* 1740 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1748 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1750 */ _(C,x), _(C,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1758 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Tagbanwa */
-
- /* 1760 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1768 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x),
- /* 1770 */ _(C,x), _(x,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1778 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
/* Khmer */
/* 1780 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -345,515 +325,72 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(M,R), _(M,T),
/* 17B8 */ _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,TL),_(M,TLR),
- /* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,x), _(Vs,x),
- /* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(RS,T),_(CSR,T), _(M,T), _(M,T), _(M,T),
- /* 17D0 */ _(M,T), _(PK,T), _(IS,x), _(M,T), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(x,x), _(x,x), _(x,x),
+ /* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,T), _(Vs,R),
+ /* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(SM,T),_(CSR,T), _(CK,T), _(SM,T), _(SM,T),
+ /* 17D0 */ _(SM,T), _(PK,T), _(IS,x), _(SM,T), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(SM,T), _(x,x), _(x,x),
/* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 17E8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-#define indic_offset_0x1900u 1704
-
-
- /* Limbu */
-
- /* 1900 */ _(CP,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1908 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
- /* 1920 */ _(M,T), _(M,T), _(M,B), _(M,R), _(M,R), _(M,TR), _(M,TR), _(M,T),
- /* 1928 */ _(M,T), _(CS,x), _(CS,x), _(CS,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1930 */ _(CF,x), _(CF,x), _(Bi,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
- /* 1938 */ _(CF,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1940 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
- /* 1948 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-
- /* Tai Le */
-
- /* 1950 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1960 */ _(C,x), _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
- /* 1968 */ _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(x,x), _(x,x),
- /* 1970 */ _(TL,x), _(TL,x), _(TL,x), _(TL,x), _(TL,x), _(x,x), _(x,x), _(x,x),
- /* 1978 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* New Tai Lue */
-
- /* 1980 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1988 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 19A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 19A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 19B0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,L), _(M,L), _(M,L),
- /* 19B8 */ _(M,R), _(M,R), _(M,L), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
- /* 19C0 */ _(M,R), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
- /* 19C8 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 19D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 19D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 19E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 19E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 19F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 19F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Buginese */
-
- /* 1A00 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1A08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1A10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T),
- /* 1A18 */ _(M,B), _(M,L), _(M,R), _(M,T), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Tai Tham */
-
- /* 1A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1A38 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1A40 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1A48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x),
- /* 1A50 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(CM,L), _(CM,x), _(CF,x),
- /* 1A58 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x),
- /* 1A60 */ _(IS,x), _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T),
- /* 1A68 */ _(M,T), _(M,B), _(M,B), _(M,T), _(M,B), _(M,R), _(M,L), _(M,L),
- /* 1A70 */ _(M,L), _(M,L), _(M,L), _(M,T), _(M,T), _(TM,x), _(TM,x), _(TM,x),
- /* 1A78 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1A80 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 1A88 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1A90 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 1A98 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x1b00u 2120
-
-
- /* Balinese */
-
- /* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x),
- /* 1B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 1B10 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1B28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1B30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,T), _(M,T),
- /* 1B38 */ _(M,B), _(M,B), _(M,B), _(M,BR), _(M,TB),_(M,TBR), _(M,L), _(M,L),
- /* 1B40 */ _(M,LR), _(M,LR), _(M,T), _(M,TR), _(V,R), _(C,x), _(C,x), _(C,x),
- /* 1B48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1B50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 1B58 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1B60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1B68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1B70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Sundanese */
-
- /* 1B80 */ _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 1B88 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1B90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1B98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1BA0 */ _(C,x), _(CS,x), _(CS,x), _(CS,x), _(M,T), _(M,B), _(M,L), _(M,R),
- /* 1BA8 */ _(M,T), _(M,T), _(PK,R), _(IS,x), _(CS,x), _(CS,x), _(C,x), _(C,x),
- /* 1BB0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 1BB8 */ _(Nd,x), _(Nd,x), _(A,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x),
-
- /* Batak */
-
- /* 1BC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1BC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1BD0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1BD8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1BE0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(N,x), _(M,R),
- /* 1BE8 */ _(M,T), _(M,T), _(M,R), _(M,R), _(M,R), _(M,T), _(M,R), _(M,T),
- /* 1BF0 */ _(CF,x), _(CF,x), _(PK,R), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Lepcha */
-
- /* 1C00 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1C08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1C10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CS,x), _(CS,x), _(M,R), _(M,L),
- /* 1C28 */ _(M,L), _(M,TL), _(M,R), _(M,R), _(M,B), _(CF,x), _(CF,x), _(CF,x),
- /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,L), _(Bi,L), _(x,x), _(N,x),
- /* 1C38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1C40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 1C48 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x),
-
-#define indic_offset_0x1cd0u 2456
+#define indic_offset_0x1cd0u 1608
/* Vedic Extensions */
- /* 1CD0 */ _(TM,x), _(TM,x), _(TM,x), _(x,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
- /* 1CD8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
- /* 1CE0 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1CE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(TM,x), _(x,x), _(x,x), _(x,x),
+ /* 1CD0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(Ca,O), _(Ca,B), _(Ca,B), _(Ca,B),
+ /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B),
+ /* 1CE0 */ _(Ca,T), _(Ca,R), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O),
+ /* 1CE8 */ _(x,O), _(x,x), _(x,x), _(x,x), _(x,x), _(x,B), _(x,x), _(x,x),
+ /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(Ca,T), _(x,x), _(x,x), _(x,x),
+ /* 1CF8 */ _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-#define indic_offset_0x2008u 2496
+#define indic_offset_0x2008u 1656
/* General Punctuation */
/* 2008 */ _(x,x), _(x,x), _(x,x), _(x,x),_(ZWNJ,x),_(ZWJ,x), _(x,x), _(x,x),
- /* 2010 */ _(x,x), _(x,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0xa800u 2512
-
-
- /* Syloti Nagri */
-
- /* A800 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(PK,T), _(C,x),
- /* A808 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A810 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A818 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A820 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,B), _(M,T), _(M,R),
- /* A828 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A830 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A838 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Phags-pa */
-
- /* A840 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A848 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A850 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A858 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Vo,x), _(Vo,x),
- /* A860 */ _(Vo,x), _(Vo,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Vo,x), _(CS,x),
- /* A868 */ _(CS,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A870 */ _(C,x), _(CS,x), _(C,x), _(Bi,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A878 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Saurashtra */
-
- /* A880 */ _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* A888 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* A890 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A898 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A8A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A8A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A8B0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(M,R), _(M,R), _(M,R),
- /* A8B8 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
- /* A8C0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x), _(x,x),
- /* A8C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A8D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* A8D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 2010 */ _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x),
+
+#define indic_offset_0x2070u 1672
+
+
+ /* Superscripts and Subscripts */
+
+ /* 2070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(SM,x), _(x,x), _(x,x), _(x,x),
+ /* 2078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 2080 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x),
+
+#define indic_offset_0xa8e0u 1696
+
/* Devanagari Extended */
- /* A8E0 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
- /* A8E8 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
- /* A8F0 */ _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A8F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Kayah Li */
-
- /* A900 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* A908 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A920 */ _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
- /* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(x,x),
-
- /* Rejang */
-
- /* A930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A938 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A940 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,B),
- /* A948 */ _(M,B), _(M,B), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B), _(CF,x),
- /* A950 */ _(CF,x), _(CF,x), _(CF,x), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A958 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A960 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A968 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A970 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A978 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Javanese */
-
- /* A980 */ _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* A988 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
- /* A990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A9A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A9A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* A9B0 */ _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,R), _(M,T), _(M,T),
- /* A9B8 */ _(M,B), _(M,B), _(M,L), _(M,L), _(M,T), _(CS,x), _(CM,x), _(CM,x),
- /* A9C0 */ _(V,BR), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A9C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A9D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* A9D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A8E0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
+ /* A8E8 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
+ /* A8F0 */ _(Ca,T), _(Ca,T), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+#define indic_offset_0xa9e0u 1720
+
/* Myanmar Extended-B */
- /* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(C,x),
+ /* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T), _(x,x), _(C,x),
/* A9E8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* A9F8 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
- /* Cham */
-
- /* AA00 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
- /* AA08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA28 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,T), _(M,L),
- /* AA30 */ _(M,L), _(M,T), _(M,B), _(CM,x), _(CM,L), _(CM,x), _(CM,x), _(x,x),
- /* AA38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
- /* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x), _(x,x),
- /* AA50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* AA58 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+#define indic_offset_0xaa60u 1752
+
/* Myanmar Extended-A */
/* AA60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(C,x),
-
- /* Tai Viet */
-
- /* AA80 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA88 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AA98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AAA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AAA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AAB0 */ _(M,T), _(M,R), _(M,T), _(M,T), _(M,B),_(M,VOL),_(M,VOL), _(M,T),
- /* AAB8 */ _(M,T),_(M,VOL), _(M,R),_(M,VOL),_(M,VOL), _(M,R), _(M,T), _(TM,x),
- /* AAC0 */ _(TL,x), _(TM,x), _(TL,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* AAC8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* AAD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* AAD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Meetei Mayek Extensions */
-
- /* AAE0 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* AAE8 */ _(C,x), _(C,x), _(C,x), _(M,L), _(M,B), _(M,T), _(M,L), _(M,R),
- /* AAF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Vs,x), _(IS,x), _(x,x),
-
-#define indic_offset_0xabc0u 3272
-
-
- /* Meetei Mayek */
-
- /* ABC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* ABC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x),
- /* ABD0 */ _(C,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* ABD8 */ _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
- /* ABE0 */ _(CF,x), _(CF,x), _(CF,x), _(M,R), _(M,R), _(M,T), _(M,R), _(M,R),
- /* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,x), _(PK,B), _(x,x), _(x,x),
- /* ABF0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* ABF8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x10a00u 3336
-
-
- /* Kharoshthi */
-
- /* 10A00 */ _(C,x), _(M,O), _(M,B), _(M,B), _(x,x), _(M,T), _(M,O), _(x,x),
- /* 10A08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(M,B), _(x,x), _(Bi,x), _(Vs,x),
- /* 10A10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
- /* 10A18 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 10A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 10A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 10A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 10A38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(IS,x),
- /* 10A40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-
-#define indic_offset_0x11000u 3408
-
-
- /* Brahmi */
-
- /* 11000 */ _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11008 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11010 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11020 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11028 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11030 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11038 */ _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B),
- /* 11040 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x),
- /* 11048 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11050 */ _(x,x), _(x,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),
- /* 11058 */_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),
- /* 11060 */_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x), _(Nd,x), _(Nd,x),
- /* 11068 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 11070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(NJ,x),
-
- /* Kaithi */
-
- /* 11080 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11088 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 11090 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11098 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 110A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 110A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 110B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,R),
- /* 110B8 */ _(M,R), _(V,B), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x11100u 3600
-
-
- /* Chakma */
-
- /* 11100 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
- /* 11108 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11110 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11118 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11120 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T),
- /* 11128 */ _(M,T), _(M,T), _(M,B), _(M,B), _(M,L), _(M,T), _(M,TB), _(M,TB),
- /* 11130 */ _(M,T), _(M,B), _(M,B), _(IS,x), _(PK,T), _(x,x), _(Nd,x), _(Nd,x),
- /* 11138 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 11140 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11148 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Mahajani */
-
- /* 11150 */ _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(C,x), _(C,x), _(C,x),
- /* 11158 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11160 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11168 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11170 */ _(C,x), _(C,x), _(C,x), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11178 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Sharada */
-
- /* 11180 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11188 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11190 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11198 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 111A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 111A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 111B0 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,L), _(M,R), _(M,B), _(M,B),
- /* 111B8 */ _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,TR),
- /* 111C0 */ _(V,R), _(A,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 111C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 111D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 111D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Sinhala Archaic Numbers */
-
- /* 111E0 */ _(x,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 111E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 111F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x),
- /* 111F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Khojki */
-
- /* 11200 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11208 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11210 */ _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11218 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11220 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11228 */ _(C,x), _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,R), _(M,B),
- /* 11230 */ _(M,T), _(M,T), _(M,TR), _(M,TR), _(Bi,x), _(V,R), _(N,x), _(GM,T),
-
-#define indic_offset_0x112b0u 3912
-
-
- /* Khudawadi */
-
- /* 112B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 112B8 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 112C0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 112C8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 112D0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 112D8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Bi,x),
- /* 112E0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
- /* 112E8 */ _(M,T), _(N,x), _(PK,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 112F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 112F8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Grantha */
-
- /* 11300 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11308 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
- /* 11310 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
- /* 11318 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11320 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11328 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11330 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
- /* 11338 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,R),
- /* 11340 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(x,x), _(M,L),
- /* 11348 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,R), _(x,x), _(x,x),
- /* 11350 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
- /* 11358 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11360 */ _(VI,x), _(VI,x), _(M,R), _(M,R), _(x,x), _(x,x), _(Ca,x), _(Ca,x),
- /* 11368 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x),
- /* 11370 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x11480u 4112
-
-
- /* Tirhuta */
-
- /* 11480 */ _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11488 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
- /* 11490 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11498 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 114A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 114A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 114B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,B),
- /* 114B8 */ _(M,B), _(M,L), _(M,T), _(M,TL), _(M,LR), _(M,R), _(M,LR), _(Bi,x),
- /* 114C0 */ _(Bi,x), _(Vs,x), _(V,B), _(N,x), _(A,x), _(x,x), _(x,x), _(x,x),
- /* 114C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 114D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 114D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x11580u 4208
-
-
- /* Siddham */
-
- /* 11580 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11588 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
- /* 11590 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11598 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 115A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 115A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,R),
- /* 115B0 */ _(M,L), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x),
- /* 115B8 */ _(M,L), _(M,TL), _(M,LR),_(M,TLR), _(Bi,x), _(Bi,x), _(Vs,x), _(V,B),
- /* 115C0 */ _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x11600u 4280
-
-
- /* Modi */
-
- /* 11600 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11608 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
- /* 11610 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11618 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11620 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11628 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11630 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,B),
- /* 11638 */ _(M,B), _(M,T), _(M,T), _(M,R), _(M,R), _(Bi,x), _(Vs,x), _(V,B),
- /* 11640 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11648 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11650 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 11658 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11660 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11668 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11670 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11678 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Takri */
-
- /* 11680 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 11688 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11690 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 11698 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 116A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 116A8 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(Vs,x), _(M,T), _(M,L), _(M,R),
- /* 116B0 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(N,x),
- /* 116B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 116C0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* 116C8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-}; /* Table items: 4488; occupancy: 73% */
+ /* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(CP,x), _(CP,x), _(CP,x), _(x,x),
+ /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,R), _(TM,T), _(TM,R), _(C,x), _(C,x),
+
+}; /* Table items: 1784; occupancy: 69% */
INDIC_TABLE_ELEMENT_TYPE
hb_indic_get_categories (hb_codepoint_t u)
@@ -862,40 +399,27 @@ hb_indic_get_categories (hb_codepoint_t u)
{
case 0x0u:
if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
- if (hb_in_range (u, 0x00D0u, 0x00D7u)) return indic_table[u - 0x00D0u + indic_offset_0x00d0u];
+ if (hb_in_range (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
if (hb_in_range (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
if (unlikely (u == 0x00A0u)) return _(CP,x);
break;
case 0x1u:
if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
- if (hb_in_range (u, 0x1700u, 0x17EFu)) return indic_table[u - 0x1700u + indic_offset_0x1700u];
- if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return indic_table[u - 0x1900u + indic_offset_0x1900u];
- if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return indic_table[u - 0x1B00u + indic_offset_0x1b00u];
- if (hb_in_range (u, 0x1CD0u, 0x1CF7u)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+ if (hb_in_range (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
+ if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
break;
case 0x2u:
if (hb_in_range (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
+ if (hb_in_range (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
if (unlikely (u == 0x25CCu)) return _(CP,x);
break;
case 0xAu:
- if (hb_in_range (u, 0xA800u, 0xAAF7u)) return indic_table[u - 0xA800u + indic_offset_0xa800u];
- if (hb_in_range (u, 0xABC0u, 0xABFFu)) return indic_table[u - 0xABC0u + indic_offset_0xabc0u];
- break;
-
- case 0x10u:
- if (hb_in_range (u, 0x10A00u, 0x10A47u)) return indic_table[u - 0x10A00u + indic_offset_0x10a00u];
- break;
-
- case 0x11u:
- if (hb_in_range (u, 0x11000u, 0x110BFu)) return indic_table[u - 0x11000u + indic_offset_0x11000u];
- if (hb_in_range (u, 0x11100u, 0x11237u)) return indic_table[u - 0x11100u + indic_offset_0x11100u];
- if (hb_in_range (u, 0x112B0u, 0x11377u)) return indic_table[u - 0x112B0u + indic_offset_0x112b0u];
- if (hb_in_range (u, 0x11480u, 0x114DFu)) return indic_table[u - 0x11480u + indic_offset_0x11480u];
- if (hb_in_range (u, 0x11580u, 0x115C7u)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
- if (hb_in_range (u, 0x11600u, 0x116CFu)) return indic_table[u - 0x11600u + indic_offset_0x11600u];
+ if (hb_in_range (u, 0xA8E0u, 0xA8F7u)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
+ if (hb_in_range (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
+ if (hb_in_range (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
break;
default:
@@ -914,11 +438,14 @@ hb_indic_get_categories (hb_codepoint_t u)
#undef ISC_CD
#undef ISC_CF
#undef ISC_CHL
+#undef ISC_CK
#undef ISC_CM
#undef ISC_CP
#undef ISC_CPR
+#undef ISC_CPrf
#undef ISC_CS
#undef ISC_CSR
+#undef ISC_CWS
#undef ISC_GM
#undef ISC_IS
#undef ISC_ZWJ
@@ -930,6 +457,7 @@ hb_indic_get_categories (hb_codepoint_t u)
#undef ISC_x
#undef ISC_PK
#undef ISC_RS
+#undef ISC_SM
#undef ISC_TL
#undef ISC_TM
#undef ISC_V
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc
index 44481dbb4c..b48fb561c3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc
@@ -176,24 +176,8 @@ set_indic_properties (hb_glyph_info_t &info)
* Re-assign category
*/
-
- /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe
- * treats a whole bunch of characters similarly.
- * TESTS: For example, for U+0951:
- * U+092E,U+0947,U+0952
- * U+092E,U+0952,U+0947
- * U+092E,U+0947,U+0951
- * U+092E,U+0951,U+0947
- * U+092E,U+0951,U+0952
- * U+092E,U+0952,U+0951
- */
- if (unlikely (hb_in_ranges (u, 0x0951u, 0x0952u,
- 0x1CD0u, 0x1CD2u,
- 0x1CD4u, 0x1CE1u) ||
- u == 0x1CF4u))
- cat = OT_A;
/* The following act more like the Bindus. */
- else if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
+ if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
cat = OT_SM;
/* The following act like consonants. */
else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
@@ -216,21 +200,10 @@ set_indic_properties (hb_glyph_info_t &info)
cat = OT_Symbol;
ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
}
- else if (unlikely (hb_in_range (u, 0x17CDu, 0x17D1u) ||
- u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
- {
- /* These are like Top Matras. */
- cat = OT_M;
- pos = POS_ABOVE_C;
- }
else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
- else if (unlikely (u == 0x17D2u)) cat = OT_Coeng; /* Khmer coeng */
else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
cat = OT_PLACEHOLDER;
else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
- else if (unlikely (u == 0xA982u)) cat = OT_SM; /* Javanese repha. */
- else if (unlikely (u == 0xA9BEu)) cat = OT_CM2; /* Javanese medial ya. */
- else if (unlikely (u == 0xA9BDu)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
/*
@@ -296,11 +269,6 @@ enum blwf_mode_t {
BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */
BLWF_MODE_POST_ONLY /* Below-forms feature applied to post-base only. */
};
-enum pref_len_t {
- PREF_LEN_1 = 1,
- PREF_LEN_2 = 2,
- PREF_LEN_DONT_CARE = PREF_LEN_2
-};
struct indic_config_t
{
hb_script_t script;
@@ -310,26 +278,24 @@ struct indic_config_t
reph_position_t reph_pos;
reph_mode_t reph_mode;
blwf_mode_t blwf_mode;
- pref_len_t pref_len;
};
static const indic_config_t indic_configs[] =
{
/* Default. Should be first. */
- {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
- {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
- {HB_SCRIPT_BENGALI, true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
- {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
- {HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
- {HB_SCRIPT_ORIYA, true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
- {HB_SCRIPT_TAMIL, true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
- {HB_SCRIPT_TELUGU, true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
- {HB_SCRIPT_KANNADA, true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
- {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+ {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_BENGALI, true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_ORIYA, true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_TAMIL, true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_TELUGU, true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY},
+ {HB_SCRIPT_KANNADA, true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY},
+ {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST},
{HB_SCRIPT_SINHALA, false,0x0DCAu,BASE_POS_LAST_SINHALA,
- REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
- {HB_SCRIPT_KHMER, false,0x17D2u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
- {HB_SCRIPT_JAVANESE, false,0xA9C0u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
+ REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST},
+ {HB_SCRIPT_KHMER, false,0x17D2u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST},
};
@@ -512,12 +478,12 @@ struct indic_shape_plan_t
hb_codepoint_t glyph = virama_glyph;
if (unlikely (virama_glyph == (hb_codepoint_t) -1))
{
- if (!config->virama || !font->get_glyph (config->virama, 0, &glyph))
+ if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph))
glyph = 0;
/* Technically speaking, the spec says we should apply 'locl' to virama too.
* Maybe one day... */
- /* Our get_glyph() function needs a font, so we can't get the virama glyph
+ /* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
* during shape planning... Instead, overwrite it here. It's safe. Don't worry! */
(const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph;
}
@@ -557,8 +523,15 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
indic_plan->virama_glyph = (hb_codepoint_t) -1;
/* Use zero-context would_substitute() matching for new-spec of the main
- * Indic scripts, and scripts with one spec only, but not for old-specs. */
- bool zero_context = !indic_plan->is_old_spec;
+ * Indic scripts, and scripts with one spec only, but not for old-specs.
+ * The new-spec for all dual-spec scripts says zero-context matching happens.
+ *
+ * However, testing with Malayalam shows that old and new spec both allow
+ * context. Testing with Bengali new-spec however shows that it doesn't.
+ * So, the heuristic here is the way it is. It should *only* be changed,
+ * as we discover more cases of what Windows does. DON'T TOUCH OTHERWISE.
+ */
+ bool zero_context = !indic_plan->is_old_spec && plan->props.script != HB_SCRIPT_MALAYALAM;
indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
@@ -600,12 +573,8 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan,
if (indic_plan->pstf.would_substitute (glyphs , 2, face) ||
indic_plan->pstf.would_substitute (glyphs+1, 2, face))
return POS_POST_C;
- unsigned int pref_len = indic_plan->config->pref_len;
- if ((pref_len == PREF_LEN_2 &&
- (indic_plan->pref.would_substitute (glyphs , 2, face) ||
- indic_plan->pref.would_substitute (glyphs+1, 2, face)))
- || (pref_len == PREF_LEN_1 &&
- indic_plan->pref.would_substitute (glyphs+1, 1, face)))
+ if (indic_plan->pref.would_substitute (glyphs , 2, face) ||
+ indic_plan->pref.would_substitute (glyphs+1, 2, face))
return POS_POST_C;
return POS_BASE_C;
}
@@ -754,10 +723,6 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
switch (indic_plan->config->base_pos)
{
- default:
- assert (false);
- HB_FALLTHROUGH;
-
case BASE_POS_LAST:
{
/* -> starting from the end of the syllable, move backwards */
@@ -1115,10 +1080,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
}
}
- unsigned int pref_len = indic_plan->config->pref_len;
+ unsigned int pref_len = 2;
if (indic_plan->mask_array[PREF] && base + pref_len < end)
{
- assert (1 <= pref_len && pref_len <= 2);
/* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
hb_codepoint_t glyphs[2];
@@ -1231,7 +1195,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t dottedcircle_glyph;
- if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+ if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle = {0};
@@ -1243,7 +1207,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->idx = 0;
unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len)
+ while (buffer->idx < buffer->len && !buffer->in_error)
{
unsigned int syllable = buffer->cur().syllable();
syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
@@ -1258,7 +1222,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* TODO Set glyph_props? */
/* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len &&
+ while (buffer->idx < buffer->len && !buffer->in_error &&
last_syllable == buffer->cur().syllable() &&
buffer->cur().indic_category() == OT_Repha)
buffer->next_glyph ();
@@ -1328,7 +1292,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
for (base = start; base < end; base++)
if (info[base].indic_position() >= POS_BASE_C)
{
- if (try_pref && base + 1 < end && indic_plan->config->pref_len == 2)
+ if (try_pref && base + 1 < end)
{
for (unsigned int i = base + 1; i < end; i++)
if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
@@ -1348,6 +1312,25 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
break;
}
}
+ /* For Malayalam, skip over unformed below- (but NOT post-) forms. */
+ if (buffer->props.script == HB_SCRIPT_MALAYALAM)
+ {
+ for (unsigned int i = base + 1; i < end; i++)
+ {
+ while (i < end && is_joiner (info[i]))
+ i++;
+ if (i == end || !is_halant_or_coeng (info[i]))
+ break;
+ i++; /* Skip halant. */
+ while (i < end && is_joiner (info[i]))
+ i++;
+ if (i < end && is_consonant (info[i]) && info[i].indic_position() == POS_BELOW_C)
+ {
+ base = i;
+ info[base].indic_position() = POS_BASE_C;
+ }
+ }
+ }
if (start < base && info[base].indic_position() > POS_BASE_C)
base--;
@@ -1591,7 +1574,6 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
{
- unsigned int pref_len = indic_plan->config->pref_len;
for (unsigned int i = base + 1; i < end; i++)
if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
{
@@ -1602,10 +1584,8 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
/* Note: We just check that something got substituted. We don't check that
* the <pref> feature actually did it...
*
- * If pref len is longer than one, then only reorder if it ligated. If
- * pref len is one, only reorder if it didn't ligate with other things. */
- if (_hb_glyph_info_substituted (&info[i]) &&
- ((pref_len == 1) ^ _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
+ * Reorder pref only if it ligated. */
+ if (_hb_glyph_info_ligated_and_didnt_multiply (&info[i]))
{
/*
* 2. Try to find a target position the same way as for pre-base matra.
@@ -1733,33 +1713,28 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
switch (ab)
{
/* Don't decompose these. */
- case 0x0931u : return false;
- case 0x0B94u : return false;
+ case 0x0931u : return false; /* DEVANAGARI LETTER RRA */
+ case 0x0B94u : return false; /* TAMIL LETTER AU */
/*
* Decompose split matras that don't have Unicode decompositions.
*/
- case 0x0F77u : *a = 0x0FB2u; *b= 0x0F81u; return true;
- case 0x0F79u : *a = 0x0FB3u; *b= 0x0F81u; return true;
+ /* Khmer */
case 0x17BEu : *a = 0x17C1u; *b= 0x17BEu; return true;
case 0x17BFu : *a = 0x17C1u; *b= 0x17BFu; return true;
case 0x17C0u : *a = 0x17C1u; *b= 0x17C0u; return true;
case 0x17C4u : *a = 0x17C1u; *b= 0x17C4u; return true;
case 0x17C5u : *a = 0x17C1u; *b= 0x17C5u; return true;
- case 0x1925u : *a = 0x1920u; *b= 0x1923u; return true;
- case 0x1926u : *a = 0x1920u; *b= 0x1924u; return true;
- case 0x1B3Cu : *a = 0x1B42u; *b= 0x1B3Cu; return true;
- case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true;
- case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true;
+
#if 0
+ /* Gujarati */
/* This one has no decomposition in Unicode, but needs no decomposition either. */
/* case 0x0AC9u : return false; */
+
+ /* Oriya */
case 0x0B57u : *a = no decomp, -> RIGHT; return true;
- case 0x1C29u : *a = no decomp, -> LEFT; return true;
- case 0xA9C0u : *a = no decomp, -> RIGHT; return true;
- case 0x111BuF : *a = no decomp, -> ABOVE; return true;
#endif
}
@@ -1796,7 +1771,7 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t glyph;
if (hb_options ().uniscribe_bug_compatible ||
- (c->font->get_glyph (ab, 0, &glyph) &&
+ (c->font->get_nominal_glyph (ab, &glyph) &&
indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
{
/* Ok, safe to use Uniscribe-style decomposition. */
@@ -1806,7 +1781,7 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c,
}
}
- return c->unicode->decompose (ab, a, b);
+ return (bool) c->unicode->decompose (ab, a, b);
}
static bool
@@ -1822,7 +1797,7 @@ compose_indic (const hb_ot_shape_normalize_context_t *c,
/* Composition-exclusion exceptions that we want to recompose. */
if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; }
- return c->unicode->compose (a, b, ab);
+ return (bool) c->unicode->compose (a, b, ab);
}
@@ -1834,10 +1809,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
data_create_indic,
data_destroy_indic,
NULL, /* preprocess_text */
+ NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
decompose_indic,
compose_indic,
setup_masks_indic,
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
index 7f74f2df82..bb68622e2a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
@@ -199,6 +199,10 @@ set_myanmar_properties (hb_glyph_info_t &info)
cat = (indic_category_t) OT_A;
break;
+ case 0x1039u:
+ cat = (indic_category_t) OT_H;
+ break;
+
case 0x103Au:
cat = (indic_category_t) OT_As;
break;
@@ -245,6 +249,11 @@ set_myanmar_properties (hb_glyph_info_t &info)
case 0x104Au: case 0x104Bu:
cat = (indic_category_t) OT_P;
break;
+
+ case 0xAA74u: case 0xAA75u: case 0xAA76u:
+ /* https://github.com/roozbehp/unicode-data/issues/3 */
+ cat = (indic_category_t) OT_C;
+ break;
}
if (cat == OT_M)
@@ -435,7 +444,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_codepoint_t dottedcircle_glyph;
- if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+ if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph))
return;
hb_glyph_info_t dottedcircle = {0};
@@ -447,7 +456,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->idx = 0;
unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len)
+ while (buffer->idx < buffer->len && !buffer->in_error)
{
unsigned int syllable = buffer->cur().syllable();
syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
@@ -507,10 +516,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
+ NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
@@ -523,10 +534,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
+ NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
NULL, /* decompose */
NULL, /* compose */
setup_masks_myanmar,
+ NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
false, /* fallback_position */
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-private.hh
index 8d03dee51f..39572dfe00 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-private.hh
@@ -41,12 +41,8 @@
enum hb_ot_shape_zero_width_marks_type_t {
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
-// HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY,
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
-
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
};
@@ -110,6 +106,15 @@ struct hb_ot_complex_shaper_t
hb_buffer_t *buffer,
hb_font_t *font);
+ /* postprocess_glyphs()
+ * Called during shape().
+ * Shapers can use to modify glyphs after shaping ends.
+ * May be NULL.
+ */
+ void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font);
+
hb_ot_shape_normalization_mode_t normalization_preference;
@@ -141,6 +146,14 @@ struct hb_ot_complex_shaper_t
hb_buffer_t *buffer,
hb_font_t *font);
+ /* disable_otl()
+ * Called during shape().
+ * If set and returns true, GDEF/GSUB/GPOS of the font are ignored
+ * and fallback operations used.
+ * May be NULL.
+ */
+ bool (*disable_otl) (const hb_ot_shape_plan_t *plan);
+
hb_ot_shape_zero_width_marks_type_t zero_width_marks;
bool fallback_position;
@@ -236,9 +249,6 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-3.0 additions */
case HB_SCRIPT_SINHALA:
- /* Unicode-5.2 additions */
- case HB_SCRIPT_JAVANESE:
-
/* If the designer designed the font for the 'DFLT' script,
* use the default shaper. Otherwise, use the specific shaper.
* Note that for some simple scripts, there may not be *any*
@@ -311,7 +321,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-5.2 additions */
case HB_SCRIPT_EGYPTIAN_HIEROGLYPHS:
- //case HB_SCRIPT_JAVANESE:
+ case HB_SCRIPT_JAVANESE:
case HB_SCRIPT_KAITHI:
case HB_SCRIPT_MEETEI_MAYEK:
case HB_SCRIPT_TAI_THAM:
@@ -340,6 +350,15 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_SIDDHAM:
case HB_SCRIPT_TIRHUTA:
+ /* Unicode-8.0 additions */
+ case HB_SCRIPT_AHOM:
+ //case HB_SCRIPT_MULTANI:
+
+ /* Unicode-9.0 additions */
+ case HB_SCRIPT_BHAIKSUKI:
+ case HB_SCRIPT_MARCHEN:
+ case HB_SCRIPT_NEWA:
+
/* If the designer designed the font for the 'DFLT' script,
* use the default shaper. Otherwise, use the specific shaper.
* Note that for some simple scripts, there may not be *any*
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc
index 8a8f2f7991..e6f80f59e7 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc
@@ -139,7 +139,6 @@ thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
};
switch (action) {
- default: assert (false); HB_FALLTHROUGH;
case NOP: return u;
case SD: pua_mappings = SD_mappings; break;
case SDL: pua_mappings = SDL_mappings; break;
@@ -315,7 +314,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
buffer->clear_output ();
unsigned int count = buffer->len;
- for (buffer->idx = 0; buffer->idx < count;)
+ for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
{
hb_codepoint_t u = buffer->cur().codepoint;
if (likely (!IS_SARA_AM (u))) {
@@ -330,7 +329,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
if (unlikely (buffer->in_error))
return;
- /* Make Nikhahit be recognized as a mark when zeroing widths. */
+ /* Make Nikhahit be recognized as a ccc=0 mark when zeroing widths. */
unsigned int end = buffer->out_len;
_hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
@@ -372,10 +371,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
NULL, /* data_create */
NULL, /* data_destroy */
preprocess_text_thai,
+ NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+ NULL, /* disable_otl */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
false,/* fallback_position */
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc
index 01465a426f..aadf59f5ad 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc
@@ -52,10 +52,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
+ NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+ NULL, /* disable_otl */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh
index ced9d97f28..44e5d0d56b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-machine.hh
@@ -36,291 +36,222 @@
#line 38 "hb-ot-shape-complex-use-machine.hh"
static const unsigned char _use_syllable_machine_trans_keys[] = {
- 0u, 0u, 4u, 4u, 1u, 1u, 0u, 39u, 21u, 21u, 8u, 39u, 8u, 39u, 1u, 1u,
- 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u,
- 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
- 8u, 39u, 8u, 39u, 8u, 39u, 1u, 1u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u,
+ 1u, 1u, 0u, 39u, 21u, 21u, 8u, 39u, 8u, 39u, 1u, 1u, 8u, 39u, 8u, 39u,
+ 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
+ 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 13u, 21u,
+ 4u, 4u, 13u, 13u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u,
8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
- 8u, 39u, 12u, 21u, 12u, 13u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u,
- 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
- 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 1u, 39u, 8u, 39u, 21u, 42u, 41u, 42u,
+ 8u, 39u, 8u, 39u, 8u, 39u, 1u, 1u, 1u, 39u, 8u, 39u, 21u, 42u, 41u, 42u,
42u, 42u, 0
};
static const char _use_syllable_machine_key_spans[] = {
- 0, 1, 1, 40, 1, 32, 32, 1,
- 32, 32, 32, 19, 19, 19, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 1, 32, 32, 19, 19,
+ 1, 40, 1, 32, 32, 1, 32, 32,
+ 32, 19, 19, 19, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 9,
+ 1, 1, 32, 32, 32, 32, 19, 19,
19, 32, 32, 32, 32, 32, 32, 32,
- 32, 10, 2, 32, 32, 32, 32, 19,
- 19, 19, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 39, 32, 22, 2,
+ 32, 32, 32, 1, 39, 32, 22, 2,
1
};
static const short _use_syllable_machine_index_offsets[] = {
- 0, 0, 2, 4, 45, 47, 80, 113,
- 115, 148, 181, 214, 234, 254, 274, 307,
- 340, 373, 406, 439, 472, 505, 538, 571,
- 604, 637, 670, 703, 705, 738, 771, 791,
- 811, 831, 864, 897, 930, 963, 996, 1029,
- 1062, 1095, 1106, 1109, 1142, 1175, 1208, 1241,
- 1261, 1281, 1301, 1334, 1367, 1400, 1433, 1466,
- 1499, 1532, 1565, 1598, 1631, 1671, 1704, 1727,
- 1730
+ 0, 2, 43, 45, 78, 111, 113, 146,
+ 179, 212, 232, 252, 272, 305, 338, 371,
+ 404, 437, 470, 503, 536, 569, 602, 635,
+ 645, 647, 649, 682, 715, 748, 781, 801,
+ 821, 841, 874, 907, 940, 973, 1006, 1039,
+ 1072, 1105, 1138, 1171, 1173, 1213, 1246, 1269,
+ 1272
};
static const char _use_syllable_machine_indicies[] = {
- 1, 0, 3, 2, 4, 5, 6,
- 4, 1, 5, 8, 8, 7, 8, 8,
- 3, 9, 8, 8, 8, 4, 4, 10,
- 11, 8, 8, 12, 13, 14, 15, 16,
- 17, 18, 12, 19, 20, 21, 22, 23,
- 24, 8, 25, 26, 27, 8, 29, 28,
- 31, 30, 30, 32, 33, 30, 30, 30,
- 30, 30, 30, 30, 30, 34, 35, 36,
- 37, 38, 39, 40, 41, 35, 42, 34,
- 43, 44, 45, 46, 30, 47, 48, 49,
- 30, 31, 30, 30, 32, 33, 30, 30,
- 30, 30, 30, 30, 30, 30, 50, 35,
- 36, 37, 38, 39, 40, 41, 35, 42,
- 43, 43, 44, 45, 46, 30, 47, 48,
- 49, 30, 32, 51, 31, 30, 30, 32,
- 33, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 35, 36, 37, 38, 39, 40,
- 41, 35, 42, 43, 43, 44, 45, 46,
- 30, 47, 48, 49, 30, 31, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 35, 36, 37, 38, 39,
- 30, 30, 30, 30, 30, 30, 44, 45,
- 46, 30, 47, 48, 49, 30, 31, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 36, 37, 38,
- 39, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 47, 48, 49, 30, 31,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 37,
- 38, 39, 30, 31, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 38, 39, 30, 31,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 39, 30, 31, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 37, 38, 39, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 47, 48, 49, 30, 31, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 37, 38, 39, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 48, 49, 30, 31, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 37, 38, 39,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 49, 30, 31, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 36, 37, 38,
- 39, 30, 30, 30, 30, 30, 30, 44,
- 45, 46, 30, 47, 48, 49, 30, 31,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 36, 37,
- 38, 39, 30, 30, 30, 30, 30, 30,
- 30, 45, 46, 30, 47, 48, 49, 30,
- 31, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 36,
- 37, 38, 39, 30, 30, 30, 30, 30,
- 30, 30, 30, 46, 30, 47, 48, 49,
- 30, 31, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 35,
- 36, 37, 38, 39, 30, 41, 35, 30,
- 30, 30, 44, 45, 46, 30, 47, 48,
- 49, 30, 31, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 35, 36, 37, 38, 39, 30, 30, 35,
- 30, 30, 30, 44, 45, 46, 30, 47,
- 48, 49, 30, 31, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 35, 36, 37, 38, 39, 40, 41,
- 35, 30, 30, 30, 44, 45, 46, 30,
- 47, 48, 49, 30, 31, 30, 30, 32,
- 33, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 35, 36, 37, 38, 39, 40,
- 41, 35, 42, 30, 43, 44, 45, 46,
- 30, 47, 48, 49, 30, 31, 30, 30,
- 32, 33, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 35, 36, 37, 38, 39,
- 40, 41, 35, 42, 34, 43, 44, 45,
- 46, 30, 47, 48, 49, 30, 53, 52,
- 52, 54, 55, 52, 52, 52, 52, 52,
- 52, 52, 52, 56, 52, 57, 58, 59,
- 60, 61, 62, 57, 63, 56, 64, 52,
- 52, 52, 52, 65, 66, 67, 52, 53,
- 52, 52, 54, 55, 52, 52, 52, 52,
- 52, 52, 52, 52, 68, 52, 57, 58,
- 59, 60, 61, 62, 57, 63, 64, 64,
- 52, 52, 52, 52, 65, 66, 67, 52,
- 54, 51, 53, 52, 52, 54, 55, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 57, 58, 59, 60, 61, 62, 57,
- 63, 64, 64, 52, 52, 52, 52, 65,
- 66, 67, 52, 53, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 57, 58, 59, 60, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 65, 66, 67, 52, 53, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 58, 59, 60, 52,
- 53, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 59, 60, 52, 53, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 60, 52,
- 53, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 58, 59, 60, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 65, 66, 67,
- 52, 53, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 58, 59, 60, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 66,
- 67, 52, 53, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 58, 59, 60, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 67, 52, 53, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 57, 58, 59, 60, 52, 62,
- 57, 52, 52, 52, 52, 52, 52, 52,
- 65, 66, 67, 52, 53, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 57, 58, 59, 60, 52,
- 52, 57, 52, 52, 52, 52, 52, 52,
- 52, 65, 66, 67, 52, 53, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 57, 58, 59, 60,
- 61, 62, 57, 52, 52, 52, 52, 52,
- 52, 52, 65, 66, 67, 52, 53, 52,
- 52, 54, 55, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 57, 58, 59,
- 60, 61, 62, 57, 63, 52, 64, 52,
- 52, 52, 52, 65, 66, 67, 52, 53,
- 52, 52, 54, 55, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 57, 58,
- 59, 60, 61, 62, 57, 63, 56, 64,
- 52, 52, 52, 52, 65, 66, 67, 52,
- 70, 71, 69, 69, 69, 69, 69, 69,
- 69, 72, 69, 70, 71, 69, 7, 73,
- 73, 3, 9, 73, 73, 73, 73, 73,
- 73, 73, 73, 74, 12, 13, 14, 15,
- 16, 17, 18, 12, 19, 21, 21, 22,
- 23, 24, 73, 25, 26, 27, 73, 7,
- 73, 73, 3, 9, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 12, 13, 14,
- 15, 16, 17, 18, 12, 19, 21, 21,
- 22, 23, 24, 73, 25, 26, 27, 73,
- 7, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 12, 13,
- 14, 15, 16, 73, 73, 73, 73, 73,
- 73, 22, 23, 24, 73, 25, 26, 27,
- 73, 7, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 13, 14, 15, 16, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 25, 26,
- 27, 73, 7, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 14, 15, 16, 73, 7, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 15,
- 16, 73, 7, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 16, 73, 7, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 14, 15,
- 16, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 25, 26, 27, 73, 7,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 14,
- 15, 16, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 26, 27, 73,
- 7, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 14, 15, 16, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 27,
- 73, 7, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 13, 14, 15, 16, 73, 73, 73, 73,
- 73, 73, 22, 23, 24, 73, 25, 26,
- 27, 73, 7, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 13, 14, 15, 16, 73, 73, 73,
- 73, 73, 73, 73, 23, 24, 73, 25,
- 26, 27, 73, 7, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 13, 14, 15, 16, 73, 73,
- 73, 73, 73, 73, 73, 73, 24, 73,
- 25, 26, 27, 73, 7, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 12, 13, 14, 15, 16, 73,
- 18, 12, 73, 73, 73, 22, 23, 24,
- 73, 25, 26, 27, 73, 7, 73, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 12, 13, 14, 15, 16,
- 73, 73, 12, 73, 73, 73, 22, 23,
- 24, 73, 25, 26, 27, 73, 7, 73,
- 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 12, 13, 14, 15,
- 16, 17, 18, 12, 73, 73, 73, 22,
- 23, 24, 73, 25, 26, 27, 73, 7,
- 73, 73, 3, 9, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 12, 13, 14,
- 15, 16, 17, 18, 12, 19, 73, 21,
- 22, 23, 24, 73, 25, 26, 27, 73,
- 5, 6, 73, 73, 5, 73, 73, 7,
- 73, 73, 3, 9, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 12, 13, 14,
- 15, 16, 17, 18, 12, 19, 20, 21,
- 22, 23, 24, 73, 25, 26, 27, 73,
- 7, 73, 73, 3, 9, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 12, 13,
- 14, 15, 16, 17, 18, 12, 19, 20,
- 21, 22, 23, 24, 73, 25, 26, 27,
- 73, 76, 75, 75, 75, 75, 75, 75,
- 75, 75, 75, 75, 75, 75, 75, 75,
- 75, 75, 75, 75, 75, 76, 77, 75,
- 76, 77, 75, 77, 75, 0
+ 1, 0, 2, 3, 4, 2, 5, 3,
+ 4, 4, 6, 4, 4, 1, 7, 4,
+ 4, 4, 2, 2, 8, 9, 4, 4,
+ 10, 11, 12, 13, 14, 15, 16, 10,
+ 17, 18, 19, 20, 21, 22, 4, 23,
+ 24, 25, 4, 27, 26, 29, 28, 28,
+ 30, 31, 28, 28, 28, 28, 28, 28,
+ 28, 28, 32, 33, 34, 35, 36, 37,
+ 38, 39, 33, 40, 32, 41, 42, 43,
+ 44, 28, 45, 46, 47, 28, 29, 28,
+ 28, 30, 31, 28, 28, 28, 28, 28,
+ 28, 28, 28, 48, 33, 34, 35, 36,
+ 37, 38, 39, 33, 40, 41, 41, 42,
+ 43, 44, 28, 45, 46, 47, 28, 30,
+ 49, 29, 28, 28, 30, 31, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 33,
+ 34, 35, 36, 37, 38, 39, 33, 40,
+ 41, 41, 42, 43, 44, 28, 45, 46,
+ 47, 28, 29, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 33, 34, 35, 36, 37, 28, 28, 28,
+ 28, 28, 28, 42, 43, 44, 28, 45,
+ 46, 47, 28, 29, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 34, 35, 36, 37, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 45, 46, 47, 28, 29, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 35, 36, 37, 28,
+ 29, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 36, 37, 28, 29, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 37, 28,
+ 29, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 35, 36, 37, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 45, 46, 47,
+ 28, 29, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 35, 36, 37, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 46,
+ 47, 28, 29, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 35, 36, 37, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 47, 28, 29, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 34, 35, 36, 37, 28, 28,
+ 28, 28, 28, 28, 42, 43, 44, 28,
+ 45, 46, 47, 28, 29, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 34, 35, 36, 37, 28,
+ 28, 28, 28, 28, 28, 28, 43, 44,
+ 28, 45, 46, 47, 28, 29, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 34, 35, 36, 37,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 44, 28, 45, 46, 47, 28, 29, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 33, 34, 35, 36,
+ 37, 28, 39, 33, 28, 28, 28, 42,
+ 43, 44, 28, 45, 46, 47, 28, 29,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 33, 34, 35,
+ 36, 37, 28, 28, 33, 28, 28, 28,
+ 42, 43, 44, 28, 45, 46, 47, 28,
+ 29, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 33, 34,
+ 35, 36, 37, 38, 39, 33, 28, 28,
+ 28, 42, 43, 44, 28, 45, 46, 47,
+ 28, 29, 28, 28, 30, 31, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 33,
+ 34, 35, 36, 37, 38, 39, 33, 40,
+ 28, 41, 42, 43, 44, 28, 45, 46,
+ 47, 28, 29, 28, 28, 30, 31, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28,
+ 33, 34, 35, 36, 37, 38, 39, 33,
+ 40, 32, 41, 42, 43, 44, 28, 45,
+ 46, 47, 28, 51, 50, 50, 50, 50,
+ 50, 50, 50, 52, 50, 5, 53, 51,
+ 50, 6, 54, 54, 1, 55, 54, 54,
+ 54, 54, 54, 54, 54, 54, 56, 10,
+ 11, 12, 13, 14, 15, 16, 10, 17,
+ 19, 19, 20, 21, 22, 54, 23, 24,
+ 25, 54, 6, 54, 54, 1, 55, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 10, 11, 12, 13, 14, 15, 16, 10,
+ 17, 19, 19, 20, 21, 22, 54, 23,
+ 24, 25, 54, 6, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 10, 11, 12, 13, 14, 54, 54,
+ 54, 54, 54, 54, 20, 21, 22, 54,
+ 23, 24, 25, 54, 6, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 11, 12, 13, 14, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 23, 24, 25, 54, 6, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 12, 13, 14,
+ 54, 6, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 13, 14, 54, 6, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 14,
+ 54, 6, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 12, 13, 14, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 23, 24,
+ 25, 54, 6, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 12, 13, 14, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 24, 25, 54, 6, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 12, 13, 14, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 25, 54, 6, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 11, 12, 13, 14, 54,
+ 54, 54, 54, 54, 54, 20, 21, 22,
+ 54, 23, 24, 25, 54, 6, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 11, 12, 13, 14,
+ 54, 54, 54, 54, 54, 54, 54, 21,
+ 22, 54, 23, 24, 25, 54, 6, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 11, 12, 13,
+ 14, 54, 54, 54, 54, 54, 54, 54,
+ 54, 22, 54, 23, 24, 25, 54, 6,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 10, 11, 12,
+ 13, 14, 54, 16, 10, 54, 54, 54,
+ 20, 21, 22, 54, 23, 24, 25, 54,
+ 6, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 10, 11,
+ 12, 13, 14, 54, 54, 10, 54, 54,
+ 54, 20, 21, 22, 54, 23, 24, 25,
+ 54, 6, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 10,
+ 11, 12, 13, 14, 15, 16, 10, 54,
+ 54, 54, 20, 21, 22, 54, 23, 24,
+ 25, 54, 6, 54, 54, 1, 55, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54,
+ 10, 11, 12, 13, 14, 15, 16, 10,
+ 17, 54, 19, 20, 21, 22, 54, 23,
+ 24, 25, 54, 1, 57, 3, 54, 54,
+ 54, 3, 54, 54, 6, 54, 54, 1,
+ 55, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 10, 11, 12, 13, 14, 15,
+ 16, 10, 17, 18, 19, 20, 21, 22,
+ 54, 23, 24, 25, 54, 6, 54, 54,
+ 1, 55, 54, 54, 54, 54, 54, 54,
+ 54, 54, 54, 10, 11, 12, 13, 14,
+ 15, 16, 10, 17, 18, 19, 20, 21,
+ 22, 54, 23, 24, 25, 54, 59, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 59, 60, 58, 59, 60, 58,
+ 60, 58, 0
};
static const char _use_syllable_machine_trans_targs[] = {
- 3, 41, 3, 43, 4, 5, 25, 3,
- 0, 2, 60, 62, 45, 46, 47, 48,
- 49, 56, 57, 58, 61, 59, 53, 54,
- 55, 50, 51, 52, 3, 3, 3, 3,
- 6, 7, 24, 9, 10, 11, 12, 13,
- 20, 21, 22, 23, 17, 18, 19, 14,
- 15, 16, 8, 3, 3, 3, 26, 27,
- 40, 29, 30, 31, 32, 36, 37, 38,
- 39, 33, 34, 35, 28, 3, 3, 1,
- 42, 3, 44, 3, 63, 64
+ 1, 26, 2, 3, 1, 23, 1, 43,
+ 44, 46, 28, 29, 30, 31, 32, 39,
+ 40, 41, 45, 42, 36, 37, 38, 33,
+ 34, 35, 1, 1, 1, 1, 4, 5,
+ 22, 7, 8, 9, 10, 11, 18, 19,
+ 20, 21, 15, 16, 17, 12, 13, 14,
+ 6, 1, 1, 24, 25, 1, 1, 0,
+ 27, 1, 1, 47, 48
};
static const char _use_syllable_machine_trans_actions[] = {
- 1, 2, 3, 4, 0, 0, 0, 7,
- 0, 0, 4, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 4, 4, 0, 0,
- 0, 0, 0, 0, 8, 9, 10, 11,
+ 1, 2, 0, 0, 5, 0, 6, 0,
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 2, 2, 0, 0, 0, 0,
+ 0, 0, 7, 8, 9, 10, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 12, 13, 14, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 15, 16, 0,
- 2, 17, 4, 18, 0, 0
+ 0, 11, 12, 0, 0, 13, 14, 0,
+ 2, 15, 16, 0, 0
};
static const char _use_syllable_machine_to_state_actions[] = {
- 0, 0, 0, 5, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -330,9 +261,7 @@ static const char _use_syllable_machine_to_state_actions[] = {
};
static const char _use_syllable_machine_from_state_actions[] = {
- 0, 0, 0, 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 4, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -342,29 +271,27 @@ static const char _use_syllable_machine_from_state_actions[] = {
};
static const short _use_syllable_machine_eof_trans[] = {
- 0, 1, 3, 0, 29, 31, 31, 52,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 53, 53, 52, 53, 53, 53, 53,
- 53, 53, 53, 53, 53, 53, 53, 53,
- 53, 70, 70, 74, 74, 74, 74, 74,
- 74, 74, 74, 74, 74, 74, 74, 74,
- 74, 74, 74, 74, 74, 74, 76, 76,
- 76
+ 1, 0, 27, 29, 29, 50, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 51,
+ 54, 51, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 58, 55, 55, 59, 59,
+ 59
};
-static const int use_syllable_machine_start = 3;
-static const int use_syllable_machine_first_final = 3;
-static const int use_syllable_machine_error = 0;
+static const int use_syllable_machine_start = 1;
+static const int use_syllable_machine_first_final = 1;
+static const int use_syllable_machine_error = -1;
-static const int use_syllable_machine_en_main = 3;
+static const int use_syllable_machine_en_main = 1;
#line 38 "hb-ot-shape-complex-use-machine.rl"
-#line 145 "hb-ot-shape-complex-use-machine.rl"
+#line 138 "hb-ot-shape-complex-use-machine.rl"
#define found_syllable(syllable_type) \
@@ -384,7 +311,7 @@ find_syllables (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 388 "hb-ot-shape-complex-use-machine.hh"
+#line 315 "hb-ot-shape-complex-use-machine.hh"
{
cs = use_syllable_machine_start;
ts = 0;
@@ -392,7 +319,7 @@ find_syllables (hb_buffer_t *buffer)
act = 0;
}
-#line 166 "hb-ot-shape-complex-use-machine.rl"
+#line 159 "hb-ot-shape-complex-use-machine.rl"
p = 0;
@@ -401,7 +328,7 @@ find_syllables (hb_buffer_t *buffer)
unsigned int last = 0;
unsigned int syllable_serial = 1;
-#line 405 "hb-ot-shape-complex-use-machine.hh"
+#line 332 "hb-ot-shape-complex-use-machine.hh"
{
int _slen;
int _trans;
@@ -409,15 +336,13 @@ find_syllables (hb_buffer_t *buffer)
const char *_inds;
if ( p == pe )
goto _test_eof;
- if ( cs == 0 )
- goto _out;
_resume:
switch ( _use_syllable_machine_from_state_actions[cs] ) {
- case 6:
+ case 4:
#line 1 "NONE"
{ts = p;}
break;
-#line 421 "hb-ot-shape-complex-use-machine.hh"
+#line 346 "hb-ot-shape-complex-use-machine.hh"
}
_keys = _use_syllable_machine_trans_keys + (cs<<1);
@@ -439,92 +364,70 @@ _eof_trans:
#line 1 "NONE"
{te = p+1;}
break;
- case 9:
-#line 134 "hb-ot-shape-complex-use-machine.rl"
+ case 8:
+#line 127 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (independent_cluster); }}
break;
- case 11:
-#line 136 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (consonant_cluster); }}
- break;
- case 14:
-#line 137 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (vowel_cluster); }}
- break;
- case 16:
-#line 138 "hb-ot-shape-complex-use-machine.rl"
- {te = p+1;{ found_syllable (number_joiner_terminated_cluster); }}
+ case 10:
+#line 129 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{ found_syllable (standard_cluster); }}
break;
- case 7:
-#line 141 "hb-ot-shape-complex-use-machine.rl"
+ case 6:
+#line 133 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (broken_cluster); }}
break;
- case 8:
+ case 5:
#line 134 "hb-ot-shape-complex-use-machine.rl"
+ {te = p+1;{ found_syllable (non_cluster); }}
+ break;
+ case 7:
+#line 127 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (independent_cluster); }}
break;
- case 12:
-#line 135 "hb-ot-shape-complex-use-machine.rl"
+ case 11:
+#line 128 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (virama_terminated_cluster); }}
break;
- case 10:
-#line 136 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (consonant_cluster); }}
+ case 9:
+#line 129 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p--;{ found_syllable (standard_cluster); }}
break;
case 13:
-#line 137 "hb-ot-shape-complex-use-machine.rl"
- {te = p;p--;{ found_syllable (vowel_cluster); }}
+#line 130 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }}
break;
- case 15:
-#line 139 "hb-ot-shape-complex-use-machine.rl"
+ case 12:
+#line 131 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (numeral_cluster); }}
break;
- case 18:
-#line 140 "hb-ot-shape-complex-use-machine.rl"
+ case 16:
+#line 132 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (symbol_cluster); }}
break;
- case 17:
-#line 141 "hb-ot-shape-complex-use-machine.rl"
+ case 14:
+#line 133 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (broken_cluster); }}
break;
- case 1:
-#line 139 "hb-ot-shape-complex-use-machine.rl"
- {{p = ((te))-1;}{ found_syllable (numeral_cluster); }}
- break;
- case 3:
-#line 1 "NONE"
- { switch( act ) {
- case 0:
- {{cs = 0; goto _again;}}
- break;
- case 8:
- {{p = ((te))-1;} found_syllable (broken_cluster); }
- break;
- }
- }
+ case 15:
+#line 134 "hb-ot-shape-complex-use-machine.rl"
+ {te = p;p--;{ found_syllable (non_cluster); }}
break;
- case 4:
-#line 1 "NONE"
- {te = p+1;}
-#line 141 "hb-ot-shape-complex-use-machine.rl"
- {act = 8;}
+ case 1:
+#line 133 "hb-ot-shape-complex-use-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (broken_cluster); }}
break;
-#line 513 "hb-ot-shape-complex-use-machine.hh"
+#line 420 "hb-ot-shape-complex-use-machine.hh"
}
_again:
switch ( _use_syllable_machine_to_state_actions[cs] ) {
- case 5:
+ case 3:
#line 1 "NONE"
{ts = 0;}
-#line 1 "NONE"
- {act = 0;}
break;
-#line 524 "hb-ot-shape-complex-use-machine.hh"
+#line 429 "hb-ot-shape-complex-use-machine.hh"
}
- if ( cs == 0 )
- goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
@@ -536,10 +439,9 @@ _again:
}
}
- _out: {}
}
-#line 175 "hb-ot-shape-complex-use-machine.rl"
+#line 168 "hb-ot-shape-complex-use-machine.rl"
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-private.hh
index a143736211..ae428cb5eb 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-private.hh
@@ -46,7 +46,6 @@ enum use_category_t {
USE_O = 0, /* OTHER */
USE_B = 1, /* BASE */
- USE_IV = 2, /* BASE_VOWEL */
USE_IND = 3, /* BASE_IND */
USE_N = 4, /* BASE_NUM */
USE_GB = 5, /* BASE_OTHER */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-table.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-table.cc
index 6cd1c5db75..38c46d002d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-table.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use-table.cc
@@ -6,12 +6,12 @@
*
* on files with these headers:
*
- * # IndicSyllabicCategory-8.0.0.txt
- * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
- * # IndicPositionalCategory-8.0.0.txt
- * # Date: 2015-05-12, 10:00:00 GMT [RP, KW, LI]
- * # Blocks-8.0.0.txt
- * # Date: 2014-11-10, 23:04:00 GMT [KW]
+ * # IndicSyllabicCategory-9.0.0.txt
+ * # Date: 2016-05-21, 02:46:00 GMT [RP]
+ * # IndicPositionalCategory-9.0.0.txt
+ * # Date: 2016-02-25, 00:48:00 GMT [RP]
+ * # Blocks-9.0.0.txt
+ * # Date: 2016-02-05, 23:48:00 GMT [KW]
* UnicodeData.txt does not have a header.
*/
@@ -24,7 +24,6 @@
#define H USE_H /* HALANT */
#define HN USE_HN /* HALANT_NUM */
#define IND USE_IND /* BASE_IND */
-#define IV USE_IV /* BASE_VOWEL */
#define N USE_N /* BASE_NUM */
#define O USE_O /* OTHER */
#define R USE_R /* REPHA */
@@ -80,30 +79,30 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Devanagari */
- /* 0900 */ VMAbv, VMAbv, VMAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
- /* 0910 */ IV, IV, IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0900 */ VMAbv, VMAbv, VMAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0920 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0930 */ B, B, B, B, B, B, B, B, B, B, VAbv, VPst, CMBlw, B, VPst, VPre,
/* 0940 */ VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VPst, VPst, VPst, VPst, H, VPre, VPst,
/* 0950 */ O, VMAbv, VMBlw, O, O, VAbv, VBlw, VBlw, B, B, B, B, B, B, B, B,
- /* 0960 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
- /* 0970 */ O, O, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B, B, B,
+ /* 0960 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
+ /* 0970 */ O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* Bengali */
- /* 0980 */ O, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, O, IV,
- /* 0990 */ IV, O, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0980 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B,
+ /* 0990 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 09A0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 09B0 */ B, O, B, O, O, O, B, B, B, B, O, O, CMBlw, B, VPst, VPre,
/* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, IND, O,
/* 09D0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, B, B, O, B,
- /* 09E0 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
+ /* 09E0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
/* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
/* Gurmukhi */
- /* 0A00 */ O, VMAbv, VMAbv, VMPst, O, IV, IV, IV, IV, IV, IV, O, O, O, O, IV,
- /* 0A10 */ IV, O, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0A00 */ O, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, O, O, O, O, B,
+ /* 0A10 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0A20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 0A30 */ B, O, B, B, O, B, B, O, B, B, O, O, CMBlw, O, VPst, VPre,
/* 0A40 */ VPst, VBlw, VBlw, O, O, O, O, VAbv, VAbv, O, O, VAbv, VAbv, H, O, O,
@@ -113,30 +112,30 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Gujarati */
- /* 0A80 */ O, VMAbv, VMAbv, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, IV, O, IV,
- /* 0A90 */ IV, IV, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0A80 */ O, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, B, B, B, O, B,
+ /* 0A90 */ B, B, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0AA0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 0AB0 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VPre,
/* 0AC0 */ VPst, VBlw, VBlw, VBlw, VBlw, VAbv, O, VAbv, VAbv, VAbv, O, VPst, VPst, H, O, O,
/* 0AD0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 0AE0 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
+ /* 0AE0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
/* 0AF0 */ O, O, O, O, O, O, O, O, O, B, O, O, O, O, O, O,
/* Oriya */
- /* 0B00 */ O, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, O, IV,
- /* 0B10 */ IV, O, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0B00 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B,
+ /* 0B10 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0B20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 0B30 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv,
/* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O,
/* 0B50 */ O, O, O, O, O, O, VAbv, VAbv, O, O, O, O, B, B, O, B,
- /* 0B60 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
+ /* 0B60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
/* 0B70 */ O, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
/* Tamil */
- /* 0B80 */ O, O, VMAbv, IND, O, IV, IV, IV, IV, IV, IV, O, O, O, IV, IV,
- /* 0B90 */ IV, O, IV, IV, IV, B, O, O, O, B, B, O, B, O, B, B,
+ /* 0B80 */ O, O, VMAbv, IND, O, B, B, B, B, B, B, O, O, O, B, B,
+ /* 0B90 */ B, O, B, B, B, B, O, O, O, B, B, O, B, O, B, B,
/* 0BA0 */ O, O, O, B, B, O, O, O, B, B, B, O, O, O, B, B,
/* 0BB0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, VPst, VPst,
/* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, O, O,
@@ -146,41 +145,41 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Telugu */
- /* 0C00 */ VMAbv, VMPst, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, IV, IV,
- /* 0C10 */ IV, O, IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0C00 */ VMAbv, VMPst, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, B, B,
+ /* 0C10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0C20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 0C30 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, VAbv, VAbv,
/* 0C40 */ VAbv, VPst, VPst, VPst, VPst, O, VAbv, VAbv, VAbv, O, VAbv, VAbv, VAbv, H, O, O,
/* 0C50 */ O, O, O, O, O, VAbv, VBlw, O, B, B, B, O, O, O, O, O,
- /* 0C60 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
+ /* 0C60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
/* 0C70 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
/* Kannada */
- /* 0C80 */ O, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, IV, IV,
- /* 0C90 */ IV, O, IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0C80 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, B, B,
+ /* 0C90 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0CA0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 0CB0 */ B, B, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv,
/* 0CC0 */ VAbv, VPst, VPst, VPst, VPst, O, VAbv, VAbv, VAbv, O, VAbv, VAbv, VAbv, H, O, O,
/* 0CD0 */ O, O, O, O, O, VPst, VPst, O, O, O, O, O, O, O, B, O,
- /* 0CE0 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
+ /* 0CE0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
/* 0CF0 */ O, R, R, O, O, O, O, O, O, O, O, O, O, O, O, O,
/* Malayalam */
- /* 0D00 */ O, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, IV, IV,
- /* 0D10 */ IV, O, IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0D00 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, B, B,
+ /* 0D10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0D30 */ B, B, B, B, B, B, B, B, B, B, B, O, O, B, VPst, VPst,
/* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, R, O,
- /* 0D50 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, IV,
- /* 0D60 */ IV, IV, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
+ /* 0D50 */ O, O, O, O, IND, IND, IND, VPst, O, O, O, O, O, O, O, B,
+ /* 0D60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
/* 0D70 */ O, O, O, O, O, O, O, O, O, O, IND, IND, IND, IND, IND, IND,
/* Sinhala */
- /* 0D80 */ O, O, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
- /* 0D90 */ IV, IV, IV, IV, IV, IV, IV, O, O, O, B, B, B, B, B, B,
+ /* 0D80 */ O, O, VMPst, VMPst, O, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0D90 */ B, B, B, B, B, B, B, O, O, O, B, B, B, B, B, B,
/* 0DA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0DB0 */ B, B, O, B, B, B, B, B, B, B, B, B, O, B, O, O,
/* 0DC0 */ B, B, B, B, B, B, B, O, O, O, H, O, O, O, O, VPst,
@@ -195,10 +194,10 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1000 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1020 */ B, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, VPst, VPst, VAbv, VAbv, VBlw,
+ /* 1020 */ B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VAbv, VAbv, VBlw,
/* 1030 */ VBlw, VPre, VAbv, VAbv, VAbv, VAbv, VMAbv, VMBlw, VMPst, H, VAbv, MPst, MPre, MBlw, MBlw, B,
/* 1040 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, GB, O,
- /* 1050 */ B, B, IV, IV, IV, IV, VPst, VPst, VBlw, VBlw, B, B, B, B, MBlw, MBlw,
+ /* 1050 */ B, B, B, B, B, B, VPst, VPst, VBlw, VBlw, B, B, B, B, MBlw, MBlw,
/* 1060 */ MBlw, B, VPst, VMPst, VMPst, B, B, VPst, VPst, VMPst, VMPst, VMPst, VMPst, VMPst, B, B,
/* 1070 */ B, VAbv, VAbv, VAbv, VAbv, B, B, B, B, B, B, B, B, B, B, B,
/* 1080 */ B, B, MBlw, VPst, VPre, VAbv, VAbv, VMPst, VMPst, VMPst, VMPst, VMPst, VMPst, VMBlw, B, VMPst,
@@ -209,30 +208,30 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Tagalog */
- /* 1700 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, O, B, B,
+ /* 1700 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, B, B,
/* 1710 */ B, B, VAbv, VBlw, VBlw, O, O, O, O, O, O, O, O, O, O, O,
/* Hanunoo */
- /* 1720 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 1720 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1730 */ B, B, VAbv, VBlw, VBlw, O, O, O, O, O, O, O, O, O, O, O,
/* Buhid */
- /* 1740 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 1740 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1750 */ B, B, VAbv, VBlw, O, O, O, O, O, O, O, O, O, O, O, O,
/* Tagbanwa */
- /* 1760 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, O, B, B,
+ /* 1760 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, B, B,
/* 1770 */ B, O, VAbv, VBlw, O, O, O, O, O, O, O, O, O, O, O, O,
/* Khmer */
/* 1780 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1790 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 17A0 */ B, B, B, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
- /* 17B0 */ IV, IV, IV, IV, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPre, VPre,
+ /* 17A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 17B0 */ B, B, B, B, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPre, VPre,
/* 17C0 */ VPre, VPre, VPre, VPre, VPre, VPre, VMAbv, VMPst, VPst, VMAbv, VMAbv, FM, FAbv, CMAbv, FM, FM,
/* 17D0 */ FM, VAbv, H, FM, O, O, O, O, O, O, O, O, B, VAbv, O, O,
/* 17E0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
@@ -274,8 +273,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1A30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1A40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, IV, IV, IV,
- /* 1A50 */ IV, IV, IV, B, B, MPre, MBlw, FPst, FAbv, FAbv, FAbv, FBlw, FBlw, FBlw, FBlw, O,
+ /* 1A40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 1A50 */ B, B, B, B, B, MPre, MBlw, FPst, FAbv, FAbv, FAbv, FBlw, FBlw, FBlw, FBlw, O,
/* 1A60 */ H, VPst, VAbv, VPst, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre,
/* 1A70 */ VPre, VPre, VPre, VAbv, VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, FM, FM, FM, O, O, FM,
/* 1A80 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
@@ -286,8 +285,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Balinese */
- /* 1B00 */ VMAbv, VMAbv, VMAbv, FAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
- /* 1B10 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 1B00 */ VMAbv, VMAbv, VMAbv, FAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B,
+ /* 1B10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1B30 */ B, B, B, B, CMAbv, VPst, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre,
/* 1B40 */ VPre, VPre, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O,
@@ -297,7 +296,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Sundanese */
- /* 1B80 */ VMAbv, FAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B,
+ /* 1B80 */ VMAbv, FAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1B90 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1BA0 */ B, SUB, SUB, SUB, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst, H, SUB, SUB, B, B,
/* 1BB0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
@@ -306,7 +305,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1BC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1BD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1BE0 */ B, B, B, B, IV, IV, CMAbv, VPst, VAbv, VAbv, VPst, VPst, VPst, VAbv, VPst, VAbv,
+ /* 1BE0 */ B, B, B, B, B, B, CMAbv, VPst, VAbv, VAbv, VPst, VPst, VPst, VAbv, VPst, VAbv,
/* 1BF0 */ FAbv, FAbv, VPst, VPst, O, O, O, O, O, O, O, O, O, O, O, O,
/* Lepcha */
@@ -326,14 +325,20 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, O, O, O, O, VMBlw, O, O,
/* 1CF0 */ O, O, VMPst, VMPst, VMAbv, O, O, O, VMAbv, VMAbv, O, O, O, O, O, O,
-#define use_offset_0x2008u 2552
+#define use_offset_0x1df8u 2552
+
+
+ /* Combining Diacritical Marks Supplement */
+ O, O, O, FM, O, O, O, O,
+
+#define use_offset_0x2008u 2560
/* General Punctuation */
O, O, O, O, ZWNJ, ZWJ, O, O,
/* 2010 */ GB, GB, GB, GB, GB, O, O, O,
-#define use_offset_0x2060u 2568
+#define use_offset_0x2060u 2576
/* 2060 */ WJ, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
@@ -342,12 +347,12 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 2070 */ O, O, O, O, FM, O, O, O, O, O, O, O, O, O, O, O,
/* 2080 */ O, O, FM, FM, FM, O, O, O,
-#define use_offset_0xa800u 2608
+#define use_offset_0xa800u 2616
/* Syloti Nagri */
- /* A800 */ IV, IV, O, IV, IV, IV, VAbv, B, B, B, B, VMAbv, B, B, B, B,
+ /* A800 */ B, B, O, B, B, B, VAbv, B, B, B, B, VMAbv, B, B, B, B,
/* A810 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* A820 */ B, B, B, VPst, VPst, VBlw, VAbv, VPst, O, O, O, O, O, O, O, O,
/* A830 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
@@ -361,11 +366,11 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Saurashtra */
- /* A880 */ VMPst, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
- /* A890 */ IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* A880 */ VMPst, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* A890 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* A8A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* A8B0 */ B, B, B, B, FPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst,
- /* A8C0 */ VPst, VPst, VPst, VPst, H, O, O, O, O, O, O, O, O, O, O, O,
+ /* A8C0 */ VPst, VPst, VPst, VPst, H, VMAbv, O, O, O, O, O, O, O, O, O, O,
/* A8D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
/* Devanagari Extended */
@@ -389,7 +394,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Javanese */
- /* A980 */ VMAbv, VMAbv, FAbv, VMPst, IV, IV, IV, IV, IV, B, B, B, IV, IV, IV, B,
+ /* A980 */ VMAbv, VMAbv, FAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B,
/* A990 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* A9A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* A9B0 */ B, B, B, CMAbv, VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VPre, VAbv, SUB, MPst, MPst,
@@ -403,7 +408,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Cham */
- /* AA00 */ IV, IV, IV, IV, IV, IV, B, B, B, B, B, B, B, B, B, B,
+ /* AA00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* AA10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* AA20 */ B, B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre,
/* AA30 */ VPre, VAbv, VBlw, MPst, MPre, MBlw, MBlw, O, O, O, O, O, O, O, O, O,
@@ -413,7 +418,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Myanmar Extended-A */
/* AA60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* AA70 */ O, B, B, B, O, O, O, O, O, O, B, VMPst, VMAbv, VMPst, B, B,
+ /* AA70 */ O, B, B, B, GB, GB, GB, O, O, O, B, VMPst, VMAbv, VMPst, B, B,
/* Tai Viet */
@@ -426,27 +431,27 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Meetei Mayek Extensions */
- /* AAE0 */ IV, IV, B, B, B, B, B, B, B, B, B, VPre, VBlw, VAbv, VPre, VPst,
+ /* AAE0 */ B, B, B, B, B, B, B, B, B, B, B, VPre, VBlw, VAbv, VPre, VPst,
/* AAF0 */ O, O, O, O, O, VMPst, H, O,
-#define use_offset_0xabc0u 3368
+#define use_offset_0xabc0u 3376
/* Meetei Mayek */
- /* ABC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, IV, IV,
- /* ABD0 */ B, IV, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* ABC0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* ABD0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* ABE0 */ B, B, B, VPst, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O, VMPst, VBlw, O, O,
/* ABF0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-#define use_offset_0xfe00u 3432
+#define use_offset_0xfe00u 3440
/* Variation Selectors */
/* FE00 */ VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS,
-#define use_offset_0x10a00u 3448
+#define use_offset_0x10a00u 3456
/* Kharoshthi */
@@ -457,13 +462,13 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 10A30 */ B, B, B, B, O, O, O, O, CMAbv, CMBlw, CMBlw, O, O, O, O, H,
/* 10A40 */ B, B, B, B, B, B, B, B,
-#define use_offset_0x11000u 3520
+#define use_offset_0x11000u 3528
/* Brahmi */
- /* 11000 */ VMPst, VMAbv, VMPst, R, R, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
- /* 11010 */ IV, IV, IV, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11000 */ VMPst, VMAbv, VMPst, R, R, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11020 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11030 */ B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw,
/* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O, O, O, O, O, O, O,
@@ -473,17 +478,17 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Kaithi */
- /* 11080 */ VMAbv, VMAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B, B,
+ /* 11080 */ VMAbv, VMAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11090 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 110A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 110B0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VPst, VPst, H, CMBlw, O, O, O, O, O,
-#define use_offset_0x11100u 3712
+#define use_offset_0x11100u 3720
/* Chakma */
- /* 11100 */ VMAbv, VMAbv, VMAbv, IV, IV, IV, IV, B, B, B, B, B, B, B, B, B,
+ /* 11100 */ VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11120 */ B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VAbv, VAbv,
/* 11130 */ VAbv, VBlw, VBlw, H, VAbv, O, B, B, B, B, B, B, B, B, B, B,
@@ -497,8 +502,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Sharada */
- /* 11180 */ VMAbv, VMAbv, VMPst, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV,
- /* 11190 */ IV, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11180 */ VMAbv, VMAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11190 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 111A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 111B0 */ B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv,
/* 111C0 */ H, B, R, R, O, O, O, O, O, O, CMBlw, VAbv, VBlw, O, O, O,
@@ -511,23 +516,23 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Khojki */
- /* 11200 */ IV, IV, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B, B, B,
+ /* 11200 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11210 */ B, B, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11220 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VBlw,
- /* 11230 */ VAbv, VAbv, VAbv, VAbv, VMAbv, H, CMAbv, CMAbv,
+ /* 11230 */ VAbv, VAbv, VAbv, VAbv, VMAbv, H, CMAbv, CMAbv, O, O, O, O, O, O, VMAbv, O,
-#define use_offset_0x11280u 4024
+#define use_offset_0x11280u 4040
/* Multani */
- /* 11280 */ IV, IV, IV, IV, B, B, B, O, B, O, B, B, B, B, O, B,
+ /* 11280 */ B, B, B, B, B, B, B, O, B, O, B, B, B, B, O, B,
/* 11290 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, B,
/* 112A0 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O,
/* Khudawadi */
- /* 112B0 */ IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B,
+ /* 112B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 112C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 112D0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VMAbv,
/* 112E0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, CMBlw, VBlw, O, O, O, O, O,
@@ -535,44 +540,55 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Grantha */
- /* 11300 */ VMAbv, VMAbv, VMPst, VMPst, O, IV, IV, IV, IV, IV, IV, IV, IV, O, O, IV,
- /* 11310 */ IV, O, O, IV, IV, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11300 */ VMAbv, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, O, B,
+ /* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 11330 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VPst,
/* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O,
/* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, O,
- /* 11360 */ IV, IV, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
+ /* 11360 */ B, B, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
/* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
-#define use_offset_0x11480u 4272
+#define use_offset_0x11400u 4288
+ /* Newa */
+
+ /* 11400 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11410 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11420 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11430 */ B, B, B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv,
+ /* 11440 */ VPst, VPst, H, VMAbv, VMAbv, VMPst, CMBlw, B, O, O, O, O, O, O, O, O,
+ /* 11450 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
+ /* 11460 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
+ /* 11470 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
+
/* Tirhuta */
- /* 11480 */ O, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B,
+ /* 11480 */ O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11490 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 114A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPre, VPre, VPst, VPre, VMAbv,
/* 114C0 */ VMAbv, VMPst, H, CMBlw, B, O, O, O, O, O, O, O, O, O, O, O,
/* 114D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-#define use_offset_0x11580u 4368
+#define use_offset_0x11580u 4512
/* Siddham */
- /* 11580 */ IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B,
+ /* 11580 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11590 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 115A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst,
/* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, VPre, VPre, VMAbv, VMAbv, VMPst, H,
/* 115C0 */ CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
- /* 115D0 */ O, O, O, O, O, O, O, O, IV, IV, IV, IV, VBlw, VBlw, O, O,
+ /* 115D0 */ O, O, O, O, O, O, O, O, B, B, B, B, VBlw, VBlw, O, O,
/* 115E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
/* 115F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
/* Modi */
- /* 11600 */ IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B,
+ /* 11600 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11610 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11620 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11630 */ VPst, VPst, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPst, VPst, VMAbv, VMPst, H,
@@ -583,7 +599,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* Takri */
- /* 11680 */ IV, IV, IV, IV, IV, IV, IV, IV, IV, IV, B, B, B, B, B, B,
+ /* 11680 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11690 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 116A0 */ B, B, B, B, B, B, B, B, B, B, B, VMAbv, VMPst, VAbv, VPre, VPst,
/* 116B0 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, CMBlw, O, O, O, O, O, O, O, O,
@@ -599,7 +615,28 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, O, O, O, O,
/* 11730 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O,
-}; /* Table items: 4816; occupancy: 72% */
+#define use_offset_0x11c00u 4960
+
+
+ /* Bhaiksuki */
+
+ /* 11C00 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
+ /* 11C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11C20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst,
+ /* 11C30 */ VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VBlw, O, VAbv, VAbv, VAbv, VAbv, VMAbv, VMAbv, VMPst, H,
+ /* 11C40 */ B, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
+ /* 11C50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11C60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O,
+
+ /* Marchen */
+
+ /* 11C70 */ O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11C80 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 11C90 */ O, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB,
+ /* 11CA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB,
+ /* 11CB0 */ VBlw, VPre, VBlw, VAbv, VPst, VMAbv, VMAbv, O,
+
+}; /* Table items: 5144; occupancy: 72% */
USE_TABLE_ELEMENT_TYPE
hb_use_get_categories (hb_codepoint_t u)
@@ -619,6 +656,7 @@ hb_use_get_categories (hb_codepoint_t u)
if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return use_table[u - 0x1900u + use_offset_0x1900u];
if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return use_table[u - 0x1B00u + use_offset_0x1b00u];
if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) return use_table[u - 0x1CD0u + use_offset_0x1cd0u];
+ if (hb_in_range (u, 0x1DF8u, 0x1DFFu)) return use_table[u - 0x1DF8u + use_offset_0x1df8u];
break;
case 0x2u:
@@ -642,10 +680,11 @@ hb_use_get_categories (hb_codepoint_t u)
case 0x11u:
if (hb_in_range (u, 0x11000u, 0x110BFu)) return use_table[u - 0x11000u + use_offset_0x11000u];
- if (hb_in_range (u, 0x11100u, 0x11237u)) return use_table[u - 0x11100u + use_offset_0x11100u];
+ if (hb_in_range (u, 0x11100u, 0x1123Fu)) return use_table[u - 0x11100u + use_offset_0x11100u];
if (hb_in_range (u, 0x11280u, 0x11377u)) return use_table[u - 0x11280u + use_offset_0x11280u];
- if (hb_in_range (u, 0x11480u, 0x114DFu)) return use_table[u - 0x11480u + use_offset_0x11480u];
+ if (hb_in_range (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u];
if (hb_in_range (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u];
+ if (hb_in_range (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u];
if (unlikely (u == 0x1107Fu)) return HN;
break;
@@ -662,7 +701,6 @@ hb_use_get_categories (hb_codepoint_t u)
#undef H
#undef HN
#undef IND
-#undef IV
#undef N
#undef O
#undef R
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
index 779a9cb1d0..5b19d5d74a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
@@ -184,6 +184,9 @@ has_arabic_joining (hb_script_t script)
case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_PSALTER_PAHLAVI:
+ /* Unicode-9.0 additions */
+ case HB_SCRIPT_ADLAM:
+
return true;
default:
@@ -227,12 +230,12 @@ data_destroy_use (void *data)
enum syllable_type_t {
independent_cluster,
virama_terminated_cluster,
- consonant_cluster,
- vowel_cluster,
+ standard_cluster,
number_joiner_terminated_cluster,
numeral_cluster,
symbol_cluster,
broken_cluster,
+ non_cluster,
};
#include "hb-ot-shape-complex-use-machine.hh"
@@ -285,6 +288,9 @@ static void
setup_topographical_masks (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer)
{
+ const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
+ if (use_plan->arabic_plan)
+ return;
ASSERT_STATIC (INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4);
hb_mask_t masks[4], all_masks = 0;
@@ -309,13 +315,13 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan,
{
case independent_cluster:
case symbol_cluster:
+ case non_cluster:
/* These don't join. Nothing to do. */
last_form = _NONE;
break;
case virama_terminated_cluster:
- case consonant_cluster:
- case vowel_cluster:
+ case standard_cluster:
case number_joiner_terminated_cluster:
case numeral_cluster:
case broken_cluster:
@@ -360,7 +366,7 @@ clear_substitution_flags (const hb_ot_shape_plan_t *plan,
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
- _hb_glyph_info_clear_substituted_and_ligated_and_multiplied (&info[i]);
+ _hb_glyph_info_clear_substituted (&info[i]);
}
static void
@@ -405,6 +411,12 @@ record_pref (const hb_ot_shape_plan_t *plan,
}
}
+static inline bool
+is_halant (const hb_glyph_info_t &info)
+{
+ return info.use_category() == USE_H && !_hb_glyph_info_ligated (&info);
+}
+
static void
reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
{
@@ -412,28 +424,26 @@ reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
/* Only a few syllable types need reordering. */
if (unlikely (!(FLAG_SAFE (syllable_type) &
(FLAG (virama_terminated_cluster) |
- FLAG (consonant_cluster) |
- FLAG (vowel_cluster) |
+ FLAG (standard_cluster) |
FLAG (broken_cluster) |
0))))
return;
hb_glyph_info_t *info = buffer->info;
-#define HALANT_FLAGS FLAG(USE_H)
-#define BASE_FLAGS (FLAG (USE_B) | FLAG (USE_GB) | FLAG (USE_IV))
+#define BASE_FLAGS (FLAG (USE_B) | FLAG (USE_GB))
/* Move things forward. */
if (info[start].use_category() == USE_R && end - start > 1)
{
/* Got a repha. Reorder it to after first base, before first halant. */
for (unsigned int i = start + 1; i < end; i++)
- if (FLAG_UNSAFE (info[i].use_category()) & (HALANT_FLAGS | BASE_FLAGS))
+ if ((FLAG_UNSAFE (info[i].use_category()) & (BASE_FLAGS)) || is_halant (info[i]))
{
/* If we hit a halant, move before it; otherwise it's a base: move to it's
* place, and shift things in between backward. */
- if (info[i].use_category() == USE_H)
+ if (is_halant (info[i]))
i--;
buffer->merge_clusters (start, i + 1);
@@ -450,11 +460,11 @@ reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end)
for (unsigned int i = start; i < end; i++)
{
uint32_t flag = FLAG_UNSAFE (info[i].use_category());
- if (flag & (HALANT_FLAGS | BASE_FLAGS))
+ if ((flag & (BASE_FLAGS)) || is_halant (info[i]))
{
- /* If we hit a halant, move before it; otherwise it's a base: move to it's
+ /* If we hit a halant, move after it; otherwise it's a base: move to it's
* place, and shift things in between backward. */
- if (info[i].use_category() == USE_H)
+ if (is_halant (info[i]))
j = i + 1;
else
j = i;
@@ -490,22 +500,16 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
if (likely (!has_broken_syllables))
return;
-
- hb_codepoint_t dottedcircle_glyph;
- if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
- return;
-
hb_glyph_info_t dottedcircle = {0};
- if (!font->get_glyph (0x25CCu, 0, &dottedcircle.codepoint))
+ if (!font->get_nominal_glyph (0x25CCu, &dottedcircle.codepoint))
return;
dottedcircle.use_category() = hb_use_get_categories (0x25CC);
buffer->clear_output ();
buffer->idx = 0;
-
unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len)
+ while (buffer->idx < buffer->len && !buffer->in_error)
{
unsigned int syllable = buffer->cur().syllable();
syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
@@ -520,7 +524,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* TODO Set glyph_props? */
/* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len &&
+ while (buffer->idx < buffer->len && !buffer->in_error &&
last_syllable == buffer->cur().syllable() &&
buffer->cur().use_category() == USE_R)
buffer->next_glyph ();
@@ -555,6 +559,47 @@ reorder (const hb_ot_shape_plan_t *plan,
}
static bool
+decompose_use (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t ab,
+ hb_codepoint_t *a,
+ hb_codepoint_t *b)
+{
+ switch (ab)
+ {
+ /* Chakma:
+ * Special case where the Unicode decomp gives matras in the wrong order
+ * for cluster validation.
+ */
+ case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true;
+ case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true;
+
+ /*
+ * Decompose split matras that don't have Unicode decompositions.
+ */
+
+ /* Limbu */
+ case 0x1925u : *a = 0x1920u; *b= 0x1923u; return true;
+ case 0x1926u : *a = 0x1920u; *b= 0x1924u; return true;
+
+ /* Balinese */
+ case 0x1B3Cu : *a = 0x1B42u; *b= 0x1B3Cu; return true;
+
+#if 0
+ /* Lepcha */
+ case 0x1C29u : *a = no decomp, -> LEFT; return true;
+
+ /* Javanese */
+ case 0xA9C0u : *a = no decomp, -> RIGHT; return true;
+
+ /* Sharada */
+ case 0x111BFu : *a = no decomp, -> ABOVE; return true;
+#endif
+ }
+
+ return (bool) c->unicode->decompose (ab, a, b);
+}
+
+static bool
compose_use (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
@@ -564,7 +609,7 @@ compose_use (const hb_ot_shape_normalize_context_t *c,
if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
return false;
- return c->unicode->compose (a, b, ab);
+ return (bool)c->unicode->compose (a, b, ab);
}
@@ -576,10 +621,12 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
data_create_use,
data_destroy_use,
NULL, /* preprocess_text */
+ NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
- NULL, /* decompose */
+ decompose_use,
compose_use,
setup_masks_use,
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+ NULL, /* disable_otl */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
false, /* fallback_position */
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback-private.hh
index ec653513f1..e134224df9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback-private.hh
@@ -45,5 +45,9 @@ HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
+HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
#endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc
index 3cb3456f1a..ea8312b223 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-fallback.cc
@@ -484,3 +484,70 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
idx = skippy_iter.idx;
}
}
+
+
+/* Adjusts width of various spaces. */
+void
+_hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+ return;
+
+ hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pos = buffer->pos;
+ unsigned int count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
+ if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i]))
+ {
+ hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]);
+ hb_codepoint_t glyph;
+ typedef hb_unicode_funcs_t t;
+ switch (space_type)
+ {
+ case t::NOT_SPACE: /* Shouldn't happen. */
+ case t::SPACE:
+ break;
+
+ case t::SPACE_EM:
+ case t::SPACE_EM_2:
+ case t::SPACE_EM_3:
+ case t::SPACE_EM_4:
+ case t::SPACE_EM_5:
+ case t::SPACE_EM_6:
+ case t::SPACE_EM_16:
+ pos[i].x_advance = (font->x_scale + ((int) space_type)/2) / (int) space_type;
+ break;
+
+ case t::SPACE_4_EM_18:
+ pos[i].x_advance = font->x_scale * 4 / 18;
+ break;
+
+ case t::SPACE_FIGURE:
+ for (char u = '0'; u <= '9'; u++)
+ if (font->get_nominal_glyph (u, &glyph))
+ {
+ pos[i].x_advance = font->get_glyph_h_advance (glyph);
+ break;
+ }
+ break;
+
+ case t::SPACE_PUNCTUATION:
+ if (font->get_nominal_glyph ('.', &glyph))
+ pos[i].x_advance = font->get_glyph_h_advance (glyph);
+ else if (font->get_nominal_glyph (',', &glyph))
+ pos[i].x_advance = font->get_glyph_h_advance (glyph);
+ break;
+
+ case t::SPACE_NARROW:
+ /* Half-space?
+ * Unicode doc http://www.unicode.org/charts/PDF/U2000.pdf says ~1/4 or 1/5 of EM.
+ * However, in my testing, many fonts have their regular space being about that
+ * size. To me, a percentage of the space width makes more sense. Half is as
+ * good as any. */
+ pos[i].x_advance /= 2;
+ break;
+ }
+ }
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc
index 0a4d40499f..107617e81c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc
@@ -76,7 +76,7 @@ decompose_unicode (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t *a,
hb_codepoint_t *b)
{
- return c->unicode->decompose (ab, a, b);
+ return (bool) c->unicode->decompose (ab, a, b);
}
static bool
@@ -85,21 +85,21 @@ compose_unicode (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
- return c->unicode->compose (a, b, ab);
+ return (bool) c->unicode->compose (a, b, ab);
}
static inline void
set_glyph (hb_glyph_info_t &info, hb_font_t *font)
{
- font->get_glyph (info.codepoint, 0, &info.glyph_index());
+ font->get_nominal_glyph (info.codepoint, &info.glyph_index());
}
static inline void
output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
{
buffer->cur().glyph_index() = glyph;
- buffer->output_glyph (unichar);
- _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
+ buffer->output_glyph (unichar); /* This is very confusing indeed. */
+ _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer);
}
static inline void
@@ -124,10 +124,10 @@ decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint
hb_font_t * const font = c->font;
if (!c->decompose (c, ab, &a, &b) ||
- (b && !font->get_glyph (b, 0, &b_glyph)))
+ (b && !font->get_nominal_glyph (b, &b_glyph)))
return 0;
- bool has_a = font->get_glyph (a, 0, &a_glyph);
+ bool has_a = (bool) font->get_nominal_glyph (a, &a_glyph);
if (shortest && has_a) {
/* Output a and b */
output_char (buffer, a, a_glyph);
@@ -166,15 +166,50 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
hb_codepoint_t u = buffer->cur().codepoint;
hb_codepoint_t glyph;
- /* Kind of a cute waterfall here... */
- if (shortest && c->font->get_glyph (u, 0, &glyph))
+ if (shortest && c->font->get_nominal_glyph (u, &glyph))
+ {
next_char (buffer, glyph);
- else if (decompose (c, shortest, u))
+ return;
+ }
+
+ if (decompose (c, shortest, u))
+ {
skip_char (buffer);
- else if (!shortest && c->font->get_glyph (u, 0, &glyph))
+ return;
+ }
+
+ if (!shortest && c->font->get_nominal_glyph (u, &glyph))
+ {
next_char (buffer, glyph);
- else
- next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
+ return;
+ }
+
+ if (_hb_glyph_info_is_unicode_space (&buffer->cur()))
+ {
+ hb_codepoint_t space_glyph;
+ hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u);
+ if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_nominal_glyph (0x0020u, &space_glyph))
+ {
+ _hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type);
+ next_char (buffer, space_glyph);
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK;
+ return;
+ }
+ }
+
+ if (u == 0x2011u)
+ {
+ /* U+2011 is the only sensible character that is a no-break version of another character
+ * and not a space. The space ones are handled already. Handle this lone one. */
+ hb_codepoint_t other_glyph;
+ if (c->font->get_nominal_glyph (0x2010u, &other_glyph))
+ {
+ next_char (buffer, other_glyph);
+ return;
+ }
+ }
+
+ next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
}
static inline void
@@ -183,10 +218,10 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, uns
/* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
hb_buffer_t * const buffer = c->buffer;
hb_font_t * const font = c->font;
- for (; buffer->idx < end - 1;) {
+ for (; buffer->idx < end - 1 && !buffer->in_error;) {
if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
/* The next two lines are some ugly lines... But work. */
- if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+ if (font->get_variation_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
{
buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
}
@@ -219,13 +254,13 @@ static inline void
decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
{
hb_buffer_t * const buffer = c->buffer;
- for (unsigned int i = buffer->idx; i < end; i++)
+ for (unsigned int i = buffer->idx; i < end && !buffer->in_error; i++)
if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
handle_variation_selector_cluster (c, end, short_circuit);
return;
}
- while (buffer->idx < end)
+ while (buffer->idx < end && !buffer->in_error)
decompose_current_character (c, short_circuit);
}
@@ -285,7 +320,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
buffer->clear_output ();
count = buffer->len;
- for (buffer->idx = 0; buffer->idx < count;)
+ for (buffer->idx = 0; buffer->idx < count && !buffer->in_error;)
{
unsigned int end;
for (end = buffer->idx + 1; end < count; end++)
@@ -335,7 +370,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
count = buffer->len;
unsigned int starter = 0;
buffer->next_glyph ();
- while (buffer->idx < count)
+ while (buffer->idx < count && !buffer->in_error)
{
hb_codepoint_t composed, glyph;
if (/* We don't try to compose a non-mark character with it's preceding starter.
@@ -353,7 +388,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
buffer->cur().codepoint,
&composed) &&
/* And the font has glyph for the composite. */
- font->get_glyph (composed, 0, &glyph))
+ font->get_nominal_glyph (composed, &glyph))
{
/* Composes. */
buffer->next_glyph (); /* Copy to out-buffer. */
@@ -364,7 +399,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
/* Modify starter and carry on. */
buffer->out_info[starter].codepoint = composed;
buffer->out_info[starter].glyph_index() = glyph;
- _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
+ _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
continue;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-private.hh
index 54ac2c3cf7..594e54c026 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-private.hh
@@ -77,11 +77,13 @@ struct hb_ot_shape_planner_t
map (face, &props) {}
~hb_ot_shape_planner_t (void) { map.finish (); }
- inline void compile (hb_ot_shape_plan_t &plan)
+ inline void compile (hb_ot_shape_plan_t &plan,
+ const int *coords,
+ unsigned int num_coords)
{
plan.props = props;
plan.shaper = shaper;
- map.compile (plan.map);
+ map.compile (plan.map, coords, num_coords);
plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
index 40332d69f1..ddd6662e84 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
@@ -69,6 +69,9 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
{
hb_ot_map_builder_t *map = &planner->map;
+ map->add_global_bool_feature (HB_TAG('r','v','r','n'));
+ map->add_gsub_pause (NULL);
+
switch (props->direction) {
case HB_DIRECTION_LTR:
map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
@@ -145,7 +148,7 @@ _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
struct hb_ot_shaper_font_data_t {};
hb_ot_shaper_font_data_t *
-_hb_ot_shaper_font_data_create (hb_font_t *font)
+_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
{
return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
@@ -163,7 +166,9 @@ _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
hb_ot_shaper_shape_plan_data_t *
_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
const hb_feature_t *user_features,
- unsigned int num_user_features)
+ unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords)
{
hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
if (unlikely (!plan))
@@ -173,9 +178,10 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
planner.shaper = hb_ot_shape_complex_categorize (&planner);
- hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
+ hb_ot_shape_collect_features (&planner, &shape_plan->props,
+ user_features, num_user_features);
- planner.compile (*plan);
+ planner.compile (*plan, coords, num_coords);
if (plan->shaper->data_create) {
plan->data = plan->shaper->data_create (plan);
@@ -212,6 +218,8 @@ struct hb_ot_shape_context_t
unsigned int num_user_features;
/* Transient stuff */
+ bool fallback_positioning;
+ bool fallback_glyph_classes;
hb_direction_t target_direction;
};
@@ -228,7 +236,7 @@ hb_set_unicode_props (hb_buffer_t *buffer)
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
- _hb_glyph_info_set_unicode_props (&info[i], buffer->unicode);
+ _hb_glyph_info_set_unicode_props (&info[i], buffer);
}
static void
@@ -245,7 +253,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
hb_glyph_info_t dottedcircle = {0};
dottedcircle.codepoint = 0x25CCu;
- _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
+ _hb_glyph_info_set_unicode_props (&dottedcircle, buffer);
buffer->clear_output ();
@@ -254,7 +262,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
info.cluster = buffer->cur().cluster;
info.mask = buffer->cur().mask;
buffer->output_info (info);
- while (buffer->idx < buffer->len)
+ while (buffer->idx < buffer->len && !buffer->in_error)
buffer->next_glyph ();
buffer->swap_buffers ();
@@ -263,16 +271,18 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
static void
hb_form_clusters (hb_buffer_t *buffer)
{
- if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
+ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
+ buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
return;
- /* Loop duplicated in hb_ensure_native_direction(). */
+ /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
unsigned int base = 0;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 1; i < count; i++)
{
- if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
+ if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
+ !_hb_glyph_info_is_joiner (&info[i])))
{
buffer->merge_clusters (base, i);
base = i;
@@ -346,7 +356,8 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c)
static inline void
hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
{
- if (!c->plan->has_frac)
+ if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
+ !c->plan->has_frac)
return;
hb_buffer_t *buffer = c->buffer;
@@ -416,7 +427,8 @@ hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
- if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
+ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
+ (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
return;
unsigned int count = buffer->len;
@@ -433,7 +445,8 @@ hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
- if (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
+ if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES) ||
+ (buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES))
return;
unsigned int count = buffer->len;
@@ -451,7 +464,7 @@ hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
return;
hb_codepoint_t space;
- if (c->font->get_glyph (' ', 0, &space))
+ if (c->font->get_nominal_glyph (' ', &space))
{
/* Replace default-ignorables with a zero-advance space glyph. */
for (/*continue*/; i < count; i++)
@@ -525,7 +538,7 @@ hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
hb_glyph_info_t *info = c->buffer->info;
for (unsigned int i = 0; i < count; i++)
{
- hb_ot_layout_glyph_class_mask_t klass;
+ hb_ot_layout_glyph_props_flags_t klass;
/* Never mark default-ignorables as marks.
* They won't get in the way of lookups anyway,
@@ -549,9 +562,6 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
- if (c->plan->shaper->preprocess_text)
- c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
-
hb_ot_shape_initialize_masks (c);
hb_ot_mirror_chars (c);
@@ -563,7 +573,7 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
hb_ot_shape_setup_masks (c);
/* This is unfortunate to go here, but necessary... */
- if (!hb_ot_layout_has_positioning (c->face))
+ if (c->fallback_positioning)
_hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
hb_ot_map_glyphs_fast (buffer);
@@ -576,7 +586,6 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
- _hb_buffer_allocate_gsubgpos_vars (buffer);
hb_ot_layout_substitute_start (c->font, buffer);
if (!hb_ot_layout_has_glyph_classes (c->face))
@@ -584,8 +593,6 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
c->plan->substitute (c->font, buffer);
- hb_ot_layout_substitute_finish (c->font, buffer);
-
return;
}
@@ -593,6 +600,9 @@ static inline void
hb_ot_substitute (hb_ot_shape_context_t *c)
{
hb_ot_substitute_default (c);
+
+ _hb_buffer_allocate_gsubgpos_vars (c->buffer);
+
hb_ot_substitute_complex (c);
}
@@ -613,20 +623,6 @@ zero_mark_width (hb_glyph_position_t *pos)
}
static inline void
-zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
-{
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 0; i < count; i++)
- if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
- {
- if (adjust_offsets)
- adjust_mark_offsets (&buffer->pos[i]);
- zero_mark_width (&buffer->pos[i]);
- }
-}
-
-static inline void
zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
{
unsigned int count = buffer->len;
@@ -647,26 +643,39 @@ hb_ot_position_default (hb_ot_shape_context_t *c)
unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
hb_glyph_position_t *pos = c->buffer->pos;
- for (unsigned int i = 0; i < count; i++)
- {
- c->font->get_glyph_advance_for_direction (info[i].codepoint,
- direction,
- &pos[i].x_advance,
- &pos[i].y_advance);
- c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
- direction,
- &pos[i].x_offset,
- &pos[i].y_offset);
+ if (HB_DIRECTION_IS_HORIZONTAL (direction))
+ {
+ for (unsigned int i = 0; i < count; i++)
+ pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
+ /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
+ if (c->font->has_glyph_h_origin_func ())
+ for (unsigned int i = 0; i < count; i++)
+ c->font->subtract_glyph_h_origin (info[i].codepoint,
+ &pos[i].x_offset,
+ &pos[i].y_offset);
}
+ else
+ {
+ for (unsigned int i = 0; i < count; i++)
+ {
+ pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
+ c->font->subtract_glyph_v_origin (info[i].codepoint,
+ &pos[i].x_offset,
+ &pos[i].y_offset);
+ }
+ }
+ if (c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK)
+ _hb_ot_shape_fallback_spaces (c->plan, c->font, c->buffer);
}
-static inline bool
+static inline void
hb_ot_position_complex (hb_ot_shape_context_t *c)
{
- bool ret = false;
+ hb_ot_layout_position_start (c->font, c->buffer);
+
unsigned int count = c->buffer->len;
- bool has_positioning = hb_ot_layout_has_positioning (c->face);
+
/* If the font has no GPOS, AND, no fallback positioning will
* happen, AND, direction is forward, then when zeroing mark
* widths, we shift the mark with it, such that the mark
@@ -676,8 +685,9 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
* If fallback positinoing happens or GPOS is present, we don't
* care.
*/
- bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
- HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
+ bool adjust_offsets_when_zeroing = c->fallback_positioning &&
+ !c->plan->shaper->fallback_position &&
+ HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
switch (c->plan->shaper->zero_width_marks)
{
@@ -685,79 +695,65 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
break;
- /* Not currently used for any shaper:
- case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
- zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
- break;
- */
-
default:
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
- case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
break;
}
- if (has_positioning)
+ if (likely (!c->fallback_positioning))
{
hb_glyph_info_t *info = c->buffer->info;
hb_glyph_position_t *pos = c->buffer->pos;
- /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
+ /* Change glyph origin to what GPOS expects (horizontal), apply GPOS, change it back. */
- for (unsigned int i = 0; i < count; i++) {
- c->font->add_glyph_origin_for_direction (info[i].codepoint,
- HB_DIRECTION_LTR,
- &pos[i].x_offset,
- &pos[i].y_offset);
- }
+ /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
+ if (c->font->has_glyph_h_origin_func ())
+ for (unsigned int i = 0; i < count; i++)
+ c->font->add_glyph_h_origin (info[i].codepoint,
+ &pos[i].x_offset,
+ &pos[i].y_offset);
c->plan->position (c->font, c->buffer);
- for (unsigned int i = 0; i < count; i++) {
- c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
- HB_DIRECTION_LTR,
- &pos[i].x_offset,
- &pos[i].y_offset);
- }
+ /* The nil glyph_h_origin() func returns 0, so no need to apply it. */
+ if (c->font->has_glyph_h_origin_func ())
+ for (unsigned int i = 0; i < count; i++)
+ c->font->subtract_glyph_h_origin (info[i].codepoint,
+ &pos[i].x_offset,
+ &pos[i].y_offset);
- ret = true;
}
switch (c->plan->shaper->zero_width_marks)
{
- case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
- zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
- break;
-
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
break;
default:
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
- //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
break;
}
- return ret;
+ /* Finishing off GPOS has to follow a certain order. */
+ hb_ot_layout_position_finish_advances (c->font, c->buffer);
+ hb_ot_zero_width_default_ignorables (c);
+ hb_ot_layout_position_finish_offsets (c->font, c->buffer);
}
static inline void
hb_ot_position (hb_ot_shape_context_t *c)
{
- hb_ot_layout_position_start (c->font, c->buffer);
+ c->buffer->clear_positions ();
hb_ot_position_default (c);
- hb_bool_t fallback = !hb_ot_position_complex (c);
-
- hb_ot_zero_width_default_ignorables (c);
-
- hb_ot_layout_position_finish (c->font, c->buffer);
+ hb_ot_position_complex (c);
- if (fallback && c->plan->shaper->fallback_position)
+ if (c->fallback_positioning && c->plan->shaper->fallback_position)
_hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
@@ -765,7 +761,7 @@ hb_ot_position (hb_ot_shape_context_t *c)
/* Visual fallback goes here. */
- if (fallback)
+ if (c->fallback_positioning)
_hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
_hb_buffer_deallocate_gsubgpos_vars (c->buffer);
@@ -778,6 +774,17 @@ static void
hb_ot_shape_internal (hb_ot_shape_context_t *c)
{
c->buffer->deallocate_var_all ();
+ c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
+ if (likely (!_hb_unsigned_int_mul_overflows (c->buffer->len, HB_BUFFER_MAX_EXPANSION_FACTOR)))
+ {
+ c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_EXPANSION_FACTOR,
+ (unsigned) HB_BUFFER_MAX_LEN_MIN);
+ }
+
+ bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan);
+ //c->fallback_substitute = disable_otl || !hb_ot_layout_has_substitution (c->face);
+ c->fallback_positioning = disable_otl || !hb_ot_layout_has_positioning (c->face);
+ c->fallback_glyph_classes = disable_otl || !hb_ot_layout_has_glyph_classes (c->face);
/* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction;
@@ -792,15 +799,22 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
hb_ensure_native_direction (c->buffer);
+ if (c->plan->shaper->preprocess_text)
+ c->plan->shaper->preprocess_text (c->plan, c->buffer, c->font);
+
hb_ot_substitute (c);
hb_ot_position (c);
hb_ot_hide_default_ignorables (c);
+ if (c->plan->shaper->postprocess_glyphs)
+ c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font);
+
_hb_buffer_deallocate_unicode_vars (c->buffer);
c->buffer->props.direction = c->target_direction;
+ c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
c->buffer->deallocate_var_all ();
}
@@ -820,6 +834,8 @@ _hb_ot_shape (hb_shape_plan_t *shape_plan,
/**
+ * hb_ot_shape_plan_collect_lookups:
+ *
* Since: 0.9.7
**/
void
@@ -841,18 +857,20 @@ add_char (hb_font_t *font,
hb_set_t *glyphs)
{
hb_codepoint_t glyph;
- if (font->get_glyph (u, 0, &glyph))
+ if (font->get_nominal_glyph (u, &glyph))
glyphs->add (glyph);
if (mirror)
{
hb_codepoint_t m = unicode->mirroring (u);
- if (m != u && font->get_glyph (m, 0, &glyph))
+ if (m != u && font->get_nominal_glyph (m, &glyph))
glyphs->add (glyph);
}
}
/**
+ * hb_ot_shape_glyphs_closure:
+ *
* Since: 0.9.2
**/
void
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h
index 1402f54acc..7b1bcc0637 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.h
@@ -36,14 +36,14 @@
HB_BEGIN_DECLS
/* TODO port to shape-plan / set. */
-void
+HB_EXTERN void
hb_ot_shape_glyphs_closure (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
hb_set_t *glyphs);
-void
+HB_EXTERN void
hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
hb_tag_t table_tag,
hb_set_t *lookup_indexes /* OUT */);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
index a2e5728fcd..5f21ac0967 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
@@ -186,14 +186,18 @@ static const LangTag ot_languages[] = {
{"aa", HB_TAG('A','F','R',' ')}, /* Afar */
{"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */
{"abq", HB_TAG('A','B','A',' ')}, /* Abaza */
+ {"acf", HB_TAG('F','A','N',' ')}, /* French Antillean */
{"ach", HB_TAG('A','C','H',' ')}, /* Acoli */
+ {"acr", HB_TAG('A','C','R',' ')}, /* Achi */
{"ada", HB_TAG('D','N','G',' ')}, /* Dangme */
{"ady", HB_TAG('A','D','Y',' ')}, /* Adyghe */
{"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */
+ {"ahg", HB_TAG('A','G','W',' ')}, /* Agaw */
{"aii", HB_TAG('S','W','A',' ')}, /* Swadaya Aramaic */
{"aio", HB_TAG('A','I','O',' ')}, /* Aiton */
{"aiw", HB_TAG('A','R','I',' ')}, /* Aari */
{"ak", HB_TAG('T','W','I',' ')}, /* Akan [macrolanguage] */
+ {"aka", HB_TAG('A','K','A',' ')}, /* Akan */
{"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */
{"am", HB_TAG('A','M','H',' ')}, /* Amharic */
{"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */
@@ -206,6 +210,7 @@ static const LangTag ot_languages[] = {
{"as", HB_TAG('A','S','M',' ')}, /* Assamese */
{"ast", HB_TAG('A','S','T',' ')}, /* Asturian/Asturleonese/Bable/Leonese */
{"ath", HB_TAG('A','T','H',' ')}, /* Athapaskan [family] */
+ {"atj", HB_TAG('R','C','R',' ')}, /* R-Cree */
{"atv", HB_TAG('A','L','T',' ')}, /* [Northern] Altai */
{"av", HB_TAG('A','V','R',' ')}, /* Avaric */
{"awa", HB_TAG('A','W','A',' ')}, /* Awadhi */
@@ -214,6 +219,7 @@ static const LangTag ot_languages[] = {
{"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani */
{"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani */
{"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */
+ {"bad", HB_TAG('B','A','D','0')}, /* Banda */
{"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */
{"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolangauge] */
{"ban", HB_TAG('B','A','N',' ')}, /* Balinese */
@@ -222,11 +228,13 @@ static const LangTag ot_languages[] = {
{"bci", HB_TAG('B','A','U',' ')}, /* Baoulé */
{"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol */
{"bcq", HB_TAG('B','C','H',' ')}, /* Bench */
+ {"bdy", HB_TAG('B','D','Y',' ')}, /* Bandjalang */
{"be", HB_TAG('B','E','L',' ')}, /* Belarusian */
{"bem", HB_TAG('B','E','M',' ')}, /* Bemba (Zambia) */
{"ber", HB_TAG('B','E','R',' ')}, /* Berber [family] */
{"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */
{"bft", HB_TAG('B','L','T',' ')}, /* Balti */
+ {"bfu", HB_TAG('L','A','H',' ')}, /* Lahuli */
{"bfy", HB_TAG('B','A','G',' ')}, /* Baghelkhandi */
{"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */
{"bgc", HB_TAG('B','G','C',' ')}, /* Haryanvi */
@@ -260,11 +268,13 @@ static const LangTag ot_languages[] = {
{"bxr", HB_TAG('R','B','U',' ')}, /* Russian Buriat */
{"byn", HB_TAG('B','I','L',' ')}, /* Bilen */
{"ca", HB_TAG('C','A','T',' ')}, /* Catalan */
+ {"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */
{"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano */
{"ce", HB_TAG('C','H','E',' ')}, /* Chechen */
{"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */
{"cgg", HB_TAG('C','G','G',' ')}, /* Chiga */
{"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */
+ {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */
{"cho", HB_TAG('C','H','O',' ')}, /* Choctaw */
{"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */
{"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */
@@ -272,9 +282,12 @@ static const LangTag ot_languages[] = {
{"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish (Sorani) */
{"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */
{"cop", HB_TAG('C','O','P',' ')}, /* Coptic */
+ {"cpp", HB_TAG('C','P','P',' ')}, /* Creoles */
{"cr", HB_TAG('C','R','E',' ')}, /* Cree */
+ {"cre", HB_TAG('Y','C','R',' ')}, /* Y-Cree */
{"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */
{"crj", HB_TAG('E','C','R',' ')}, /* [Southern] East Cree */
+ {"crk", HB_TAG('W','C','R',' ')}, /* West-Cree */
{"crl", HB_TAG('E','C','R',' ')}, /* [Northern] East Cree */
{"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */
{"crx", HB_TAG('C','R','R',' ')}, /* Carrier */
@@ -283,21 +296,27 @@ static const LangTag ot_languages[] = {
{"ctg", HB_TAG('C','T','G',' ')}, /* Chittagonian */
{"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol */
{"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */
+ {"cuk", HB_TAG('C','U','K',' ')}, /* San Blas Kuna */
{"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */
{"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */
{"cy", HB_TAG('W','E','L',' ')}, /* Welsh */
{"da", HB_TAG('D','A','N',' ')}, /* Danish */
{"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */
{"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */
+ {"dax", HB_TAG('D','A','X',' ')}, /* Dayi */
{"de", HB_TAG('D','E','U',' ')}, /* German */
{"dgo", HB_TAG('D','G','O',' ')}, /* Dogri */
{"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari */
+ {"dhg", HB_TAG('D','H','G',' ')}, /* Dhangu */
{"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */
{"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */
{"dje", HB_TAG('D','J','R',' ')}, /* Zarma */
+ {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */
{"dng", HB_TAG('D','U','N',' ')}, /* Dungan */
+ {"dnj", HB_TAG('D','N','J',' ')}, /* Dan */
{"doi", HB_TAG('D','G','R',' ')}, /* Dogri [macrolanguage] */
{"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */
+ {"duj", HB_TAG('D','U','J',' ')}, /* Dhuwal */
{"dv", HB_TAG('D','I','V',' ')}, /* Dhivehi/Divehi/Maldivian */
{"dyu", HB_TAG('J','U','L',' ')}, /* Jula */
{"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */
@@ -307,23 +326,30 @@ static const LangTag ot_languages[] = {
{"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) */
{"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan */
{"en", HB_TAG('E','N','G',' ')}, /* English */
+ {"enf", HB_TAG('F','N','E',' ')}, /* Forest Nenets */
+ {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Nenets */
{"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */
{"eot", HB_TAG('B','T','I',' ')}, /* Beti (Côte d'Ivoire) */
{"es", HB_TAG('E','S','P',' ')}, /* Spanish */
+ {"esu", HB_TAG('E','S','U',' ')}, /* Central Yupik */
{"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */
{"eu", HB_TAG('E','U','Q',' ')}, /* Basque */
{"eve", HB_TAG('E','V','N',' ')}, /* Even */
{"evn", HB_TAG('E','V','K',' ')}, /* Evenki */
{"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */
+ {"fan", HB_TAG('F','A','N','0')}, /* Fang */
+ {"fat", HB_TAG('F','A','T',' ')}, /* Fanti */
{"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */
{"fi", HB_TAG('F','I','N',' ')}, /* Finnish */
{"fil", HB_TAG('P','I','L',' ')}, /* Filipino */
{"fj", HB_TAG('F','J','I',' ')}, /* Fijian */
+ {"flm", HB_TAG('H','A','L',' ')}, /* Halam */
{"fo", HB_TAG('F','O','S',' ')}, /* Faroese */
{"fon", HB_TAG('F','O','N',' ')}, /* Fon */
{"fr", HB_TAG('F','R','A',' ')}, /* French */
{"frc", HB_TAG('F','R','C',' ')}, /* Cajun French */
{"frp", HB_TAG('F','R','P',' ')}, /* Arpitan/Francoprovençal */
+ {"fuf", HB_TAG('F','T','A',' ')}, /* Futa */
{"fur", HB_TAG('F','R','L',' ')}, /* Friulian */
{"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */
{"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian */
@@ -334,17 +360,24 @@ static const LangTag ot_languages[] = {
{"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */
{"gez", HB_TAG('G','E','Z',' ')}, /* Ge'ez */
{"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi */
+ {"gih", HB_TAG('G','I','H',' ')}, /* Githabul */
+ {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */
+ {"gkp", HB_TAG('G','K','P',' ')}, /* Kpelle (Guinea) */
{"gl", HB_TAG('G','A','L',' ')}, /* Galician */
{"gld", HB_TAG('N','A','N',' ')}, /* Nanai */
+ {"gle", HB_TAG('I','R','T',' ')}, /* Irish Traditional */
{"glk", HB_TAG('G','L','K',' ')}, /* Gilaki */
{"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
+ {"gnn", HB_TAG('G','N','N',' ')}, /* Gumatj */
{"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi */
{"gog", HB_TAG('G','O','G',' ')}, /* Gogo */
{"gon", HB_TAG('G','O','N',' ')}, /* Gondi [macrolanguage] */
{"grt", HB_TAG('G','R','O',' ')}, /* Garo */
{"gru", HB_TAG('S','O','G',' ')}, /* Sodo Gurage */
+ {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */
{"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */
{"guc", HB_TAG('G','U','C',' ')}, /* Wayuu */
+ {"guf", HB_TAG('G','U','F',' ')}, /* Gupapuyngu */
{"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */
/*{"guk", HB_TAG('G','U','K',' ')},*/ /* Gumuz (in SIL fonts) */
{"guz", HB_TAG('G','U','Z',' ')}, /* Ekegusii/Gusii */
@@ -355,9 +388,9 @@ static const LangTag ot_languages[] = {
{"hay", HB_TAG('H','A','Y',' ')}, /* Haya */
{"haz", HB_TAG('H','A','Z',' ')}, /* Hazaragi */
{"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
- {"hz", HB_TAG('H','E','R',' ')}, /* Herero */
{"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
{"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */
+ {"hmn", HB_TAG('H','M','N',' ')}, /* Hmong */
{"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */
{"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */
{"hno", HB_TAG('H','N','D',' ')}, /* [Northern] Hindko */
@@ -371,11 +404,13 @@ static const LangTag ot_languages[] = {
{"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */
{"hz", HB_TAG('H','E','R',' ')}, /* Herero */
{"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */
+ {"iba", HB_TAG('I','B','A',' ')}, /* Iban */
{"ibb", HB_TAG('I','B','B',' ')}, /* Ibibio */
{"id", HB_TAG('I','N','D',' ')}, /* Indonesian */
{"ie", HB_TAG('I','L','E',' ')}, /* Interlingue/Occidental */
{"ig", HB_TAG('I','B','O',' ')}, /* Igbo */
{"igb", HB_TAG('E','B','I',' ')}, /* Ebira */
+ {"ii", HB_TAG('Y','I','M',' ')}, /* Yi Modern */
{"ijc", HB_TAG('I','J','O',' ')}, /* Izon */
{"ijo", HB_TAG('I','J','O',' ')}, /* Ijo [family] */
{"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] */
@@ -391,15 +426,20 @@ static const LangTag ot_languages[] = {
{"jv", HB_TAG('J','A','V',' ')}, /* Javanese */
{"ka", HB_TAG('K','A','T',' ')}, /* Georgian */
{"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */
- {"kab", HB_TAG('K','A','B',' ')}, /* Kabyle */
+ {"kab", HB_TAG('K','A','B','0')}, /* Kabyle */
{"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */
{"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */
+ {"kat", HB_TAG('K','G','E',' ')}, /* Khutsuri Georgian */
{"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */
{"kde", HB_TAG('K','D','E',' ')}, /* Makonde */
{"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */
{"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */
+ {"kea", HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */
+ {"kek", HB_TAG('K','E','K',' ')}, /* Kekchi */
{"kex", HB_TAG('K','K','N',' ')}, /* Kokni */
+ {"kfa", HB_TAG('K','O','D',' ')}, /* Kodagu */
{"kfr", HB_TAG('K','A','C',' ')}, /* Kachchi */
+ {"kfx", HB_TAG('K','U','L',' ')}, /* Kulvi */
{"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */
{"kg", HB_TAG('K','O','N',' ')}, /* Kongo [macrolanguage] */
{"kha", HB_TAG('K','S','I',' ')}, /* Khasi */
@@ -408,7 +448,9 @@ static const LangTag ot_languages[] = {
/*{"kht", HB_TAG('K','H','T',' ')},*/ /* Khamti (OpenType spec and SIL fonts) */
{"khw", HB_TAG('K','H','W',' ')}, /* Khowar */
{"ki", HB_TAG('K','I','K',' ')}, /* Gikuyu/Kikuyu */
+ {"kiu", HB_TAG('K','I','U',' ')}, /* Kirmanjki */
{"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama/Kwanyama */
+ {"kjd", HB_TAG('K','J','D',' ')}, /* Southern Kiwai */
{"kjh", HB_TAG('K','H','A',' ')}, /* Khakass */
{"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen */
{"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */
@@ -422,6 +464,8 @@ static const LangTag ot_languages[] = {
{"ko", HB_TAG('K','O','R',' ')}, /* Korean */
{"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */
{"kok", HB_TAG('K','O','K',' ')}, /* Konkani [macrolanguage] */
+ {"kon", HB_TAG('K','O','N','0')}, /* Kongo */
+ {"kos", HB_TAG('K','O','S',' ')}, /* Kosraean */
{"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */
{"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */
{"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */
@@ -431,9 +475,11 @@ static const LangTag ot_languages[] = {
{"krl", HB_TAG('K','R','L',' ')}, /* Karelian */
{"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */
{"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */
- {"ksh", HB_TAG('K','S','H',' ')}, /* Kölsch */
+ {"ksh", HB_TAG('K','S','H','0')}, /* Ripuarian, Kölsch */
/*{"ksw", HB_TAG('K','R','N',' ')},*/ /* S'gaw Karen (Microsoft fonts?) */
{"ksw", HB_TAG('K','S','W',' ')}, /* S'gaw Karen (OpenType spec and SIL fonts) */
+ {"ktb", HB_TAG('K','E','B',' ')}, /* Kebena */
+ {"ktu", HB_TAG('K','O','N',' ')}, /* Kikongo */
{"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */
{"kum", HB_TAG('K','U','M',' ')}, /* Kumyk */
{"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */
@@ -461,6 +507,7 @@ static const LangTag ot_languages[] = {
{"lmo", HB_TAG('L','M','O',' ')}, /* Lombard */
{"ln", HB_TAG('L','I','N',' ')}, /* Lingala */
{"lo", HB_TAG('L','A','O',' ')}, /* Lao */
+ {"lom", HB_TAG('L','O','M',' ')}, /* Loma */
{"lrc", HB_TAG('L','R','C',' ')}, /* Northern Luri */
{"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */
{"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */
@@ -475,6 +522,8 @@ static const LangTag ot_languages[] = {
{"mag", HB_TAG('M','A','G',' ')}, /* Magahi */
{"mai", HB_TAG('M','T','H',' ')}, /* Maithili */
{"mak", HB_TAG('M','K','R',' ')}, /* Makasar */
+ {"mal", HB_TAG('M','A','L',' ')}, /* Malayalam */
+ {"mam", HB_TAG('M','A','M',' ')}, /* Mam */
{"man", HB_TAG('M','N','K',' ')}, /* Manding/Mandingo [macrolanguage] */
{"mdc", HB_TAG('M','L','E',' ')}, /* Male (Papua New Guinea) */
{"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */
@@ -517,6 +566,7 @@ static const LangTag ot_languages[] = {
{"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */
{"my", HB_TAG('B','R','M',' ')}, /* Burmese */
{"mym", HB_TAG('M','E','N',' ')}, /* Me'en */
+ {"myn", HB_TAG('M','Y','N',' ')}, /* Mayan */
{"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) */
{"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */
{"mzn", HB_TAG('M','Z','N',' ')}, /* Mazanderani */
@@ -534,6 +584,7 @@ static const LangTag ot_languages[] = {
{"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */
{"nga", HB_TAG('N','G','A',' ')}, /* Ngabaka */
{"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */
+ {"ngo", HB_TAG('S','X','T',' ')}, /* Sutu */
{"niu", HB_TAG('N','I','U',' ')}, /* Niuean */
{"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */
{"nl", HB_TAG('N','L','D',' ')}, /* Dutch */
@@ -554,13 +605,15 @@ static const LangTag ot_languages[] = {
{"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */
{"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] */
{"ojs", HB_TAG('O','C','R',' ')}, /* Oji-Cree */
+ {"okm", HB_TAG('K','O','H',' ')}, /* Korean Old Hangul */
{"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */
{"or", HB_TAG('O','R','I',' ')}, /* Oriya */
{"os", HB_TAG('O','S','S',' ')}, /* Ossetian */
{"pa", HB_TAG('P','A','N',' ')}, /* Panjabi */
{"pag", HB_TAG('P','A','G',' ')}, /* Pangasinan */
{"pam", HB_TAG('P','A','M',' ')}, /* Kapampangan/Pampanga */
- {"pap", HB_TAG('P','A','P',' ')}, /* Papiamento */
+ {"pap", HB_TAG('P','A','P','0')}, /* Papiamento */
+ {"pau", HB_TAG('P','A','U',' ')}, /* Palauan */
{"pcc", HB_TAG('P','C','C',' ')}, /* Bouyei */
{"pcd", HB_TAG('P','C','D',' ')}, /* Picard */
{"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */
@@ -574,24 +627,34 @@ static const LangTag ot_languages[] = {
{"plp", HB_TAG('P','A','P',' ')}, /* Palpa */
{"pms", HB_TAG('P','M','S',' ')}, /* Piemontese */
{"pnb", HB_TAG('P','N','B',' ')}, /* Western Panjabi */
+ {"poh", HB_TAG('P','O','H',' ')}, /* Pocomchi */
+ {"pon", HB_TAG('P','O','N',' ')}, /* Pohnpeian */
{"prs", HB_TAG('D','R','I',' ')}, /* Afghan Persian/Dari */
{"ps", HB_TAG('P','A','S',' ')}, /* Pashto/Pushto [macrolanguage] */
{"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */
{"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen */
{"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */
{"quc", HB_TAG('Q','U','C',' ')}, /* K'iche'/Quiché */
+ {"quh", HB_TAG('Q','U','H',' ')}, /* Quechua (Bolivia) */
{"quz", HB_TAG('Q','U','Z',' ')}, /* Cusco Quechua */
+ {"qvi", HB_TAG('Q','V','I',' ')}, /* Quechua (Ecuador) */
+ {"qwh", HB_TAG('Q','W','H',' ')}, /* Quechua (Peru) */
{"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani [macrolanguage] */
+ {"rar", HB_TAG('R','A','R',' ')}, /* Rarotongan */
{"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung */
{"rej", HB_TAG('R','E','J',' ')}, /* Rejang */
{"ria", HB_TAG('R','I','A',' ')}, /* Riang (India) */
+ {"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */
{"ril", HB_TAG('R','I','A',' ')}, /* Riang (Myanmar) */
+ {"rit", HB_TAG('R','I','T',' ')}, /* Ritarungo */
{"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */
+ {"rkw", HB_TAG('R','K','W',' ')}, /* Arakwal */
{"rm", HB_TAG('R','M','S',' ')}, /* Romansh */
{"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */
{"rn", HB_TAG('R','U','N',' ')}, /* Rundi */
{"ro", HB_TAG('R','O','M',' ')}, /* Romanian */
{"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */
+ {"rtm", HB_TAG('R','T','M',' ')}, /* Rotuman */
{"ru", HB_TAG('R','U','S',' ')}, /* Russian */
{"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */
{"rup", HB_TAG('R','U','P',' ')}, /* Aromanian/Arumanian/Macedo-Romanian */
@@ -599,10 +662,11 @@ static const LangTag ot_languages[] = {
{"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */
{"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */
{"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */
+ {"sam", HB_TAG('P','A','A',' ')}, /* Palestinian Aramaic */
{"sas", HB_TAG('S','A','S',' ')}, /* Sasak */
{"sat", HB_TAG('S','A','T',' ')}, /* Santali */
- {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
{"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
+ {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
{"scn", HB_TAG('S','C','N',' ')}, /* Sicilian */
{"sco", HB_TAG('S','C','O',' ')}, /* Scots */
{"scs", HB_TAG('S','L','A',' ')}, /* [North] Slavey */
@@ -615,6 +679,7 @@ static const LangTag ot_languages[] = {
{"sgs", HB_TAG('S','G','S',' ')}, /* Samogitian */
{"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage */
/*{"sgw", HB_TAG('S','G','W',' ')},*/ /* Sebat Bet Gurage (in SIL fonts) */
+ {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */
{"shn", HB_TAG('S','H','N',' ')}, /* Shan */
{"si", HB_TAG('S','N','H',' ')}, /* Sinhala */
{"sid", HB_TAG('S','I','D',' ')}, /* Sidamo */
@@ -627,7 +692,7 @@ static const LangTag ot_languages[] = {
{"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */
{"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */
{"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */
- {"sn", HB_TAG('S','N','A',' ')}, /* Shona */
+ {"sn", HB_TAG('S','N','A','0')}, /* Shona */
{"snk", HB_TAG('S','N','K',' ')}, /* Soninke */
{"so", HB_TAG('S','M','L',' ')}, /* Somali */
{"sop", HB_TAG('S','O','P',' ')}, /* Songe */
@@ -665,20 +730,24 @@ static const LangTag ot_languages[] = {
{"tiv", HB_TAG('T','I','V',' ')}, /* Tiv */
{"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */
{"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */
- {"tmh", HB_TAG('t','m','h',' ')}, /* Tamashek [macrolanguage] */
+ {"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek */
{"tn", HB_TAG('T','N','A',' ')}, /* Tswana */
{"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) */
+ {"tod", HB_TAG('T','O','D','0')}, /* Toma */
+ {"toi", HB_TAG('T','N','G',' ')}, /* Tonga */
{"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */
{"tr", HB_TAG('T','R','K',' ')}, /* Turkish */
{"tru", HB_TAG('T','U','A',' ')}, /* Turoyo Aramaic */
{"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */
{"tt", HB_TAG('T','A','T',' ')}, /* Tatar */
{"tum", HB_TAG('T','U','M',' ')}, /* Tumbuka */
+ {"tvl", HB_TAG('T','V','L',' ')}, /* Tuvalu */
{"tw", HB_TAG('T','W','I',' ')}, /* Twi */
{"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */
{"tyv", HB_TAG('T','U','V',' ')}, /* Tuvin */
{"tyz", HB_TAG('T','Y','Z',' ')}, /* Tày */
{"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight */
+ {"tzo", HB_TAG('T','Z','O',' ')}, /* Tzotzil */
{"udm", HB_TAG('U','D','M',' ')}, /* Udmurt */
{"ug", HB_TAG('U','Y','G',' ')}, /* Uighur */
{"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */
@@ -690,8 +759,8 @@ static const LangTag ot_languages[] = {
{"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek */
{"ve", HB_TAG('V','E','N',' ')}, /* Venda */
{"vec", HB_TAG('V','E','C',' ')}, /* Venetian */
- {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */
{"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */
+ {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */
{"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */
{"vo", HB_TAG('V','O','L',' ')}, /* Volapük */
{"vro", HB_TAG('V','R','O',' ')}, /* Võro */
@@ -700,85 +769,76 @@ static const LangTag ot_languages[] = {
{"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */
{"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */
{"wle", HB_TAG('S','I','G',' ')}, /* Wolane */
+ {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
{"wry", HB_TAG('M','A','W',' ')}, /* Merwari */
{"wtm", HB_TAG('W','T','M',' ')}, /* Mewati */
- {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
{"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */
+ {"xan", HB_TAG('S','E','K',' ')}, /* Sekota */
{"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */
+ {"xjb", HB_TAG('X','J','B',' ')}, /* Minjangbal */
{"xog", HB_TAG('X','O','G',' ')}, /* Soga */
{"xom", HB_TAG('K','M','O',' ')}, /* Komo (Sudan) */
+ {"xpe", HB_TAG('X','P','E',' ')}, /* Kpelle (Liberia) */
{"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */
{"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) */
{"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat (Todo) */
{"yao", HB_TAG('Y','A','O',' ')}, /* Yao */
+ {"yap", HB_TAG('Y','A','P',' ')}, /* Yapese */
{"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
{"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
{"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */
{"za", HB_TAG('Z','H','A',' ')}, /* Chuang/Zhuang [macrolanguage] */
{"zea", HB_TAG('Z','E','A',' ')}, /* Zeeuws */
+ {"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Morrocan Tamazigh */
{"zne", HB_TAG('Z','N','D',' ')}, /* Zande */
{"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */
- {"zum", HB_TAG('L','R','C',' ')} /* Kumzari */
+ {"zum", HB_TAG('L','R','C',' ')}, /* Kumzari */
+ {"zza", HB_TAG('Z','Z','A',' ')}, /* Zazaki */
/* The corresponding languages IDs for the following IDs are unclear,
* overlap, or are architecturally weird. Needs more research. */
-/*{"ahg/awn/xan?", HB_TAG('A','G','W',' ')},*/ /* Agaw */
-/*{"gsw?/gsw-FR?", HB_TAG('A','L','S',' ')},*/ /* Alsatian */
+/*{"chp", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */
+/*{"cwd", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */
+/*{"emk", HB_TAG('E','M','K',' ')},*/ /* Eastern Maninkakan */
/*{"krc", HB_TAG('B','A','L',' ')},*/ /* Balkar */
/*{"??", HB_TAG('B','C','R',' ')},*/ /* Bible Cree */
/*{"zh?", HB_TAG('C','H','N',' ')},*/ /* Chinese (seen in Microsoft fonts) */
-/*{"acf/gcf?", HB_TAG('F','A','N',' ')},*/ /* French Antillean */
-/*{"enf?/yrk?", HB_TAG('F','N','E',' ')},*/ /* Forest Nenets */
-/*{"fuf?", HB_TAG('F','T','A',' ')},*/ /* Futa */
/*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/ /* Garshuni */
-/*{"cfm/rnl?", HB_TAG('H','A','L',' ')},*/ /* Halam */
-/*{"ga-Latg?/Latg?", HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */
+/*{"hy?", HB_TAG('H','Y','E','0')},*/ /* Armenian East (ISO 639-3 hye according to Microsoft, but that’s equivalent to ISO 639-1 hy) */
+/*{"ga-Latg?/" HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */
/*{"krc", HB_TAG('K','A','R',' ')},*/ /* Karachay */
-/*{"alw?/ktb?", HB_TAG('K','E','B',' ')},*/ /* Kebena */
-/*{"Geok", HB_TAG('K','G','E',' ')},*/ /* Khutsuri Georgian */
+/*{"ka-Geok?", HB_TAG('K','G','E',' ')},*/ /* Khutsuri Georgian */
/*{"kca", HB_TAG('K','H','K',' ')},*/ /* Khanty-Kazim */
/*{"kca", HB_TAG('K','H','S',' ')},*/ /* Khanty-Shurishkar */
/*{"kca", HB_TAG('K','H','V',' ')},*/ /* Khanty-Vakhi */
-/*{"guz?/kqs?/kss?", HB_TAG('K','I','S',' ')},*/ /* Kisii */
-/*{"kfa/kfi?/kpb?/xua?/xuj?", HB_TAG('K','O','D',' ')},*/ /* Kodagu */
-/*{"okm?/oko?", HB_TAG('K','O','H',' ')},*/ /* Korean Old Hangul */
-/*{"kon?/ktu?/...", HB_TAG('K','O','N',' ')},*/ /* Kikongo */
-/*{"kfx?", HB_TAG('K','U','L',' ')},*/ /* Kulvi */
-/*{"??", HB_TAG('L','A','H',' ')},*/ /* Lahuli */
-/*{"??", HB_TAG('L','C','R',' ')},*/ /* L-Cree */
+/*{"kqs, kss", HB_TAG('K','I','S',' ')},*/ /* Kisii */
+/*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */
+/*{"mlq", HB_TAG('M','L','N',' ')},*/ /* Malinke */
+/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Sotho, Northern */
/*{"??", HB_TAG('M','A','L',' ')},*/ /* Malayalam Traditional */
-/*{"mnk?/mlq?/...", HB_TAG('M','L','N',' ')},*/ /* Malinke */
-/*{"??", HB_TAG('N','C','R',' ')},*/ /* N-Cree */
-/*{"??", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */
-/*{"jpa?/sam?", HB_TAG('P','A','A',' ')},*/ /* Palestinian Aramaic */
-/*{"polyton", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */
-/*{"??", HB_TAG('Q','I','N',' ')},*/ /* Asho Chin */
-/*{"??", HB_TAG('R','C','R',' ')},*/ /* R-Cree */
-/*{"chp?", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */
-/*{"xan?", HB_TAG('S','E','K',' ')},*/ /* Sekota */
-/*{"ngo?", HB_TAG('S','X','T',' ')},*/ /* Sutu */
-/*{"??", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */
-/*{"tnz?/tog?/toi?", HB_TAG('T','N','G',' ')},*/ /* Tonga */
-/*{"enh?/yrk?", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */
-/*{"??", HB_TAG('W','C','R',' ')},*/ /* West-Cree */
-/*{"cre?", HB_TAG('Y','C','R',' ')},*/ /* Y-Cree */
+/*{"csw", HB_TAG('N','C','R',' ')},*/ /* N-Cree */
+/*{"csw", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */
+/*{"el-polyton", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */
+/*{"bgr, cnh, cnw, czt, sez, tcp, csy, ctd, flm, pck, tcz, zom, cmr, dao, hlt, cka, cnk, mrh, mwg, cbl, cnb, csh", HB_TAG('Q','I','N',' ')},*/ /* Chin */
/*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */
-/*{"ii?/Yiii?", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */
-/*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */
+/*{"zh-Latn-pinyin", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */
};
typedef struct {
- char language[8];
+ char language[11];
hb_tag_t tag;
} LangTagLong;
static const LangTagLong ot_languages_zh[] = {
+ /* Store longest-first, if one is a prefix of another. */
{"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */
{"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */
- {"zh-mo", HB_TAG('Z','H','T',' ')}, /* Chinese (Macao) */
+ {"zh-mo", HB_TAG('Z','H','H',' ')}, /* Chinese (Macao) */
{"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */
{"zh-tw", HB_TAG('Z','H','T',' ')}, /* Chinese (Taiwan) */
{"zh-hans", HB_TAG('Z','H','S',' ')}, /* Chinese (Simplified) */
+ {"zh-hant-hk",HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */
+ {"zh-hant-mo",HB_TAG('Z','H','H',' ')}, /* Chinese (Macao) */
{"zh-hant", HB_TAG('Z','H','T',' ')}, /* Chinese (Traditional) */
};
@@ -832,13 +892,21 @@ hb_ot_tag_from_language (hb_language_t language)
}
/*
- * The International Phonetic Alphabet is a variant tag in BCP-47,
- * which can be applied to any language.
+ * "fonipa" is a variant tag in BCP-47, meaning the International Phonetic Alphabet.
+ * It can be applied to any language.
*/
if (strstr (lang_str, "-fonipa")) {
return HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */
}
+ /*
+ * "fonnapa" is a variant tag in BCP-47, meaning the North American Phonetic Alphabet
+ * also known as Americanist Phonetic Notation. It can be applied to any language.
+ */
+ if (strstr (lang_str, "-fonnapa")) {
+ return HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */
+ }
+
/* Find a language matching in the first component */
{
const LangTag *lang_tag;
@@ -910,6 +978,8 @@ hb_ot_tag_to_language (hb_tag_t tag)
/* struct LangTag has only room for 3-letter language tags. */
switch (tag) {
+ case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */
+ return hb_language_from_string ("und-fonnapa", -1);
case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
return hb_language_from_string ("und-fonipa", -1);
}
@@ -928,4 +998,27 @@ hb_ot_tag_to_language (hb_tag_t tag)
}
}
+#ifdef MAIN
+static inline void
+test_langs_sorted (void)
+{
+ for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++)
+ {
+ int c = lang_compare_first_component (ot_languages[i-1].language, ot_languages[i].language);
+ if (c >= 0)
+ {
+ fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n",
+ i, ot_languages[i-1].language, c, ot_languages[i].language);
+ abort();
+ }
+ }
+}
+
+int
+main (void)
+{
+ test_langs_sorted ();
+ return 0;
+}
+#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.h b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.h
index 1bf12ab3c0..54fb747f58 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.h
@@ -39,18 +39,18 @@ HB_BEGIN_DECLS
#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T')
#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't')
-void
+HB_EXTERN void
hb_ot_tags_from_script (hb_script_t script,
hb_tag_t *script_tag_1,
hb_tag_t *script_tag_2);
-hb_script_t
+HB_EXTERN hb_script_t
hb_ot_tag_to_script (hb_tag_t tag);
-hb_tag_t
+HB_EXTERN hb_tag_t
hb_ot_tag_from_language (hb_language_t language);
-hb_language_t
+HB_EXTERN hb_language_t
hb_ot_tag_to_language (hb_tag_t tag);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot.h b/src/3rdparty/harfbuzz-ng/src/hb-ot.h
index 47c92a58e4..113e37b08a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot.h
@@ -32,6 +32,7 @@
#include "hb-ot-font.h"
#include "hb-ot-layout.h"
+#include "hb-ot-math.h"
#include "hb-ot-tag.h"
#include "hb-ot-shape.h"
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-private.hh
index 53e0510a92..666af6260b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-private.hh
@@ -83,7 +83,7 @@ extern "C" void hb_free_impl(void *ptr);
#define unlikely(expr) (expr)
#endif
-#ifndef __GNUC__
+#if !defined(__GNUC__) && !defined(__clang__)
#undef __attribute__
#define __attribute__(x)
#endif
@@ -169,6 +169,7 @@ extern "C" void hb_free_impl(void *ptr);
# if defined(_WIN32_WCE)
/* Some things not defined on Windows CE. */
# define strdup _strdup
+# define vsnprintf _vsnprintf
# define getenv(Name) NULL
# if _WIN32_WCE < 0x800
# define setlocale(Category, Locale) "C"
@@ -179,6 +180,9 @@ static int errno = 0; /* Use something better? */
# endif
# if defined(_MSC_VER) && _MSC_VER < 1900
# define snprintf _snprintf
+# elif defined(_MSC_VER) && _MSC_VER >= 1900
+# /* Covers VC++ Error for strdup being a deprecated POSIX name and to instead use _strdup instead */
+# define strdup _strdup
# endif
#endif
@@ -608,6 +612,15 @@ static inline unsigned char TOLOWER (unsigned char c)
/* Debug */
+/* HB_NDEBUG disables some sanity checks that are very safe to disable and
+ * should be disabled in production systems. If NDEBUG is defined, enable
+ * HB_NDEBUG; but if it's desirable that normal assert()s (which are very
+ * light-weight) to be enabled, then HB_DEBUG can be defined to disable
+ * the costlier checks. */
+#ifdef NDEBUG
+#define HB_NDEBUG
+#endif
+
#ifndef HB_DEBUG
#define HB_DEBUG 0
#endif
@@ -676,17 +689,20 @@ _hb_debug_msg_va (const char *what,
fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), "");
if (indented) {
-/* One may want to add ASCII version of these. See:
- * https://bugs.freedesktop.org/show_bug.cgi?id=50970 */
#define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
#define VRBAR "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
#define DLBAR "\342\225\256" /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
#define ULBAR "\342\225\257" /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
#define LBAR "\342\225\264" /* U+2574 BOX DRAWINGS LIGHT LEFT */
- static const char bars[] = VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
+ static const char bars[] =
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
+ VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
fprintf (stderr, "%2u %s" VRBAR "%s",
level,
- bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level),
+ bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
} else
fprintf (stderr, " " VRBAR LBAR);
@@ -891,6 +907,29 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
}
+/* Enable bitwise ops on enums marked as flags_t */
+/* To my surprise, looks like the function resolver is happy to silently cast
+ * one enum to another... So this doesn't provide the type-checking that I
+ * originally had in mind... :(.
+ *
+ * For MSVC warnings, see: https://github.com/behdad/harfbuzz/pull/163
+ */
+#ifdef _MSC_VER
+# pragma warning(disable:4200)
+# pragma warning(disable:4800)
+#endif
+#define HB_MARK_AS_FLAG_T(T) \
+ extern "C++" { \
+ static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \
+ static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \
+ static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \
+ static inline T operator ~ (T r) { return T (~(unsigned int) r); } \
+ static inline T& operator |= (T &l, T r) { l = l | r; return l; } \
+ static inline T& operator &= (T& l, T r) { l = l & r; return l; } \
+ static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
+ }
+
+
/* Useful for set-operations on small enums.
* For example, for testing "x ∈ {x1, x2, x3}" use:
* (FLAG_SAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
@@ -979,5 +1018,7 @@ hb_options (void)
return _hb_options.opts;
}
+/* Size signifying variable-sized array */
+#define VAR 1
#endif /* HB_PRIVATE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-set-private.hh
index 3c302b1daf..e2010d7626 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set-private.hh
@@ -313,7 +313,7 @@ struct hb_set_t
for (unsigned int i = 0; i < ELTS; i++)
if (elts[i])
for (unsigned int j = 0; j < BITS; j++)
- if (elts[i] & (1 << j))
+ if (elts[i] & (1u << j))
return i * BITS + j;
return INVALID;
}
@@ -322,7 +322,7 @@ struct hb_set_t
for (unsigned int i = ELTS; i; i--)
if (elts[i - 1])
for (unsigned int j = BITS; j; j--)
- if (elts[i - 1] & (1 << (j - 1)))
+ if (elts[i - 1] & (1u << (j - 1)))
return (i - 1) * BITS + (j - 1);
return INVALID;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.h b/src/3rdparty/harfbuzz-ng/src/hb-set.h
index 29bf6556ab..2164c1a654 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set.h
@@ -44,109 +44,109 @@ HB_BEGIN_DECLS
typedef struct hb_set_t hb_set_t;
-hb_set_t *
+HB_EXTERN hb_set_t *
hb_set_create (void);
-hb_set_t *
+HB_EXTERN hb_set_t *
hb_set_get_empty (void);
-hb_set_t *
+HB_EXTERN hb_set_t *
hb_set_reference (hb_set_t *set);
-void
+HB_EXTERN void
hb_set_destroy (hb_set_t *set);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_set_set_user_data (hb_set_t *set,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
-void *
+HB_EXTERN void *
hb_set_get_user_data (hb_set_t *set,
hb_user_data_key_t *key);
/* Returns false if allocation has failed before */
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_set_allocation_successful (const hb_set_t *set);
-void
+HB_EXTERN void
hb_set_clear (hb_set_t *set);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_set_is_empty (const hb_set_t *set);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_set_has (const hb_set_t *set,
hb_codepoint_t codepoint);
/* Right now limited to 16-bit integers. Eventually will do full codepoint range, sans -1
* which we will use as a sentinel. */
-void
+HB_EXTERN void
hb_set_add (hb_set_t *set,
hb_codepoint_t codepoint);
-void
+HB_EXTERN void
hb_set_add_range (hb_set_t *set,
hb_codepoint_t first,
hb_codepoint_t last);
-void
+HB_EXTERN void
hb_set_del (hb_set_t *set,
hb_codepoint_t codepoint);
-void
+HB_EXTERN void
hb_set_del_range (hb_set_t *set,
hb_codepoint_t first,
hb_codepoint_t last);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_set_is_equal (const hb_set_t *set,
const hb_set_t *other);
-void
+HB_EXTERN void
hb_set_set (hb_set_t *set,
const hb_set_t *other);
-void
+HB_EXTERN void
hb_set_union (hb_set_t *set,
const hb_set_t *other);
-void
+HB_EXTERN void
hb_set_intersect (hb_set_t *set,
const hb_set_t *other);
-void
+HB_EXTERN void
hb_set_subtract (hb_set_t *set,
const hb_set_t *other);
-void
+HB_EXTERN void
hb_set_symmetric_difference (hb_set_t *set,
const hb_set_t *other);
-void
+HB_EXTERN void
hb_set_invert (hb_set_t *set);
-unsigned int
+HB_EXTERN unsigned int
hb_set_get_population (const hb_set_t *set);
/* Returns -1 if set empty. */
-hb_codepoint_t
+HB_EXTERN hb_codepoint_t
hb_set_get_min (const hb_set_t *set);
/* Returns -1 if set empty. */
-hb_codepoint_t
+HB_EXTERN hb_codepoint_t
hb_set_get_max (const hb_set_t *set);
/* Pass -1 in to get started. */
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_set_next (const hb_set_t *set,
hb_codepoint_t *codepoint);
/* Pass -1 for first and last to get started. */
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_set_next_range (const hb_set_t *set,
hb_codepoint_t *first,
hb_codepoint_t *last);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan-private.hh
index 607da5e779..aa0413a272 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan-private.hh
@@ -47,12 +47,17 @@ struct hb_shape_plan_t
hb_feature_t *user_features;
unsigned int num_user_features;
+ int *coords;
+ unsigned int num_coords;
+
struct hb_shaper_data_t shaper_data;
};
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \
- , const hb_feature_t *user_features \
- , unsigned int num_user_features
+ , const hb_feature_t *user_features \
+ , unsigned int num_user_features \
+ , const int *coords \
+ , unsigned int num_coords
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc
index 56e2ea5c19..600faaeb18 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.cc
@@ -46,11 +46,14 @@ static void
hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
const hb_feature_t *user_features,
unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords,
const char * const *shaper_list)
{
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
- "num_features=%d shaper_list=%p",
+ "num_features=%d num_coords=%d shaper_list=%p",
num_user_features,
+ num_coords,
shaper_list);
const hb_shaper_pair_t *shapers = _hb_shapers_get ();
@@ -59,7 +62,9 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
HB_STMT_START { \
if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
HB_SHAPER_DATA (shaper, shape_plan) = \
- HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
+ HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \
+ user_features, num_user_features, \
+ coords, num_coords); \
shape_plan->shaper_func = _hb_##shaper##_shape; \
shape_plan->shaper_name = #shaper; \
return; \
@@ -115,14 +120,31 @@ hb_shape_plan_create (hb_face_t *face,
unsigned int num_user_features,
const char * const *shaper_list)
{
+ return hb_shape_plan_create2 (face, props,
+ user_features, num_user_features,
+ NULL, 0,
+ shaper_list);
+}
+
+hb_shape_plan_t *
+hb_shape_plan_create2 (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const int *orig_coords,
+ unsigned int num_coords,
+ const char * const *shaper_list)
+{
DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
- "face=%p num_features=%d shaper_list=%p",
+ "face=%p num_features=%d num_coords=%d shaper_list=%p",
face,
num_user_features,
+ num_coords,
shaper_list);
hb_shape_plan_t *shape_plan;
hb_feature_t *features = NULL;
+ int *coords = NULL;
if (unlikely (!face))
face = hb_face_get_empty ();
@@ -130,7 +152,14 @@ hb_shape_plan_create (hb_face_t *face,
return hb_shape_plan_get_empty ();
if (num_user_features && !(features = (hb_feature_t *) calloc (num_user_features, sizeof (hb_feature_t))))
return hb_shape_plan_get_empty ();
- if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
+ if (num_coords && !(coords = (int *) calloc (num_coords, sizeof (int))))
+ {
+ free (features);
+ return hb_shape_plan_get_empty ();
+ }
+ if (!(shape_plan = hb_object_create<hb_shape_plan_t> ()))
+ {
+ free (coords);
free (features);
return hb_shape_plan_get_empty ();
}
@@ -145,8 +174,15 @@ hb_shape_plan_create (hb_face_t *face,
shape_plan->user_features = features;
if (num_user_features)
memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
+ shape_plan->num_coords = num_coords;
+ shape_plan->coords = coords;
+ if (num_coords)
+ memcpy (coords, orig_coords, num_coords * sizeof (int));
- hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
+ hb_shape_plan_plan (shape_plan,
+ user_features, num_user_features,
+ coords, num_coords,
+ shaper_list);
return shape_plan;
}
@@ -176,6 +212,9 @@ hb_shape_plan_get_empty (void)
NULL, /* user_features */
0, /* num_user_featurs */
+ NULL, /* coords */
+ 0, /* num_coords */
+
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
#include "hb-shaper-list.hh"
@@ -220,6 +259,7 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
#undef HB_SHAPER_IMPLEMENT
free (shape_plan->user_features);
+ free (shape_plan->coords);
free (shape_plan);
}
@@ -289,9 +329,10 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
unsigned int num_features)
{
DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
- "num_features=%d shaper_func=%p",
+ "num_features=%d shaper_func=%p, shaper_name=%s",
num_features,
- shape_plan->shaper_func);
+ shape_plan->shaper_func,
+ shape_plan->shaper_name);
if (unlikely (!buffer->len))
return true;
@@ -350,6 +391,8 @@ struct hb_shape_plan_proposal_t
const char * const *shaper_list;
const hb_feature_t *user_features;
unsigned int num_user_features;
+ const int *coords;
+ unsigned int num_coords;
hb_shape_func_t *shaper_func;
};
@@ -357,12 +400,26 @@ static inline hb_bool_t
hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan,
const hb_shape_plan_proposal_t *proposal)
{
- if (proposal->num_user_features != shape_plan->num_user_features) return false;
+ if (proposal->num_user_features != shape_plan->num_user_features)
+ return false;
for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
if (proposal->user_features[i].tag != shape_plan->user_features[i].tag ||
proposal->user_features[i].value != shape_plan->user_features[i].value ||
proposal->user_features[i].start != shape_plan->user_features[i].start ||
- proposal->user_features[i].end != shape_plan->user_features[i].end) return false;
+ proposal->user_features[i].end != shape_plan->user_features[i].end)
+ return false;
+ return true;
+}
+
+static inline hb_bool_t
+hb_shape_plan_coords_match (const hb_shape_plan_t *shape_plan,
+ const hb_shape_plan_proposal_t *proposal)
+{
+ if (proposal->num_coords != shape_plan->num_coords)
+ return false;
+ for (unsigned int i = 0, n = proposal->num_coords; i < n; i++)
+ if (proposal->coords[i] != shape_plan->coords[i])
+ return false;
return true;
}
@@ -372,6 +429,7 @@ hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
{
return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
hb_shape_plan_user_features_match (shape_plan, proposal) &&
+ hb_shape_plan_coords_match (shape_plan, proposal) &&
((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
(shape_plan->shaper_func == proposal->shaper_func));
}
@@ -388,6 +446,13 @@ hb_non_global_user_features_present (const hb_feature_t *user_features,
return false;
}
+static inline hb_bool_t
+hb_coords_present (const int *coords,
+ unsigned int num_coords)
+{
+ return num_coords != 0;
+}
+
/**
* hb_shape_plan_create_cached:
* @face:
@@ -409,6 +474,21 @@ hb_shape_plan_create_cached (hb_face_t *face,
unsigned int num_user_features,
const char * const *shaper_list)
{
+ return hb_shape_plan_create_cached2 (face, props,
+ user_features, num_user_features,
+ NULL, 0,
+ shaper_list);
+}
+
+hb_shape_plan_t *
+hb_shape_plan_create_cached2 (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords,
+ const char * const *shaper_list)
+{
DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
"face=%p num_features=%d shaper_list=%p",
face,
@@ -455,16 +535,21 @@ retry:
/* Not found. */
- hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create2 (face, props,
+ user_features, num_user_features,
+ coords, num_coords,
+ shaper_list);
/* Don't add to the cache if face is inert. */
if (unlikely (hb_object_is_inert (face)))
return shape_plan;
/* Don't add the plan to the cache if there were user features with non-global ranges */
-
if (hb_non_global_user_features_present (user_features, num_user_features))
return shape_plan;
+ /* Don't add the plan to the cache if there were variation coordinates XXX Fix me. */
+ if (hb_coords_present (coords, num_coords))
+ return shape_plan;
hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
if (unlikely (!node))
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.h b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.h
index 8f54552f90..b62ae7ca35 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape-plan.h
@@ -38,49 +38,68 @@ HB_BEGIN_DECLS
typedef struct hb_shape_plan_t hb_shape_plan_t;
-hb_shape_plan_t *
+HB_EXTERN hb_shape_plan_t *
hb_shape_plan_create (hb_face_t *face,
const hb_segment_properties_t *props,
const hb_feature_t *user_features,
unsigned int num_user_features,
const char * const *shaper_list);
-hb_shape_plan_t *
+HB_EXTERN hb_shape_plan_t *
hb_shape_plan_create_cached (hb_face_t *face,
const hb_segment_properties_t *props,
const hb_feature_t *user_features,
unsigned int num_user_features,
const char * const *shaper_list);
-hb_shape_plan_t *
+HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_create2 (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords,
+ const char * const *shaper_list);
+
+HB_EXTERN hb_shape_plan_t *
+hb_shape_plan_create_cached2 (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const int *coords,
+ unsigned int num_coords,
+ const char * const *shaper_list);
+
+
+HB_EXTERN hb_shape_plan_t *
hb_shape_plan_get_empty (void);
-hb_shape_plan_t *
+HB_EXTERN hb_shape_plan_t *
hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
-void
+HB_EXTERN void
hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
-void *
+HB_EXTERN void *
hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
hb_user_data_key_t *key);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features);
-const char *
+HB_EXTERN const char *
hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc
index 8a98583989..706f14420d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc
@@ -210,13 +210,15 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
/**
* hb_feature_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
- * @len: length of @str, or -1 if string is nul-terminated
+ * @len: length of @str, or -1 if string is %NULL terminated
* @feature: (out): the #hb_feature_t to initialize with the parsed values
*
- * Parses a string into a #hb_feature_t. If @len is -1 then @str is
- * %NULL-terminated.
+ * Parses a string into a #hb_feature_t.
*
- * Return value: %TRUE if @str is successfully parsed, %FALSE otherwise
+ * TODO: document the syntax here.
+ *
+ * Return value:
+ * %true if @str is successfully parsed, %false otherwise.
*
* Since: 0.9.5
**/
@@ -371,7 +373,10 @@ hb_shape_full (hb_font_t *font,
unsigned int num_features,
const char * const *shaper_list)
{
- hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props,
+ features, num_features,
+ font->coords, font->num_coords,
+ shaper_list);
hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
hb_shape_plan_destroy (shape_plan);
@@ -392,8 +397,6 @@ hb_shape_full (hb_font_t *font,
* positioned glyphs. If @features is not %NULL, it will be used to control the
* features applied during shaping.
*
- * Return value: %FALSE if all shapers failed, %TRUE otherwise
- *
* Since: 0.9.2
**/
void
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape.h b/src/3rdparty/harfbuzz-ng/src/hb-shape.h
index b665509a0d..53bb845bf4 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape.h
@@ -47,29 +47,29 @@ typedef struct hb_feature_t {
unsigned int end;
} hb_feature_t;
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature);
-void
+HB_EXTERN void
hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size);
-void
+HB_EXTERN void
hb_shape (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_shape_full (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
const char * const *shaper_list);
-const char **
+HB_EXTERN const char **
hb_shape_list_shapers (void);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh
index 6c537d4921..b0835d31ab 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh
@@ -46,6 +46,9 @@ HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
#ifdef HAVE_UNISCRIBE
HB_SHAPER_IMPLEMENT (uniscribe)
#endif
+#ifdef HAVE_DIRECTWRITE
+HB_SHAPER_IMPLEMENT (directwrite)
+#endif
#ifdef HAVE_CORETEXT
HB_SHAPER_IMPLEMENT (coretext)
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-unicode-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-unicode-private.hh
index 968bca5567..a4d118b6dc 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-unicode-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-unicode-private.hh
@@ -115,6 +115,8 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
/* XXX This hack belongs to the Tibetan shaper:
* Reorder PADMA to ensure it comes after any vowel marks. */
if (unlikely (unicode == 0x0FC6u)) return 254;
+ /* Reorder TSA -PHRU to reorder before U+0F74 */
+ if (unlikely (unicode == 0x0F39u)) return 127;
return _hb_modified_combining_class[combining_class (unicode)];
}
@@ -180,8 +182,8 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
case 0x17: return hb_in_range (ch, 0x17B4u, 0x17B5u);
case 0x18: return hb_in_range (ch, 0x180Bu, 0x180Eu);
case 0x20: return hb_in_ranges (ch, 0x200Bu, 0x200Fu,
- 0x202Au, 0x202Eu,
- 0x2060u, 0x206Fu);
+ 0x202Au, 0x202Eu,
+ 0x2060u, 0x206Fu);
case 0xFE: return hb_in_range (ch, 0xFE00u, 0xFE0Fu) || ch == 0xFEFFu;
case 0xFF: return hb_in_range (ch, 0xFFF0u, 0xFFF8u);
default: return false;
@@ -199,6 +201,50 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
}
}
+ /* Space estimates based on:
+ * http://www.unicode.org/charts/PDF/U2000.pdf
+ * https://www.microsoft.com/typography/developers/fdsspec/spaces.aspx
+ */
+ enum space_t {
+ NOT_SPACE = 0,
+ SPACE_EM = 1,
+ SPACE_EM_2 = 2,
+ SPACE_EM_3 = 3,
+ SPACE_EM_4 = 4,
+ SPACE_EM_5 = 5,
+ SPACE_EM_6 = 6,
+ SPACE_EM_16 = 16,
+ SPACE_4_EM_18, /* 4/18th of an EM! */
+ SPACE,
+ SPACE_FIGURE,
+ SPACE_PUNCTUATION,
+ SPACE_NARROW,
+ };
+ static inline space_t
+ space_fallback_type (hb_codepoint_t u)
+ {
+ switch (u)
+ {
+ /* All GC=Zs chars that can use a fallback. */
+ default: return NOT_SPACE; /* U+1680 OGHAM SPACE MARK */
+ case 0x0020u: return SPACE; /* U+0020 SPACE */
+ case 0x00A0u: return SPACE; /* U+00A0 NO-BREAK SPACE */
+ case 0x2000u: return SPACE_EM_2; /* U+2000 EN QUAD */
+ case 0x2001u: return SPACE_EM; /* U+2001 EM QUAD */
+ case 0x2002u: return SPACE_EM_2; /* U+2002 EN SPACE */
+ case 0x2003u: return SPACE_EM; /* U+2003 EM SPACE */
+ case 0x2004u: return SPACE_EM_3; /* U+2004 THREE-PER-EM SPACE */
+ case 0x2005u: return SPACE_EM_4; /* U+2005 FOUR-PER-EM SPACE */
+ case 0x2006u: return SPACE_EM_6; /* U+2006 SIX-PER-EM SPACE */
+ case 0x2007u: return SPACE_FIGURE; /* U+2007 FIGURE SPACE */
+ case 0x2008u: return SPACE_PUNCTUATION; /* U+2008 PUNCTUATION SPACE */
+ case 0x2009u: return SPACE_EM_5; /* U+2009 THIN SPACE */
+ case 0x200Au: return SPACE_EM_16; /* U+200A HAIR SPACE */
+ case 0x202Fu: return SPACE_NARROW; /* U+202F NARROW NO-BREAK SPACE */
+ case 0x205Fu: return SPACE_4_EM_18; /* U+205F MEDIUM MATHEMATICAL SPACE */
+ case 0x3000u: return SPACE_EM; /* U+3000 IDEOGRAPHIC SPACE */
+ }
+ }
struct {
#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
@@ -299,10 +345,12 @@ extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
#define HB_MODIFIED_COMBINING_CLASS_CCC118 118 /* sign u / sign uu */
#define HB_MODIFIED_COMBINING_CLASS_CCC122 122 /* mai * */
-/* Tibetan */
+/* Tibetan
+ * Modify U+0F74 (ccc=132) to reorder before ccc=130 marks.
+ */
#define HB_MODIFIED_COMBINING_CLASS_CCC129 129 /* sign aa */
#define HB_MODIFIED_COMBINING_CLASS_CCC130 130 /* sign i */
-#define HB_MODIFIED_COMBINING_CLASS_CCC132 132 /* sign u */
+#define HB_MODIFIED_COMBINING_CLASS_CCC132 128 /* sign u */
/* Misc */
@@ -313,5 +361,10 @@ extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
+#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL(gen_cat) \
+ (FLAG_SAFE (gen_cat) & \
+ (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL)))
#endif /* HB_UNICODE_PRIVATE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc b/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc
index 487d10b939..d553a7172f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-unicode.cc
@@ -131,12 +131,12 @@ hb_unicode_funcs_get_default (void)
#define HB_UNICODE_FUNCS_IMPLEMENT(set) \
return hb_##set##_get_unicode_funcs ();
-#ifdef HAVE_GLIB
+#if defined(HAVE_UCDN)
+ HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
+#elif defined(HAVE_GLIB)
HB_UNICODE_FUNCS_IMPLEMENT(glib)
#elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
HB_UNICODE_FUNCS_IMPLEMENT(icu)
-#elif defined(HAVE_UCDN)
- HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
#else
#define HB_UNICODE_FUNCS_NIL 1
HB_UNICODE_FUNCS_IMPLEMENT(nil)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-unicode.h b/src/3rdparty/harfbuzz-ng/src/hb-unicode.h
index 3a12e2f9a2..2657f48130 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-unicode.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-unicode.h
@@ -174,23 +174,23 @@ typedef struct hb_unicode_funcs_t hb_unicode_funcs_t;
/*
* just give me the best implementation you've got there.
*/
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
hb_unicode_funcs_get_default (void);
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
hb_unicode_funcs_create (hb_unicode_funcs_t *parent);
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
hb_unicode_funcs_get_empty (void);
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs);
-void
+HB_EXTERN void
hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key,
void * data,
@@ -198,18 +198,18 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
hb_bool_t replace);
-void *
+HB_EXTERN void *
hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key);
-void
+HB_EXTERN void
hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs);
-hb_unicode_funcs_t *
+HB_EXTERN hb_unicode_funcs_t *
hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
@@ -285,7 +285,7 @@ typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_combining_class_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -301,7 +301,7 @@ hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_eastasian_width_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -317,7 +317,7 @@ hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_general_category_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -333,7 +333,7 @@ hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_mirroring_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -349,7 +349,7 @@ hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_script_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -365,7 +365,7 @@ hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_compose_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -381,7 +381,7 @@ hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_decompose_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -397,7 +397,7 @@ hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
*
* Since: 0.9.2
**/
-void
+HB_EXTERN void
hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_decompose_compatibility_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -405,62 +405,63 @@ hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
/* accessors */
/**
+ * hb_unicode_combining_class:
+ *
* Since: 0.9.2
**/
-hb_unicode_combining_class_t
+HB_EXTERN hb_unicode_combining_class_t
hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
/**
+ * hb_unicode_eastasian_width:
+ *
* Since: 0.9.2
**/
-unsigned int
+HB_EXTERN unsigned int
hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
/**
+ * hb_unicode_general_category:
+ *
* Since: 0.9.2
**/
-hb_unicode_general_category_t
+HB_EXTERN hb_unicode_general_category_t
hb_unicode_general_category (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
/**
+ * hb_unicode_mirroring:
+ *
* Since: 0.9.2
**/
-hb_codepoint_t
+HB_EXTERN hb_codepoint_t
hb_unicode_mirroring (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
/**
+ * hb_unicode_script:
+ *
* Since: 0.9.2
**/
-hb_script_t
+HB_EXTERN hb_script_t
hb_unicode_script (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
-/**
- * Since: 0.9.2
- **/
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab);
-/**
- * Since: 0.9.2
- **/
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b);
-/**
- * Since: 0.9.2
- **/
-unsigned int
+HB_EXTERN unsigned int
hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t u,
hb_codepoint_t *decomposed);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-utf-private.hh b/src/3rdparty/harfbuzz-ng/src/hb-utf-private.hh
index 14d3c2e369..74cf5d66a2 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-utf-private.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-utf-private.hh
@@ -146,11 +146,11 @@ struct hb_utf16_t
return text;
}
- if (likely (hb_in_range (c, 0xD800u, 0xDBFFu)))
+ if (likely (c <= 0xDBFFu && text < end))
{
/* High-surrogate in c */
- hb_codepoint_t l;
- if (text < end && ((l = *text), likely (hb_in_range (l, 0xDC00u, 0xDFFFu))))
+ hb_codepoint_t l = *text;
+ if (likely (hb_in_range (l, 0xDC00u, 0xDFFFu)))
{
/* Low-surrogate in l */
*unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
@@ -170,8 +170,7 @@ struct hb_utf16_t
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
- const uint16_t *end = text--;
- hb_codepoint_t c = *text;
+ hb_codepoint_t c = *--text;
if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
{
@@ -179,14 +178,22 @@ struct hb_utf16_t
return text;
}
- if (likely (start < text && hb_in_range (c, 0xDC00u, 0xDFFFu)))
- text--;
-
- if (likely (next (text, end, unicode, replacement) == end))
- return text;
+ if (likely (c >= 0xDC00u && start < text))
+ {
+ /* Low-surrogate in c */
+ hb_codepoint_t h = text[-1];
+ if (likely (hb_in_range (h, 0xD800u, 0xDBFFu)))
+ {
+ /* High-surrogate in h */
+ *unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u);
+ text--;
+ return text;
+ }
+ }
+ /* Lonely / out-of-order surrogate. */
*unicode = replacement;
- return end - 1;
+ return text;
}
@@ -211,14 +218,9 @@ struct hb_utf32_t
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
- hb_codepoint_t c = *text++;
- if (validate && unlikely (c > 0x10FFFFu || hb_in_range (c, 0xD800u, 0xDFFFu)))
- goto error;
- *unicode = c;
- return text;
-
- error:
- *unicode = replacement;
+ hb_codepoint_t c = *unicode = *text++;
+ if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
+ *unicode = replacement;
return text;
}
@@ -228,8 +230,10 @@ struct hb_utf32_t
hb_codepoint_t *unicode,
hb_codepoint_t replacement)
{
- next (text - 1, text, unicode, replacement);
- return text - 1;
+ hb_codepoint_t c = *unicode = *--text;
+ if (validate && unlikely (c >= 0xD800u && (c <= 0xDFFFu || c > 0x10FFFFu)))
+ *unicode = replacement;
+ return text;
}
static inline unsigned int
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-version.h b/src/3rdparty/harfbuzz-ng/src/hb-version.h
index bd9ac3d1fc..0cbe947062 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-version.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-version.h
@@ -37,25 +37,25 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 1
-#define HB_VERSION_MINOR 0
-#define HB_VERSION_MICRO 6
+#define HB_VERSION_MINOR 4
+#define HB_VERSION_MICRO 1
-#define HB_VERSION_STRING "1.0.6"
+#define HB_VERSION_STRING "1.4.1"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
-void
+HB_EXTERN void
hb_version (unsigned int *major,
unsigned int *minor,
unsigned int *micro);
-const char *
+HB_EXTERN const char *
hb_version_string (void);
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_version_atleast (unsigned int major,
unsigned int minor,
unsigned int micro);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb.h b/src/3rdparty/harfbuzz-ng/src/hb.h
index c5a938a381..7402034f43 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb.h
@@ -28,6 +28,10 @@
#define HB_H
#define HB_H_IN
+#ifndef HB_EXTERN
+#define HB_EXTERN extern
+#endif
+
#include "hb-blob.h"
#include "hb-buffer.h"
#include "hb-common.h"
diff --git a/src/3rdparty/pcre/COPYING b/src/3rdparty/pcre/COPYING
deleted file mode 100644
index 58eed01b61..0000000000
--- a/src/3rdparty/pcre/COPYING
+++ /dev/null
@@ -1,5 +0,0 @@
-PCRE LICENCE
-
-Please see the file LICENCE in the PCRE distribution for licensing details.
-
-End
diff --git a/src/3rdparty/pcre/config.h b/src/3rdparty/pcre/config.h
deleted file mode 100644
index de3832a8e2..0000000000
--- a/src/3rdparty/pcre/config.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#define HAVE_MEMMOVE 1
-#define HAVE_STDLIB_H 1
-#define HAVE_STRING_H 1
-
-#define LINK_SIZE 2
-#define MATCH_LIMIT 10000000
-#define MATCH_LIMIT_RECURSION MATCH_LIMIT
-#define MAX_NAME_COUNT 10000
-#define MAX_NAME_SIZE 32
-#define NEWLINE 10
-#define PARENS_NEST_LIMIT 250
-
-#define POSIX_MALLOC_THRESHOLD 10
-#define SUPPORT_UCP
-#define SUPPORT_UTF16
-
-/*
- man 3 pcrejit for a list of supported platforms;
- as PCRE 8.35, stable JIT support is available for:
- - ARM v5, v7, and Thumb2 (__GNUC__ compilers only)
- - x86/x86-64
- - MIPS 32bit (__GNUC__ compilers only)
- - Power PC 32-bit and 64-bit (__GNUC__ compilers only)
-*/
-#if !defined(PCRE_DISABLE_JIT) && (\
- /* ARM */ \
- (defined(__GNUC__) && (defined(__arm__) || defined(__TARGET_ARCH_ARM))) \
- /* x86 32/64 */ \
- || defined(__i386) || defined(__i386__) || defined(_M_IX86) \
- || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) \
- /* MIPS32 */ \
- || (defined(__GNUC__) \
- && (defined(__mips) || defined(__mips__)) \
- && !(defined(_MIPS_ARCH_MIPS64) || defined(__mips64))) \
- || (defined(__GNUC__) \
- && (defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \
- || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \
- || defined(_M_MPPC) || defined(_M_PPC))) \
- )
-# define SUPPORT_JIT
-#endif
diff --git a/src/3rdparty/pcre/patches/README b/src/3rdparty/pcre/patches/README
deleted file mode 100644
index 1d2bc389dd..0000000000
--- a/src/3rdparty/pcre/patches/README
+++ /dev/null
@@ -1,3 +0,0 @@
-These patches are landed in upstream PCRE (they're marked with
-their SVN revision number). When upgrading PCRE remember check
-if the version you're upgrading to already contains them or not.
diff --git a/src/3rdparty/pcre/pcre.h b/src/3rdparty/pcre/pcre.h
deleted file mode 100644
index 7055970065..0000000000
--- a/src/3rdparty/pcre/pcre.h
+++ /dev/null
@@ -1,677 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* This is the public header file for the PCRE library, to be #included by
-applications that call the PCRE functions.
-
- Copyright (c) 1997-2014 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-#ifndef _PCRE_H
-#define _PCRE_H
-
-/* The current PCRE version information. */
-
-#define PCRE_MAJOR 8
-#define PCRE_MINOR 39
-#define PCRE_PRERELEASE
-#define PCRE_DATE 2016-06-14
-
-/* When an application links to a PCRE DLL in Windows, the symbols that are
-imported have to be identified as such. When building PCRE, the appropriate
-export setting is defined in pcre_internal.h, which includes this file. So we
-don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL. */
-
-#if defined(_WIN32) && !defined(PCRE_STATIC)
-# ifndef PCRE_EXP_DECL
-# define PCRE_EXP_DECL extern __declspec(dllimport)
-# endif
-# ifdef __cplusplus
-# ifndef PCRECPP_EXP_DECL
-# define PCRECPP_EXP_DECL extern __declspec(dllimport)
-# endif
-# ifndef PCRECPP_EXP_DEFN
-# define PCRECPP_EXP_DEFN __declspec(dllimport)
-# endif
-# endif
-#endif
-
-/* By default, we use the standard "extern" declarations. */
-
-#ifndef PCRE_EXP_DECL
-# ifdef __cplusplus
-# define PCRE_EXP_DECL extern "C"
-# else
-# define PCRE_EXP_DECL extern
-# endif
-#endif
-
-#ifdef __cplusplus
-# ifndef PCRECPP_EXP_DECL
-# define PCRECPP_EXP_DECL extern
-# endif
-# ifndef PCRECPP_EXP_DEFN
-# define PCRECPP_EXP_DEFN
-# endif
-#endif
-
-/* Have to include stdlib.h in order to ensure that size_t is defined;
-it is needed here for malloc. */
-
-#include <stdlib.h>
-
-/* Allow for C++ users */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Public options. Some are compile-time only, some are run-time only, and some
-are both. Most of the compile-time options are saved with the compiled regex so
-that they can be inspected during studying (and therefore JIT compiling). Note
-that pcre_study() has its own set of options. Originally, all the options
-defined here used distinct bits. However, almost all the bits in a 32-bit word
-are now used, so in order to conserve them, option bits that were previously
-only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may
-also be used for compile-time options that affect only compiling and are not
-relevant for studying or JIT compiling.
-
-Some options for pcre_compile() change its behaviour but do not affect the
-behaviour of the execution functions. Other options are passed through to the
-execution functions and affect their behaviour, with or without affecting the
-behaviour of pcre_compile().
-
-Options that can be passed to pcre_compile() are tagged Cx below, with these
-variants:
-
-C1 Affects compile only
-C2 Does not affect compile; affects exec, dfa_exec
-C3 Affects compile, exec, dfa_exec
-C4 Affects compile, exec, dfa_exec, study
-C5 Affects compile, exec, study
-
-Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged with
-E and D, respectively. They take precedence over C3, C4, and C5 settings passed
-from pcre_compile(). Those that are compatible with JIT execution are flagged
-with J. */
-
-#define PCRE_CASELESS 0x00000001 /* C1 */
-#define PCRE_MULTILINE 0x00000002 /* C1 */
-#define PCRE_DOTALL 0x00000004 /* C1 */
-#define PCRE_EXTENDED 0x00000008 /* C1 */
-#define PCRE_ANCHORED 0x00000010 /* C4 E D */
-#define PCRE_DOLLAR_ENDONLY 0x00000020 /* C2 */
-#define PCRE_EXTRA 0x00000040 /* C1 */
-#define PCRE_NOTBOL 0x00000080 /* E D J */
-#define PCRE_NOTEOL 0x00000100 /* E D J */
-#define PCRE_UNGREEDY 0x00000200 /* C1 */
-#define PCRE_NOTEMPTY 0x00000400 /* E D J */
-#define PCRE_UTF8 0x00000800 /* C4 ) */
-#define PCRE_UTF16 0x00000800 /* C4 ) Synonyms */
-#define PCRE_UTF32 0x00000800 /* C4 ) */
-#define PCRE_NO_AUTO_CAPTURE 0x00001000 /* C1 */
-#define PCRE_NO_UTF8_CHECK 0x00002000 /* C1 E D J ) */
-#define PCRE_NO_UTF16_CHECK 0x00002000 /* C1 E D J ) Synonyms */
-#define PCRE_NO_UTF32_CHECK 0x00002000 /* C1 E D J ) */
-#define PCRE_AUTO_CALLOUT 0x00004000 /* C1 */
-#define PCRE_PARTIAL_SOFT 0x00008000 /* E D J ) Synonyms */
-#define PCRE_PARTIAL 0x00008000 /* E D J ) */
-
-/* This pair use the same bit. */
-#define PCRE_NEVER_UTF 0x00010000 /* C1 ) Overlaid */
-#define PCRE_DFA_SHORTEST 0x00010000 /* D ) Overlaid */
-
-/* This pair use the same bit. */
-#define PCRE_NO_AUTO_POSSESS 0x00020000 /* C1 ) Overlaid */
-#define PCRE_DFA_RESTART 0x00020000 /* D ) Overlaid */
-
-#define PCRE_FIRSTLINE 0x00040000 /* C3 */
-#define PCRE_DUPNAMES 0x00080000 /* C1 */
-#define PCRE_NEWLINE_CR 0x00100000 /* C3 E D */
-#define PCRE_NEWLINE_LF 0x00200000 /* C3 E D */
-#define PCRE_NEWLINE_CRLF 0x00300000 /* C3 E D */
-#define PCRE_NEWLINE_ANY 0x00400000 /* C3 E D */
-#define PCRE_NEWLINE_ANYCRLF 0x00500000 /* C3 E D */
-#define PCRE_BSR_ANYCRLF 0x00800000 /* C3 E D */
-#define PCRE_BSR_UNICODE 0x01000000 /* C3 E D */
-#define PCRE_JAVASCRIPT_COMPAT 0x02000000 /* C5 */
-#define PCRE_NO_START_OPTIMIZE 0x04000000 /* C2 E D ) Synonyms */
-#define PCRE_NO_START_OPTIMISE 0x04000000 /* C2 E D ) */
-#define PCRE_PARTIAL_HARD 0x08000000 /* E D J */
-#define PCRE_NOTEMPTY_ATSTART 0x10000000 /* E D J */
-#define PCRE_UCP 0x20000000 /* C3 */
-
-/* Exec-time and get/set-time error codes */
-
-#define PCRE_ERROR_NOMATCH (-1)
-#define PCRE_ERROR_NULL (-2)
-#define PCRE_ERROR_BADOPTION (-3)
-#define PCRE_ERROR_BADMAGIC (-4)
-#define PCRE_ERROR_UNKNOWN_OPCODE (-5)
-#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */
-#define PCRE_ERROR_NOMEMORY (-6)
-#define PCRE_ERROR_NOSUBSTRING (-7)
-#define PCRE_ERROR_MATCHLIMIT (-8)
-#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */
-#define PCRE_ERROR_BADUTF8 (-10) /* Same for 8/16/32 */
-#define PCRE_ERROR_BADUTF16 (-10) /* Same for 8/16/32 */
-#define PCRE_ERROR_BADUTF32 (-10) /* Same for 8/16/32 */
-#define PCRE_ERROR_BADUTF8_OFFSET (-11) /* Same for 8/16 */
-#define PCRE_ERROR_BADUTF16_OFFSET (-11) /* Same for 8/16 */
-#define PCRE_ERROR_PARTIAL (-12)
-#define PCRE_ERROR_BADPARTIAL (-13)
-#define PCRE_ERROR_INTERNAL (-14)
-#define PCRE_ERROR_BADCOUNT (-15)
-#define PCRE_ERROR_DFA_UITEM (-16)
-#define PCRE_ERROR_DFA_UCOND (-17)
-#define PCRE_ERROR_DFA_UMLIMIT (-18)
-#define PCRE_ERROR_DFA_WSSIZE (-19)
-#define PCRE_ERROR_DFA_RECURSE (-20)
-#define PCRE_ERROR_RECURSIONLIMIT (-21)
-#define PCRE_ERROR_NULLWSLIMIT (-22) /* No longer actually used */
-#define PCRE_ERROR_BADNEWLINE (-23)
-#define PCRE_ERROR_BADOFFSET (-24)
-#define PCRE_ERROR_SHORTUTF8 (-25)
-#define PCRE_ERROR_SHORTUTF16 (-25) /* Same for 8/16 */
-#define PCRE_ERROR_RECURSELOOP (-26)
-#define PCRE_ERROR_JIT_STACKLIMIT (-27)
-#define PCRE_ERROR_BADMODE (-28)
-#define PCRE_ERROR_BADENDIANNESS (-29)
-#define PCRE_ERROR_DFA_BADRESTART (-30)
-#define PCRE_ERROR_JIT_BADOPTION (-31)
-#define PCRE_ERROR_BADLENGTH (-32)
-#define PCRE_ERROR_UNSET (-33)
-
-/* Specific error codes for UTF-8 validity checks */
-
-#define PCRE_UTF8_ERR0 0
-#define PCRE_UTF8_ERR1 1
-#define PCRE_UTF8_ERR2 2
-#define PCRE_UTF8_ERR3 3
-#define PCRE_UTF8_ERR4 4
-#define PCRE_UTF8_ERR5 5
-#define PCRE_UTF8_ERR6 6
-#define PCRE_UTF8_ERR7 7
-#define PCRE_UTF8_ERR8 8
-#define PCRE_UTF8_ERR9 9
-#define PCRE_UTF8_ERR10 10
-#define PCRE_UTF8_ERR11 11
-#define PCRE_UTF8_ERR12 12
-#define PCRE_UTF8_ERR13 13
-#define PCRE_UTF8_ERR14 14
-#define PCRE_UTF8_ERR15 15
-#define PCRE_UTF8_ERR16 16
-#define PCRE_UTF8_ERR17 17
-#define PCRE_UTF8_ERR18 18
-#define PCRE_UTF8_ERR19 19
-#define PCRE_UTF8_ERR20 20
-#define PCRE_UTF8_ERR21 21
-#define PCRE_UTF8_ERR22 22 /* Unused (was non-character) */
-
-/* Specific error codes for UTF-16 validity checks */
-
-#define PCRE_UTF16_ERR0 0
-#define PCRE_UTF16_ERR1 1
-#define PCRE_UTF16_ERR2 2
-#define PCRE_UTF16_ERR3 3
-#define PCRE_UTF16_ERR4 4 /* Unused (was non-character) */
-
-/* Specific error codes for UTF-32 validity checks */
-
-#define PCRE_UTF32_ERR0 0
-#define PCRE_UTF32_ERR1 1
-#define PCRE_UTF32_ERR2 2 /* Unused (was non-character) */
-#define PCRE_UTF32_ERR3 3
-
-/* Request types for pcre_fullinfo() */
-
-#define PCRE_INFO_OPTIONS 0
-#define PCRE_INFO_SIZE 1
-#define PCRE_INFO_CAPTURECOUNT 2
-#define PCRE_INFO_BACKREFMAX 3
-#define PCRE_INFO_FIRSTBYTE 4
-#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */
-#define PCRE_INFO_FIRSTTABLE 5
-#define PCRE_INFO_LASTLITERAL 6
-#define PCRE_INFO_NAMEENTRYSIZE 7
-#define PCRE_INFO_NAMECOUNT 8
-#define PCRE_INFO_NAMETABLE 9
-#define PCRE_INFO_STUDYSIZE 10
-#define PCRE_INFO_DEFAULT_TABLES 11
-#define PCRE_INFO_OKPARTIAL 12
-#define PCRE_INFO_JCHANGED 13
-#define PCRE_INFO_HASCRORLF 14
-#define PCRE_INFO_MINLENGTH 15
-#define PCRE_INFO_JIT 16
-#define PCRE_INFO_JITSIZE 17
-#define PCRE_INFO_MAXLOOKBEHIND 18
-#define PCRE_INFO_FIRSTCHARACTER 19
-#define PCRE_INFO_FIRSTCHARACTERFLAGS 20
-#define PCRE_INFO_REQUIREDCHAR 21
-#define PCRE_INFO_REQUIREDCHARFLAGS 22
-#define PCRE_INFO_MATCHLIMIT 23
-#define PCRE_INFO_RECURSIONLIMIT 24
-#define PCRE_INFO_MATCH_EMPTY 25
-
-/* Request types for pcre_config(). Do not re-arrange, in order to remain
-compatible. */
-
-#define PCRE_CONFIG_UTF8 0
-#define PCRE_CONFIG_NEWLINE 1
-#define PCRE_CONFIG_LINK_SIZE 2
-#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3
-#define PCRE_CONFIG_MATCH_LIMIT 4
-#define PCRE_CONFIG_STACKRECURSE 5
-#define PCRE_CONFIG_UNICODE_PROPERTIES 6
-#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7
-#define PCRE_CONFIG_BSR 8
-#define PCRE_CONFIG_JIT 9
-#define PCRE_CONFIG_UTF16 10
-#define PCRE_CONFIG_JITTARGET 11
-#define PCRE_CONFIG_UTF32 12
-#define PCRE_CONFIG_PARENS_LIMIT 13
-
-/* Request types for pcre_study(). Do not re-arrange, in order to remain
-compatible. */
-
-#define PCRE_STUDY_JIT_COMPILE 0x0001
-#define PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE 0x0002
-#define PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE 0x0004
-#define PCRE_STUDY_EXTRA_NEEDED 0x0008
-
-/* Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine
-these bits, just add new ones on the end, in order to remain compatible. */
-
-#define PCRE_EXTRA_STUDY_DATA 0x0001
-#define PCRE_EXTRA_MATCH_LIMIT 0x0002
-#define PCRE_EXTRA_CALLOUT_DATA 0x0004
-#define PCRE_EXTRA_TABLES 0x0008
-#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010
-#define PCRE_EXTRA_MARK 0x0020
-#define PCRE_EXTRA_EXECUTABLE_JIT 0x0040
-
-/* Types */
-
-struct real_pcre; /* declaration; the definition is private */
-typedef struct real_pcre pcre;
-
-struct real_pcre16; /* declaration; the definition is private */
-typedef struct real_pcre16 pcre16;
-
-struct real_pcre32; /* declaration; the definition is private */
-typedef struct real_pcre32 pcre32;
-
-struct real_pcre_jit_stack; /* declaration; the definition is private */
-typedef struct real_pcre_jit_stack pcre_jit_stack;
-
-struct real_pcre16_jit_stack; /* declaration; the definition is private */
-typedef struct real_pcre16_jit_stack pcre16_jit_stack;
-
-struct real_pcre32_jit_stack; /* declaration; the definition is private */
-typedef struct real_pcre32_jit_stack pcre32_jit_stack;
-
-/* If PCRE is compiled with 16 bit character support, PCRE_UCHAR16 must contain
-a 16 bit wide signed data type. Otherwise it can be a dummy data type since
-pcre16 functions are not implemented. There is a check for this in pcre_internal.h. */
-#ifndef PCRE_UCHAR16
-#define PCRE_UCHAR16 unsigned short
-#endif
-
-#ifndef PCRE_SPTR16
-#define PCRE_SPTR16 const PCRE_UCHAR16 *
-#endif
-
-/* If PCRE is compiled with 32 bit character support, PCRE_UCHAR32 must contain
-a 32 bit wide signed data type. Otherwise it can be a dummy data type since
-pcre32 functions are not implemented. There is a check for this in pcre_internal.h. */
-#ifndef PCRE_UCHAR32
-#define PCRE_UCHAR32 unsigned int
-#endif
-
-#ifndef PCRE_SPTR32
-#define PCRE_SPTR32 const PCRE_UCHAR32 *
-#endif
-
-/* When PCRE is compiled as a C++ library, the subject pointer type can be
-replaced with a custom type. For conventional use, the public interface is a
-const char *. */
-
-#ifndef PCRE_SPTR
-#define PCRE_SPTR const char *
-#endif
-
-/* The structure for passing additional data to pcre_exec(). This is defined in
-such as way as to be extensible. Always add new fields at the end, in order to
-remain compatible. */
-
-typedef struct pcre_extra {
- unsigned long int flags; /* Bits for which fields are set */
- void *study_data; /* Opaque data from pcre_study() */
- unsigned long int match_limit; /* Maximum number of calls to match() */
- void *callout_data; /* Data passed back in callouts */
- const unsigned char *tables; /* Pointer to character tables */
- unsigned long int match_limit_recursion; /* Max recursive calls to match() */
- unsigned char **mark; /* For passing back a mark pointer */
- void *executable_jit; /* Contains a pointer to a compiled jit code */
-} pcre_extra;
-
-/* Same structure as above, but with 16 bit char pointers. */
-
-typedef struct pcre16_extra {
- unsigned long int flags; /* Bits for which fields are set */
- void *study_data; /* Opaque data from pcre_study() */
- unsigned long int match_limit; /* Maximum number of calls to match() */
- void *callout_data; /* Data passed back in callouts */
- const unsigned char *tables; /* Pointer to character tables */
- unsigned long int match_limit_recursion; /* Max recursive calls to match() */
- PCRE_UCHAR16 **mark; /* For passing back a mark pointer */
- void *executable_jit; /* Contains a pointer to a compiled jit code */
-} pcre16_extra;
-
-/* Same structure as above, but with 32 bit char pointers. */
-
-typedef struct pcre32_extra {
- unsigned long int flags; /* Bits for which fields are set */
- void *study_data; /* Opaque data from pcre_study() */
- unsigned long int match_limit; /* Maximum number of calls to match() */
- void *callout_data; /* Data passed back in callouts */
- const unsigned char *tables; /* Pointer to character tables */
- unsigned long int match_limit_recursion; /* Max recursive calls to match() */
- PCRE_UCHAR32 **mark; /* For passing back a mark pointer */
- void *executable_jit; /* Contains a pointer to a compiled jit code */
-} pcre32_extra;
-
-/* The structure for passing out data via the pcre_callout_function. We use a
-structure so that new fields can be added on the end in future versions,
-without changing the API of the function, thereby allowing old clients to work
-without modification. */
-
-typedef struct pcre_callout_block {
- int version; /* Identifies version of block */
- /* ------------------------ Version 0 ------------------------------- */
- int callout_number; /* Number compiled into pattern */
- int *offset_vector; /* The offset vector */
- PCRE_SPTR subject; /* The subject being matched */
- int subject_length; /* The length of the subject */
- int start_match; /* Offset to start of this match attempt */
- int current_position; /* Where we currently are in the subject */
- int capture_top; /* Max current capture */
- int capture_last; /* Most recently closed capture */
- void *callout_data; /* Data passed in with the call */
- /* ------------------- Added for Version 1 -------------------------- */
- int pattern_position; /* Offset to next item in the pattern */
- int next_item_length; /* Length of next item in the pattern */
- /* ------------------- Added for Version 2 -------------------------- */
- const unsigned char *mark; /* Pointer to current mark or NULL */
- /* ------------------------------------------------------------------ */
-} pcre_callout_block;
-
-/* Same structure as above, but with 16 bit char pointers. */
-
-typedef struct pcre16_callout_block {
- int version; /* Identifies version of block */
- /* ------------------------ Version 0 ------------------------------- */
- int callout_number; /* Number compiled into pattern */
- int *offset_vector; /* The offset vector */
- PCRE_SPTR16 subject; /* The subject being matched */
- int subject_length; /* The length of the subject */
- int start_match; /* Offset to start of this match attempt */
- int current_position; /* Where we currently are in the subject */
- int capture_top; /* Max current capture */
- int capture_last; /* Most recently closed capture */
- void *callout_data; /* Data passed in with the call */
- /* ------------------- Added for Version 1 -------------------------- */
- int pattern_position; /* Offset to next item in the pattern */
- int next_item_length; /* Length of next item in the pattern */
- /* ------------------- Added for Version 2 -------------------------- */
- const PCRE_UCHAR16 *mark; /* Pointer to current mark or NULL */
- /* ------------------------------------------------------------------ */
-} pcre16_callout_block;
-
-/* Same structure as above, but with 32 bit char pointers. */
-
-typedef struct pcre32_callout_block {
- int version; /* Identifies version of block */
- /* ------------------------ Version 0 ------------------------------- */
- int callout_number; /* Number compiled into pattern */
- int *offset_vector; /* The offset vector */
- PCRE_SPTR32 subject; /* The subject being matched */
- int subject_length; /* The length of the subject */
- int start_match; /* Offset to start of this match attempt */
- int current_position; /* Where we currently are in the subject */
- int capture_top; /* Max current capture */
- int capture_last; /* Most recently closed capture */
- void *callout_data; /* Data passed in with the call */
- /* ------------------- Added for Version 1 -------------------------- */
- int pattern_position; /* Offset to next item in the pattern */
- int next_item_length; /* Length of next item in the pattern */
- /* ------------------- Added for Version 2 -------------------------- */
- const PCRE_UCHAR32 *mark; /* Pointer to current mark or NULL */
- /* ------------------------------------------------------------------ */
-} pcre32_callout_block;
-
-/* Indirection for store get and free functions. These can be set to
-alternative malloc/free functions if required. Special ones are used in the
-non-recursive case for "frames". There is also an optional callout function
-that is triggered by the (?) regex item. For Virtual Pascal, these definitions
-have to take another form. */
-
-#ifndef VPCOMPAT
-PCRE_EXP_DECL void *(*pcre_malloc)(size_t);
-PCRE_EXP_DECL void (*pcre_free)(void *);
-PCRE_EXP_DECL void *(*pcre_stack_malloc)(size_t);
-PCRE_EXP_DECL void (*pcre_stack_free)(void *);
-PCRE_EXP_DECL int (*pcre_callout)(pcre_callout_block *);
-PCRE_EXP_DECL int (*pcre_stack_guard)(void);
-
-PCRE_EXP_DECL void *(*pcre16_malloc)(size_t);
-PCRE_EXP_DECL void (*pcre16_free)(void *);
-PCRE_EXP_DECL void *(*pcre16_stack_malloc)(size_t);
-PCRE_EXP_DECL void (*pcre16_stack_free)(void *);
-PCRE_EXP_DECL int (*pcre16_callout)(pcre16_callout_block *);
-PCRE_EXP_DECL int (*pcre16_stack_guard)(void);
-
-PCRE_EXP_DECL void *(*pcre32_malloc)(size_t);
-PCRE_EXP_DECL void (*pcre32_free)(void *);
-PCRE_EXP_DECL void *(*pcre32_stack_malloc)(size_t);
-PCRE_EXP_DECL void (*pcre32_stack_free)(void *);
-PCRE_EXP_DECL int (*pcre32_callout)(pcre32_callout_block *);
-PCRE_EXP_DECL int (*pcre32_stack_guard)(void);
-#else /* VPCOMPAT */
-PCRE_EXP_DECL void *pcre_malloc(size_t);
-PCRE_EXP_DECL void pcre_free(void *);
-PCRE_EXP_DECL void *pcre_stack_malloc(size_t);
-PCRE_EXP_DECL void pcre_stack_free(void *);
-PCRE_EXP_DECL int pcre_callout(pcre_callout_block *);
-PCRE_EXP_DECL int pcre_stack_guard(void);
-
-PCRE_EXP_DECL void *pcre16_malloc(size_t);
-PCRE_EXP_DECL void pcre16_free(void *);
-PCRE_EXP_DECL void *pcre16_stack_malloc(size_t);
-PCRE_EXP_DECL void pcre16_stack_free(void *);
-PCRE_EXP_DECL int pcre16_callout(pcre16_callout_block *);
-PCRE_EXP_DECL int pcre16_stack_guard(void);
-
-PCRE_EXP_DECL void *pcre32_malloc(size_t);
-PCRE_EXP_DECL void pcre32_free(void *);
-PCRE_EXP_DECL void *pcre32_stack_malloc(size_t);
-PCRE_EXP_DECL void pcre32_stack_free(void *);
-PCRE_EXP_DECL int pcre32_callout(pcre32_callout_block *);
-PCRE_EXP_DECL int pcre32_stack_guard(void);
-#endif /* VPCOMPAT */
-
-/* User defined callback which provides a stack just before the match starts. */
-
-typedef pcre_jit_stack *(*pcre_jit_callback)(void *);
-typedef pcre16_jit_stack *(*pcre16_jit_callback)(void *);
-typedef pcre32_jit_stack *(*pcre32_jit_callback)(void *);
-
-/* Exported PCRE functions */
-
-PCRE_EXP_DECL pcre *pcre_compile(const char *, int, const char **, int *,
- const unsigned char *);
-PCRE_EXP_DECL pcre16 *pcre16_compile(PCRE_SPTR16, int, const char **, int *,
- const unsigned char *);
-PCRE_EXP_DECL pcre32 *pcre32_compile(PCRE_SPTR32, int, const char **, int *,
- const unsigned char *);
-PCRE_EXP_DECL pcre *pcre_compile2(const char *, int, int *, const char **,
- int *, const unsigned char *);
-PCRE_EXP_DECL pcre16 *pcre16_compile2(PCRE_SPTR16, int, int *, const char **,
- int *, const unsigned char *);
-PCRE_EXP_DECL pcre32 *pcre32_compile2(PCRE_SPTR32, int, int *, const char **,
- int *, const unsigned char *);
-PCRE_EXP_DECL int pcre_config(int, void *);
-PCRE_EXP_DECL int pcre16_config(int, void *);
-PCRE_EXP_DECL int pcre32_config(int, void *);
-PCRE_EXP_DECL int pcre_copy_named_substring(const pcre *, const char *,
- int *, int, const char *, char *, int);
-PCRE_EXP_DECL int pcre16_copy_named_substring(const pcre16 *, PCRE_SPTR16,
- int *, int, PCRE_SPTR16, PCRE_UCHAR16 *, int);
-PCRE_EXP_DECL int pcre32_copy_named_substring(const pcre32 *, PCRE_SPTR32,
- int *, int, PCRE_SPTR32, PCRE_UCHAR32 *, int);
-PCRE_EXP_DECL int pcre_copy_substring(const char *, int *, int, int,
- char *, int);
-PCRE_EXP_DECL int pcre16_copy_substring(PCRE_SPTR16, int *, int, int,
- PCRE_UCHAR16 *, int);
-PCRE_EXP_DECL int pcre32_copy_substring(PCRE_SPTR32, int *, int, int,
- PCRE_UCHAR32 *, int);
-PCRE_EXP_DECL int pcre_dfa_exec(const pcre *, const pcre_extra *,
- const char *, int, int, int, int *, int , int *, int);
-PCRE_EXP_DECL int pcre16_dfa_exec(const pcre16 *, const pcre16_extra *,
- PCRE_SPTR16, int, int, int, int *, int , int *, int);
-PCRE_EXP_DECL int pcre32_dfa_exec(const pcre32 *, const pcre32_extra *,
- PCRE_SPTR32, int, int, int, int *, int , int *, int);
-PCRE_EXP_DECL int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR,
- int, int, int, int *, int);
-PCRE_EXP_DECL int pcre16_exec(const pcre16 *, const pcre16_extra *,
- PCRE_SPTR16, int, int, int, int *, int);
-PCRE_EXP_DECL int pcre32_exec(const pcre32 *, const pcre32_extra *,
- PCRE_SPTR32, int, int, int, int *, int);
-PCRE_EXP_DECL int pcre_jit_exec(const pcre *, const pcre_extra *,
- PCRE_SPTR, int, int, int, int *, int,
- pcre_jit_stack *);
-PCRE_EXP_DECL int pcre16_jit_exec(const pcre16 *, const pcre16_extra *,
- PCRE_SPTR16, int, int, int, int *, int,
- pcre16_jit_stack *);
-PCRE_EXP_DECL int pcre32_jit_exec(const pcre32 *, const pcre32_extra *,
- PCRE_SPTR32, int, int, int, int *, int,
- pcre32_jit_stack *);
-PCRE_EXP_DECL void pcre_free_substring(const char *);
-PCRE_EXP_DECL void pcre16_free_substring(PCRE_SPTR16);
-PCRE_EXP_DECL void pcre32_free_substring(PCRE_SPTR32);
-PCRE_EXP_DECL void pcre_free_substring_list(const char **);
-PCRE_EXP_DECL void pcre16_free_substring_list(PCRE_SPTR16 *);
-PCRE_EXP_DECL void pcre32_free_substring_list(PCRE_SPTR32 *);
-PCRE_EXP_DECL int pcre_fullinfo(const pcre *, const pcre_extra *, int,
- void *);
-PCRE_EXP_DECL int pcre16_fullinfo(const pcre16 *, const pcre16_extra *, int,
- void *);
-PCRE_EXP_DECL int pcre32_fullinfo(const pcre32 *, const pcre32_extra *, int,
- void *);
-PCRE_EXP_DECL int pcre_get_named_substring(const pcre *, const char *,
- int *, int, const char *, const char **);
-PCRE_EXP_DECL int pcre16_get_named_substring(const pcre16 *, PCRE_SPTR16,
- int *, int, PCRE_SPTR16, PCRE_SPTR16 *);
-PCRE_EXP_DECL int pcre32_get_named_substring(const pcre32 *, PCRE_SPTR32,
- int *, int, PCRE_SPTR32, PCRE_SPTR32 *);
-PCRE_EXP_DECL int pcre_get_stringnumber(const pcre *, const char *);
-PCRE_EXP_DECL int pcre16_get_stringnumber(const pcre16 *, PCRE_SPTR16);
-PCRE_EXP_DECL int pcre32_get_stringnumber(const pcre32 *, PCRE_SPTR32);
-PCRE_EXP_DECL int pcre_get_stringtable_entries(const pcre *, const char *,
- char **, char **);
-PCRE_EXP_DECL int pcre16_get_stringtable_entries(const pcre16 *, PCRE_SPTR16,
- PCRE_UCHAR16 **, PCRE_UCHAR16 **);
-PCRE_EXP_DECL int pcre32_get_stringtable_entries(const pcre32 *, PCRE_SPTR32,
- PCRE_UCHAR32 **, PCRE_UCHAR32 **);
-PCRE_EXP_DECL int pcre_get_substring(const char *, int *, int, int,
- const char **);
-PCRE_EXP_DECL int pcre16_get_substring(PCRE_SPTR16, int *, int, int,
- PCRE_SPTR16 *);
-PCRE_EXP_DECL int pcre32_get_substring(PCRE_SPTR32, int *, int, int,
- PCRE_SPTR32 *);
-PCRE_EXP_DECL int pcre_get_substring_list(const char *, int *, int,
- const char ***);
-PCRE_EXP_DECL int pcre16_get_substring_list(PCRE_SPTR16, int *, int,
- PCRE_SPTR16 **);
-PCRE_EXP_DECL int pcre32_get_substring_list(PCRE_SPTR32, int *, int,
- PCRE_SPTR32 **);
-PCRE_EXP_DECL const unsigned char *pcre_maketables(void);
-PCRE_EXP_DECL const unsigned char *pcre16_maketables(void);
-PCRE_EXP_DECL const unsigned char *pcre32_maketables(void);
-PCRE_EXP_DECL int pcre_refcount(pcre *, int);
-PCRE_EXP_DECL int pcre16_refcount(pcre16 *, int);
-PCRE_EXP_DECL int pcre32_refcount(pcre32 *, int);
-PCRE_EXP_DECL pcre_extra *pcre_study(const pcre *, int, const char **);
-PCRE_EXP_DECL pcre16_extra *pcre16_study(const pcre16 *, int, const char **);
-PCRE_EXP_DECL pcre32_extra *pcre32_study(const pcre32 *, int, const char **);
-PCRE_EXP_DECL void pcre_free_study(pcre_extra *);
-PCRE_EXP_DECL void pcre16_free_study(pcre16_extra *);
-PCRE_EXP_DECL void pcre32_free_study(pcre32_extra *);
-PCRE_EXP_DECL const char *pcre_version(void);
-PCRE_EXP_DECL const char *pcre16_version(void);
-PCRE_EXP_DECL const char *pcre32_version(void);
-
-/* Utility functions for byte order swaps. */
-PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *, pcre_extra *,
- const unsigned char *);
-PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *, pcre16_extra *,
- const unsigned char *);
-PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *, pcre32_extra *,
- const unsigned char *);
-PCRE_EXP_DECL int pcre16_utf16_to_host_byte_order(PCRE_UCHAR16 *,
- PCRE_SPTR16, int, int *, int);
-PCRE_EXP_DECL int pcre32_utf32_to_host_byte_order(PCRE_UCHAR32 *,
- PCRE_SPTR32, int, int *, int);
-
-/* JIT compiler related functions. */
-
-PCRE_EXP_DECL pcre_jit_stack *pcre_jit_stack_alloc(int, int);
-PCRE_EXP_DECL pcre16_jit_stack *pcre16_jit_stack_alloc(int, int);
-PCRE_EXP_DECL pcre32_jit_stack *pcre32_jit_stack_alloc(int, int);
-PCRE_EXP_DECL void pcre_jit_stack_free(pcre_jit_stack *);
-PCRE_EXP_DECL void pcre16_jit_stack_free(pcre16_jit_stack *);
-PCRE_EXP_DECL void pcre32_jit_stack_free(pcre32_jit_stack *);
-PCRE_EXP_DECL void pcre_assign_jit_stack(pcre_extra *,
- pcre_jit_callback, void *);
-PCRE_EXP_DECL void pcre16_assign_jit_stack(pcre16_extra *,
- pcre16_jit_callback, void *);
-PCRE_EXP_DECL void pcre32_assign_jit_stack(pcre32_extra *,
- pcre32_jit_callback, void *);
-PCRE_EXP_DECL void pcre_jit_free_unused_memory(void);
-PCRE_EXP_DECL void pcre16_jit_free_unused_memory(void);
-PCRE_EXP_DECL void pcre32_jit_free_unused_memory(void);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* End of pcre.h */
diff --git a/src/3rdparty/pcre/pcre.pro b/src/3rdparty/pcre/pcre.pro
deleted file mode 100644
index add4a932b3..0000000000
--- a/src/3rdparty/pcre/pcre.pro
+++ /dev/null
@@ -1,46 +0,0 @@
-TARGET = qtpcre
-
-CONFIG += \
- static \
- hide_symbols \
- exceptions_off rtti_off warn_off
-
-win32: MODULE_DEFINES += PCRE_STATIC
-MODULE_INCLUDEPATH += $$PWD
-
-load(qt_helper_lib)
-
-DEFINES += HAVE_CONFIG_H
-
-# platform/compiler specific definitions
-uikit|qnx|winrt: DEFINES += PCRE_DISABLE_JIT
-
-SOURCES += \
- $$PWD/pcre16_byte_order.c \
- $$PWD/pcre16_chartables.c \
- $$PWD/pcre16_compile.c \
- $$PWD/pcre16_config.c \
- $$PWD/pcre16_dfa_exec.c \
- $$PWD/pcre16_exec.c \
- $$PWD/pcre16_fullinfo.c \
- $$PWD/pcre16_get.c \
- $$PWD/pcre16_globals.c \
- $$PWD/pcre16_jit_compile.c \
- $$PWD/pcre16_maketables.c \
- $$PWD/pcre16_newline.c \
- $$PWD/pcre16_ord2utf16.c \
- $$PWD/pcre16_refcount.c \
- $$PWD/pcre16_string_utils.c \
- $$PWD/pcre16_study.c \
- $$PWD/pcre16_tables.c \
- $$PWD/pcre16_ucd.c \
- $$PWD/pcre16_utf16_utils.c \
- $$PWD/pcre16_valid_utf16.c \
- $$PWD/pcre16_version.c \
- $$PWD/pcre16_xclass.c
-
-HEADERS += \
- $$PWD/config.h \
- $$PWD/pcre.h \
- $$PWD/pcre_internal.h \
- $$PWD/ucp.h
diff --git a/src/3rdparty/pcre/pcre16_byte_order.c b/src/3rdparty/pcre/pcre16_byte_order.c
deleted file mode 100644
index 11d2973a3d..0000000000
--- a/src/3rdparty/pcre/pcre16_byte_order.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_byte_order.c"
-
-/* End of pcre16_byte_order.c */
diff --git a/src/3rdparty/pcre/pcre16_chartables.c b/src/3rdparty/pcre/pcre16_chartables.c
deleted file mode 100644
index 7c0ff35f5e..0000000000
--- a/src/3rdparty/pcre/pcre16_chartables.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_chartables.c"
-
-/* End of pcre16_chartables.c */
diff --git a/src/3rdparty/pcre/pcre16_compile.c b/src/3rdparty/pcre/pcre16_compile.c
deleted file mode 100644
index e499b67087..0000000000
--- a/src/3rdparty/pcre/pcre16_compile.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_compile.c"
-
-/* End of pcre16_compile.c */
diff --git a/src/3rdparty/pcre/pcre16_config.c b/src/3rdparty/pcre/pcre16_config.c
deleted file mode 100644
index b52138764f..0000000000
--- a/src/3rdparty/pcre/pcre16_config.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_config.c"
-
-/* End of pcre16_config.c */
diff --git a/src/3rdparty/pcre/pcre16_dfa_exec.c b/src/3rdparty/pcre/pcre16_dfa_exec.c
deleted file mode 100644
index 2ba740e972..0000000000
--- a/src/3rdparty/pcre/pcre16_dfa_exec.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_dfa_exec.c"
-
-/* End of pcre16_dfa_exec.c */
diff --git a/src/3rdparty/pcre/pcre16_exec.c b/src/3rdparty/pcre/pcre16_exec.c
deleted file mode 100644
index 7417b1770c..0000000000
--- a/src/3rdparty/pcre/pcre16_exec.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_exec.c"
-
-/* End of pcre16_exec.c */
diff --git a/src/3rdparty/pcre/pcre16_fullinfo.c b/src/3rdparty/pcre/pcre16_fullinfo.c
deleted file mode 100644
index 544dca6ed5..0000000000
--- a/src/3rdparty/pcre/pcre16_fullinfo.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_fullinfo.c"
-
-/* End of pcre16_fullinfo.c */
diff --git a/src/3rdparty/pcre/pcre16_get.c b/src/3rdparty/pcre/pcre16_get.c
deleted file mode 100644
index 3ded08c622..0000000000
--- a/src/3rdparty/pcre/pcre16_get.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_get.c"
-
-/* End of pcre16_get.c */
diff --git a/src/3rdparty/pcre/pcre16_globals.c b/src/3rdparty/pcre/pcre16_globals.c
deleted file mode 100644
index a136b3d8c2..0000000000
--- a/src/3rdparty/pcre/pcre16_globals.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_globals.c"
-
-/* End of pcre16_globals.c */
diff --git a/src/3rdparty/pcre/pcre16_jit_compile.c b/src/3rdparty/pcre/pcre16_jit_compile.c
deleted file mode 100644
index ab0cacd764..0000000000
--- a/src/3rdparty/pcre/pcre16_jit_compile.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_jit_compile.c"
-
-/* End of pcre16_jit_compile.c */
diff --git a/src/3rdparty/pcre/pcre16_maketables.c b/src/3rdparty/pcre/pcre16_maketables.c
deleted file mode 100644
index b1cd1c579d..0000000000
--- a/src/3rdparty/pcre/pcre16_maketables.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_maketables.c"
-
-/* End of pcre16_maketables.c */
diff --git a/src/3rdparty/pcre/pcre16_newline.c b/src/3rdparty/pcre/pcre16_newline.c
deleted file mode 100644
index 7fe201400f..0000000000
--- a/src/3rdparty/pcre/pcre16_newline.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_newline.c"
-
-/* End of pcre16_newline.c */
diff --git a/src/3rdparty/pcre/pcre16_ord2utf16.c b/src/3rdparty/pcre/pcre16_ord2utf16.c
deleted file mode 100644
index 8e2ce5ea6c..0000000000
--- a/src/3rdparty/pcre/pcre16_ord2utf16.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This file contains a private PCRE function that converts an ordinal
-character value into a UTF16 string. */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_internal.h"
-
-/*************************************************
-* Convert character value to UTF-16 *
-*************************************************/
-
-/* This function takes an integer value in the range 0 - 0x10ffff
-and encodes it as a UTF-16 character in 1 to 2 pcre_uchars.
-
-Arguments:
- cvalue the character value
- buffer pointer to buffer for result - at least 2 pcre_uchars long
-
-Returns: number of characters placed in the buffer
-*/
-
-unsigned int
-PRIV(ord2utf)(pcre_uint32 cvalue, pcre_uchar *buffer)
-{
-#ifdef SUPPORT_UTF
-
-if (cvalue <= 0xffff)
- {
- *buffer = (pcre_uchar)cvalue;
- return 1;
- }
-
-cvalue -= 0x10000;
-*buffer++ = 0xd800 | (cvalue >> 10);
-*buffer = 0xdc00 | (cvalue & 0x3ff);
-return 2;
-
-#else /* SUPPORT_UTF */
-(void)(cvalue); /* Keep compiler happy; this function won't ever be */
-(void)(buffer); /* called when SUPPORT_UTF is not defined. */
-return 0;
-#endif /* SUPPORT_UTF */
-}
-
-/* End of pcre16_ord2utf16.c */
diff --git a/src/3rdparty/pcre/pcre16_refcount.c b/src/3rdparty/pcre/pcre16_refcount.c
deleted file mode 100644
index d3d1543973..0000000000
--- a/src/3rdparty/pcre/pcre16_refcount.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_refcount.c"
-
-/* End of pcre16_refcount.c */
diff --git a/src/3rdparty/pcre/pcre16_string_utils.c b/src/3rdparty/pcre/pcre16_string_utils.c
deleted file mode 100644
index 382c40799f..0000000000
--- a/src/3rdparty/pcre/pcre16_string_utils.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_string_utils.c"
-
-/* End of pcre16_string_utils.c */
diff --git a/src/3rdparty/pcre/pcre16_study.c b/src/3rdparty/pcre/pcre16_study.c
deleted file mode 100644
index f87de081fc..0000000000
--- a/src/3rdparty/pcre/pcre16_study.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_study.c"
-
-/* End of pcre16_study.c */
diff --git a/src/3rdparty/pcre/pcre16_tables.c b/src/3rdparty/pcre/pcre16_tables.c
deleted file mode 100644
index d84297093a..0000000000
--- a/src/3rdparty/pcre/pcre16_tables.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_tables.c"
-
-/* End of pcre16_tables.c */
diff --git a/src/3rdparty/pcre/pcre16_ucd.c b/src/3rdparty/pcre/pcre16_ucd.c
deleted file mode 100644
index ee23439a01..0000000000
--- a/src/3rdparty/pcre/pcre16_ucd.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_ucd.c"
-
-/* End of pcre16_ucd.c */
diff --git a/src/3rdparty/pcre/pcre16_utf16_utils.c b/src/3rdparty/pcre/pcre16_utf16_utils.c
deleted file mode 100644
index 49ced0c0b1..0000000000
--- a/src/3rdparty/pcre/pcre16_utf16_utils.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains a function for converting any UTF-16 character
-strings to host byte order. */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_internal.h"
-
-/*************************************************
-* Convert any UTF-16 string to host byte order *
-*************************************************/
-
-/* This function takes an UTF-16 string and converts
-it to host byte order. The length can be explicitly set,
-or automatically detected for zero terminated strings.
-BOMs can be kept or discarded during the conversion.
-Conversion can be done in place (output == input).
-
-Arguments:
- output the output buffer, its size must be greater
- or equal than the input string
- input any UTF-16 string
- length the number of 16-bit units in the input string
- can be less than zero for zero terminated strings
- host_byte_order
- A non-zero value means the input is in host byte
- order, which can be dynamically changed by BOMs later.
- Initially it contains the starting byte order and returns
- with the last byte order so it can be used for stream
- processing. It can be NULL, which set the host byte
- order mode by default.
- keep_boms for a non-zero value, the BOM (0xfeff) characters
- are copied as well
-
-Returns: the number of 16-bit units placed into the output buffer,
- including the zero-terminator
-*/
-
-int
-pcre16_utf16_to_host_byte_order(PCRE_UCHAR16 *output, PCRE_SPTR16 input,
- int length, int *host_byte_order, int keep_boms)
-{
-#ifdef SUPPORT_UTF
-/* This function converts any UTF-16 string to host byte order and optionally
-removes any Byte Order Marks (BOMS). Returns with the remainig length. */
-int host_bo = host_byte_order != NULL ? *host_byte_order : 1;
-pcre_uchar *optr = (pcre_uchar *)output;
-const pcre_uchar *iptr = (const pcre_uchar *)input;
-const pcre_uchar *end;
-/* The c variable must be unsigned. */
-register pcre_uchar c;
-
-if (length < 0)
- length = STRLEN_UC(iptr) + 1;
-end = iptr + length;
-
-while (iptr < end)
- {
- c = *iptr++;
- if (c == 0xfeff || c == 0xfffe)
- {
- /* Detecting the byte order of the machine is unnecessary, it is
- enough to know that the UTF-16 string has the same byte order or not. */
- host_bo = c == 0xfeff;
- if (keep_boms != 0)
- *optr++ = 0xfeff;
- else
- length--;
- }
- else
- *optr++ = host_bo ? c : ((c >> 8) | (c << 8)); /* Flip bytes if needed. */
- }
-if (host_byte_order != NULL)
- *host_byte_order = host_bo;
-
-#else /* Not SUPPORT_UTF */
-(void)(output); /* Keep picky compilers happy */
-(void)(input);
-(void)(keep_boms);
-(void)(host_byte_order);
-#endif /* SUPPORT_UTF */
-return length;
-}
-
-/* End of pcre16_utf16_utils.c */
diff --git a/src/3rdparty/pcre/pcre16_valid_utf16.c b/src/3rdparty/pcre/pcre16_valid_utf16.c
deleted file mode 100644
index 09076539d0..0000000000
--- a/src/3rdparty/pcre/pcre16_valid_utf16.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2013 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains an internal function for validating UTF-16 character
-strings. */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_internal.h"
-
-
-/*************************************************
-* Validate a UTF-16 string *
-*************************************************/
-
-/* This function is called (optionally) at the start of compile or match, to
-check that a supposed UTF-16 string is actually valid. The early check means
-that subsequent code can assume it is dealing with a valid string. The check
-can be turned off for maximum performance, but the consequences of supplying an
-invalid string are then undefined.
-
-From release 8.21 more information about the details of the error are passed
-back in the returned value:
-
-PCRE_UTF16_ERR0 No error
-PCRE_UTF16_ERR1 Missing low surrogate at the end of the string
-PCRE_UTF16_ERR2 Invalid low surrogate
-PCRE_UTF16_ERR3 Isolated low surrogate
-PCRE_UTF16_ERR4 Unused (was non-character)
-
-Arguments:
- string points to the string
- length length of string, or -1 if the string is zero-terminated
- errp pointer to an error position offset variable
-
-Returns: = 0 if the string is a valid UTF-16 string
- > 0 otherwise, setting the offset of the bad character
-*/
-
-int
-PRIV(valid_utf)(PCRE_PUCHAR string, int length, int *erroroffset)
-{
-#ifdef SUPPORT_UTF
-register PCRE_PUCHAR p;
-register pcre_uint32 c;
-
-if (length < 0)
- {
- for (p = string; *p != 0; p++);
- length = p - string;
- }
-
-for (p = string; length-- > 0; p++)
- {
- c = *p;
-
- if ((c & 0xf800) != 0xd800)
- {
- /* Normal UTF-16 code point. Neither high nor low surrogate. */
- }
- else if ((c & 0x0400) == 0)
- {
- /* High surrogate. Must be a followed by a low surrogate. */
- if (length == 0)
- {
- *erroroffset = p - string;
- return PCRE_UTF16_ERR1;
- }
- p++;
- length--;
- if ((*p & 0xfc00) != 0xdc00)
- {
- *erroroffset = p - string;
- return PCRE_UTF16_ERR2;
- }
- }
- else
- {
- /* Isolated low surrogate. Always an error. */
- *erroroffset = p - string;
- return PCRE_UTF16_ERR3;
- }
- }
-
-#else /* SUPPORT_UTF */
-(void)(string); /* Keep picky compilers happy */
-(void)(length);
-(void)(erroroffset);
-#endif /* SUPPORT_UTF */
-
-return PCRE_UTF16_ERR0; /* This indicates success */
-}
-
-/* End of pcre16_valid_utf16.c */
diff --git a/src/3rdparty/pcre/pcre16_version.c b/src/3rdparty/pcre/pcre16_version.c
deleted file mode 100644
index e991b1a8cf..0000000000
--- a/src/3rdparty/pcre/pcre16_version.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_version.c"
-
-/* End of pcre16_version.c */
diff --git a/src/3rdparty/pcre/pcre16_xclass.c b/src/3rdparty/pcre/pcre16_xclass.c
deleted file mode 100644
index 5aac2a36c6..0000000000
--- a/src/3rdparty/pcre/pcre16_xclass.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-/* Generate code with 16 bit character support. */
-#define COMPILE_PCRE16
-
-#include "pcre_xclass.c"
-
-/* End of pcre16_xclass.c */
diff --git a/src/3rdparty/pcre/pcre_byte_order.c b/src/3rdparty/pcre/pcre_byte_order.c
deleted file mode 100644
index cf5f12b04e..0000000000
--- a/src/3rdparty/pcre/pcre_byte_order.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2014 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains an internal function that tests a compiled pattern to
-see if it was compiled with the opposite endianness. If so, it uses an
-auxiliary local function to flip the appropriate bytes. */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "pcre_internal.h"
-
-
-/*************************************************
-* Swap byte functions *
-*************************************************/
-
-/* The following functions swap the bytes of a pcre_uint16
-and pcre_uint32 value.
-
-Arguments:
- value any number
-
-Returns: the byte swapped value
-*/
-
-static pcre_uint32
-swap_uint32(pcre_uint32 value)
-{
-return ((value & 0x000000ff) << 24) |
- ((value & 0x0000ff00) << 8) |
- ((value & 0x00ff0000) >> 8) |
- (value >> 24);
-}
-
-static pcre_uint16
-swap_uint16(pcre_uint16 value)
-{
-return (value >> 8) | (value << 8);
-}
-
-
-/*************************************************
-* Test for a byte-flipped compiled regex *
-*************************************************/
-
-/* This function swaps the bytes of a compiled pattern usually
-loaded form the disk. It also sets the tables pointer, which
-is likely an invalid pointer after reload.
-
-Arguments:
- argument_re points to the compiled expression
- extra_data points to extra data or is NULL
- tables points to the character tables or NULL
-
-Returns: 0 if the swap is successful, negative on error
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *argument_re,
- pcre_extra *extra_data, const unsigned char *tables)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DECL int pcre16_pattern_to_host_byte_order(pcre16 *argument_re,
- pcre16_extra *extra_data, const unsigned char *tables)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DECL int pcre32_pattern_to_host_byte_order(pcre32 *argument_re,
- pcre32_extra *extra_data, const unsigned char *tables)
-#endif
-{
-REAL_PCRE *re = (REAL_PCRE *)argument_re;
-pcre_study_data *study;
-#ifndef COMPILE_PCRE8
-pcre_uchar *ptr;
-int length;
-#if defined SUPPORT_UTF && defined COMPILE_PCRE16
-BOOL utf;
-BOOL utf16_char;
-#endif /* SUPPORT_UTF && COMPILE_PCRE16 */
-#endif /* !COMPILE_PCRE8 */
-
-if (re == NULL) return PCRE_ERROR_NULL;
-if (re->magic_number == MAGIC_NUMBER)
- {
- if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
- re->tables = tables;
- return 0;
- }
-
-if (re->magic_number != REVERSED_MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
-if ((swap_uint32(re->flags) & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
-
-re->magic_number = MAGIC_NUMBER;
-re->size = swap_uint32(re->size);
-re->options = swap_uint32(re->options);
-re->flags = swap_uint32(re->flags);
-re->limit_match = swap_uint32(re->limit_match);
-re->limit_recursion = swap_uint32(re->limit_recursion);
-
-#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16
-re->first_char = swap_uint16(re->first_char);
-re->req_char = swap_uint16(re->req_char);
-#elif defined COMPILE_PCRE32
-re->first_char = swap_uint32(re->first_char);
-re->req_char = swap_uint32(re->req_char);
-#endif
-
-re->max_lookbehind = swap_uint16(re->max_lookbehind);
-re->top_bracket = swap_uint16(re->top_bracket);
-re->top_backref = swap_uint16(re->top_backref);
-re->name_table_offset = swap_uint16(re->name_table_offset);
-re->name_entry_size = swap_uint16(re->name_entry_size);
-re->name_count = swap_uint16(re->name_count);
-re->ref_count = swap_uint16(re->ref_count);
-re->tables = tables;
-
-if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0)
- {
- study = (pcre_study_data *)extra_data->study_data;
- study->size = swap_uint32(study->size);
- study->flags = swap_uint32(study->flags);
- study->minlength = swap_uint32(study->minlength);
- }
-
-#ifndef COMPILE_PCRE8
-ptr = (pcre_uchar *)re + re->name_table_offset;
-length = re->name_count * re->name_entry_size;
-#if defined SUPPORT_UTF && defined COMPILE_PCRE16
-utf = (re->options & PCRE_UTF16) != 0;
-utf16_char = FALSE;
-#endif /* SUPPORT_UTF && COMPILE_PCRE16 */
-
-while(TRUE)
- {
- /* Swap previous characters. */
- while (length-- > 0)
- {
-#if defined COMPILE_PCRE16
- *ptr = swap_uint16(*ptr);
-#elif defined COMPILE_PCRE32
- *ptr = swap_uint32(*ptr);
-#endif
- ptr++;
- }
-#if defined SUPPORT_UTF && defined COMPILE_PCRE16
- if (utf16_char)
- {
- if (HAS_EXTRALEN(ptr[-1]))
- {
- /* We know that there is only one extra character in UTF-16. */
- *ptr = swap_uint16(*ptr);
- ptr++;
- }
- }
- utf16_char = FALSE;
-#endif /* SUPPORT_UTF */
-
- /* Get next opcode. */
- length = 0;
-#if defined COMPILE_PCRE16
- *ptr = swap_uint16(*ptr);
-#elif defined COMPILE_PCRE32
- *ptr = swap_uint32(*ptr);
-#endif
- switch (*ptr)
- {
- case OP_END:
- return 0;
-
-#if defined SUPPORT_UTF && defined COMPILE_PCRE16
- case OP_CHAR:
- case OP_CHARI:
- case OP_NOT:
- case OP_NOTI:
- case OP_STAR:
- case OP_MINSTAR:
- case OP_PLUS:
- case OP_MINPLUS:
- case OP_QUERY:
- case OP_MINQUERY:
- case OP_UPTO:
- case OP_MINUPTO:
- case OP_EXACT:
- case OP_POSSTAR:
- case OP_POSPLUS:
- case OP_POSQUERY:
- case OP_POSUPTO:
- case OP_STARI:
- case OP_MINSTARI:
- case OP_PLUSI:
- case OP_MINPLUSI:
- case OP_QUERYI:
- case OP_MINQUERYI:
- case OP_UPTOI:
- case OP_MINUPTOI:
- case OP_EXACTI:
- case OP_POSSTARI:
- case OP_POSPLUSI:
- case OP_POSQUERYI:
- case OP_POSUPTOI:
- case OP_NOTSTAR:
- case OP_NOTMINSTAR:
- case OP_NOTPLUS:
- case OP_NOTMINPLUS:
- case OP_NOTQUERY:
- case OP_NOTMINQUERY:
- case OP_NOTUPTO:
- case OP_NOTMINUPTO:
- case OP_NOTEXACT:
- case OP_NOTPOSSTAR:
- case OP_NOTPOSPLUS:
- case OP_NOTPOSQUERY:
- case OP_NOTPOSUPTO:
- case OP_NOTSTARI:
- case OP_NOTMINSTARI:
- case OP_NOTPLUSI:
- case OP_NOTMINPLUSI:
- case OP_NOTQUERYI:
- case OP_NOTMINQUERYI:
- case OP_NOTUPTOI:
- case OP_NOTMINUPTOI:
- case OP_NOTEXACTI:
- case OP_NOTPOSSTARI:
- case OP_NOTPOSPLUSI:
- case OP_NOTPOSQUERYI:
- case OP_NOTPOSUPTOI:
- if (utf) utf16_char = TRUE;
-#endif
- /* Fall through. */
-
- default:
- length = PRIV(OP_lengths)[*ptr] - 1;
- break;
-
- case OP_CLASS:
- case OP_NCLASS:
- /* Skip the character bit map. */
- ptr += 32/sizeof(pcre_uchar);
- length = 0;
- break;
-
- case OP_XCLASS:
- /* Reverse the size of the XCLASS instance. */
- ptr++;
-#if defined COMPILE_PCRE16
- *ptr = swap_uint16(*ptr);
-#elif defined COMPILE_PCRE32
- *ptr = swap_uint32(*ptr);
-#endif
-#ifndef COMPILE_PCRE32
- if (LINK_SIZE > 1)
- {
- /* LINK_SIZE can be 1 or 2 in 16 bit mode. */
- ptr++;
- *ptr = swap_uint16(*ptr);
- }
-#endif
- ptr++;
- length = (GET(ptr, -LINK_SIZE)) - (1 + LINK_SIZE + 1);
-#if defined COMPILE_PCRE16
- *ptr = swap_uint16(*ptr);
-#elif defined COMPILE_PCRE32
- *ptr = swap_uint32(*ptr);
-#endif
- if ((*ptr & XCL_MAP) != 0)
- {
- /* Skip the character bit map. */
- ptr += 32/sizeof(pcre_uchar);
- length -= 32/sizeof(pcre_uchar);
- }
- break;
- }
- ptr++;
- }
-/* Control should never reach here in 16/32 bit mode. */
-#else /* In 8-bit mode, the pattern does not need to be processed. */
-return 0;
-#endif /* !COMPILE_PCRE8 */
-}
-
-/* End of pcre_byte_order.c */
diff --git a/src/3rdparty/pcre/pcre_config.c b/src/3rdparty/pcre/pcre_config.c
deleted file mode 100644
index 1cbdd9c960..0000000000
--- a/src/3rdparty/pcre/pcre_config.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains the external function pcre_config(). */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* Keep the original link size. */
-static int real_link_size = LINK_SIZE;
-
-#include "pcre_internal.h"
-
-
-/*************************************************
-* Return info about what features are configured *
-*************************************************/
-
-/* This function has an extensible interface so that additional items can be
-added compatibly.
-
-Arguments:
- what what information is required
- where where to put the information
-
-Returns: 0 if data returned, negative on error
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_config(int what, void *where)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_config(int what, void *where)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_config(int what, void *where)
-#endif
-{
-switch (what)
- {
- case PCRE_CONFIG_UTF8:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
- *((int *)where) = 0;
- return PCRE_ERROR_BADOPTION;
-#else
-#if defined SUPPORT_UTF
- *((int *)where) = 1;
-#else
- *((int *)where) = 0;
-#endif
- break;
-#endif
-
- case PCRE_CONFIG_UTF16:
-#if defined COMPILE_PCRE8 || defined COMPILE_PCRE32
- *((int *)where) = 0;
- return PCRE_ERROR_BADOPTION;
-#else
-#if defined SUPPORT_UTF
- *((int *)where) = 1;
-#else
- *((int *)where) = 0;
-#endif
- break;
-#endif
-
- case PCRE_CONFIG_UTF32:
-#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16
- *((int *)where) = 0;
- return PCRE_ERROR_BADOPTION;
-#else
-#if defined SUPPORT_UTF
- *((int *)where) = 1;
-#else
- *((int *)where) = 0;
-#endif
- break;
-#endif
-
- case PCRE_CONFIG_UNICODE_PROPERTIES:
-#ifdef SUPPORT_UCP
- *((int *)where) = 1;
-#else
- *((int *)where) = 0;
-#endif
- break;
-
- case PCRE_CONFIG_JIT:
-#ifdef SUPPORT_JIT
- *((int *)where) = 1;
-#else
- *((int *)where) = 0;
-#endif
- break;
-
- case PCRE_CONFIG_JITTARGET:
-#ifdef SUPPORT_JIT
- *((const char **)where) = PRIV(jit_get_target)();
-#else
- *((const char **)where) = NULL;
-#endif
- break;
-
- case PCRE_CONFIG_NEWLINE:
- *((int *)where) = NEWLINE;
- break;
-
- case PCRE_CONFIG_BSR:
-#ifdef BSR_ANYCRLF
- *((int *)where) = 1;
-#else
- *((int *)where) = 0;
-#endif
- break;
-
- case PCRE_CONFIG_LINK_SIZE:
- *((int *)where) = real_link_size;
- break;
-
- case PCRE_CONFIG_POSIX_MALLOC_THRESHOLD:
- *((int *)where) = POSIX_MALLOC_THRESHOLD;
- break;
-
- case PCRE_CONFIG_PARENS_LIMIT:
- *((unsigned long int *)where) = PARENS_NEST_LIMIT;
- break;
-
- case PCRE_CONFIG_MATCH_LIMIT:
- *((unsigned long int *)where) = MATCH_LIMIT;
- break;
-
- case PCRE_CONFIG_MATCH_LIMIT_RECURSION:
- *((unsigned long int *)where) = MATCH_LIMIT_RECURSION;
- break;
-
- case PCRE_CONFIG_STACKRECURSE:
-#ifdef NO_RECURSE
- *((int *)where) = 0;
-#else
- *((int *)where) = 1;
-#endif
- break;
-
- default: return PCRE_ERROR_BADOPTION;
- }
-
-return 0;
-}
-
-/* End of pcre_config.c */
diff --git a/src/3rdparty/pcre/pcre_fullinfo.c b/src/3rdparty/pcre/pcre_fullinfo.c
deleted file mode 100644
index a6c2ece6ca..0000000000
--- a/src/3rdparty/pcre/pcre_fullinfo.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2013 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains the external function pcre_fullinfo(), which returns
-information about a compiled pattern. */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "pcre_internal.h"
-
-
-/*************************************************
-* Return info about compiled pattern *
-*************************************************/
-
-/* This is a newer "info" function which has an extensible interface so
-that additional items can be added compatibly.
-
-Arguments:
- argument_re points to compiled code
- extra_data points extra data, or NULL
- what what information is required
- where where to put the information
-
-Returns: 0 if data returned, negative on error
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_fullinfo(const pcre *argument_re, const pcre_extra *extra_data,
- int what, void *where)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_fullinfo(const pcre16 *argument_re, const pcre16_extra *extra_data,
- int what, void *where)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_fullinfo(const pcre32 *argument_re, const pcre32_extra *extra_data,
- int what, void *where)
-#endif
-{
-const REAL_PCRE *re = (const REAL_PCRE *)argument_re;
-const pcre_study_data *study = NULL;
-
-if (re == NULL || where == NULL) return PCRE_ERROR_NULL;
-
-if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_STUDY_DATA) != 0)
- study = (const pcre_study_data *)extra_data->study_data;
-
-/* Check that the first field in the block is the magic number. If it is not,
-return with PCRE_ERROR_BADMAGIC. However, if the magic number is equal to
-REVERSED_MAGIC_NUMBER we return with PCRE_ERROR_BADENDIANNESS, which
-means that the pattern is likely compiled with different endianness. */
-
-if (re->magic_number != MAGIC_NUMBER)
- return re->magic_number == REVERSED_MAGIC_NUMBER?
- PCRE_ERROR_BADENDIANNESS:PCRE_ERROR_BADMAGIC;
-
-/* Check that this pattern was compiled in the correct bit mode */
-
-if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
-
-switch (what)
- {
- case PCRE_INFO_OPTIONS:
- *((unsigned long int *)where) = re->options & PUBLIC_COMPILE_OPTIONS;
- break;
-
- case PCRE_INFO_SIZE:
- *((size_t *)where) = re->size;
- break;
-
- case PCRE_INFO_STUDYSIZE:
- *((size_t *)where) = (study == NULL)? 0 : study->size;
- break;
-
- case PCRE_INFO_JITSIZE:
-#ifdef SUPPORT_JIT
- *((size_t *)where) =
- (extra_data != NULL &&
- (extra_data->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 &&
- extra_data->executable_jit != NULL)?
- PRIV(jit_get_size)(extra_data->executable_jit) : 0;
-#else
- *((size_t *)where) = 0;
-#endif
- break;
-
- case PCRE_INFO_CAPTURECOUNT:
- *((int *)where) = re->top_bracket;
- break;
-
- case PCRE_INFO_BACKREFMAX:
- *((int *)where) = re->top_backref;
- break;
-
- case PCRE_INFO_FIRSTBYTE:
- *((int *)where) =
- ((re->flags & PCRE_FIRSTSET) != 0)? (int)re->first_char :
- ((re->flags & PCRE_STARTLINE) != 0)? -1 : -2;
- break;
-
- case PCRE_INFO_FIRSTCHARACTER:
- *((pcre_uint32 *)where) =
- (re->flags & PCRE_FIRSTSET) != 0 ? re->first_char : 0;
- break;
-
- case PCRE_INFO_FIRSTCHARACTERFLAGS:
- *((int *)where) =
- ((re->flags & PCRE_FIRSTSET) != 0) ? 1 :
- ((re->flags & PCRE_STARTLINE) != 0) ? 2 : 0;
- break;
-
- /* Make sure we pass back the pointer to the bit vector in the external
- block, not the internal copy (with flipped integer fields). */
-
- case PCRE_INFO_FIRSTTABLE:
- *((const pcre_uint8 **)where) =
- (study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0)?
- ((const pcre_study_data *)extra_data->study_data)->start_bits : NULL;
- break;
-
- case PCRE_INFO_MINLENGTH:
- *((int *)where) =
- (study != NULL && (study->flags & PCRE_STUDY_MINLEN) != 0)?
- (int)(study->minlength) : -1;
- break;
-
- case PCRE_INFO_JIT:
- *((int *)where) = extra_data != NULL &&
- (extra_data->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 &&
- extra_data->executable_jit != NULL;
- break;
-
- case PCRE_INFO_LASTLITERAL:
- *((int *)where) =
- ((re->flags & PCRE_REQCHSET) != 0)? (int)re->req_char : -1;
- break;
-
- case PCRE_INFO_REQUIREDCHAR:
- *((pcre_uint32 *)where) =
- ((re->flags & PCRE_REQCHSET) != 0) ? re->req_char : 0;
- break;
-
- case PCRE_INFO_REQUIREDCHARFLAGS:
- *((int *)where) =
- ((re->flags & PCRE_REQCHSET) != 0);
- break;
-
- case PCRE_INFO_NAMEENTRYSIZE:
- *((int *)where) = re->name_entry_size;
- break;
-
- case PCRE_INFO_NAMECOUNT:
- *((int *)where) = re->name_count;
- break;
-
- case PCRE_INFO_NAMETABLE:
- *((const pcre_uchar **)where) = (const pcre_uchar *)re + re->name_table_offset;
- break;
-
- case PCRE_INFO_DEFAULT_TABLES:
- *((const pcre_uint8 **)where) = (const pcre_uint8 *)(PRIV(default_tables));
- break;
-
- /* From release 8.00 this will always return TRUE because NOPARTIAL is
- no longer ever set (the restrictions have been removed). */
-
- case PCRE_INFO_OKPARTIAL:
- *((int *)where) = (re->flags & PCRE_NOPARTIAL) == 0;
- break;
-
- case PCRE_INFO_JCHANGED:
- *((int *)where) = (re->flags & PCRE_JCHANGED) != 0;
- break;
-
- case PCRE_INFO_HASCRORLF:
- *((int *)where) = (re->flags & PCRE_HASCRORLF) != 0;
- break;
-
- case PCRE_INFO_MAXLOOKBEHIND:
- *((int *)where) = re->max_lookbehind;
- break;
-
- case PCRE_INFO_MATCHLIMIT:
- if ((re->flags & PCRE_MLSET) == 0) return PCRE_ERROR_UNSET;
- *((pcre_uint32 *)where) = re->limit_match;
- break;
-
- case PCRE_INFO_RECURSIONLIMIT:
- if ((re->flags & PCRE_RLSET) == 0) return PCRE_ERROR_UNSET;
- *((pcre_uint32 *)where) = re->limit_recursion;
- break;
-
- case PCRE_INFO_MATCH_EMPTY:
- *((int *)where) = (re->flags & PCRE_MATCH_EMPTY) != 0;
- break;
-
- default: return PCRE_ERROR_BADOPTION;
- }
-
-return 0;
-}
-
-/* End of pcre_fullinfo.c */
diff --git a/src/3rdparty/pcre/pcre_get.c b/src/3rdparty/pcre/pcre_get.c
deleted file mode 100644
index 9475d5e88c..0000000000
--- a/src/3rdparty/pcre/pcre_get.c
+++ /dev/null
@@ -1,669 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains some convenience functions for extracting substrings
-from the subject string after a regex match has succeeded. The original idea
-for these functions came from Scott Wimer. */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "pcre_internal.h"
-
-
-/*************************************************
-* Find number for named string *
-*************************************************/
-
-/* This function is used by the get_first_set() function below, as well
-as being generally available. It assumes that names are unique.
-
-Arguments:
- code the compiled regex
- stringname the name whose number is required
-
-Returns: the number of the named parentheses, or a negative number
- (PCRE_ERROR_NOSUBSTRING) if not found
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_get_stringnumber(const pcre *code, const char *stringname)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_get_stringnumber(const pcre16 *code, PCRE_SPTR16 stringname)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_get_stringnumber(const pcre32 *code, PCRE_SPTR32 stringname)
-#endif
-{
-int rc;
-int entrysize;
-int top, bot;
-pcre_uchar *nametable;
-
-#ifdef COMPILE_PCRE8
-if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
- return rc;
-if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
-
-if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
- return rc;
-if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
- return rc;
-#endif
-#ifdef COMPILE_PCRE16
-if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
- return rc;
-if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
-
-if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
- return rc;
-if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
- return rc;
-#endif
-#ifdef COMPILE_PCRE32
-if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
- return rc;
-if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
-
-if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
- return rc;
-if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
- return rc;
-#endif
-
-bot = 0;
-while (top > bot)
- {
- int mid = (top + bot) / 2;
- pcre_uchar *entry = nametable + entrysize*mid;
- int c = STRCMP_UC_UC((pcre_uchar *)stringname,
- (pcre_uchar *)(entry + IMM2_SIZE));
- if (c == 0) return GET2(entry, 0);
- if (c > 0) bot = mid + 1; else top = mid;
- }
-
-return PCRE_ERROR_NOSUBSTRING;
-}
-
-
-
-/*************************************************
-* Find (multiple) entries for named string *
-*************************************************/
-
-/* This is used by the get_first_set() function below, as well as being
-generally available. It is used when duplicated names are permitted.
-
-Arguments:
- code the compiled regex
- stringname the name whose entries required
- firstptr where to put the pointer to the first entry
- lastptr where to put the pointer to the last entry
-
-Returns: the length of each entry, or a negative number
- (PCRE_ERROR_NOSUBSTRING) if not found
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_get_stringtable_entries(const pcre *code, const char *stringname,
- char **firstptr, char **lastptr)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_get_stringtable_entries(const pcre16 *code, PCRE_SPTR16 stringname,
- PCRE_UCHAR16 **firstptr, PCRE_UCHAR16 **lastptr)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_get_stringtable_entries(const pcre32 *code, PCRE_SPTR32 stringname,
- PCRE_UCHAR32 **firstptr, PCRE_UCHAR32 **lastptr)
-#endif
-{
-int rc;
-int entrysize;
-int top, bot;
-pcre_uchar *nametable, *lastentry;
-
-#ifdef COMPILE_PCRE8
-if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
- return rc;
-if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
-
-if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
- return rc;
-if ((rc = pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
- return rc;
-#endif
-#ifdef COMPILE_PCRE16
-if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
- return rc;
-if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
-
-if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
- return rc;
-if ((rc = pcre16_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
- return rc;
-#endif
-#ifdef COMPILE_PCRE32
-if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top)) != 0)
- return rc;
-if (top <= 0) return PCRE_ERROR_NOSUBSTRING;
-
-if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize)) != 0)
- return rc;
-if ((rc = pcre32_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable)) != 0)
- return rc;
-#endif
-
-lastentry = nametable + entrysize * (top - 1);
-bot = 0;
-while (top > bot)
- {
- int mid = (top + bot) / 2;
- pcre_uchar *entry = nametable + entrysize*mid;
- int c = STRCMP_UC_UC((pcre_uchar *)stringname,
- (pcre_uchar *)(entry + IMM2_SIZE));
- if (c == 0)
- {
- pcre_uchar *first = entry;
- pcre_uchar *last = entry;
- while (first > nametable)
- {
- if (STRCMP_UC_UC((pcre_uchar *)stringname,
- (pcre_uchar *)(first - entrysize + IMM2_SIZE)) != 0) break;
- first -= entrysize;
- }
- while (last < lastentry)
- {
- if (STRCMP_UC_UC((pcre_uchar *)stringname,
- (pcre_uchar *)(last + entrysize + IMM2_SIZE)) != 0) break;
- last += entrysize;
- }
-#if defined COMPILE_PCRE8
- *firstptr = (char *)first;
- *lastptr = (char *)last;
-#elif defined COMPILE_PCRE16
- *firstptr = (PCRE_UCHAR16 *)first;
- *lastptr = (PCRE_UCHAR16 *)last;
-#elif defined COMPILE_PCRE32
- *firstptr = (PCRE_UCHAR32 *)first;
- *lastptr = (PCRE_UCHAR32 *)last;
-#endif
- return entrysize;
- }
- if (c > 0) bot = mid + 1; else top = mid;
- }
-
-return PCRE_ERROR_NOSUBSTRING;
-}
-
-
-
-/*************************************************
-* Find first set of multiple named strings *
-*************************************************/
-
-/* This function allows for duplicate names in the table of named substrings.
-It returns the number of the first one that was set in a pattern match.
-
-Arguments:
- code the compiled regex
- stringname the name of the capturing substring
- ovector the vector of matched substrings
- stringcount number of captured substrings
-
-Returns: the number of the first that is set,
- or the number of the last one if none are set,
- or a negative number on error
-*/
-
-#if defined COMPILE_PCRE8
-static int
-get_first_set(const pcre *code, const char *stringname, int *ovector,
- int stringcount)
-#elif defined COMPILE_PCRE16
-static int
-get_first_set(const pcre16 *code, PCRE_SPTR16 stringname, int *ovector,
- int stringcount)
-#elif defined COMPILE_PCRE32
-static int
-get_first_set(const pcre32 *code, PCRE_SPTR32 stringname, int *ovector,
- int stringcount)
-#endif
-{
-const REAL_PCRE *re = (const REAL_PCRE *)code;
-int entrysize;
-pcre_uchar *entry;
-#if defined COMPILE_PCRE8
-char *first, *last;
-#elif defined COMPILE_PCRE16
-PCRE_UCHAR16 *first, *last;
-#elif defined COMPILE_PCRE32
-PCRE_UCHAR32 *first, *last;
-#endif
-
-#if defined COMPILE_PCRE8
-if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0)
- return pcre_get_stringnumber(code, stringname);
-entrysize = pcre_get_stringtable_entries(code, stringname, &first, &last);
-#elif defined COMPILE_PCRE16
-if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0)
- return pcre16_get_stringnumber(code, stringname);
-entrysize = pcre16_get_stringtable_entries(code, stringname, &first, &last);
-#elif defined COMPILE_PCRE32
-if ((re->options & PCRE_DUPNAMES) == 0 && (re->flags & PCRE_JCHANGED) == 0)
- return pcre32_get_stringnumber(code, stringname);
-entrysize = pcre32_get_stringtable_entries(code, stringname, &first, &last);
-#endif
-if (entrysize <= 0) return entrysize;
-for (entry = (pcre_uchar *)first; entry <= (pcre_uchar *)last; entry += entrysize)
- {
- int n = GET2(entry, 0);
- if (n < stringcount && ovector[n*2] >= 0) return n;
- }
-return GET2(entry, 0);
-}
-
-
-
-
-/*************************************************
-* Copy captured string to given buffer *
-*************************************************/
-
-/* This function copies a single captured substring into a given buffer.
-Note that we use memcpy() rather than strncpy() in case there are binary zeros
-in the string.
-
-Arguments:
- subject the subject string that was matched
- ovector pointer to the offsets table
- stringcount the number of substrings that were captured
- (i.e. the yield of the pcre_exec call, unless
- that was zero, in which case it should be 1/3
- of the offset table size)
- stringnumber the number of the required substring
- buffer where to put the substring
- size the size of the buffer
-
-Returns: if successful:
- the length of the copied string, not including the zero
- that is put on the end; can be zero
- if not successful:
- PCRE_ERROR_NOMEMORY (-6) buffer too small
- PCRE_ERROR_NOSUBSTRING (-7) no such captured substring
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_copy_substring(const char *subject, int *ovector, int stringcount,
- int stringnumber, char *buffer, int size)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_copy_substring(PCRE_SPTR16 subject, int *ovector, int stringcount,
- int stringnumber, PCRE_UCHAR16 *buffer, int size)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_copy_substring(PCRE_SPTR32 subject, int *ovector, int stringcount,
- int stringnumber, PCRE_UCHAR32 *buffer, int size)
-#endif
-{
-int yield;
-if (stringnumber < 0 || stringnumber >= stringcount)
- return PCRE_ERROR_NOSUBSTRING;
-stringnumber *= 2;
-yield = ovector[stringnumber+1] - ovector[stringnumber];
-if (size < yield + 1) return PCRE_ERROR_NOMEMORY;
-memcpy(buffer, subject + ovector[stringnumber], IN_UCHARS(yield));
-buffer[yield] = 0;
-return yield;
-}
-
-
-
-/*************************************************
-* Copy named captured string to given buffer *
-*************************************************/
-
-/* This function copies a single captured substring into a given buffer,
-identifying it by name. If the regex permits duplicate names, the first
-substring that is set is chosen.
-
-Arguments:
- code the compiled regex
- subject the subject string that was matched
- ovector pointer to the offsets table
- stringcount the number of substrings that were captured
- (i.e. the yield of the pcre_exec call, unless
- that was zero, in which case it should be 1/3
- of the offset table size)
- stringname the name of the required substring
- buffer where to put the substring
- size the size of the buffer
-
-Returns: if successful:
- the length of the copied string, not including the zero
- that is put on the end; can be zero
- if not successful:
- PCRE_ERROR_NOMEMORY (-6) buffer too small
- PCRE_ERROR_NOSUBSTRING (-7) no such captured substring
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_copy_named_substring(const pcre *code, const char *subject,
- int *ovector, int stringcount, const char *stringname,
- char *buffer, int size)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_copy_named_substring(const pcre16 *code, PCRE_SPTR16 subject,
- int *ovector, int stringcount, PCRE_SPTR16 stringname,
- PCRE_UCHAR16 *buffer, int size)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_copy_named_substring(const pcre32 *code, PCRE_SPTR32 subject,
- int *ovector, int stringcount, PCRE_SPTR32 stringname,
- PCRE_UCHAR32 *buffer, int size)
-#endif
-{
-int n = get_first_set(code, stringname, ovector, stringcount);
-if (n <= 0) return n;
-#if defined COMPILE_PCRE8
-return pcre_copy_substring(subject, ovector, stringcount, n, buffer, size);
-#elif defined COMPILE_PCRE16
-return pcre16_copy_substring(subject, ovector, stringcount, n, buffer, size);
-#elif defined COMPILE_PCRE32
-return pcre32_copy_substring(subject, ovector, stringcount, n, buffer, size);
-#endif
-}
-
-
-
-/*************************************************
-* Copy all captured strings to new store *
-*************************************************/
-
-/* This function gets one chunk of store and builds a list of pointers and all
-of the captured substrings in it. A NULL pointer is put on the end of the list.
-
-Arguments:
- subject the subject string that was matched
- ovector pointer to the offsets table
- stringcount the number of substrings that were captured
- (i.e. the yield of the pcre_exec call, unless
- that was zero, in which case it should be 1/3
- of the offset table size)
- listptr set to point to the list of pointers
-
-Returns: if successful: 0
- if not successful:
- PCRE_ERROR_NOMEMORY (-6) failed to get store
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_get_substring_list(const char *subject, int *ovector, int stringcount,
- const char ***listptr)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_get_substring_list(PCRE_SPTR16 subject, int *ovector, int stringcount,
- PCRE_SPTR16 **listptr)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_get_substring_list(PCRE_SPTR32 subject, int *ovector, int stringcount,
- PCRE_SPTR32 **listptr)
-#endif
-{
-int i;
-int size = sizeof(pcre_uchar *);
-int double_count = stringcount * 2;
-pcre_uchar **stringlist;
-pcre_uchar *p;
-
-for (i = 0; i < double_count; i += 2)
- {
- size += sizeof(pcre_uchar *) + IN_UCHARS(1);
- if (ovector[i+1] > ovector[i]) size += IN_UCHARS(ovector[i+1] - ovector[i]);
- }
-
-stringlist = (pcre_uchar **)(PUBL(malloc))(size);
-if (stringlist == NULL) return PCRE_ERROR_NOMEMORY;
-
-#if defined COMPILE_PCRE8
-*listptr = (const char **)stringlist;
-#elif defined COMPILE_PCRE16
-*listptr = (PCRE_SPTR16 *)stringlist;
-#elif defined COMPILE_PCRE32
-*listptr = (PCRE_SPTR32 *)stringlist;
-#endif
-p = (pcre_uchar *)(stringlist + stringcount + 1);
-
-for (i = 0; i < double_count; i += 2)
- {
- int len = (ovector[i+1] > ovector[i])? (ovector[i+1] - ovector[i]) : 0;
- memcpy(p, subject + ovector[i], IN_UCHARS(len));
- *stringlist++ = p;
- p += len;
- *p++ = 0;
- }
-
-*stringlist = NULL;
-return 0;
-}
-
-
-
-/*************************************************
-* Free store obtained by get_substring_list *
-*************************************************/
-
-/* This function exists for the benefit of people calling PCRE from non-C
-programs that can call its functions, but not free() or (PUBL(free))()
-directly.
-
-Argument: the result of a previous pcre_get_substring_list()
-Returns: nothing
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
-pcre_free_substring_list(const char **pointer)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
-pcre16_free_substring_list(PCRE_SPTR16 *pointer)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
-pcre32_free_substring_list(PCRE_SPTR32 *pointer)
-#endif
-{
-(PUBL(free))((void *)pointer);
-}
-
-
-
-/*************************************************
-* Copy captured string to new store *
-*************************************************/
-
-/* This function copies a single captured substring into a piece of new
-store
-
-Arguments:
- subject the subject string that was matched
- ovector pointer to the offsets table
- stringcount the number of substrings that were captured
- (i.e. the yield of the pcre_exec call, unless
- that was zero, in which case it should be 1/3
- of the offset table size)
- stringnumber the number of the required substring
- stringptr where to put a pointer to the substring
-
-Returns: if successful:
- the length of the string, not including the zero that
- is put on the end; can be zero
- if not successful:
- PCRE_ERROR_NOMEMORY (-6) failed to get store
- PCRE_ERROR_NOSUBSTRING (-7) substring not present
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_get_substring(const char *subject, int *ovector, int stringcount,
- int stringnumber, const char **stringptr)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_get_substring(PCRE_SPTR16 subject, int *ovector, int stringcount,
- int stringnumber, PCRE_SPTR16 *stringptr)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_get_substring(PCRE_SPTR32 subject, int *ovector, int stringcount,
- int stringnumber, PCRE_SPTR32 *stringptr)
-#endif
-{
-int yield;
-pcre_uchar *substring;
-if (stringnumber < 0 || stringnumber >= stringcount)
- return PCRE_ERROR_NOSUBSTRING;
-stringnumber *= 2;
-yield = ovector[stringnumber+1] - ovector[stringnumber];
-substring = (pcre_uchar *)(PUBL(malloc))(IN_UCHARS(yield + 1));
-if (substring == NULL) return PCRE_ERROR_NOMEMORY;
-memcpy(substring, subject + ovector[stringnumber], IN_UCHARS(yield));
-substring[yield] = 0;
-#if defined COMPILE_PCRE8
-*stringptr = (const char *)substring;
-#elif defined COMPILE_PCRE16
-*stringptr = (PCRE_SPTR16)substring;
-#elif defined COMPILE_PCRE32
-*stringptr = (PCRE_SPTR32)substring;
-#endif
-return yield;
-}
-
-
-
-/*************************************************
-* Copy named captured string to new store *
-*************************************************/
-
-/* This function copies a single captured substring, identified by name, into
-new store. If the regex permits duplicate names, the first substring that is
-set is chosen.
-
-Arguments:
- code the compiled regex
- subject the subject string that was matched
- ovector pointer to the offsets table
- stringcount the number of substrings that were captured
- (i.e. the yield of the pcre_exec call, unless
- that was zero, in which case it should be 1/3
- of the offset table size)
- stringname the name of the required substring
- stringptr where to put the pointer
-
-Returns: if successful:
- the length of the copied string, not including the zero
- that is put on the end; can be zero
- if not successful:
- PCRE_ERROR_NOMEMORY (-6) couldn't get memory
- PCRE_ERROR_NOSUBSTRING (-7) no such captured substring
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_get_named_substring(const pcre *code, const char *subject,
- int *ovector, int stringcount, const char *stringname,
- const char **stringptr)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_get_named_substring(const pcre16 *code, PCRE_SPTR16 subject,
- int *ovector, int stringcount, PCRE_SPTR16 stringname,
- PCRE_SPTR16 *stringptr)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_get_named_substring(const pcre32 *code, PCRE_SPTR32 subject,
- int *ovector, int stringcount, PCRE_SPTR32 stringname,
- PCRE_SPTR32 *stringptr)
-#endif
-{
-int n = get_first_set(code, stringname, ovector, stringcount);
-if (n <= 0) return n;
-#if defined COMPILE_PCRE8
-return pcre_get_substring(subject, ovector, stringcount, n, stringptr);
-#elif defined COMPILE_PCRE16
-return pcre16_get_substring(subject, ovector, stringcount, n, stringptr);
-#elif defined COMPILE_PCRE32
-return pcre32_get_substring(subject, ovector, stringcount, n, stringptr);
-#endif
-}
-
-
-
-
-/*************************************************
-* Free store obtained by get_substring *
-*************************************************/
-
-/* This function exists for the benefit of people calling PCRE from non-C
-programs that can call its functions, but not free() or (PUBL(free))()
-directly.
-
-Argument: the result of a previous pcre_get_substring()
-Returns: nothing
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
-pcre_free_substring(const char *pointer)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
-pcre16_free_substring(PCRE_SPTR16 pointer)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN void PCRE_CALL_CONVENTION
-pcre32_free_substring(PCRE_SPTR32 pointer)
-#endif
-{
-(PUBL(free))((void *)pointer);
-}
-
-/* End of pcre_get.c */
diff --git a/src/3rdparty/pcre/pcre_globals.c b/src/3rdparty/pcre/pcre_globals.c
deleted file mode 100644
index 0f106aa901..0000000000
--- a/src/3rdparty/pcre/pcre_globals.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2014 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains global variables that are exported by the PCRE library.
-PCRE is thread-clean and doesn't use any global variables in the normal sense.
-However, it calls memory allocation and freeing functions via the four
-indirections below, and it can optionally do callouts, using the fifth
-indirection. These values can be changed by the caller, but are shared between
-all threads.
-
-For MS Visual Studio and Symbian OS, there are problems in initializing these
-variables to non-local functions. In these cases, therefore, an indirection via
-a local function is used.
-
-Also, when compiling for Virtual Pascal, things are done differently, and
-global variables are not used. */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "pcre_internal.h"
-
-#if defined _MSC_VER || defined __SYMBIAN32__
-static void* LocalPcreMalloc(size_t aSize)
- {
- return malloc(aSize);
- }
-static void LocalPcreFree(void* aPtr)
- {
- free(aPtr);
- }
-PCRE_EXP_DATA_DEFN void *(*PUBL(malloc))(size_t) = LocalPcreMalloc;
-PCRE_EXP_DATA_DEFN void (*PUBL(free))(void *) = LocalPcreFree;
-PCRE_EXP_DATA_DEFN void *(*PUBL(stack_malloc))(size_t) = LocalPcreMalloc;
-PCRE_EXP_DATA_DEFN void (*PUBL(stack_free))(void *) = LocalPcreFree;
-PCRE_EXP_DATA_DEFN int (*PUBL(callout))(PUBL(callout_block) *) = NULL;
-PCRE_EXP_DATA_DEFN int (*PUBL(stack_guard))(void) = NULL;
-
-#elif !defined VPCOMPAT
-PCRE_EXP_DATA_DEFN void *(*PUBL(malloc))(size_t) = malloc;
-PCRE_EXP_DATA_DEFN void (*PUBL(free))(void *) = free;
-PCRE_EXP_DATA_DEFN void *(*PUBL(stack_malloc))(size_t) = malloc;
-PCRE_EXP_DATA_DEFN void (*PUBL(stack_free))(void *) = free;
-PCRE_EXP_DATA_DEFN int (*PUBL(callout))(PUBL(callout_block) *) = NULL;
-PCRE_EXP_DATA_DEFN int (*PUBL(stack_guard))(void) = NULL;
-#endif
-
-/* End of pcre_globals.c */
diff --git a/src/3rdparty/pcre/pcre_refcount.c b/src/3rdparty/pcre/pcre_refcount.c
deleted file mode 100644
index 79efa90f21..0000000000
--- a/src/3rdparty/pcre/pcre_refcount.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains the external function pcre_refcount(), which is an
-auxiliary function that can be used to maintain a reference count in a compiled
-pattern data block. This might be helpful in applications where the block is
-shared by different users. */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "pcre_internal.h"
-
-
-/*************************************************
-* Maintain reference count *
-*************************************************/
-
-/* The reference count is a 16-bit field, initialized to zero. It is not
-possible to transfer a non-zero count from one host to a different host that
-has a different byte order - though I can't see why anyone in their right mind
-would ever want to do that!
-
-Arguments:
- argument_re points to compiled code
- adjust value to add to the count
-
-Returns: the (possibly updated) count value (a non-negative number), or
- a negative error number
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_refcount(pcre *argument_re, int adjust)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_refcount(pcre16 *argument_re, int adjust)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_refcount(pcre32 *argument_re, int adjust)
-#endif
-{
-REAL_PCRE *re = (REAL_PCRE *)argument_re;
-if (re == NULL) return PCRE_ERROR_NULL;
-if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
-if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
-re->ref_count = (-adjust > re->ref_count)? 0 :
- (adjust + re->ref_count > 65535)? 65535 :
- re->ref_count + adjust;
-return re->ref_count;
-}
-
-/* End of pcre_refcount.c */
diff --git a/src/3rdparty/pcre/pcre_string_utils.c b/src/3rdparty/pcre/pcre_string_utils.c
deleted file mode 100644
index 25eacc8507..0000000000
--- a/src/3rdparty/pcre/pcre_string_utils.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2014 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains internal functions for comparing and finding the length
-of strings for different data item sizes. */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "pcre_internal.h"
-
-#ifndef COMPILE_PCRE8
-
-/*************************************************
-* Compare string utilities *
-*************************************************/
-
-/* The following two functions compares two strings. Basically a strcmp
-for non 8 bit characters.
-
-Arguments:
- str1 first string
- str2 second string
-
-Returns: 0 if both string are equal (like strcmp), 1 otherwise
-*/
-
-int
-PRIV(strcmp_uc_uc)(const pcre_uchar *str1, const pcre_uchar *str2)
-{
-pcre_uchar c1;
-pcre_uchar c2;
-
-while (*str1 != '\0' || *str2 != '\0')
- {
- c1 = *str1++;
- c2 = *str2++;
- if (c1 != c2)
- return ((c1 > c2) << 1) - 1;
- }
-/* Both length and characters must be equal. */
-return 0;
-}
-
-#ifdef COMPILE_PCRE32
-
-int
-PRIV(strcmp_uc_uc_utf)(const pcre_uchar *str1, const pcre_uchar *str2)
-{
-pcre_uchar c1;
-pcre_uchar c2;
-
-while (*str1 != '\0' || *str2 != '\0')
- {
- c1 = UCHAR21INC(str1);
- c2 = UCHAR21INC(str2);
- if (c1 != c2)
- return ((c1 > c2) << 1) - 1;
- }
-/* Both length and characters must be equal. */
-return 0;
-}
-
-#endif /* COMPILE_PCRE32 */
-
-int
-PRIV(strcmp_uc_c8)(const pcre_uchar *str1, const char *str2)
-{
-const pcre_uint8 *ustr2 = (pcre_uint8 *)str2;
-pcre_uchar c1;
-pcre_uchar c2;
-
-while (*str1 != '\0' || *ustr2 != '\0')
- {
- c1 = *str1++;
- c2 = (pcre_uchar)*ustr2++;
- if (c1 != c2)
- return ((c1 > c2) << 1) - 1;
- }
-/* Both length and characters must be equal. */
-return 0;
-}
-
-#ifdef COMPILE_PCRE32
-
-int
-PRIV(strcmp_uc_c8_utf)(const pcre_uchar *str1, const char *str2)
-{
-const pcre_uint8 *ustr2 = (pcre_uint8 *)str2;
-pcre_uchar c1;
-pcre_uchar c2;
-
-while (*str1 != '\0' || *ustr2 != '\0')
- {
- c1 = UCHAR21INC(str1);
- c2 = (pcre_uchar)*ustr2++;
- if (c1 != c2)
- return ((c1 > c2) << 1) - 1;
- }
-/* Both length and characters must be equal. */
-return 0;
-}
-
-#endif /* COMPILE_PCRE32 */
-
-/* The following two functions compares two, fixed length
-strings. Basically an strncmp for non 8 bit characters.
-
-Arguments:
- str1 first string
- str2 second string
- num size of the string
-
-Returns: 0 if both string are equal (like strcmp), 1 otherwise
-*/
-
-int
-PRIV(strncmp_uc_uc)(const pcre_uchar *str1, const pcre_uchar *str2, unsigned int num)
-{
-pcre_uchar c1;
-pcre_uchar c2;
-
-while (num-- > 0)
- {
- c1 = *str1++;
- c2 = *str2++;
- if (c1 != c2)
- return ((c1 > c2) << 1) - 1;
- }
-/* Both length and characters must be equal. */
-return 0;
-}
-
-int
-PRIV(strncmp_uc_c8)(const pcre_uchar *str1, const char *str2, unsigned int num)
-{
-const pcre_uint8 *ustr2 = (pcre_uint8 *)str2;
-pcre_uchar c1;
-pcre_uchar c2;
-
-while (num-- > 0)
- {
- c1 = *str1++;
- c2 = (pcre_uchar)*ustr2++;
- if (c1 != c2)
- return ((c1 > c2) << 1) - 1;
- }
-/* Both length and characters must be equal. */
-return 0;
-}
-
-/* The following function returns with the length of
-a zero terminated string. Basically an strlen for non 8 bit characters.
-
-Arguments:
- str string
-
-Returns: length of the string
-*/
-
-unsigned int
-PRIV(strlen_uc)(const pcre_uchar *str)
-{
-unsigned int len = 0;
-while (*str++ != 0)
- len++;
-return len;
-}
-
-#endif /* !COMPILE_PCRE8 */
-
-/* End of pcre_string_utils.c */
diff --git a/src/3rdparty/pcre/pcre_version.c b/src/3rdparty/pcre/pcre_version.c
deleted file mode 100644
index ae86ff28bc..0000000000
--- a/src/3rdparty/pcre/pcre_version.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language.
-
- Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
-
------------------------------------------------------------------------------
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the name of the University of Cambridge nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------
-*/
-
-
-/* This module contains the external function pcre_version(), which returns a
-string that identifies the PCRE version that is in use. */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "pcre_internal.h"
-
-
-/*************************************************
-* Return version string *
-*************************************************/
-
-/* These macros are the standard way of turning unquoted text into C strings.
-They allow macros like PCRE_MAJOR to be defined without quotes, which is
-convenient for user programs that want to test its value. */
-
-#define STRING(a) # a
-#define XSTRING(s) STRING(s)
-
-/* A problem turned up with PCRE_PRERELEASE, which is defined empty for
-production releases. Originally, it was used naively in this code:
-
- return XSTRING(PCRE_MAJOR)
- "." XSTRING(PCRE_MINOR)
- XSTRING(PCRE_PRERELEASE)
- " " XSTRING(PCRE_DATE);
-
-However, when PCRE_PRERELEASE is empty, this leads to an attempted expansion of
-STRING(). The C standard states: "If (before argument substitution) any
-argument consists of no preprocessing tokens, the behavior is undefined." It
-turns out the gcc treats this case as a single empty string - which is what we
-really want - but Visual C grumbles about the lack of an argument for the
-macro. Unfortunately, both are within their rights. To cope with both ways of
-handling this, I had resort to some messy hackery that does a test at run time.
-I could find no way of detecting that a macro is defined as an empty string at
-pre-processor time. This hack uses a standard trick for avoiding calling
-the STRING macro with an empty argument when doing the test. */
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION
-pcre_version(void)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION
-pcre16_version(void)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN const char * PCRE_CALL_CONVENTION
-pcre32_version(void)
-#endif
-{
-return (XSTRING(Z PCRE_PRERELEASE)[1] == 0)?
- XSTRING(PCRE_MAJOR.PCRE_MINOR PCRE_DATE) :
- XSTRING(PCRE_MAJOR.PCRE_MINOR) XSTRING(PCRE_PRERELEASE PCRE_DATE);
-}
-
-/* End of pcre_version.c */
diff --git a/src/3rdparty/pcre/AUTHORS b/src/3rdparty/pcre2/AUTHORS
index 342417a8a1..d9a0e15690 100644
--- a/src/3rdparty/pcre/AUTHORS
+++ b/src/3rdparty/pcre2/AUTHORS
@@ -1,5 +1,5 @@
-THE MAIN PCRE LIBRARY
----------------------
+THE MAIN PCRE2 LIBRARY CODE
+---------------------------
Written by: Philip Hazel
Email local part: ph10
@@ -12,8 +12,8 @@ Copyright (c) 1997-2016 University of Cambridge
All rights reserved
-PCRE JUST-IN-TIME COMPILATION SUPPORT
--------------------------------------
+PCRE2 JUST-IN-TIME COMPILATION SUPPORT
+--------------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
@@ -33,13 +33,4 @@ Emain domain: freemail.hu
Copyright(c) 2009-2016 Zoltan Herczeg
All rights reserved.
-
-THE C++ WRAPPER LIBRARY
------------------------
-
-Written by: Google Inc.
-
-Copyright (c) 2007-2012 Google Inc
-All rights reserved
-
####
diff --git a/src/3rdparty/pcre/LICENCE b/src/3rdparty/pcre2/LICENCE
index dd977af971..6600a65907 100644
--- a/src/3rdparty/pcre/LICENCE
+++ b/src/3rdparty/pcre2/LICENCE
@@ -1,18 +1,18 @@
-PCRE LICENCE
-------------
+PCRE2 LICENCE
+-------------
-PCRE is a library of functions to support regular expressions whose syntax
+PCRE2 is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
-Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
-specified below. The documentation for PCRE, supplied in the "doc"
+Release 10 of PCRE2 is distributed under the terms of the "BSD" licence, as
+specified below. The documentation for PCRE2, supplied in the "doc"
directory, is distributed under the same terms as the software itself. The data
in the testdata directory is not copyrighted and is in the public domain.
The basic library functions are written in C and are freestanding. Also
-included in the distribution is a set of C++ wrapper functions, and a
-just-in-time compiler that can be used to optimize pattern matching. These
-are both optional features that can be omitted when the library is built.
+included in the distribution is a just-in-time compiler that can be used to
+optimize pattern matching. This is an optional feature that can be omitted when
+the library is built.
THE BASIC LIBRARY FUNCTIONS
@@ -29,8 +29,8 @@ Copyright (c) 1997-2016 University of Cambridge
All rights reserved.
-PCRE JUST-IN-TIME COMPILATION SUPPORT
--------------------------------------
+PCRE2 JUST-IN-TIME COMPILATION SUPPORT
+--------------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
@@ -51,15 +51,6 @@ Copyright(c) 2009-2016 Zoltan Herczeg
All rights reserved.
-THE C++ WRAPPER FUNCTIONS
--------------------------
-
-Contributed by: Google Inc.
-
-Copyright (c) 2007-2012, Google Inc.
-All rights reserved.
-
-
THE "BSD" LICENCE
-----------------
@@ -73,10 +64,9 @@ modification, are permitted provided that the following conditions are met:
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- * Neither the name of the University of Cambridge nor the name of Google
- Inc. nor the names of their contributors may be used to endorse or
- promote products derived from this software without specific prior
- written permission.
+ * Neither the name of the University of Cambridge nor the names of any
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff --git a/src/3rdparty/pcre/import_from_pcre_tarball.sh b/src/3rdparty/pcre2/import_from_pcre2_tarball.sh
index 6bab1d4581..9e9c90b4bf 100755
--- a/src/3rdparty/pcre/import_from_pcre_tarball.sh
+++ b/src/3rdparty/pcre2/import_from_pcre2_tarball.sh
@@ -1,7 +1,7 @@
#! /bin/sh
#############################################################################
##
-## Copyright (C) 2012 Giuseppe D'Angelo <dangelog@gmail.com>.
+## Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
## Contact: https://www.qt.io/licensing/
##
## This file is the build configuration utility of the Qt Toolkit.
@@ -38,26 +38,26 @@
##
#############################################################################
-# This is a small script to copy the required files from a PCRE tarball
-# into 3rdparty/pcre/ , following the instructions found in the NON-UNIX-USE
+# This is a small script to copy the required files from a PCRE2 tarball
+# into 3rdparty/pcre2/ , following the instructions found in the NON-AUTOTOOLS-BUILD
# file. Documentation, tests, demos etc. are not imported.
if [ $# -ne 2 ]; then
- echo "Usage: $0 pcre_tarball_dir/ \$QTDIR/src/3rdparty/pcre/"
+ echo "Usage: $0 pcre2_tarball_dir/ \$QTDIR/src/3rdparty/pcre2/"
exit 1
fi
-PCRE_DIR=$1
+PCRE2_DIR=$1
TARGET_DIR=$2
-if [ ! -d "$PCRE_DIR" -o ! -r "$PCRE_DIR" -o ! -d "$TARGET_DIR" -o ! -w "$TARGET_DIR" ]; then
- echo "Either the PCRE source dir or the target dir do not exist,"
+if [ ! -d "$PCRE2_DIR" -o ! -r "$PCRE2_DIR" -o ! -d "$TARGET_DIR" -o ! -w "$TARGET_DIR" ]; then
+ echo "Either the PCRE2 source dir or the target dir do not exist,"
echo "are not directories or have the wrong permissions."
exit 2
fi
-# with 1 argument, copies PCRE_DIR/$1 to TARGET_DIR/$1
-# with 2 arguments, copies PCRE_DIR/$1 to TARGET_DIR/$2
+# with 1 argument, copies PCRE2_DIR/$1 to TARGET_DIR/$1
+# with 2 arguments, copies PCRE2_DIR/$1 to TARGET_DIR/$2
copy_file() {
if [ $# -lt 1 -o $# -gt 2 ]; then
echo "Wrong number of arguments to copy_file"
@@ -72,82 +72,67 @@ copy_file() {
fi
mkdir -p "$TARGET_DIR/$(dirname "$SOURCE_FILE")"
- cp "$PCRE_DIR/$SOURCE_FILE" "$TARGET_DIR/$DEST_FILE"
+ cp "$PCRE2_DIR/$SOURCE_FILE" "$TARGET_DIR/$DEST_FILE"
}
-copy_file "pcre.h.generic" "pcre.h"
-copy_file "pcre_chartables.c.dist" "pcre_chartables.c"
+copy_file "src/pcre2.h.generic" "src/pcre2.h"
+copy_file "src/pcre2_chartables.c.dist" "src/pcre2_chartables.c"
FILES="
AUTHORS
- COPYING
LICENCE
- pcre_internal.h
- ucp.h
- pcre_byte_order.c
- pcre_compile.c
- pcre_config.c
- pcre_dfa_exec.c
- pcre_exec.c
- pcre_fullinfo.c
- pcre_get.c
- pcre_globals.c
- pcre_jit_compile.c
- pcre_maketables.c
- pcre_newline.c
- pcre_ord2utf8.c
- pcre_refcount.c
- pcre_string_utils.c
- pcre_study.c
- pcre_tables.c
- pcre_ucd.c
- pcre_valid_utf8.c
- pcre_version.c
- pcre_xclass.c
- pcre16_byte_order.c
- pcre16_chartables.c
- pcre16_compile.c
- pcre16_config.c
- pcre16_dfa_exec.c
- pcre16_exec.c
- pcre16_fullinfo.c
- pcre16_get.c
- pcre16_globals.c
- pcre16_jit_compile.c
- pcre16_maketables.c
- pcre16_newline.c
- pcre16_ord2utf16.c
- pcre16_refcount.c
- pcre16_string_utils.c
- pcre16_study.c
- pcre16_tables.c
- pcre16_ucd.c
- pcre16_utf16_utils.c
- pcre16_valid_utf16.c
- pcre16_version.c
- pcre16_xclass.c
- sljit/sljitConfig.h
- sljit/sljitConfigInternal.h
- sljit/sljitExecAllocator.c
- sljit/sljitLir.c
- sljit/sljitLir.h
- sljit/sljitNativeARM_32.c
- sljit/sljitNativeARM_64.c
- sljit/sljitNativeARM_T2_32.c
- sljit/sljitNativeMIPS_32.c
- sljit/sljitNativeMIPS_64.c
- sljit/sljitNativeMIPS_common.c
- sljit/sljitNativePPC_32.c
- sljit/sljitNativePPC_64.c
- sljit/sljitNativePPC_common.c
- sljit/sljitNativeSPARC_32.c
- sljit/sljitNativeSPARC_common.c
- sljit/sljitNativeTILEGX_64.c
- sljit/sljitNativeTILEGX-encoder.c
- sljit/sljitNativeX86_32.c
- sljit/sljitNativeX86_64.c
- sljit/sljitNativeX86_common.c
- sljit/sljitUtils.c
+
+ src/pcre2_auto_possess.c
+ src/pcre2_compile.c
+ src/pcre2_config.c
+ src/pcre2_context.c
+ src/pcre2_dfa_match.c
+ src/pcre2_error.c
+ src/pcre2_find_bracket.c
+ src/pcre2_internal.h
+ src/pcre2_intmodedep.h
+ src/pcre2_jit_compile.c
+ src/pcre2_jit_match.c
+ src/pcre2_jit_misc.c
+ src/pcre2_maketables.c
+ src/pcre2_match.c
+ src/pcre2_match_data.c
+ src/pcre2_newline.c
+ src/pcre2_ord2utf.c
+ src/pcre2_pattern_info.c
+ src/pcre2_printint.c
+ src/pcre2_serialize.c
+ src/pcre2_string_utils.c
+ src/pcre2_study.c
+ src/pcre2_substitute.c
+ src/pcre2_substring.c
+ src/pcre2_tables.c
+ src/pcre2_ucd.c
+ src/pcre2_ucp.h
+ src/pcre2_valid_utf.c
+ src/pcre2_xclass.c
+ src/sljit/sljitConfig.h
+ src/sljit/sljitConfigInternal.h
+ src/sljit/sljitExecAllocator.c
+ src/sljit/sljitLir.c
+ src/sljit/sljitLir.h
+ src/sljit/sljitNativeARM_32.c
+ src/sljit/sljitNativeARM_64.c
+ src/sljit/sljitNativeARM_T2_32.c
+ src/sljit/sljitNativeMIPS_32.c
+ src/sljit/sljitNativeMIPS_64.c
+ src/sljit/sljitNativeMIPS_common.c
+ src/sljit/sljitNativePPC_32.c
+ src/sljit/sljitNativePPC_64.c
+ src/sljit/sljitNativePPC_common.c
+ src/sljit/sljitNativeSPARC_32.c
+ src/sljit/sljitNativeSPARC_common.c
+ src/sljit/sljitNativeTILEGX_64.c
+ src/sljit/sljitNativeTILEGX-encoder.c
+ src/sljit/sljitNativeX86_32.c
+ src/sljit/sljitNativeX86_64.c
+ src/sljit/sljitNativeX86_common.c
+ src/sljit/sljitUtils.c
"
for i in $FILES; do
diff --git a/src/3rdparty/pcre2/pcre2.pro b/src/3rdparty/pcre2/pcre2.pro
new file mode 100644
index 0000000000..d3a4e08bc5
--- /dev/null
+++ b/src/3rdparty/pcre2/pcre2.pro
@@ -0,0 +1,52 @@
+TARGET = qtpcre2
+
+CONFIG += \
+ static \
+ hide_symbols \
+ exceptions_off rtti_off warn_off
+
+
+MODULE_DEFINES += PCRE2_CODE_UNIT_WIDTH=16
+win32: MODULE_DEFINES += PCRE2_STATIC
+MODULE_INCLUDEPATH += $$PWD/src
+
+load(qt_helper_lib)
+
+DEFINES += HAVE_CONFIG_H
+
+# platform/compiler specific definitions
+ios|qnx|winrt: DEFINES += PCRE2_DISABLE_JIT
+
+SOURCES += \
+ $$PWD/src/pcre2_auto_possess.c \
+ $$PWD/src/pcre2_chartables.c \
+ $$PWD/src/pcre2_compile.c \
+ $$PWD/src/pcre2_config.c \
+ $$PWD/src/pcre2_context.c \
+ $$PWD/src/pcre2_dfa_match.c \
+ $$PWD/src/pcre2_error.c \
+ $$PWD/src/pcre2_find_bracket.c \
+ $$PWD/src/pcre2_jit_compile.c \
+ $$PWD/src/pcre2_maketables.c \
+ $$PWD/src/pcre2_match.c \
+ $$PWD/src/pcre2_match_data.c \
+ $$PWD/src/pcre2_newline.c \
+ $$PWD/src/pcre2_ord2utf.c \
+ $$PWD/src/pcre2_pattern_info.c \
+ $$PWD/src/pcre2_printint.c \
+ $$PWD/src/pcre2_serialize.c \
+ $$PWD/src/pcre2_string_utils.c \
+ $$PWD/src/pcre2_study.c \
+ $$PWD/src/pcre2_substitute.c \
+ $$PWD/src/pcre2_substring.c \
+ $$PWD/src/pcre2_tables.c \
+ $$PWD/src/pcre2_ucd.c \
+ $$PWD/src/pcre2_valid_utf.c \
+ $$PWD/src/pcre2_xclass.c
+
+HEADERS += \
+ $$PWD/src/config.h \
+ $$PWD/src/pcre2.h \
+ $$PWD/src/pcre2_internal.h \
+ $$PWD/src/pcre2_intmodedep.h \
+ $$PWD/src/pcre2_ucp.h
diff --git a/src/3rdparty/pcre/qt_attribution.json b/src/3rdparty/pcre2/qt_attribution.json
index fc7515175a..bcf7650993 100644
--- a/src/3rdparty/pcre/qt_attribution.json
+++ b/src/3rdparty/pcre2/qt_attribution.json
@@ -1,16 +1,17 @@
{
- "Id": "pcre",
- "Name": "PCRE",
+ "Id": "pcre2",
+ "Name": "PCRE2",
"QDocModule": "qtcore",
"QtUsage": "Optionally used in Qt Core (QRegularExpression). Configure with -system-pcre or -no-pcre to avoid.",
"Description": "The PCRE library is a set of functions that implement regular expression pattern matching using the same syntax and semantics as Perl 5.",
"Homepage": "http://www.pcre.org/",
- "Version": "8.39",
+ "Version": "10.22",
"License": "BSD 3-clause \"New\" or \"Revised\" License",
"LicenseId": "BSD-3-Clause",
"LicenseFile": "LICENCE",
"Copyright": "Copyright (c) 1997-2016 University of Cambridge
Copyright (c) 2009-2016 Zoltan Herczeg
-Copyright (c) 2007-2012, Google Inc."
+Copyright (c) 2007-2012 Google Inc.
+Copyright (c) 2013-2013 Tilera Corporation (jiwang@tilera.com)"
}
diff --git a/src/3rdparty/pcre2/src/config.h b/src/3rdparty/pcre2/src/config.h
new file mode 100644
index 0000000000..fbebfe6be0
--- /dev/null
+++ b/src/3rdparty/pcre2/src/config.h
@@ -0,0 +1,52 @@
+#define HAVE_INTTYPES_H 1
+#define HAVE_MEMMOVE 1
+#define HAVE_LIMITS_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRING_H 1
+
+#define LINK_SIZE 2
+#define MATCH_LIMIT 10000000
+#define MATCH_LIMIT_RECURSION MATCH_LIMIT
+#define MAX_NAME_COUNT 10000
+#define MAX_NAME_SIZE 32
+#define NEWLINE_DEFAULT 2
+#define PARENS_NEST_LIMIT 250
+
+#define SUPPORT_UNICODE
+
+/*
+ man 3 pcre2jit for a list of supported platforms;
+ as PCRE2 10.22, stable JIT support is available for:
+ - ARM 32-bit (v5, v7, and Thumb2)
+ - ARM 64-bit
+ - Intel x86 32-bit and 64-bit
+ - MIPS 32-bit and 64-bit
+ - Power PC 32-bit and 64-bit
+ - SPARC 32-bit
+
+ For non-x86 platforms we stick to the __GNUC__ compilers only.
+*/
+#if !defined(PCRE2_DISABLE_JIT) && (\
+ /* ARM */ \
+ (defined(__GNUC__) \
+ && (defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(__aarch64__))) \
+ /* x86 32/64 */ \
+ || defined(__i386) || defined(__i386__) || defined(_M_IX86) \
+ || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) \
+ /* MIPS */ \
+ || (defined(__GNUC__) \
+ && (defined(__mips) || defined(__mips__))) \
+ /* PPC */ \
+ || (defined(__GNUC__) \
+ && (defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \
+ || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \
+ || defined(_M_MPPC) || defined(_M_PPC))) \
+ /* SPARC */ \
+ || (defined(__GNUC__) \
+ && (defined(__sparc__) && !defined(__sparc64__))) \
+ )
+# define SUPPORT_JIT
+#endif
+
diff --git a/src/3rdparty/pcre2/src/pcre2.h b/src/3rdparty/pcre2/src/pcre2.h
new file mode 100644
index 0000000000..20d221b803
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2.h
@@ -0,0 +1,732 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* This is the public header file for the PCRE library, second API, to be
+#included by applications that call PCRE2 functions.
+
+ Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef _PCRE2_H
+#define _PCRE2_H
+
+/* The current PCRE version information. */
+
+#define PCRE2_MAJOR 10
+#define PCRE2_MINOR 22
+#define PCRE2_PRERELEASE
+#define PCRE2_DATE 2016-07-29
+
+/* When an application links to a PCRE DLL in Windows, the symbols that are
+imported have to be identified as such. When building PCRE2, the appropriate
+export setting is defined in pcre2_internal.h, which includes this file. So we
+don't change existing definitions of PCRE2_EXP_DECL. */
+
+#if defined(_WIN32) && !defined(PCRE2_STATIC)
+# ifndef PCRE2_EXP_DECL
+# define PCRE2_EXP_DECL extern __declspec(dllimport)
+# endif
+#endif
+
+/* By default, we use the standard "extern" declarations. */
+
+#ifndef PCRE2_EXP_DECL
+# ifdef __cplusplus
+# define PCRE2_EXP_DECL extern "C"
+# else
+# define PCRE2_EXP_DECL extern
+# endif
+#endif
+
+/* Have to include limits.h, stdlib.h and stdint.h to ensure that size_t and
+uint8_t, UCHAR_MAX, etc are defined. */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+/* Allow for C++ users compiling this directly. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The following option bits can be passed to pcre2_compile(), pcre2_match(),
+or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it
+is passed. Put these bits at the most significant end of the options word so
+others can be added next to them */
+
+#define PCRE2_ANCHORED 0x80000000u
+#define PCRE2_NO_UTF_CHECK 0x40000000u
+
+/* The following option bits can be passed only to pcre2_compile(). However,
+they may affect compilation, JIT compilation, and/or interpretive execution.
+The following tags indicate which:
+
+C alters what is compiled by pcre2_compile()
+J alters what is compiled by pcre2_jit_compile()
+M is inspected during pcre2_match() execution
+D is inspected during pcre2_dfa_match() execution
+*/
+
+#define PCRE2_ALLOW_EMPTY_CLASS 0x00000001u /* C */
+#define PCRE2_ALT_BSUX 0x00000002u /* C */
+#define PCRE2_AUTO_CALLOUT 0x00000004u /* C */
+#define PCRE2_CASELESS 0x00000008u /* C */
+#define PCRE2_DOLLAR_ENDONLY 0x00000010u /* J M D */
+#define PCRE2_DOTALL 0x00000020u /* C */
+#define PCRE2_DUPNAMES 0x00000040u /* C */
+#define PCRE2_EXTENDED 0x00000080u /* C */
+#define PCRE2_FIRSTLINE 0x00000100u /* J M D */
+#define PCRE2_MATCH_UNSET_BACKREF 0x00000200u /* C J M */
+#define PCRE2_MULTILINE 0x00000400u /* C */
+#define PCRE2_NEVER_UCP 0x00000800u /* C */
+#define PCRE2_NEVER_UTF 0x00001000u /* C */
+#define PCRE2_NO_AUTO_CAPTURE 0x00002000u /* C */
+#define PCRE2_NO_AUTO_POSSESS 0x00004000u /* C */
+#define PCRE2_NO_DOTSTAR_ANCHOR 0x00008000u /* C */
+#define PCRE2_NO_START_OPTIMIZE 0x00010000u /* J M D */
+#define PCRE2_UCP 0x00020000u /* C J M D */
+#define PCRE2_UNGREEDY 0x00040000u /* C */
+#define PCRE2_UTF 0x00080000u /* C J M D */
+#define PCRE2_NEVER_BACKSLASH_C 0x00100000u /* C */
+#define PCRE2_ALT_CIRCUMFLEX 0x00200000u /* J M D */
+#define PCRE2_ALT_VERBNAMES 0x00400000u /* C */
+#define PCRE2_USE_OFFSET_LIMIT 0x00800000u /* J M D */
+
+/* These are for pcre2_jit_compile(). */
+
+#define PCRE2_JIT_COMPLETE 0x00000001u /* For full matching */
+#define PCRE2_JIT_PARTIAL_SOFT 0x00000002u
+#define PCRE2_JIT_PARTIAL_HARD 0x00000004u
+
+/* These are for pcre2_match(), pcre2_dfa_match(), and pcre2_jit_match(). Note
+that PCRE2_ANCHORED and PCRE2_NO_UTF_CHECK can also be passed to these
+functions (though pcre2_jit_match() ignores the latter since it bypasses all
+sanity checks). */
+
+#define PCRE2_NOTBOL 0x00000001u
+#define PCRE2_NOTEOL 0x00000002u
+#define PCRE2_NOTEMPTY 0x00000004u /* ) These two must be kept */
+#define PCRE2_NOTEMPTY_ATSTART 0x00000008u /* ) adjacent to each other. */
+#define PCRE2_PARTIAL_SOFT 0x00000010u
+#define PCRE2_PARTIAL_HARD 0x00000020u
+
+/* These are additional options for pcre2_dfa_match(). */
+
+#define PCRE2_DFA_RESTART 0x00000040u
+#define PCRE2_DFA_SHORTEST 0x00000080u
+
+/* These are additional options for pcre2_substitute(), which passes any others
+through to pcre2_match(). */
+
+#define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u
+#define PCRE2_SUBSTITUTE_EXTENDED 0x00000200u
+#define PCRE2_SUBSTITUTE_UNSET_EMPTY 0x00000400u
+#define PCRE2_SUBSTITUTE_UNKNOWN_UNSET 0x00000800u
+#define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH 0x00001000u
+
+/* A further option for pcre2_match(), not allowed for pcre2_dfa_match(),
+ignored for pcre2_jit_match(). */
+
+#define PCRE2_NO_JIT 0x00002000u
+
+/* Newline and \R settings, for use in compile contexts. The newline values
+must be kept in step with values set in config.h and both sets must all be
+greater than zero. */
+
+#define PCRE2_NEWLINE_CR 1
+#define PCRE2_NEWLINE_LF 2
+#define PCRE2_NEWLINE_CRLF 3
+#define PCRE2_NEWLINE_ANY 4
+#define PCRE2_NEWLINE_ANYCRLF 5
+
+#define PCRE2_BSR_UNICODE 1
+#define PCRE2_BSR_ANYCRLF 2
+
+/* Error codes: no match and partial match are "expected" errors. */
+
+#define PCRE2_ERROR_NOMATCH (-1)
+#define PCRE2_ERROR_PARTIAL (-2)
+
+/* Error codes for UTF-8 validity checks */
+
+#define PCRE2_ERROR_UTF8_ERR1 (-3)
+#define PCRE2_ERROR_UTF8_ERR2 (-4)
+#define PCRE2_ERROR_UTF8_ERR3 (-5)
+#define PCRE2_ERROR_UTF8_ERR4 (-6)
+#define PCRE2_ERROR_UTF8_ERR5 (-7)
+#define PCRE2_ERROR_UTF8_ERR6 (-8)
+#define PCRE2_ERROR_UTF8_ERR7 (-9)
+#define PCRE2_ERROR_UTF8_ERR8 (-10)
+#define PCRE2_ERROR_UTF8_ERR9 (-11)
+#define PCRE2_ERROR_UTF8_ERR10 (-12)
+#define PCRE2_ERROR_UTF8_ERR11 (-13)
+#define PCRE2_ERROR_UTF8_ERR12 (-14)
+#define PCRE2_ERROR_UTF8_ERR13 (-15)
+#define PCRE2_ERROR_UTF8_ERR14 (-16)
+#define PCRE2_ERROR_UTF8_ERR15 (-17)
+#define PCRE2_ERROR_UTF8_ERR16 (-18)
+#define PCRE2_ERROR_UTF8_ERR17 (-19)
+#define PCRE2_ERROR_UTF8_ERR18 (-20)
+#define PCRE2_ERROR_UTF8_ERR19 (-21)
+#define PCRE2_ERROR_UTF8_ERR20 (-22)
+#define PCRE2_ERROR_UTF8_ERR21 (-23)
+
+/* Error codes for UTF-16 validity checks */
+
+#define PCRE2_ERROR_UTF16_ERR1 (-24)
+#define PCRE2_ERROR_UTF16_ERR2 (-25)
+#define PCRE2_ERROR_UTF16_ERR3 (-26)
+
+/* Error codes for UTF-32 validity checks */
+
+#define PCRE2_ERROR_UTF32_ERR1 (-27)
+#define PCRE2_ERROR_UTF32_ERR2 (-28)
+
+/* Error codes for pcre2[_dfa]_match(), substring extraction functions, context
+functions, and serializing functions. They are in numerical order. Originally
+they were in alphabetical order too, but now that PCRE2 is released, the
+numbers must not be changed. */
+
+#define PCRE2_ERROR_BADDATA (-29)
+#define PCRE2_ERROR_MIXEDTABLES (-30) /* Name was changed */
+#define PCRE2_ERROR_BADMAGIC (-31)
+#define PCRE2_ERROR_BADMODE (-32)
+#define PCRE2_ERROR_BADOFFSET (-33)
+#define PCRE2_ERROR_BADOPTION (-34)
+#define PCRE2_ERROR_BADREPLACEMENT (-35)
+#define PCRE2_ERROR_BADUTFOFFSET (-36)
+#define PCRE2_ERROR_CALLOUT (-37) /* Never used by PCRE2 itself */
+#define PCRE2_ERROR_DFA_BADRESTART (-38)
+#define PCRE2_ERROR_DFA_RECURSE (-39)
+#define PCRE2_ERROR_DFA_UCOND (-40)
+#define PCRE2_ERROR_DFA_UFUNC (-41)
+#define PCRE2_ERROR_DFA_UITEM (-42)
+#define PCRE2_ERROR_DFA_WSSIZE (-43)
+#define PCRE2_ERROR_INTERNAL (-44)
+#define PCRE2_ERROR_JIT_BADOPTION (-45)
+#define PCRE2_ERROR_JIT_STACKLIMIT (-46)
+#define PCRE2_ERROR_MATCHLIMIT (-47)
+#define PCRE2_ERROR_NOMEMORY (-48)
+#define PCRE2_ERROR_NOSUBSTRING (-49)
+#define PCRE2_ERROR_NOUNIQUESUBSTRING (-50)
+#define PCRE2_ERROR_NULL (-51)
+#define PCRE2_ERROR_RECURSELOOP (-52)
+#define PCRE2_ERROR_RECURSIONLIMIT (-53)
+#define PCRE2_ERROR_UNAVAILABLE (-54)
+#define PCRE2_ERROR_UNSET (-55)
+#define PCRE2_ERROR_BADOFFSETLIMIT (-56)
+#define PCRE2_ERROR_BADREPESCAPE (-57)
+#define PCRE2_ERROR_REPMISSINGBRACE (-58)
+#define PCRE2_ERROR_BADSUBSTITUTION (-59)
+#define PCRE2_ERROR_BADSUBSPATTERN (-60)
+#define PCRE2_ERROR_TOOMANYREPLACE (-61)
+#define PCRE2_ERROR_BADSERIALIZEDDATA (-62)
+
+/* Request types for pcre2_pattern_info() */
+
+#define PCRE2_INFO_ALLOPTIONS 0
+#define PCRE2_INFO_ARGOPTIONS 1
+#define PCRE2_INFO_BACKREFMAX 2
+#define PCRE2_INFO_BSR 3
+#define PCRE2_INFO_CAPTURECOUNT 4
+#define PCRE2_INFO_FIRSTCODEUNIT 5
+#define PCRE2_INFO_FIRSTCODETYPE 6
+#define PCRE2_INFO_FIRSTBITMAP 7
+#define PCRE2_INFO_HASCRORLF 8
+#define PCRE2_INFO_JCHANGED 9
+#define PCRE2_INFO_JITSIZE 10
+#define PCRE2_INFO_LASTCODEUNIT 11
+#define PCRE2_INFO_LASTCODETYPE 12
+#define PCRE2_INFO_MATCHEMPTY 13
+#define PCRE2_INFO_MATCHLIMIT 14
+#define PCRE2_INFO_MAXLOOKBEHIND 15
+#define PCRE2_INFO_MINLENGTH 16
+#define PCRE2_INFO_NAMECOUNT 17
+#define PCRE2_INFO_NAMEENTRYSIZE 18
+#define PCRE2_INFO_NAMETABLE 19
+#define PCRE2_INFO_NEWLINE 20
+#define PCRE2_INFO_RECURSIONLIMIT 21
+#define PCRE2_INFO_SIZE 22
+#define PCRE2_INFO_HASBACKSLASHC 23
+
+/* Request types for pcre2_config(). */
+
+#define PCRE2_CONFIG_BSR 0
+#define PCRE2_CONFIG_JIT 1
+#define PCRE2_CONFIG_JITTARGET 2
+#define PCRE2_CONFIG_LINKSIZE 3
+#define PCRE2_CONFIG_MATCHLIMIT 4
+#define PCRE2_CONFIG_NEWLINE 5
+#define PCRE2_CONFIG_PARENSLIMIT 6
+#define PCRE2_CONFIG_RECURSIONLIMIT 7
+#define PCRE2_CONFIG_STACKRECURSE 8
+#define PCRE2_CONFIG_UNICODE 9
+#define PCRE2_CONFIG_UNICODE_VERSION 10
+#define PCRE2_CONFIG_VERSION 11
+
+/* Types for code units in patterns and subject strings. */
+
+typedef uint8_t PCRE2_UCHAR8;
+typedef uint16_t PCRE2_UCHAR16;
+typedef uint32_t PCRE2_UCHAR32;
+
+typedef const PCRE2_UCHAR8 *PCRE2_SPTR8;
+typedef const PCRE2_UCHAR16 *PCRE2_SPTR16;
+typedef const PCRE2_UCHAR32 *PCRE2_SPTR32;
+
+/* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2,
+including pattern offsets for errors and subject offsets after a match. We
+define special values to indicate zero-terminated strings and unset offsets in
+the offset vector (ovector). */
+
+#define PCRE2_SIZE size_t
+#define PCRE2_SIZE_MAX SIZE_MAX
+#define PCRE2_ZERO_TERMINATED (~(PCRE2_SIZE)0)
+#define PCRE2_UNSET (~(PCRE2_SIZE)0)
+
+/* Generic types for opaque structures and JIT callback functions. These
+declarations are defined in a macro that is expanded for each width later. */
+
+#define PCRE2_TYPES_LIST \
+struct pcre2_real_general_context; \
+typedef struct pcre2_real_general_context pcre2_general_context; \
+\
+struct pcre2_real_compile_context; \
+typedef struct pcre2_real_compile_context pcre2_compile_context; \
+\
+struct pcre2_real_match_context; \
+typedef struct pcre2_real_match_context pcre2_match_context; \
+\
+struct pcre2_real_code; \
+typedef struct pcre2_real_code pcre2_code; \
+\
+struct pcre2_real_match_data; \
+typedef struct pcre2_real_match_data pcre2_match_data; \
+\
+struct pcre2_real_jit_stack; \
+typedef struct pcre2_real_jit_stack pcre2_jit_stack; \
+\
+typedef pcre2_jit_stack *(*pcre2_jit_callback)(void *);
+
+
+/* The structure for passing out data via the pcre_callout_function. We use a
+structure so that new fields can be added on the end in future versions,
+without changing the API of the function, thereby allowing old clients to work
+without modification. Define the generic version in a macro; the width-specific
+versions are generated from this macro below. */
+
+#define PCRE2_STRUCTURE_LIST \
+typedef struct pcre2_callout_block { \
+ uint32_t version; /* Identifies version of block */ \
+ /* ------------------------ Version 0 ------------------------------- */ \
+ uint32_t callout_number; /* Number compiled into pattern */ \
+ uint32_t capture_top; /* Max current capture */ \
+ uint32_t capture_last; /* Most recently closed capture */ \
+ PCRE2_SIZE *offset_vector; /* The offset vector */ \
+ PCRE2_SPTR mark; /* Pointer to current mark or NULL */ \
+ PCRE2_SPTR subject; /* The subject being matched */ \
+ PCRE2_SIZE subject_length; /* The length of the subject */ \
+ PCRE2_SIZE start_match; /* Offset to start of this match attempt */ \
+ PCRE2_SIZE current_position; /* Where we currently are in the subject */ \
+ PCRE2_SIZE pattern_position; /* Offset to next item in the pattern */ \
+ PCRE2_SIZE next_item_length; /* Length of next item in the pattern */ \
+ /* ------------------- Added for Version 1 -------------------------- */ \
+ PCRE2_SIZE callout_string_offset; /* Offset to string within pattern */ \
+ PCRE2_SIZE callout_string_length; /* Length of string compiled into pattern */ \
+ PCRE2_SPTR callout_string; /* String compiled into pattern */ \
+ /* ------------------------------------------------------------------ */ \
+} pcre2_callout_block; \
+\
+typedef struct pcre2_callout_enumerate_block { \
+ uint32_t version; /* Identifies version of block */ \
+ /* ------------------------ Version 0 ------------------------------- */ \
+ PCRE2_SIZE pattern_position; /* Offset to next item in the pattern */ \
+ PCRE2_SIZE next_item_length; /* Length of next item in the pattern */ \
+ uint32_t callout_number; /* Number compiled into pattern */ \
+ PCRE2_SIZE callout_string_offset; /* Offset to string within pattern */ \
+ PCRE2_SIZE callout_string_length; /* Length of string compiled into pattern */ \
+ PCRE2_SPTR callout_string; /* String compiled into pattern */ \
+ /* ------------------------------------------------------------------ */ \
+} pcre2_callout_enumerate_block;
+
+
+/* List the generic forms of all other functions in macros, which will be
+expanded for each width below. Start with functions that give general
+information. */
+
+#define PCRE2_GENERAL_INFO_FUNCTIONS \
+PCRE2_EXP_DECL int pcre2_config(uint32_t, void *);
+
+
+/* Functions for manipulating contexts. */
+
+#define PCRE2_GENERAL_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL \
+ pcre2_general_context *pcre2_general_context_copy(pcre2_general_context *); \
+PCRE2_EXP_DECL \
+ pcre2_general_context *pcre2_general_context_create( \
+ void *(*)(PCRE2_SIZE, void *), \
+ void (*)(void *, void *), void *); \
+PCRE2_EXP_DECL void pcre2_general_context_free(pcre2_general_context *);
+
+#define PCRE2_COMPILE_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL \
+ pcre2_compile_context *pcre2_compile_context_copy(pcre2_compile_context *); \
+PCRE2_EXP_DECL \
+ pcre2_compile_context *pcre2_compile_context_create(pcre2_general_context *);\
+PCRE2_EXP_DECL void pcre2_compile_context_free(pcre2_compile_context *); \
+PCRE2_EXP_DECL int pcre2_set_bsr(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int pcre2_set_character_tables(pcre2_compile_context *, \
+ const unsigned char *); \
+PCRE2_EXP_DECL int pcre2_set_max_pattern_length(pcre2_compile_context *, \
+ PCRE2_SIZE); \
+PCRE2_EXP_DECL int pcre2_set_newline(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int pcre2_set_parens_nest_limit(pcre2_compile_context *, \
+ uint32_t); \
+PCRE2_EXP_DECL int pcre2_set_compile_recursion_guard(\
+ pcre2_compile_context *, int (*)(uint32_t, void *), \
+ void *);
+
+#define PCRE2_MATCH_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL \
+ pcre2_match_context *pcre2_match_context_copy(pcre2_match_context *); \
+PCRE2_EXP_DECL \
+ pcre2_match_context *pcre2_match_context_create(pcre2_general_context *); \
+PCRE2_EXP_DECL void pcre2_match_context_free(pcre2_match_context *); \
+PCRE2_EXP_DECL int pcre2_set_callout(pcre2_match_context *, \
+ int (*)(pcre2_callout_block *, void *), void *); \
+PCRE2_EXP_DECL int pcre2_set_match_limit(pcre2_match_context *, \
+ uint32_t); \
+PCRE2_EXP_DECL int pcre2_set_offset_limit(pcre2_match_context *, \
+ PCRE2_SIZE); \
+PCRE2_EXP_DECL int pcre2_set_recursion_limit(pcre2_match_context *, \
+ uint32_t); \
+PCRE2_EXP_DECL int pcre2_set_recursion_memory_management( \
+ pcre2_match_context *, void *(*)(PCRE2_SIZE, void *), \
+ void (*)(void *, void *), void *);
+
+
+/* Functions concerned with compiling a pattern to PCRE internal code. */
+
+#define PCRE2_COMPILE_FUNCTIONS \
+PCRE2_EXP_DECL \
+ pcre2_code *pcre2_compile(PCRE2_SPTR, PCRE2_SIZE, uint32_t, \
+ int *, PCRE2_SIZE *, pcre2_compile_context *); \
+PCRE2_EXP_DECL void pcre2_code_free(pcre2_code *); \
+PCRE2_EXP_DECL \
+ pcre2_code *pcre2_code_copy(const pcre2_code *);
+
+
+/* Functions that give information about a compiled pattern. */
+
+#define PCRE2_PATTERN_INFO_FUNCTIONS \
+PCRE2_EXP_DECL int pcre2_pattern_info(const pcre2_code *, uint32_t, \
+ void *); \
+PCRE2_EXP_DECL int pcre2_callout_enumerate(const pcre2_code *, \
+ int (*)(pcre2_callout_enumerate_block *, void *), \
+ void *);
+
+
+/* Functions for running a match and inspecting the result. */
+
+#define PCRE2_MATCH_FUNCTIONS \
+PCRE2_EXP_DECL \
+ pcre2_match_data *pcre2_match_data_create(uint32_t, \
+ pcre2_general_context *); \
+PCRE2_EXP_DECL \
+ pcre2_match_data *pcre2_match_data_create_from_pattern(\
+ const pcre2_code *, \
+ pcre2_general_context *); \
+PCRE2_EXP_DECL int pcre2_dfa_match(const pcre2_code *, PCRE2_SPTR, \
+ PCRE2_SIZE, PCRE2_SIZE, uint32_t, \
+ pcre2_match_data *, pcre2_match_context *, int *, \
+ PCRE2_SIZE); \
+PCRE2_EXP_DECL int pcre2_match(const pcre2_code *, \
+ PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, \
+ pcre2_match_data *, pcre2_match_context *); \
+PCRE2_EXP_DECL void pcre2_match_data_free(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SPTR pcre2_get_mark(pcre2_match_data *); \
+PCRE2_EXP_DECL uint32_t pcre2_get_ovector_count(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SIZE *pcre2_get_ovector_pointer(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SIZE pcre2_get_startchar(pcre2_match_data *);
+
+
+/* Convenience functions for handling matched substrings. */
+
+#define PCRE2_SUBSTRING_FUNCTIONS \
+PCRE2_EXP_DECL int pcre2_substring_copy_byname(pcre2_match_data *, \
+ PCRE2_SPTR, PCRE2_UCHAR *, PCRE2_SIZE *); \
+PCRE2_EXP_DECL int pcre2_substring_copy_bynumber(pcre2_match_data *, \
+ uint32_t, PCRE2_UCHAR *, PCRE2_SIZE *); \
+PCRE2_EXP_DECL void pcre2_substring_free(PCRE2_UCHAR *); \
+PCRE2_EXP_DECL int pcre2_substring_get_byname(pcre2_match_data *, \
+ PCRE2_SPTR, PCRE2_UCHAR **, PCRE2_SIZE *); \
+PCRE2_EXP_DECL int pcre2_substring_get_bynumber(pcre2_match_data *, \
+ uint32_t, PCRE2_UCHAR **, PCRE2_SIZE *); \
+PCRE2_EXP_DECL int pcre2_substring_length_byname(pcre2_match_data *, \
+ PCRE2_SPTR, PCRE2_SIZE *); \
+PCRE2_EXP_DECL int pcre2_substring_length_bynumber(pcre2_match_data *, \
+ uint32_t, PCRE2_SIZE *); \
+PCRE2_EXP_DECL int pcre2_substring_nametable_scan(const pcre2_code *, \
+ PCRE2_SPTR, PCRE2_SPTR *, PCRE2_SPTR *); \
+PCRE2_EXP_DECL int pcre2_substring_number_from_name(\
+ const pcre2_code *, PCRE2_SPTR); \
+PCRE2_EXP_DECL void pcre2_substring_list_free(PCRE2_SPTR *); \
+PCRE2_EXP_DECL int pcre2_substring_list_get(pcre2_match_data *, \
+ PCRE2_UCHAR ***, PCRE2_SIZE **);
+
+/* Functions for serializing / deserializing compiled patterns. */
+
+#define PCRE2_SERIALIZE_FUNCTIONS \
+PCRE2_EXP_DECL int32_t pcre2_serialize_encode(const pcre2_code **, \
+ int32_t, uint8_t **, PCRE2_SIZE *, \
+ pcre2_general_context *); \
+PCRE2_EXP_DECL int32_t pcre2_serialize_decode(pcre2_code **, int32_t, \
+ const uint8_t *, pcre2_general_context *); \
+PCRE2_EXP_DECL int32_t pcre2_serialize_get_number_of_codes(const uint8_t *); \
+PCRE2_EXP_DECL void pcre2_serialize_free(uint8_t *);
+
+
+/* Convenience function for match + substitute. */
+
+#define PCRE2_SUBSTITUTE_FUNCTION \
+PCRE2_EXP_DECL int pcre2_substitute(const pcre2_code *, \
+ PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, \
+ pcre2_match_data *, pcre2_match_context *, \
+ PCRE2_SPTR, PCRE2_SIZE, PCRE2_UCHAR *, \
+ PCRE2_SIZE *);
+
+
+/* Functions for JIT processing */
+
+#define PCRE2_JIT_FUNCTIONS \
+PCRE2_EXP_DECL int pcre2_jit_compile(pcre2_code *, uint32_t); \
+PCRE2_EXP_DECL int pcre2_jit_match(const pcre2_code *, \
+ PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, uint32_t, \
+ pcre2_match_data *, pcre2_match_context *); \
+PCRE2_EXP_DECL void pcre2_jit_free_unused_memory(pcre2_general_context *); \
+PCRE2_EXP_DECL \
+ pcre2_jit_stack *pcre2_jit_stack_create(PCRE2_SIZE, PCRE2_SIZE, \
+ pcre2_general_context *); \
+PCRE2_EXP_DECL void pcre2_jit_stack_assign(pcre2_match_context *, \
+ pcre2_jit_callback, void *); \
+PCRE2_EXP_DECL void pcre2_jit_stack_free(pcre2_jit_stack *);
+
+
+/* Other miscellaneous functions. */
+
+#define PCRE2_OTHER_FUNCTIONS \
+PCRE2_EXP_DECL int pcre2_get_error_message(int, PCRE2_UCHAR *, PCRE2_SIZE); \
+PCRE2_EXP_DECL \
+ const uint8_t *pcre2_maketables(pcre2_general_context *); \
+
+
+/* Define macros that generate width-specific names from generic versions. The
+three-level macro scheme is necessary to get the macros expanded when we want
+them to be. First we get the width from PCRE2_LOCAL_WIDTH, which is used for
+generating three versions of everything below. After that, PCRE2_SUFFIX will be
+re-defined to use PCRE2_CODE_UNIT_WIDTH, for use when macros such as
+pcre2_compile are called by application code. */
+
+#define PCRE2_JOIN(a,b) a ## b
+#define PCRE2_GLUE(a,b) PCRE2_JOIN(a,b)
+#define PCRE2_SUFFIX(a) PCRE2_GLUE(a,PCRE2_LOCAL_WIDTH)
+
+
+/* Data types */
+
+#define PCRE2_UCHAR PCRE2_SUFFIX(PCRE2_UCHAR)
+#define PCRE2_SPTR PCRE2_SUFFIX(PCRE2_SPTR)
+
+#define pcre2_code PCRE2_SUFFIX(pcre2_code_)
+#define pcre2_jit_callback PCRE2_SUFFIX(pcre2_jit_callback_)
+#define pcre2_jit_stack PCRE2_SUFFIX(pcre2_jit_stack_)
+
+#define pcre2_real_code PCRE2_SUFFIX(pcre2_real_code_)
+#define pcre2_real_general_context PCRE2_SUFFIX(pcre2_real_general_context_)
+#define pcre2_real_compile_context PCRE2_SUFFIX(pcre2_real_compile_context_)
+#define pcre2_real_match_context PCRE2_SUFFIX(pcre2_real_match_context_)
+#define pcre2_real_jit_stack PCRE2_SUFFIX(pcre2_real_jit_stack_)
+#define pcre2_real_match_data PCRE2_SUFFIX(pcre2_real_match_data_)
+
+
+/* Data blocks */
+
+#define pcre2_callout_block PCRE2_SUFFIX(pcre2_callout_block_)
+#define pcre2_callout_enumerate_block PCRE2_SUFFIX(pcre2_callout_enumerate_block_)
+#define pcre2_general_context PCRE2_SUFFIX(pcre2_general_context_)
+#define pcre2_compile_context PCRE2_SUFFIX(pcre2_compile_context_)
+#define pcre2_match_context PCRE2_SUFFIX(pcre2_match_context_)
+#define pcre2_match_data PCRE2_SUFFIX(pcre2_match_data_)
+
+
+/* Functions: the complete list in alphabetical order */
+
+#define pcre2_callout_enumerate PCRE2_SUFFIX(pcre2_callout_enumerate_)
+#define pcre2_code_copy PCRE2_SUFFIX(pcre2_code_copy_)
+#define pcre2_code_free PCRE2_SUFFIX(pcre2_code_free_)
+#define pcre2_compile PCRE2_SUFFIX(pcre2_compile_)
+#define pcre2_compile_context_copy PCRE2_SUFFIX(pcre2_compile_context_copy_)
+#define pcre2_compile_context_create PCRE2_SUFFIX(pcre2_compile_context_create_)
+#define pcre2_compile_context_free PCRE2_SUFFIX(pcre2_compile_context_free_)
+#define pcre2_config PCRE2_SUFFIX(pcre2_config_)
+#define pcre2_dfa_match PCRE2_SUFFIX(pcre2_dfa_match_)
+#define pcre2_general_context_copy PCRE2_SUFFIX(pcre2_general_context_copy_)
+#define pcre2_general_context_create PCRE2_SUFFIX(pcre2_general_context_create_)
+#define pcre2_general_context_free PCRE2_SUFFIX(pcre2_general_context_free_)
+#define pcre2_get_error_message PCRE2_SUFFIX(pcre2_get_error_message_)
+#define pcre2_get_mark PCRE2_SUFFIX(pcre2_get_mark_)
+#define pcre2_get_ovector_pointer PCRE2_SUFFIX(pcre2_get_ovector_pointer_)
+#define pcre2_get_ovector_count PCRE2_SUFFIX(pcre2_get_ovector_count_)
+#define pcre2_get_startchar PCRE2_SUFFIX(pcre2_get_startchar_)
+#define pcre2_jit_compile PCRE2_SUFFIX(pcre2_jit_compile_)
+#define pcre2_jit_match PCRE2_SUFFIX(pcre2_jit_match_)
+#define pcre2_jit_free_unused_memory PCRE2_SUFFIX(pcre2_jit_free_unused_memory_)
+#define pcre2_jit_stack_assign PCRE2_SUFFIX(pcre2_jit_stack_assign_)
+#define pcre2_jit_stack_create PCRE2_SUFFIX(pcre2_jit_stack_create_)
+#define pcre2_jit_stack_free PCRE2_SUFFIX(pcre2_jit_stack_free_)
+#define pcre2_maketables PCRE2_SUFFIX(pcre2_maketables_)
+#define pcre2_match PCRE2_SUFFIX(pcre2_match_)
+#define pcre2_match_context_copy PCRE2_SUFFIX(pcre2_match_context_copy_)
+#define pcre2_match_context_create PCRE2_SUFFIX(pcre2_match_context_create_)
+#define pcre2_match_context_free PCRE2_SUFFIX(pcre2_match_context_free_)
+#define pcre2_match_data_create PCRE2_SUFFIX(pcre2_match_data_create_)
+#define pcre2_match_data_create_from_pattern PCRE2_SUFFIX(pcre2_match_data_create_from_pattern_)
+#define pcre2_match_data_free PCRE2_SUFFIX(pcre2_match_data_free_)
+#define pcre2_pattern_info PCRE2_SUFFIX(pcre2_pattern_info_)
+#define pcre2_serialize_decode PCRE2_SUFFIX(pcre2_serialize_decode_)
+#define pcre2_serialize_encode PCRE2_SUFFIX(pcre2_serialize_encode_)
+#define pcre2_serialize_free PCRE2_SUFFIX(pcre2_serialize_free_)
+#define pcre2_serialize_get_number_of_codes PCRE2_SUFFIX(pcre2_serialize_get_number_of_codes_)
+#define pcre2_set_bsr PCRE2_SUFFIX(pcre2_set_bsr_)
+#define pcre2_set_callout PCRE2_SUFFIX(pcre2_set_callout_)
+#define pcre2_set_character_tables PCRE2_SUFFIX(pcre2_set_character_tables_)
+#define pcre2_set_compile_recursion_guard PCRE2_SUFFIX(pcre2_set_compile_recursion_guard_)
+#define pcre2_set_match_limit PCRE2_SUFFIX(pcre2_set_match_limit_)
+#define pcre2_set_max_pattern_length PCRE2_SUFFIX(pcre2_set_max_pattern_length_)
+#define pcre2_set_newline PCRE2_SUFFIX(pcre2_set_newline_)
+#define pcre2_set_parens_nest_limit PCRE2_SUFFIX(pcre2_set_parens_nest_limit_)
+#define pcre2_set_offset_limit PCRE2_SUFFIX(pcre2_set_offset_limit_)
+#define pcre2_set_recursion_limit PCRE2_SUFFIX(pcre2_set_recursion_limit_)
+#define pcre2_set_recursion_memory_management PCRE2_SUFFIX(pcre2_set_recursion_memory_management_)
+#define pcre2_substitute PCRE2_SUFFIX(pcre2_substitute_)
+#define pcre2_substring_copy_byname PCRE2_SUFFIX(pcre2_substring_copy_byname_)
+#define pcre2_substring_copy_bynumber PCRE2_SUFFIX(pcre2_substring_copy_bynumber_)
+#define pcre2_substring_free PCRE2_SUFFIX(pcre2_substring_free_)
+#define pcre2_substring_get_byname PCRE2_SUFFIX(pcre2_substring_get_byname_)
+#define pcre2_substring_get_bynumber PCRE2_SUFFIX(pcre2_substring_get_bynumber_)
+#define pcre2_substring_length_byname PCRE2_SUFFIX(pcre2_substring_length_byname_)
+#define pcre2_substring_length_bynumber PCRE2_SUFFIX(pcre2_substring_length_bynumber_)
+#define pcre2_substring_list_get PCRE2_SUFFIX(pcre2_substring_list_get_)
+#define pcre2_substring_list_free PCRE2_SUFFIX(pcre2_substring_list_free_)
+#define pcre2_substring_nametable_scan PCRE2_SUFFIX(pcre2_substring_nametable_scan_)
+#define pcre2_substring_number_from_name PCRE2_SUFFIX(pcre2_substring_number_from_name_)
+
+
+/* Now generate all three sets of width-specific structures and function
+prototypes. */
+
+#define PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS \
+PCRE2_TYPES_LIST \
+PCRE2_STRUCTURE_LIST \
+PCRE2_GENERAL_INFO_FUNCTIONS \
+PCRE2_GENERAL_CONTEXT_FUNCTIONS \
+PCRE2_COMPILE_CONTEXT_FUNCTIONS \
+PCRE2_MATCH_CONTEXT_FUNCTIONS \
+PCRE2_COMPILE_FUNCTIONS \
+PCRE2_PATTERN_INFO_FUNCTIONS \
+PCRE2_MATCH_FUNCTIONS \
+PCRE2_SUBSTRING_FUNCTIONS \
+PCRE2_SERIALIZE_FUNCTIONS \
+PCRE2_SUBSTITUTE_FUNCTION \
+PCRE2_JIT_FUNCTIONS \
+PCRE2_OTHER_FUNCTIONS
+
+#define PCRE2_LOCAL_WIDTH 8
+PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+#undef PCRE2_LOCAL_WIDTH
+
+#define PCRE2_LOCAL_WIDTH 16
+PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+#undef PCRE2_LOCAL_WIDTH
+
+#define PCRE2_LOCAL_WIDTH 32
+PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+#undef PCRE2_LOCAL_WIDTH
+
+/* Undefine the list macros; they are no longer needed. */
+
+#undef PCRE2_TYPES_LIST
+#undef PCRE2_STRUCTURE_LIST
+#undef PCRE2_GENERAL_INFO_FUNCTIONS
+#undef PCRE2_GENERAL_CONTEXT_FUNCTIONS
+#undef PCRE2_COMPILE_CONTEXT_FUNCTIONS
+#undef PCRE2_MATCH_CONTEXT_FUNCTIONS
+#undef PCRE2_COMPILE_FUNCTIONS
+#undef PCRE2_PATTERN_INFO_FUNCTIONS
+#undef PCRE2_MATCH_FUNCTIONS
+#undef PCRE2_SUBSTRING_FUNCTIONS
+#undef PCRE2_SERIALIZE_FUNCTIONS
+#undef PCRE2_SUBSTITUTE_FUNCTION
+#undef PCRE2_JIT_FUNCTIONS
+#undef PCRE2_OTHER_FUNCTIONS
+#undef PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+
+/* PCRE2_CODE_UNIT_WIDTH must be defined. If it is 8, 16, or 32, redefine
+PCRE2_SUFFIX to use it. If it is 0, undefine the other macros and make
+PCRE2_SUFFIX a no-op. Otherwise, generate an error. */
+
+#undef PCRE2_SUFFIX
+#ifndef PCRE2_CODE_UNIT_WIDTH
+#error PCRE2_CODE_UNIT_WIDTH must be defined before including pcre2.h.
+#error Use 8, 16, or 32; or 0 for a multi-width application.
+#else /* PCRE2_CODE_UNIT_WIDTH is defined */
+#if PCRE2_CODE_UNIT_WIDTH == 8 || \
+ PCRE2_CODE_UNIT_WIDTH == 16 || \
+ PCRE2_CODE_UNIT_WIDTH == 32
+#define PCRE2_SUFFIX(a) PCRE2_GLUE(a, PCRE2_CODE_UNIT_WIDTH)
+#elif PCRE2_CODE_UNIT_WIDTH == 0
+#undef PCRE2_JOIN
+#undef PCRE2_GLUE
+#define PCRE2_SUFFIX(a) a
+#else
+#error PCRE2_CODE_UNIT_WIDTH must be 0, 8, 16, or 32.
+#endif
+#endif /* PCRE2_CODE_UNIT_WIDTH is defined */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* End of pcre2.h */
diff --git a/src/3rdparty/pcre2/src/pcre2_auto_possess.c b/src/3rdparty/pcre2/src/pcre2_auto_possess.c
new file mode 100644
index 0000000000..8d0fa896ec
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_auto_possess.c
@@ -0,0 +1,1289 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains functions that scan a compiled pattern and change
+repeats into possessive repeats where possible. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+* Tables for auto-possessification *
+*************************************************/
+
+/* This table is used to check whether auto-possessification is possible
+between adjacent character-type opcodes. The left-hand (repeated) opcode is
+used to select the row, and the right-hand opcode is use to select the column.
+A value of 1 means that auto-possessification is OK. For example, the second
+value in the first row means that \D+\d can be turned into \D++\d.
+
+The Unicode property types (\P and \p) have to be present to fill out the table
+because of what their opcode values are, but the table values should always be
+zero because property types are handled separately in the code. The last four
+columns apply to items that cannot be repeated, so there is no need to have
+rows for them. Note that OP_DIGIT etc. are generated only when PCRE_UCP is
+*not* set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
+
+#define APTROWS (LAST_AUTOTAB_LEFT_OP - FIRST_AUTOTAB_OP + 1)
+#define APTCOLS (LAST_AUTOTAB_RIGHT_OP - FIRST_AUTOTAB_OP + 1)
+
+static const uint8_t autoposstab[APTROWS][APTCOLS] = {
+/* \D \d \S \s \W \w . .+ \C \P \p \R \H \h \V \v \X \Z \z $ $M */
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \D */
+ { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \d */
+ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \S */
+ { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \s */
+ { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \W */
+ { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \w */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* . */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* .+ */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \C */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \P */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \p */
+ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \R */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \H */
+ { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \h */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \V */
+ { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, /* \v */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 } /* \X */
+};
+
+#ifdef SUPPORT_UNICODE
+/* This table is used to check whether auto-possessification is possible
+between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP). The
+left-hand (repeated) opcode is used to select the row, and the right-hand
+opcode is used to select the column. The values are as follows:
+
+ 0 Always return FALSE (never auto-possessify)
+ 1 Character groups are distinct (possessify if both are OP_PROP)
+ 2 Check character categories in the same group (general or particular)
+ 3 TRUE if the two opcodes are not the same (PROP vs NOTPROP)
+
+ 4 Check left general category vs right particular category
+ 5 Check right general category vs left particular category
+
+ 6 Left alphanum vs right general category
+ 7 Left space vs right general category
+ 8 Left word vs right general category
+
+ 9 Right alphanum vs left general category
+ 10 Right space vs left general category
+ 11 Right word vs left general category
+
+ 12 Left alphanum vs right particular category
+ 13 Left space vs right particular category
+ 14 Left word vs right particular category
+
+ 15 Right alphanum vs left particular category
+ 16 Right space vs left particular category
+ 17 Right word vs left particular category
+*/
+
+static const uint8_t propposstab[PT_TABSIZE][PT_TABSIZE] = {
+/* ANY LAMP GC PC SC ALNUM SPACE PXSPACE WORD CLIST UCNC */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_ANY */
+ { 0, 3, 0, 0, 0, 3, 1, 1, 0, 0, 0 }, /* PT_LAMP */
+ { 0, 0, 2, 4, 0, 9, 10, 10, 11, 0, 0 }, /* PT_GC */
+ { 0, 0, 5, 2, 0, 15, 16, 16, 17, 0, 0 }, /* PT_PC */
+ { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, /* PT_SC */
+ { 0, 3, 6, 12, 0, 3, 1, 1, 0, 0, 0 }, /* PT_ALNUM */
+ { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_SPACE */
+ { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_PXSPACE */
+ { 0, 0, 8, 14, 0, 0, 1, 1, 3, 0, 0 }, /* PT_WORD */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_CLIST */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 } /* PT_UCNC */
+};
+
+/* This table is used to check whether auto-possessification is possible
+between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP) when one
+specifies a general category and the other specifies a particular category. The
+row is selected by the general category and the column by the particular
+category. The value is 1 if the particular category is not part of the general
+category. */
+
+static const uint8_t catposstab[7][30] = {
+/* Cc Cf Cn Co Cs Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc Pd Pe Pf Pi Po Ps Sc Sk Sm So Zl Zp Zs */
+ { 0, 0, 0, 0, 0, 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 }, /* C */
+ { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* L */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* M */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* N */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }, /* P */
+ { 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, 1, 1, 1 }, /* S */
+ { 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 } /* Z */
+};
+
+/* This table is used when checking ALNUM, (PX)SPACE, SPACE, and WORD against
+a general or particular category. The properties in each row are those
+that apply to the character set in question. Duplication means that a little
+unnecessary work is done when checking, but this keeps things much simpler
+because they can all use the same code. For more details see the comment where
+this table is used.
+
+Note: SPACE and PXSPACE used to be different because Perl excluded VT from
+"space", but from Perl 5.18 it's included, so both categories are treated the
+same here. */
+
+static const uint8_t posspropstab[3][4] = {
+ { ucp_L, ucp_N, ucp_N, ucp_Nl }, /* ALNUM, 3rd and 4th values redundant */
+ { ucp_Z, ucp_Z, ucp_C, ucp_Cc }, /* SPACE and PXSPACE, 2nd value redundant */
+ { ucp_L, ucp_N, ucp_P, ucp_Po } /* WORD */
+};
+#endif /* SUPPORT_UNICODE */
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+* Check a character and a property *
+*************************************************/
+
+/* This function is called by compare_opcodes() when a property item is
+adjacent to a fixed character.
+
+Arguments:
+ c the character
+ ptype the property type
+ pdata the data for the type
+ negated TRUE if it's a negated property (\P or \p{^)
+
+Returns: TRUE if auto-possessifying is OK
+*/
+
+static BOOL
+check_char_prop(uint32_t c, unsigned int ptype, unsigned int pdata,
+ BOOL negated)
+{
+const uint32_t *p;
+const ucd_record *prop = GET_UCD(c);
+
+switch(ptype)
+ {
+ case PT_LAMP:
+ return (prop->chartype == ucp_Lu ||
+ prop->chartype == ucp_Ll ||
+ prop->chartype == ucp_Lt) == negated;
+
+ case PT_GC:
+ return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated;
+
+ case PT_PC:
+ return (pdata == prop->chartype) == negated;
+
+ case PT_SC:
+ return (pdata == prop->script) == negated;
+
+ /* These are specials */
+
+ case PT_ALNUM:
+ return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included, which
+ means that Perl space and POSIX space are now identical. PCRE was changed
+ at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ switch(c)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ return negated;
+
+ default:
+ return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == negated;
+ }
+ break; /* Control never reaches here */
+
+ case PT_WORD:
+ return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+ c == CHAR_UNDERSCORE) == negated;
+
+ case PT_CLIST:
+ p = PRIV(ucd_caseless_sets) + prop->caseset;
+ for (;;)
+ {
+ if (c < *p) return !negated;
+ if (c == *p++) return negated;
+ }
+ break; /* Control never reaches here */
+ }
+
+return FALSE;
+}
+#endif /* SUPPORT_UNICODE */
+
+
+
+/*************************************************
+* Base opcode of repeated opcodes *
+*************************************************/
+
+/* Returns the base opcode for repeated single character type opcodes. If the
+opcode is not a repeated character type, it returns with the original value.
+
+Arguments: c opcode
+Returns: base opcode for the type
+*/
+
+static PCRE2_UCHAR
+get_repeat_base(PCRE2_UCHAR c)
+{
+return (c > OP_TYPEPOSUPTO)? c :
+ (c >= OP_TYPESTAR)? OP_TYPESTAR :
+ (c >= OP_NOTSTARI)? OP_NOTSTARI :
+ (c >= OP_NOTSTAR)? OP_NOTSTAR :
+ (c >= OP_STARI)? OP_STARI :
+ OP_STAR;
+}
+
+
+/*************************************************
+* Fill the character property list *
+*************************************************/
+
+/* Checks whether the code points to an opcode that can take part in auto-
+possessification, and if so, fills a list with its properties.
+
+Arguments:
+ code points to start of expression
+ utf TRUE if in UTF mode
+ fcc points to the case-flipping table
+ list points to output list
+ list[0] will be filled with the opcode
+ list[1] will be non-zero if this opcode
+ can match an empty character string
+ list[2..7] depends on the opcode
+
+Returns: points to the start of the next opcode if *code is accepted
+ NULL if *code is not accepted
+*/
+
+static PCRE2_SPTR
+get_chr_property_list(PCRE2_SPTR code, BOOL utf, const uint8_t *fcc,
+ uint32_t *list)
+{
+PCRE2_UCHAR c = *code;
+PCRE2_UCHAR base;
+PCRE2_SPTR end;
+uint32_t chr;
+
+#ifdef SUPPORT_UNICODE
+uint32_t *clist_dest;
+const uint32_t *clist_src;
+#else
+(void)utf; /* Suppress "unused parameter" compiler warning */
+#endif
+
+list[0] = c;
+list[1] = FALSE;
+code++;
+
+if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
+ {
+ base = get_repeat_base(c);
+ c -= (base - OP_STAR);
+
+ if (c == OP_UPTO || c == OP_MINUPTO || c == OP_EXACT || c == OP_POSUPTO)
+ code += IMM2_SIZE;
+
+ list[1] = (c != OP_PLUS && c != OP_MINPLUS && c != OP_EXACT &&
+ c != OP_POSPLUS);
+
+ switch(base)
+ {
+ case OP_STAR:
+ list[0] = OP_CHAR;
+ break;
+
+ case OP_STARI:
+ list[0] = OP_CHARI;
+ break;
+
+ case OP_NOTSTAR:
+ list[0] = OP_NOT;
+ break;
+
+ case OP_NOTSTARI:
+ list[0] = OP_NOTI;
+ break;
+
+ case OP_TYPESTAR:
+ list[0] = *code;
+ code++;
+ break;
+ }
+ c = list[0];
+ }
+
+switch(c)
+ {
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ case OP_ANY:
+ case OP_ALLANY:
+ case OP_ANYNL:
+ case OP_NOT_HSPACE:
+ case OP_HSPACE:
+ case OP_NOT_VSPACE:
+ case OP_VSPACE:
+ case OP_EXTUNI:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_DOLL:
+ case OP_DOLLM:
+ return code;
+
+ case OP_CHAR:
+ case OP_NOT:
+ GETCHARINCTEST(chr, code);
+ list[2] = chr;
+ list[3] = NOTACHAR;
+ return code;
+
+ case OP_CHARI:
+ case OP_NOTI:
+ list[0] = (c == OP_CHARI) ? OP_CHAR : OP_NOT;
+ GETCHARINCTEST(chr, code);
+ list[2] = chr;
+
+#ifdef SUPPORT_UNICODE
+ if (chr < 128 || (chr < 256 && !utf))
+ list[3] = fcc[chr];
+ else
+ list[3] = UCD_OTHERCASE(chr);
+#elif defined SUPPORT_WIDE_CHARS
+ list[3] = (chr < 256) ? fcc[chr] : chr;
+#else
+ list[3] = fcc[chr];
+#endif
+
+ /* The othercase might be the same value. */
+
+ if (chr == list[3])
+ list[3] = NOTACHAR;
+ else
+ list[4] = NOTACHAR;
+ return code;
+
+#ifdef SUPPORT_UNICODE
+ case OP_PROP:
+ case OP_NOTPROP:
+ if (code[0] != PT_CLIST)
+ {
+ list[2] = code[0];
+ list[3] = code[1];
+ return code + 2;
+ }
+
+ /* Convert only if we have enough space. */
+
+ clist_src = PRIV(ucd_caseless_sets) + code[1];
+ clist_dest = list + 2;
+ code += 2;
+
+ do {
+ if (clist_dest >= list + 8)
+ {
+ /* Early return if there is not enough space. This should never
+ happen, since all clists are shorter than 5 character now. */
+ list[2] = code[0];
+ list[3] = code[1];
+ return code;
+ }
+ *clist_dest++ = *clist_src;
+ }
+ while(*clist_src++ != NOTACHAR);
+
+ /* All characters are stored. The terminating NOTACHAR is copied from the
+ clist itself. */
+
+ list[0] = (c == OP_PROP) ? OP_CHAR : OP_NOT;
+ return code;
+#endif
+
+ case OP_NCLASS:
+ case OP_CLASS:
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ if (c == OP_XCLASS)
+ end = code + GET(code, 0) - 1;
+ else
+#endif
+ end = code + 32 / sizeof(PCRE2_UCHAR);
+
+ switch(*end)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSQUERY:
+ list[1] = TRUE;
+ end++;
+ break;
+
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRPOSPLUS:
+ end++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ list[1] = (GET2(end, 1) == 0);
+ end += 1 + 2 * IMM2_SIZE;
+ break;
+ }
+ list[2] = (uint32_t)(end - code);
+ return end;
+ }
+return NULL; /* Opcode not accepted */
+}
+
+
+
+/*************************************************
+* Scan further character sets for match *
+*************************************************/
+
+/* Checks whether the base and the current opcode have a common character, in
+which case the base cannot be possessified.
+
+Arguments:
+ code points to the byte code
+ utf TRUE in UTF mode
+ cb compile data block
+ base_list the data list of the base opcode
+ base_end the end of the data list
+ rec_limit points to recursion depth counter
+
+Returns: TRUE if the auto-possessification is possible
+*/
+
+static BOOL
+compare_opcodes(PCRE2_SPTR code, BOOL utf, const compile_block *cb,
+ const uint32_t *base_list, PCRE2_SPTR base_end, int *rec_limit)
+{
+PCRE2_UCHAR c;
+uint32_t list[8];
+const uint32_t *chr_ptr;
+const uint32_t *ochr_ptr;
+const uint32_t *list_ptr;
+PCRE2_SPTR next_code;
+#ifdef SUPPORT_WIDE_CHARS
+PCRE2_SPTR xclass_flags;
+#endif
+const uint8_t *class_bitset;
+const uint8_t *set1, *set2, *set_end;
+uint32_t chr;
+BOOL accepted, invert_bits;
+BOOL entered_a_group = FALSE;
+
+if (--(*rec_limit) <= 0) return FALSE; /* Recursion has gone too deep */
+
+/* Note: the base_list[1] contains whether the current opcode has a greedy
+(represented by a non-zero value) quantifier. This is a different from
+other character type lists, which store here that the character iterator
+matches to an empty string (also represented by a non-zero value). */
+
+for(;;)
+ {
+ /* All operations move the code pointer forward.
+ Therefore infinite recursions are not possible. */
+
+ c = *code;
+
+ /* Skip over callouts */
+
+ if (c == OP_CALLOUT)
+ {
+ code += PRIV(OP_lengths)[c];
+ continue;
+ }
+
+ if (c == OP_CALLOUT_STR)
+ {
+ code += GET(code, 1 + 2*LINK_SIZE);
+ continue;
+ }
+
+ if (c == OP_ALT)
+ {
+ do code += GET(code, 1); while (*code == OP_ALT);
+ c = *code;
+ }
+
+ switch(c)
+ {
+ case OP_END:
+ case OP_KETRPOS:
+ /* TRUE only in greedy case. The non-greedy case could be replaced by
+ an OP_EXACT, but it is probably not worth it. (And note that OP_EXACT
+ uses more memory, which we cannot get at this stage.) */
+
+ return base_list[1] != 0;
+
+ case OP_KET:
+ /* If the bracket is capturing, and referenced by an OP_RECURSE, or
+ it is an atomic sub-pattern (assert, once, etc.) the non-greedy case
+ cannot be converted to a possessive form. */
+
+ if (base_list[1] == 0) return FALSE;
+
+ switch(*(code - GET(code, 1)))
+ {
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+ case OP_ONCE_NC:
+ /* Atomic sub-patterns and assertions can always auto-possessify their
+ last iterator. However, if the group was entered as a result of checking
+ a previous iterator, this is not possible. */
+
+ return !entered_a_group;
+ }
+
+ code += PRIV(OP_lengths)[c];
+ continue;
+
+ case OP_ONCE:
+ case OP_ONCE_NC:
+ case OP_BRA:
+ case OP_CBRA:
+ next_code = code + GET(code, 1);
+ code += PRIV(OP_lengths)[c];
+
+ while (*next_code == OP_ALT)
+ {
+ if (!compare_opcodes(code, utf, cb, base_list, base_end, rec_limit))
+ return FALSE;
+ code = next_code + 1 + LINK_SIZE;
+ next_code += GET(next_code, 1);
+ }
+
+ entered_a_group = TRUE;
+ continue;
+
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+
+ next_code = code + 1;
+ if (*next_code != OP_BRA && *next_code != OP_CBRA
+ && *next_code != OP_ONCE && *next_code != OP_ONCE_NC) return FALSE;
+
+ do next_code += GET(next_code, 1); while (*next_code == OP_ALT);
+
+ /* The bracket content will be checked by the OP_BRA/OP_CBRA case above. */
+
+ next_code += 1 + LINK_SIZE;
+ if (!compare_opcodes(next_code, utf, cb, base_list, base_end, rec_limit))
+ return FALSE;
+
+ code += PRIV(OP_lengths)[c];
+ continue;
+
+ default:
+ break;
+ }
+
+ /* Check for a supported opcode, and load its properties. */
+
+ code = get_chr_property_list(code, utf, cb->fcc, list);
+ if (code == NULL) return FALSE; /* Unsupported */
+
+ /* If either opcode is a small character list, set pointers for comparing
+ characters from that list with another list, or with a property. */
+
+ if (base_list[0] == OP_CHAR)
+ {
+ chr_ptr = base_list + 2;
+ list_ptr = list;
+ }
+ else if (list[0] == OP_CHAR)
+ {
+ chr_ptr = list + 2;
+ list_ptr = base_list;
+ }
+
+ /* Character bitsets can also be compared to certain opcodes. */
+
+ else if (base_list[0] == OP_CLASS || list[0] == OP_CLASS
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ /* In 8 bit, non-UTF mode, OP_CLASS and OP_NCLASS are the same. */
+ || (!utf && (base_list[0] == OP_NCLASS || list[0] == OP_NCLASS))
+#endif
+ )
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (base_list[0] == OP_CLASS || (!utf && base_list[0] == OP_NCLASS))
+#else
+ if (base_list[0] == OP_CLASS)
+#endif
+ {
+ set1 = (uint8_t *)(base_end - base_list[2]);
+ list_ptr = list;
+ }
+ else
+ {
+ set1 = (uint8_t *)(code - list[2]);
+ list_ptr = base_list;
+ }
+
+ invert_bits = FALSE;
+ switch(list_ptr[0])
+ {
+ case OP_CLASS:
+ case OP_NCLASS:
+ set2 = (uint8_t *)
+ ((list_ptr == list ? code : base_end) - list_ptr[2]);
+ break;
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ xclass_flags = (list_ptr == list ? code : base_end) - list_ptr[2] + LINK_SIZE;
+ if ((*xclass_flags & XCL_HASPROP) != 0) return FALSE;
+ if ((*xclass_flags & XCL_MAP) == 0)
+ {
+ /* No bits are set for characters < 256. */
+ if (list[1] == 0) return TRUE;
+ /* Might be an empty repeat. */
+ continue;
+ }
+ set2 = (uint8_t *)(xclass_flags + 1);
+ break;
+#endif
+
+ case OP_NOT_DIGIT:
+ invert_bits = TRUE;
+ /* Fall through */
+ case OP_DIGIT:
+ set2 = (uint8_t *)(cb->cbits + cbit_digit);
+ break;
+
+ case OP_NOT_WHITESPACE:
+ invert_bits = TRUE;
+ /* Fall through */
+ case OP_WHITESPACE:
+ set2 = (uint8_t *)(cb->cbits + cbit_space);
+ break;
+
+ case OP_NOT_WORDCHAR:
+ invert_bits = TRUE;
+ /* Fall through */
+ case OP_WORDCHAR:
+ set2 = (uint8_t *)(cb->cbits + cbit_word);
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ /* Because the bit sets are unaligned bytes, we need to perform byte
+ comparison here. */
+
+ set_end = set1 + 32;
+ if (invert_bits)
+ {
+ do
+ {
+ if ((*set1++ & ~(*set2++)) != 0) return FALSE;
+ }
+ while (set1 < set_end);
+ }
+ else
+ {
+ do
+ {
+ if ((*set1++ & *set2++) != 0) return FALSE;
+ }
+ while (set1 < set_end);
+ }
+
+ if (list[1] == 0) return TRUE;
+ /* Might be an empty repeat. */
+ continue;
+ }
+
+ /* Some property combinations also acceptable. Unicode property opcodes are
+ processed specially; the rest can be handled with a lookup table. */
+
+ else
+ {
+ uint32_t leftop, rightop;
+
+ leftop = base_list[0];
+ rightop = list[0];
+
+#ifdef SUPPORT_UNICODE
+ accepted = FALSE; /* Always set in non-unicode case. */
+ if (leftop == OP_PROP || leftop == OP_NOTPROP)
+ {
+ if (rightop == OP_EOD)
+ accepted = TRUE;
+ else if (rightop == OP_PROP || rightop == OP_NOTPROP)
+ {
+ int n;
+ const uint8_t *p;
+ BOOL same = leftop == rightop;
+ BOOL lisprop = leftop == OP_PROP;
+ BOOL risprop = rightop == OP_PROP;
+ BOOL bothprop = lisprop && risprop;
+
+ /* There's a table that specifies how each combination is to be
+ processed:
+ 0 Always return FALSE (never auto-possessify)
+ 1 Character groups are distinct (possessify if both are OP_PROP)
+ 2 Check character categories in the same group (general or particular)
+ 3 Return TRUE if the two opcodes are not the same
+ ... see comments below
+ */
+
+ n = propposstab[base_list[2]][list[2]];
+ switch(n)
+ {
+ case 0: break;
+ case 1: accepted = bothprop; break;
+ case 2: accepted = (base_list[3] == list[3]) != same; break;
+ case 3: accepted = !same; break;
+
+ case 4: /* Left general category, right particular category */
+ accepted = risprop && catposstab[base_list[3]][list[3]] == same;
+ break;
+
+ case 5: /* Right general category, left particular category */
+ accepted = lisprop && catposstab[list[3]][base_list[3]] == same;
+ break;
+
+ /* This code is logically tricky. Think hard before fiddling with it.
+ The posspropstab table has four entries per row. Each row relates to
+ one of PCRE's special properties such as ALNUM or SPACE or WORD.
+ Only WORD actually needs all four entries, but using repeats for the
+ others means they can all use the same code below.
+
+ The first two entries in each row are Unicode general categories, and
+ apply always, because all the characters they include are part of the
+ PCRE character set. The third and fourth entries are a general and a
+ particular category, respectively, that include one or more relevant
+ characters. One or the other is used, depending on whether the check
+ is for a general or a particular category. However, in both cases the
+ category contains more characters than the specials that are defined
+ for the property being tested against. Therefore, it cannot be used
+ in a NOTPROP case.
+
+ Example: the row for WORD contains ucp_L, ucp_N, ucp_P, ucp_Po.
+ Underscore is covered by ucp_P or ucp_Po. */
+
+ case 6: /* Left alphanum vs right general category */
+ case 7: /* Left space vs right general category */
+ case 8: /* Left word vs right general category */
+ p = posspropstab[n-6];
+ accepted = risprop && lisprop ==
+ (list[3] != p[0] &&
+ list[3] != p[1] &&
+ (list[3] != p[2] || !lisprop));
+ break;
+
+ case 9: /* Right alphanum vs left general category */
+ case 10: /* Right space vs left general category */
+ case 11: /* Right word vs left general category */
+ p = posspropstab[n-9];
+ accepted = lisprop && risprop ==
+ (base_list[3] != p[0] &&
+ base_list[3] != p[1] &&
+ (base_list[3] != p[2] || !risprop));
+ break;
+
+ case 12: /* Left alphanum vs right particular category */
+ case 13: /* Left space vs right particular category */
+ case 14: /* Left word vs right particular category */
+ p = posspropstab[n-12];
+ accepted = risprop && lisprop ==
+ (catposstab[p[0]][list[3]] &&
+ catposstab[p[1]][list[3]] &&
+ (list[3] != p[3] || !lisprop));
+ break;
+
+ case 15: /* Right alphanum vs left particular category */
+ case 16: /* Right space vs left particular category */
+ case 17: /* Right word vs left particular category */
+ p = posspropstab[n-15];
+ accepted = lisprop && risprop ==
+ (catposstab[p[0]][base_list[3]] &&
+ catposstab[p[1]][base_list[3]] &&
+ (base_list[3] != p[3] || !risprop));
+ break;
+ }
+ }
+ }
+
+ else
+#endif /* SUPPORT_UNICODE */
+
+ accepted = leftop >= FIRST_AUTOTAB_OP && leftop <= LAST_AUTOTAB_LEFT_OP &&
+ rightop >= FIRST_AUTOTAB_OP && rightop <= LAST_AUTOTAB_RIGHT_OP &&
+ autoposstab[leftop - FIRST_AUTOTAB_OP][rightop - FIRST_AUTOTAB_OP];
+
+ if (!accepted) return FALSE;
+
+ if (list[1] == 0) return TRUE;
+ /* Might be an empty repeat. */
+ continue;
+ }
+
+ /* Control reaches here only if one of the items is a small character list.
+ All characters are checked against the other side. */
+
+ do
+ {
+ chr = *chr_ptr;
+
+ switch(list_ptr[0])
+ {
+ case OP_CHAR:
+ ochr_ptr = list_ptr + 2;
+ do
+ {
+ if (chr == *ochr_ptr) return FALSE;
+ ochr_ptr++;
+ }
+ while(*ochr_ptr != NOTACHAR);
+ break;
+
+ case OP_NOT:
+ ochr_ptr = list_ptr + 2;
+ do
+ {
+ if (chr == *ochr_ptr)
+ break;
+ ochr_ptr++;
+ }
+ while(*ochr_ptr != NOTACHAR);
+ if (*ochr_ptr == NOTACHAR) return FALSE; /* Not found */
+ break;
+
+ /* Note that OP_DIGIT etc. are generated only when PCRE2_UCP is *not*
+ set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
+
+ case OP_DIGIT:
+ if (chr < 256 && (cb->ctypes[chr] & ctype_digit) != 0) return FALSE;
+ break;
+
+ case OP_NOT_DIGIT:
+ if (chr > 255 || (cb->ctypes[chr] & ctype_digit) == 0) return FALSE;
+ break;
+
+ case OP_WHITESPACE:
+ if (chr < 256 && (cb->ctypes[chr] & ctype_space) != 0) return FALSE;
+ break;
+
+ case OP_NOT_WHITESPACE:
+ if (chr > 255 || (cb->ctypes[chr] & ctype_space) == 0) return FALSE;
+ break;
+
+ case OP_WORDCHAR:
+ if (chr < 255 && (cb->ctypes[chr] & ctype_word) != 0) return FALSE;
+ break;
+
+ case OP_NOT_WORDCHAR:
+ if (chr > 255 || (cb->ctypes[chr] & ctype_word) == 0) return FALSE;
+ break;
+
+ case OP_HSPACE:
+ switch(chr)
+ {
+ HSPACE_CASES: return FALSE;
+ default: break;
+ }
+ break;
+
+ case OP_NOT_HSPACE:
+ switch(chr)
+ {
+ HSPACE_CASES: break;
+ default: return FALSE;
+ }
+ break;
+
+ case OP_ANYNL:
+ case OP_VSPACE:
+ switch(chr)
+ {
+ VSPACE_CASES: return FALSE;
+ default: break;
+ }
+ break;
+
+ case OP_NOT_VSPACE:
+ switch(chr)
+ {
+ VSPACE_CASES: break;
+ default: return FALSE;
+ }
+ break;
+
+ case OP_DOLL:
+ case OP_EODN:
+ switch (chr)
+ {
+ case CHAR_CR:
+ case CHAR_LF:
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#ifndef EBCDIC
+ case 0x2028:
+ case 0x2029:
+#endif /* Not EBCDIC */
+ return FALSE;
+ }
+ break;
+
+ case OP_EOD: /* Can always possessify before \z */
+ break;
+
+#ifdef SUPPORT_UNICODE
+ case OP_PROP:
+ case OP_NOTPROP:
+ if (!check_char_prop(chr, list_ptr[2], list_ptr[3],
+ list_ptr[0] == OP_NOTPROP))
+ return FALSE;
+ break;
+#endif
+
+ case OP_NCLASS:
+ if (chr > 255) return FALSE;
+ /* Fall through */
+
+ case OP_CLASS:
+ if (chr > 255) break;
+ class_bitset = (uint8_t *)
+ ((list_ptr == list ? code : base_end) - list_ptr[2]);
+ if ((class_bitset[chr >> 3] & (1 << (chr & 7))) != 0) return FALSE;
+ break;
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ if (PRIV(xclass)(chr, (list_ptr == list ? code : base_end) -
+ list_ptr[2] + LINK_SIZE, utf)) return FALSE;
+ break;
+#endif
+
+ default:
+ return FALSE;
+ }
+
+ chr_ptr++;
+ }
+ while(*chr_ptr != NOTACHAR);
+
+ /* At least one character must be matched from this opcode. */
+
+ if (list[1] == 0) return TRUE;
+ }
+
+/* Control never reaches here. There used to be a fail-save return FALSE; here,
+but some compilers complain about an unreachable statement. */
+}
+
+
+
+/*************************************************
+* Scan compiled regex for auto-possession *
+*************************************************/
+
+/* Replaces single character iterations with their possessive alternatives
+if appropriate. This function modifies the compiled opcode! Hitting a
+non-existant opcode may indicate a bug in PCRE2, but it can also be caused if a
+bad UTF string was compiled with PCRE2_NO_UTF_CHECK.
+
+Arguments:
+ code points to start of the byte code
+ utf TRUE in UTF mode
+ cb compile data block
+
+Returns: 0 for success
+ -1 if a non-existant opcode is encountered
+*/
+
+int
+PRIV(auto_possessify)(PCRE2_UCHAR *code, BOOL utf, const compile_block *cb)
+{
+register PCRE2_UCHAR c;
+PCRE2_SPTR end;
+PCRE2_UCHAR *repeat_opcode;
+uint32_t list[8];
+int rec_limit;
+
+for (;;)
+ {
+ c = *code;
+
+ if (c > OP_TABLE_LENGTH) return -1; /* Something gone wrong */
+
+ if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
+ {
+ c -= get_repeat_base(c) - OP_STAR;
+ end = (c <= OP_MINUPTO) ?
+ get_chr_property_list(code, utf, cb->fcc, list) : NULL;
+ list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO;
+
+ rec_limit = 1000;
+ if (end != NULL && compare_opcodes(end, utf, cb, list, end, &rec_limit))
+ {
+ switch(c)
+ {
+ case OP_STAR:
+ *code += OP_POSSTAR - OP_STAR;
+ break;
+
+ case OP_MINSTAR:
+ *code += OP_POSSTAR - OP_MINSTAR;
+ break;
+
+ case OP_PLUS:
+ *code += OP_POSPLUS - OP_PLUS;
+ break;
+
+ case OP_MINPLUS:
+ *code += OP_POSPLUS - OP_MINPLUS;
+ break;
+
+ case OP_QUERY:
+ *code += OP_POSQUERY - OP_QUERY;
+ break;
+
+ case OP_MINQUERY:
+ *code += OP_POSQUERY - OP_MINQUERY;
+ break;
+
+ case OP_UPTO:
+ *code += OP_POSUPTO - OP_UPTO;
+ break;
+
+ case OP_MINUPTO:
+ *code += OP_POSUPTO - OP_MINUPTO;
+ break;
+ }
+ }
+ c = *code;
+ }
+ else if (c == OP_CLASS || c == OP_NCLASS || c == OP_XCLASS)
+ {
+#ifdef SUPPORT_WIDE_CHARS
+ if (c == OP_XCLASS)
+ repeat_opcode = code + GET(code, 1);
+ else
+#endif
+ repeat_opcode = code + 1 + (32 / sizeof(PCRE2_UCHAR));
+
+ c = *repeat_opcode;
+ if (c >= OP_CRSTAR && c <= OP_CRMINRANGE)
+ {
+ /* end must not be NULL. */
+ end = get_chr_property_list(code, utf, cb->fcc, list);
+
+ list[1] = (c & 1) == 0;
+
+ rec_limit = 1000;
+ if (compare_opcodes(end, utf, cb, list, end, &rec_limit))
+ {
+ switch (c)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ *repeat_opcode = OP_CRPOSSTAR;
+ break;
+
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ *repeat_opcode = OP_CRPOSPLUS;
+ break;
+
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ *repeat_opcode = OP_CRPOSQUERY;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ *repeat_opcode = OP_CRPOSRANGE;
+ break;
+ }
+ }
+ }
+ c = *code;
+ }
+
+ switch(c)
+ {
+ case OP_END:
+ return 0;
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+ break;
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSUPTO:
+ if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+ code += 2;
+ break;
+
+ case OP_CALLOUT_STR:
+ code += GET(code, 1 + 2*LINK_SIZE);
+ break;
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ code += GET(code, 1);
+ break;
+#endif
+
+ case OP_MARK:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ code += code[1];
+ break;
+ }
+
+ /* Add in the fixed length from the table */
+
+ code += PRIV(OP_lengths)[c];
+
+ /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may be
+ followed by a multi-byte character. The length in the table is a minimum, so
+ we have to arrange to skip the extra code units. */
+
+#ifdef MAYBE_UTF_MULTI
+ if (utf) switch(c)
+ {
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_EXACT:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+ case OP_POSQUERY:
+ case OP_POSUPTO:
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_EXACTI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+ case OP_POSQUERYI:
+ case OP_POSUPTOI:
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTEXACT:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSUPTO:
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTEXACTI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSUPTOI:
+ if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+ break;
+ }
+#else
+ (void)(utf); /* Keep compiler happy by referencing function argument */
+#endif /* SUPPORT_WIDE_CHARS */
+ }
+}
+
+/* End of pcre2_auto_possess.c */
diff --git a/src/3rdparty/pcre/pcre_chartables.c b/src/3rdparty/pcre2/src/pcre2_chartables.c
index 1e20ec29d0..203cb1a4ab 100644
--- a/src/3rdparty/pcre/pcre_chartables.c
+++ b/src/3rdparty/pcre2/src/pcre2_chartables.c
@@ -3,19 +3,19 @@
*************************************************/
/* This file contains character tables that are used when no external tables
-are passed to PCRE by the application that calls it. The tables are used only
+are passed to PCRE2 by the application that calls it. The tables are used only
for characters whose code values are less than 256.
This is a default version of the tables that assumes ASCII encoding. A program
-called dftables (which is distributed with PCRE) can be used to build
+called dftables (which is distributed with PCRE2) can be used to build
alternative versions of this file. This is necessary if you are running in an
EBCDIC environment, or if you want to default to a different encoding, for
example ISO-8859-1. When dftables is run, it creates these tables in the
-current locale. If PCRE is configured with --enable-rebuild-chartables, this
+current locale. If PCRE2 is configured with --enable-rebuild-chartables, this
happens automatically.
The following #includes are present because without them gcc 4.x may remove the
-array definition from the final binary if PCRE is built into a static library
+array definition from the final binary if PCRE2 is built into a static library
and dead code stripping is activated. This leads to link errors. Pulling in the
header ensures that the array gets flagged as "someone outside this compilation
unit might reference this" and so it will always be supplied to the linker. */
@@ -24,9 +24,9 @@ unit might reference this" and so it will always be supplied to the linker. */
#include "config.h"
#endif
-#include "pcre_internal.h"
+#include "pcre2_internal.h"
-const pcre_uint8 PRIV(default_tables)[] = {
+const uint8_t PRIV(default_tables)[] = {
/* This table is a lower casing table. */
@@ -195,4 +195,4 @@ graph, print, punct, and cntrl. Other classes are built from combinations. */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
-/* End of pcre_chartables.c */
+/* End of pcre2_chartables.c */
diff --git a/src/3rdparty/pcre/pcre_compile.c b/src/3rdparty/pcre2/src/pcre2_compile.c
index 7cd3950123..bb9736cd51 100644
--- a/src/3rdparty/pcre/pcre_compile.c
+++ b/src/3rdparty/pcre2/src/pcre2_compile.c
@@ -6,7 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2016 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -38,55 +39,56 @@ POSSIBILITY OF SUCH DAMAGE.
*/
-/* This module contains the external function pcre_compile(), along with
-supporting internal functions that are not used by other modules. */
-
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#define NLBLOCK cd /* Block containing newline information */
-#define PSSTART start_pattern /* Field containing pattern start */
-#define PSEND end_pattern /* Field containing pattern end */
-
-#include "pcre_internal.h"
+#define NLBLOCK cb /* Block containing newline information */
+#define PSSTART start_pattern /* Field containing processed string start */
+#define PSEND end_pattern /* Field containing processed string end */
+#include "pcre2_internal.h"
-/* When PCRE_DEBUG is defined, we need the pcre(16|32)_printint() function, which
-is also used by pcretest. PCRE_DEBUG is not defined when building a production
-library. We do not need to select pcre16_printint.c specially, because the
-COMPILE_PCREx macro will already be appropriately set. */
+/* In rare error cases debugging might require calling pcre2_printint(). */
-#ifdef PCRE_DEBUG
-/* pcre_printint.c should not include any headers */
-#define PCRE_INCLUDED
-#include "pcre_printint.c"
-#undef PCRE_INCLUDED
+#if 0
+#ifdef EBCDIC
+#define PRINTABLE(c) ((c) >= 64 && (c) < 255)
+#else
+#define PRINTABLE(c) ((c) >= 32 && (c) < 127)
+#endif
+#include "pcre2_printint.c"
+#define CALL_PRINTINT
#endif
+/* There are a few things that vary with different code unit sizes. Handle them
+by defining macros in order to minimize #if usage. */
-/* Macro for setting individual bits in class bitmaps. */
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define STRING_UTFn_RIGHTPAR STRING_UTF8_RIGHTPAR, 5
+#define XDIGIT(c) xdigitab[c]
-#define SETBIT(a,b) a[(b)/8] |= (1 << ((b)&7))
+#else /* Either 16-bit or 32-bit */
+#define XDIGIT(c) (MAX_255(c)? xdigitab[c] : 0xff)
-/* Maximum length value to check against when making sure that the integer that
-holds the compiled pattern length does not overflow. We make it a bit less than
-INT_MAX to allow for adding in group terminating bytes, so that we don't have
-to check them every time. */
+#if PCRE2_CODE_UNIT_WIDTH == 16
+#define STRING_UTFn_RIGHTPAR STRING_UTF16_RIGHTPAR, 6
-#define OFLOW_MAX (INT_MAX - 20)
+#else /* 32-bit */
+#define STRING_UTFn_RIGHTPAR STRING_UTF32_RIGHTPAR, 6
+#endif
+#endif
-/* Definitions to allow mutual recursion */
+/* Function definitions to allow mutual recursion */
-static int
- add_list_to_class(pcre_uint8 *, pcre_uchar **, int, compile_data *,
- const pcre_uint32 *, unsigned int);
+static unsigned int
+ add_list_to_class(uint8_t *, PCRE2_UCHAR **, uint32_t, compile_block *,
+ const uint32_t *, unsigned int);
static BOOL
- compile_regex(int, pcre_uchar **, const pcre_uchar **, int *, BOOL, BOOL, int, int,
- pcre_uint32 *, pcre_int32 *, pcre_uint32 *, pcre_int32 *, branch_chain *,
- compile_data *, int *);
+ compile_regex(uint32_t, PCRE2_UCHAR **, PCRE2_SPTR *, int *, BOOL, BOOL,
+ uint32_t, int, uint32_t *, int32_t *, uint32_t *, int32_t *,
+ branch_chain *, compile_block *, size_t *);
@@ -94,60 +96,197 @@ static BOOL
* Code parameters and static tables *
*************************************************/
-/* This value specifies the size of stack workspace that is used during the
-first pre-compile phase that determines how much memory is required. The regex
-is partly compiled into this space, but the compiled parts are discarded as
-soon as they can be, so that hopefully there will never be an overrun. The code
-does, however, check for an overrun. The largest amount I've seen used is 218,
-so this number is very generous.
-
-The same workspace is used during the second, actual compile phase for
-remembering forward references to groups so that they can be filled in at the
-end. Each entry in this list occupies LINK_SIZE bytes, so even when LINK_SIZE
-is 4 there is plenty of room for most patterns. However, the memory can get
-filled up by repetitions of forward references, for example patterns like
-/(?1){0,1999}(b)/, and one user did hit the limit. The code has been changed so
-that the workspace is expanded using malloc() in this situation. The value
-below is therefore a minimum, and we put a maximum on it for safety. The
-minimum is now also defined in terms of LINK_SIZE so that the use of malloc()
-kicks in at the same number of forward references in all cases. */
-
-#define COMPILE_WORK_SIZE (2048*LINK_SIZE)
-#define COMPILE_WORK_SIZE_MAX (100*COMPILE_WORK_SIZE)
+/* This value specifies the size of stack workspace, which is used in different
+ways in the different pattern scans. The group-identifying pre-scan uses it to
+handle nesting, and needs it to be 16-bit aligned.
-/* This value determines the size of the initial vector that is used for
-remembering named groups during the pre-compile. It is allocated on the stack,
-but if it is too small, it is expanded using malloc(), in a similar way to the
-workspace. The value is the number of slots in the list. */
+During the first compiling phase, when determining how much memory is required,
+the regex is partly compiled into this space, but the compiled parts are
+discarded as soon as they can be, so that hopefully there will never be an
+overrun. The code does, however, check for an overrun, which can occur for
+pathological patterns. The size of the workspace depends on LINK_SIZE because
+the length of compiled items varies with this.
-#define NAMED_GROUP_LIST_SIZE 20
+In the real compile phase, the workspace is used for remembering data about
+numbered groups, provided there are not too many of them (if there are, extra
+memory is acquired). For this phase the memory must be 32-bit aligned. Having
+defined the size in code units, we set up C32_WORK_SIZE as the number of
+elements in the 32-bit vector. */
+
+#define COMPILE_WORK_SIZE (2048*LINK_SIZE) /* Size in code units */
+
+#define C32_WORK_SIZE \
+ ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint32_t))
/* The overrun tests check for a slightly smaller size so that they detect the
overrun before it actually does run off the end of the data block. */
#define WORK_SIZE_SAFETY_MARGIN (100)
-/* Private flags added to firstchar and reqchar. */
+/* This value determines the size of the initial vector that is used for
+remembering named groups during the pre-compile. It is allocated on the stack,
+but if it is too small, it is expanded, in a similar way to the workspace. The
+value is the number of slots in the list. */
+
+#define NAMED_GROUP_LIST_SIZE 20
+
+/* The original PCRE required patterns to be zero-terminated, and it simplifies
+the compiling code if it is guaranteed that there is a zero code unit at the
+end of the pattern, because this means that tests for coding sequences such as
+(*SKIP) or even just (?<= can check a sequence of code units without having to
+keep checking for the end of the pattern. The new PCRE2 API allows zero code
+units within patterns if a positive length is given, but in order to keep most
+of the compiling code as it was, we copy such patterns and add a zero on the
+end. This value determines the size of space on the stack that is used if the
+pattern fits; if not, heap memory is used. */
+
+#define COPIED_PATTERN_SIZE 1024
+
+/* Maximum length value to check against when making sure that the variable
+that holds the compiled pattern length does not overflow. We make it a bit less
+than INT_MAX to allow for adding in group terminating bytes, so that we don't
+have to check them every time. */
+
+#define OFLOW_MAX (INT_MAX - 20)
+
+/* Macro for setting individual bits in class bitmaps. It took some
+experimenting to figure out how to stop gcc 5.3.0 from warning with
+-Wconversion. This version gets a warning:
+
+ #define SETBIT(a,b) a[(b)/8] |= (uint8_t)(1 << ((b)&7))
+
+Let's hope the apparently less efficient version isn't actually so bad if the
+compiler is clever with identical subexpressions. */
+
+#define SETBIT(a,b) a[(b)/8] = (uint8_t)(a[(b)/8] | (1 << ((b)&7)))
+
+/* Private flags added to firstcu and reqcu. */
#define REQ_CASELESS (1 << 0) /* Indicates caselessness */
-#define REQ_VARY (1 << 1) /* Reqchar followed non-literal item */
-/* Negative values for the firstchar and reqchar flags */
-#define REQ_UNSET (-2)
-#define REQ_NONE (-1)
+#define REQ_VARY (1 << 1) /* reqcu followed non-literal item */
+/* Negative values for the firstcu and reqcu flags */
+#define REQ_UNSET (-2) /* Not yet found anything */
+#define REQ_NONE (-1) /* Found not fixed char */
+
+/* These flags are used in the groupinfo vector. */
+
+#define GI_SET_COULD_BE_EMPTY 0x80000000u
+#define GI_COULD_BE_EMPTY 0x40000000u
+#define GI_NOT_FIXED_LENGTH 0x20000000u
+#define GI_SET_FIXED_LENGTH 0x10000000u
+#define GI_FIXED_LENGTH_MASK 0x0000ffffu
-/* Repeated character flags. */
+/* This bit (which is greater than any UTF value) is used to indicate that a
+variable contains a number of code units instead of an actual code point. */
-#define UTF_LENGTH 0x10000000l /* The char contains its length. */
+#define UTF_LENGTH 0x10000000l
-/* Table for handling escaped characters in the range '0'-'z'. Positive returns
-are simple data values; negative values are for special things like \d and so
-on. Zero means further processing is needed (for things like \x), or the escape
-is invalid. */
+/* This simple test for a decimal digit works for both ASCII/Unicode and EBCDIC
+and is fast (a good compiler can turn it into a subtraction and unsigned
+comparison). */
+
+#define IS_DIGIT(x) ((x) >= CHAR_0 && (x) <= CHAR_9)
+
+/* Table to identify hex digits. The tables in chartables are dependent on the
+locale, and may mark arbitrary characters as digits. We want to recognize only
+0-9, a-z, and A-Z as hex digits, which is why we have a private table here. It
+costs 256 bytes, but it is a lot faster than doing character value tests (at
+least in some simple cases I timed), and in some applications one wants PCRE to
+compile efficiently as well as match efficiently. The value in the table is
+the binary hex digit value, or 0xff for non-hex digits. */
+
+/* This is the "normal" case, for ASCII systems, and EBCDIC systems running in
+UTF-8 mode. */
#ifndef EBCDIC
+static const uint8_t xdigitab[] =
+ {
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - ' */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ( - / */
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 */
+ 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff, /* 8 - ? */
+ 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* @ - G */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H - O */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* P - W */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* X - _ */
+ 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* ` - g */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h - o */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* p - w */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* x -127 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 128-135 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 136-143 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144-151 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 152-159 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160-167 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 168-175 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 176-183 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 192-199 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 2ff-207 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 208-215 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 216-223 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 224-231 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 232-239 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 240-247 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};/* 248-255 */
+
+#else
+
+/* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */
+
+static const uint8_t xdigitab[] =
+ {
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 10 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 32- 39 20 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 40- 47 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 48- 55 30 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 56- 63 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - 71 40 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 72- | */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* & - 87 50 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 88- 95 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - -103 60 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 104- ? */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 112-119 70 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 120- " */
+ 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* 128- g 80 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h -143 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144- p 90 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* q -159 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160- x A0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* y -175 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ^ -183 B0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */
+ 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* { - G C0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H -207 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* } - P D0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Q -223 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* \ - X E0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Y -239 */
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 F0 */
+ 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff};/* 8 -255 */
+#endif /* EBCDIC */
+
+
+/* Table for handling alphanumeric escaped characters. Positive returns are
+simple data values; negative values are for special things like \d and so on.
+Zero means further processing is needed (for things like \x), or the escape is
+invalid. */
/* This is the "normal" table for ASCII systems or for EBCDIC systems running
-in UTF-8 mode. */
+in UTF-8 mode. It runs from '0' to 'z'. */
+
+#ifndef EBCDIC
+#define ESCAPES_FIRST CHAR_0
+#define ESCAPES_LAST CHAR_z
+#define UPPER_CASE(c) (c-32)
static const short int escapes[] = {
0, 0,
@@ -192,17 +331,23 @@ static const short int escapes[] = {
#else
-/* This is the "abnormal" table for EBCDIC systems without UTF-8 support. */
+/* This is the "abnormal" table for EBCDIC systems without UTF-8 support.
+It runs from 'a' to '9'. For some minimal testing of EBCDIC features, the code
+is sometimes compiled on an ASCII system. In this case, we must not use CHAR_a
+because it is defined as 'a', which of course picks up the ASCII value. */
+
+#if 'a' == 0x81 /* Check for a real EBCDIC environment */
+#define ESCAPES_FIRST CHAR_a
+#define ESCAPES_LAST CHAR_9
+#define UPPER_CASE(c) (c+64)
+#else /* Testing in an ASCII environment */
+#define ESCAPES_FIRST ((unsigned char)'\x81') /* EBCDIC 'a' */
+#define ESCAPES_LAST ((unsigned char)'\xf9') /* EBCDIC '9' */
+#define UPPER_CASE(c) (c-32)
+#endif
static const short int escapes[] = {
-/* 48 */ 0, 0, 0, '.', '<', '(', '+', '|',
-/* 50 */ '&', 0, 0, 0, 0, 0, 0, 0,
-/* 58 */ 0, 0, '!', '$', '*', ')', ';', '~',
-/* 60 */ '-', '/', 0, 0, 0, 0, 0, 0,
-/* 68 */ 0, 0, '|', ',', '%', '_', '>', '?',
-/* 70 */ 0, 0, 0, 0, 0, 0, 0, 0,
-/* 78 */ 0, '`', ':', '#', '@', '\'', '=', '"',
-/* 80 */ 0, ESC_a, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0,
+/* 80 */ ESC_a, -ESC_b, 0, -ESC_d, ESC_e, ESC_f, 0,
/* 88 */-ESC_h, 0, 0, '{', 0, 0, 0, 0,
/* 90 */ 0, 0, -ESC_k, 0, 0, ESC_n, 0, -ESC_p,
/* 98 */ 0, ESC_r, 0, '}', 0, 0, 0, 0,
@@ -217,7 +362,7 @@ static const short int escapes[] = {
/* E0 */ '\\', 0, -ESC_S, 0, 0,-ESC_V, -ESC_W, -ESC_X,
/* E8 */ 0,-ESC_Z, 0, 0, 0, 0, 0, 0,
/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0,
-/* F8 */ 0, 0, 0, 0, 0, 0, 0, 0
+/* F8 */ 0, 0
};
/* We also need a table of characters that may follow \c in an EBCDIC
@@ -225,7 +370,7 @@ environment for characters 0-31. */
static unsigned char ebcdic_escape_c[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
-#endif
+#endif /* EBCDIC */
/* Table of special "verbs" like (*PRUNE). This is a short table, so it is
@@ -269,11 +414,11 @@ static const int verbcount = sizeof(verbs)/sizeof(verbitem);
/* Substitutes for [[:<:]] and [[:>:]], which mean start and end of word in
another regex library. */
-static const pcre_uchar sub_start_of_word[] = {
+static const PCRE2_UCHAR sub_start_of_word[] = {
CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK,
CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w, CHAR_RIGHT_PARENTHESIS, '\0' };
-static const pcre_uchar sub_end_of_word[] = {
+static const PCRE2_UCHAR sub_end_of_word[] = {
CHAR_BACKSLASH, CHAR_b, CHAR_LEFT_PARENTHESIS, CHAR_QUESTION_MARK,
CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN, CHAR_BACKSLASH, CHAR_w,
CHAR_RIGHT_PARENTHESIS, '\0' };
@@ -292,7 +437,7 @@ static const char posix_names[] =
STRING_graph0 STRING_print0 STRING_punct0 STRING_space0
STRING_word0 STRING_xdigit;
-static const pcre_uint8 posix_name_lengths[] = {
+static const uint8_t posix_name_lengths[] = {
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };
#define PC_GRAPH 8
@@ -327,30 +472,30 @@ static const int posix_class_maps[] = {
cbit_xdigit,-1, 0 /* xdigit */
};
-/* Table of substitutes for \d etc when PCRE_UCP is set. They are replaced by
+/* Table of substitutes for \d etc when PCRE2_UCP is set. They are replaced by
Unicode property escapes. */
-#ifdef SUPPORT_UCP
-static const pcre_uchar string_PNd[] = {
+#ifdef SUPPORT_UNICODE
+static const PCRE2_UCHAR string_PNd[] = {
CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_pNd[] = {
+static const PCRE2_UCHAR string_pNd[] = {
CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
CHAR_N, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_PXsp[] = {
+static const PCRE2_UCHAR string_PXsp[] = {
CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_pXsp[] = {
+static const PCRE2_UCHAR string_pXsp[] = {
CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
CHAR_X, CHAR_s, CHAR_p, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_PXwd[] = {
+static const PCRE2_UCHAR string_PXwd[] = {
CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_pXwd[] = {
+static const PCRE2_UCHAR string_pXwd[] = {
CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
CHAR_X, CHAR_w, CHAR_d, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar *substitutes[] = {
+static PCRE2_SPTR substitutes[] = {
string_PNd, /* \D */
string_pNd, /* \d */
string_PXsp, /* \S */ /* Xsp is Perl space, but from 8.34, Perl */
@@ -365,49 +510,55 @@ general substitute of a Unicode property escape (\p or \P). However, for some
POSIX classes (e.g. graph, print, punct) a special property code is compiled
directly. */
-static const pcre_uchar string_pL[] = {
+static const PCRE2_UCHAR string_pCc[] = {
+ CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
+ CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' };
+static const PCRE2_UCHAR string_pL[] = {
CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_pLl[] = {
+static const PCRE2_UCHAR string_pLl[] = {
CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_pLu[] = {
+static const PCRE2_UCHAR string_pLu[] = {
CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_pXan[] = {
+static const PCRE2_UCHAR string_pXan[] = {
CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_h[] = {
+static const PCRE2_UCHAR string_h[] = {
CHAR_BACKSLASH, CHAR_h, '\0' };
-static const pcre_uchar string_pXps[] = {
+static const PCRE2_UCHAR string_pXps[] = {
CHAR_BACKSLASH, CHAR_p, CHAR_LEFT_CURLY_BRACKET,
CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_PL[] = {
+static const PCRE2_UCHAR string_PCc[] = {
+ CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
+ CHAR_C, CHAR_c, CHAR_RIGHT_CURLY_BRACKET, '\0' };
+static const PCRE2_UCHAR string_PL[] = {
CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
CHAR_L, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_PLl[] = {
+static const PCRE2_UCHAR string_PLl[] = {
CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
CHAR_L, CHAR_l, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_PLu[] = {
+static const PCRE2_UCHAR string_PLu[] = {
CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
CHAR_L, CHAR_u, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_PXan[] = {
+static const PCRE2_UCHAR string_PXan[] = {
CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
CHAR_X, CHAR_a, CHAR_n, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar string_H[] = {
+static const PCRE2_UCHAR string_H[] = {
CHAR_BACKSLASH, CHAR_H, '\0' };
-static const pcre_uchar string_PXps[] = {
+static const PCRE2_UCHAR string_PXps[] = {
CHAR_BACKSLASH, CHAR_P, CHAR_LEFT_CURLY_BRACKET,
CHAR_X, CHAR_p, CHAR_s, CHAR_RIGHT_CURLY_BRACKET, '\0' };
-static const pcre_uchar *posix_substitutes[] = {
+static PCRE2_SPTR posix_substitutes[] = {
string_pL, /* alpha */
string_pLl, /* lower */
string_pLu, /* upper */
string_pXan, /* alnum */
NULL, /* ascii */
string_h, /* blank */
- NULL, /* cntrl */
+ string_pCc, /* cntrl */
string_pNd, /* digit */
NULL, /* graph */
NULL, /* print */
@@ -422,7 +573,7 @@ static const pcre_uchar *posix_substitutes[] = {
string_PXan, /* ^alnum */
NULL, /* ^ascii */
string_H, /* ^blank */
- NULL, /* ^cntrl */
+ string_PCc, /* ^cntrl */
string_PNd, /* ^digit */
NULL, /* ^graph */
NULL, /* ^print */
@@ -431,391 +582,91 @@ static const pcre_uchar *posix_substitutes[] = {
string_PXwd, /* ^word */ /* Perl and POSIX space are the same */
NULL /* ^xdigit */
};
-#define POSIX_SUBSIZE (sizeof(posix_substitutes) / sizeof(pcre_uchar *))
-#endif
-
-#define STRING(a) # a
-#define XSTRING(s) STRING(s)
-
-/* The texts of compile-time error messages. These are "char *" because they
-are passed to the outside world. Do not ever re-use any error number, because
-they are documented. Always add a new error instead. Messages marked DEAD below
-are no longer used. This used to be a table of strings, but in order to reduce
-the number of relocations needed when a shared library is loaded dynamically,
-it is now one long string. We cannot use a table of offsets, because the
-lengths of inserts such as XSTRING(MAX_NAME_SIZE) are not known. Instead, we
-simply count through to the one we want - this isn't a performance issue
-because these strings are used only when there is a compilation error.
-
-Each substring ends with \0 to insert a null character. This includes the final
-substring, so that the whole string ends with \0\0, which can be detected when
-counting through. */
-
-static const char error_texts[] =
- "no error\0"
- "\\ at end of pattern\0"
- "\\c at end of pattern\0"
- "unrecognized character follows \\\0"
- "numbers out of order in {} quantifier\0"
- /* 5 */
- "number too big in {} quantifier\0"
- "missing terminating ] for character class\0"
- "invalid escape sequence in character class\0"
- "range out of order in character class\0"
- "nothing to repeat\0"
- /* 10 */
- "internal error: invalid forward reference offset\0"
- "internal error: unexpected repeat\0"
- "unrecognized character after (? or (?-\0"
- "POSIX named classes are supported only within a class\0"
- "missing )\0"
- /* 15 */
- "reference to non-existent subpattern\0"
- "erroffset passed as NULL\0"
- "unknown option bit(s) set\0"
- "missing ) after comment\0"
- "parentheses nested too deeply\0" /** DEAD **/
- /* 20 */
- "regular expression is too large\0"
- "failed to get memory\0"
- "unmatched parentheses\0"
- "internal error: code overflow\0"
- "unrecognized character after (?<\0"
- /* 25 */
- "lookbehind assertion is not fixed length\0"
- "malformed number or name after (?(\0"
- "conditional group contains more than two branches\0"
- "assertion expected after (?( or (?(?C)\0"
- "(?R or (?[+-]digits must be followed by )\0"
- /* 30 */
- "unknown POSIX class name\0"
- "POSIX collating elements are not supported\0"
- "this version of PCRE is compiled without UTF support\0"
- "spare error\0" /** DEAD **/
- "character value in \\x{} or \\o{} is too large\0"
- /* 35 */
- "invalid condition (?(0)\0"
- "\\C not allowed in lookbehind assertion\0"
- "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u\0"
- "number after (?C is > 255\0"
- "closing ) for (?C expected\0"
- /* 40 */
- "recursive call could loop indefinitely\0"
- "unrecognized character after (?P\0"
- "syntax error in subpattern name (missing terminator)\0"
- "two named subpatterns have the same name\0"
- "invalid UTF-8 string\0"
- /* 45 */
- "support for \\P, \\p, and \\X has not been compiled\0"
- "malformed \\P or \\p sequence\0"
- "unknown property name after \\P or \\p\0"
- "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)\0"
- "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0"
- /* 50 */
- "repeated subpattern is too long\0" /** DEAD **/
- "octal value is greater than \\377 in 8-bit non-UTF-8 mode\0"
- "internal error: overran compiling workspace\0"
- "internal error: previously-checked referenced subpattern not found\0"
- "DEFINE group contains more than one branch\0"
- /* 55 */
- "repeating a DEFINE group is not allowed\0" /** DEAD **/
- "inconsistent NEWLINE options\0"
- "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0"
- "a numbered reference must not be zero\0"
- "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0"
- /* 60 */
- "(*VERB) not recognized or malformed\0"
- "number is too big\0"
- "subpattern name expected\0"
- "digit expected after (?+\0"
- "] is an invalid data character in JavaScript compatibility mode\0"
- /* 65 */
- "different names for subpatterns of the same number are not allowed\0"
- "(*MARK) must have an argument\0"
- "this version of PCRE is not compiled with Unicode property support\0"
-#ifndef EBCDIC
- "\\c must be followed by an ASCII character\0"
-#else
- "\\c must be followed by a letter or one of [\\]^_?\0"
-#endif
- "\\k is not followed by a braced, angle-bracketed, or quoted name\0"
- /* 70 */
- "internal error: unknown opcode in find_fixedlength()\0"
- "\\N is not supported in a class\0"
- "too many forward references\0"
- "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)\0"
- "invalid UTF-16 string\0"
- /* 75 */
- "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0"
- "character value in \\u.... sequence is too large\0"
- "invalid UTF-32 string\0"
- "setting UTF is disabled by the application\0"
- "non-hex character in \\x{} (closing brace missing?)\0"
- /* 80 */
- "non-octal character in \\o{} (closing brace missing?)\0"
- "missing opening brace after \\o\0"
- "parentheses are too deeply nested\0"
- "invalid range in character class\0"
- "group name must start with a non-digit\0"
- /* 85 */
- "parentheses are too deeply nested (stack check)\0"
- "digits missing in \\x{} or \\o{}\0"
- "regular expression is too complicated\0"
- ;
-
-/* Table to identify digits and hex digits. This is used when compiling
-patterns. Note that the tables in chartables are dependent on the locale, and
-may mark arbitrary characters as digits - but the PCRE compiling code expects
-to handle only 0-9, a-z, and A-Z as digits when compiling. That is why we have
-a private table here. It costs 256 bytes, but it is a lot faster than doing
-character value tests (at least in some simple cases I timed), and in some
-applications one wants PCRE to compile efficiently as well as match
-efficiently.
-
-For convenience, we use the same bit definitions as in chartables:
-
- 0x04 decimal digit
- 0x08 hexadecimal digit
-
-Then we can use ctype_digit and ctype_xdigit in the code. */
-
-/* Using a simple comparison for decimal numbers rather than a memory read
-is much faster, and the resulting code is simpler (the compiler turns it
-into a subtraction and unsigned comparison). */
-
-#define IS_DIGIT(x) ((x) >= CHAR_0 && (x) <= CHAR_9)
-
-#ifndef EBCDIC
-
-/* This is the "normal" case, for ASCII systems, and EBCDIC systems running in
-UTF-8 mode. */
-
-static const pcre_uint8 digitab[] =
+#define POSIX_SUBSIZE (sizeof(posix_substitutes) / sizeof(PCRE2_UCHAR *))
+#endif /* SUPPORT_UNICODE */
+
+/* Masks for checking option settings. */
+
+#define PUBLIC_COMPILE_OPTIONS \
+ (PCRE2_ANCHORED|PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \
+ PCRE2_ALT_VERBNAMES|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_DOLLAR_ENDONLY| \
+ PCRE2_DOTALL|PCRE2_DUPNAMES|PCRE2_EXTENDED|PCRE2_FIRSTLINE| \
+ PCRE2_MATCH_UNSET_BACKREF|PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C| \
+ PCRE2_NEVER_UCP|PCRE2_NEVER_UTF|PCRE2_NO_AUTO_CAPTURE| \
+ PCRE2_NO_AUTO_POSSESS|PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_NO_START_OPTIMIZE| \
+ PCRE2_NO_UTF_CHECK|PCRE2_UCP|PCRE2_UNGREEDY|PCRE2_USE_OFFSET_LIMIT| \
+ PCRE2_UTF)
+
+/* Compile time error code numbers. They are given names so that they can more
+easily be tracked. When a new number is added, the tables called eint1 and
+eint2 in pcre2posix.c may need to be updated, and a new error text must be
+added to compile_error_texts in pcre2_error.c. */
+
+enum { ERR0 = COMPILE_ERROR_BASE,
+ ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10,
+ ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20,
+ ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, ERR30,
+ ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, ERR40,
+ ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, ERR50,
+ ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60,
+ ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70,
+ ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80,
+ ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88 };
+
+/* Error codes that correspond to negative error codes returned by
+find_fixedlength(). */
+
+static int fixed_length_errors[] =
{
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */
- 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 */
- 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */
- 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* @ - G */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H - O */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* P - W */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* X - _ */
- 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* ` - g */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h - o */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* p - w */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* x -127 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
-
-#else
-
-/* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */
-
-static const pcre_uint8 digitab[] =
- {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 0 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8- 15 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 10 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 32- 39 20 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 30 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 40 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 72- | */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 50 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 88- 95 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 60 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 104- ? */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 70 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */
- 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* 128- g 80 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144- p 90 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160- x A0 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 B0 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
- 0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x00, /* { - G C0 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* } - P D0 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* \ - X E0 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */
- 0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c, /* 0 - 7 F0 */
- 0x0c,0x0c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */
-
-static const pcre_uint8 ebcdic_chartab[] = { /* chartable partial dup */
- 0x80,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 0- 7 */
- 0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00, /* 8- 15 */
- 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 16- 23 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
- 0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, /* 32- 39 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 40- 47 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 48- 55 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 56- 63 */
- 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - 71 */
- 0x00,0x00,0x00,0x80,0x00,0x80,0x80,0x80, /* 72- | */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* & - 87 */
- 0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00, /* 88- 95 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - -103 */
- 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x80, /* 104- ? */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 112-119 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 120- " */
- 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* 128- g */
- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* h -143 */
- 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* 144- p */
- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* q -159 */
- 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* 160- x */
- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* y -175 */
- 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ^ -183 */
- 0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
- 0x80,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* { - G */
- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* H -207 */
- 0x00,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* } - P */
- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Q -223 */
- 0x00,0x00,0x12,0x12,0x12,0x12,0x12,0x12, /* \ - X */
- 0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x00, /* Y -239 */
- 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */
- 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00};/* 8 -255 */
-#endif
-
-
-/* This table is used to check whether auto-possessification is possible
-between adjacent character-type opcodes. The left-hand (repeated) opcode is
-used to select the row, and the right-hand opcode is use to select the column.
-A value of 1 means that auto-possessification is OK. For example, the second
-value in the first row means that \D+\d can be turned into \D++\d.
-
-The Unicode property types (\P and \p) have to be present to fill out the table
-because of what their opcode values are, but the table values should always be
-zero because property types are handled separately in the code. The last four
-columns apply to items that cannot be repeated, so there is no need to have
-rows for them. Note that OP_DIGIT etc. are generated only when PCRE_UCP is
-*not* set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
-
-#define APTROWS (LAST_AUTOTAB_LEFT_OP - FIRST_AUTOTAB_OP + 1)
-#define APTCOLS (LAST_AUTOTAB_RIGHT_OP - FIRST_AUTOTAB_OP + 1)
-
-static const pcre_uint8 autoposstab[APTROWS][APTCOLS] = {
-/* \D \d \S \s \W \w . .+ \C \P \p \R \H \h \V \v \X \Z \z $ $M */
- { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \D */
- { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \d */
- { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \S */
- { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \s */
- { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \W */
- { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \w */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* . */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* .+ */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \C */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \P */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \p */
- { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \R */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \H */
- { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \h */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \V */
- { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, /* \v */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 } /* \X */
-};
-
-
-/* This table is used to check whether auto-possessification is possible
-between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP). The
-left-hand (repeated) opcode is used to select the row, and the right-hand
-opcode is used to select the column. The values are as follows:
-
- 0 Always return FALSE (never auto-possessify)
- 1 Character groups are distinct (possessify if both are OP_PROP)
- 2 Check character categories in the same group (general or particular)
- 3 TRUE if the two opcodes are not the same (PROP vs NOTPROP)
-
- 4 Check left general category vs right particular category
- 5 Check right general category vs left particular category
-
- 6 Left alphanum vs right general category
- 7 Left space vs right general category
- 8 Left word vs right general category
-
- 9 Right alphanum vs left general category
- 10 Right space vs left general category
- 11 Right word vs left general category
-
- 12 Left alphanum vs right particular category
- 13 Left space vs right particular category
- 14 Left word vs right particular category
-
- 15 Right alphanum vs left particular category
- 16 Right space vs left particular category
- 17 Right word vs left particular category
-*/
-
-static const pcre_uint8 propposstab[PT_TABSIZE][PT_TABSIZE] = {
-/* ANY LAMP GC PC SC ALNUM SPACE PXSPACE WORD CLIST UCNC */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_ANY */
- { 0, 3, 0, 0, 0, 3, 1, 1, 0, 0, 0 }, /* PT_LAMP */
- { 0, 0, 2, 4, 0, 9, 10, 10, 11, 0, 0 }, /* PT_GC */
- { 0, 0, 5, 2, 0, 15, 16, 16, 17, 0, 0 }, /* PT_PC */
- { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, /* PT_SC */
- { 0, 3, 6, 12, 0, 3, 1, 1, 0, 0, 0 }, /* PT_ALNUM */
- { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_SPACE */
- { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_PXSPACE */
- { 0, 0, 8, 14, 0, 0, 1, 1, 3, 0, 0 }, /* PT_WORD */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_CLIST */
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 } /* PT_UCNC */
-};
-
-/* This table is used to check whether auto-possessification is possible
-between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP) when one
-specifies a general category and the other specifies a particular category. The
-row is selected by the general category and the column by the particular
-category. The value is 1 if the particular category is not part of the general
-category. */
-
-static const pcre_uint8 catposstab[7][30] = {
-/* Cc Cf Cn Co Cs Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc Pd Pe Pf Pi Po Ps Sc Sk Sm So Zl Zp Zs */
- { 0, 0, 0, 0, 0, 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 }, /* C */
- { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* L */
- { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* M */
- { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* N */
- { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }, /* P */
- { 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, 1, 1, 1 }, /* S */
- { 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 } /* Z */
-};
-
-/* This table is used when checking ALNUM, (PX)SPACE, SPACE, and WORD against
-a general or particular category. The properties in each row are those
-that apply to the character set in question. Duplication means that a little
-unnecessary work is done when checking, but this keeps things much simpler
-because they can all use the same code. For more details see the comment where
-this table is used.
-
-Note: SPACE and PXSPACE used to be different because Perl excluded VT from
-"space", but from Perl 5.18 it's included, so both categories are treated the
-same here. */
-
-static const pcre_uint8 posspropstab[3][4] = {
- { ucp_L, ucp_N, ucp_N, ucp_Nl }, /* ALNUM, 3rd and 4th values redundant */
- { ucp_Z, ucp_Z, ucp_C, ucp_Cc }, /* SPACE and PXSPACE, 2nd value redundant */
- { ucp_L, ucp_N, ucp_P, ucp_Po } /* WORD */
+ ERR0, /* Not an error */
+ ERR0, /* Not an error; -1 is used for "process later" */
+ ERR25, /* Lookbehind is not fixed length */
+ ERR36, /* \C in lookbehind is not allowed */
+ ERR87, /* Lookbehind is too long */
+ ERR86, /* Pattern too complicated */
+ ERR70 /* Internal error: unknown opcode encountered */
+ };
+
+/* This is a table of start-of-pattern options such as (*UTF) and settings such
+as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward
+compatibility, (*UTFn) is supported in the relevant libraries, but (*UTF) is
+generic and always supported. */
+
+enum { PSO_OPT, /* Value is an option bit */
+ PSO_FLG, /* Value is a flag bit */
+ PSO_NL, /* Value is a newline type */
+ PSO_BSR, /* Value is a \R type */
+ PSO_LIMM, /* Read integer value for match limit */
+ PSO_LIMR }; /* Read integer value for recursion limit */
+
+typedef struct pso {
+ const uint8_t *name;
+ uint16_t length;
+ uint16_t type;
+ uint32_t value;
+} pso;
+
+/* NB: STRING_UTFn_RIGHTPAR contains the length as well */
+
+static pso pso_list[] = {
+ { (uint8_t *)STRING_UTFn_RIGHTPAR, PSO_OPT, PCRE2_UTF },
+ { (uint8_t *)STRING_UTF_RIGHTPAR, 4, PSO_OPT, PCRE2_UTF },
+ { (uint8_t *)STRING_UCP_RIGHTPAR, 4, PSO_OPT, PCRE2_UCP },
+ { (uint8_t *)STRING_NOTEMPTY_RIGHTPAR, 9, PSO_FLG, PCRE2_NOTEMPTY_SET },
+ { (uint8_t *)STRING_NOTEMPTY_ATSTART_RIGHTPAR, 17, PSO_FLG, PCRE2_NE_ATST_SET },
+ { (uint8_t *)STRING_NO_AUTO_POSSESS_RIGHTPAR, 16, PSO_OPT, PCRE2_NO_AUTO_POSSESS },
+ { (uint8_t *)STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR, 18, PSO_OPT, PCRE2_NO_DOTSTAR_ANCHOR },
+ { (uint8_t *)STRING_NO_JIT_RIGHTPAR, 7, PSO_FLG, PCRE2_NOJIT },
+ { (uint8_t *)STRING_NO_START_OPT_RIGHTPAR, 13, PSO_OPT, PCRE2_NO_START_OPTIMIZE },
+ { (uint8_t *)STRING_LIMIT_MATCH_EQ, 12, PSO_LIMM, 0 },
+ { (uint8_t *)STRING_LIMIT_RECURSION_EQ, 16, PSO_LIMR, 0 },
+ { (uint8_t *)STRING_CR_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_CR },
+ { (uint8_t *)STRING_LF_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_LF },
+ { (uint8_t *)STRING_CRLF_RIGHTPAR, 5, PSO_NL, PCRE2_NEWLINE_CRLF },
+ { (uint8_t *)STRING_ANY_RIGHTPAR, 4, PSO_NL, PCRE2_NEWLINE_ANY },
+ { (uint8_t *)STRING_ANYCRLF_RIGHTPAR, 8, PSO_NL, PCRE2_NEWLINE_ANYCRLF },
+ { (uint8_t *)STRING_BSR_ANYCRLF_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_ANYCRLF },
+ { (uint8_t *)STRING_BSR_UNICODE_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_UNICODE }
};
/* This table is used when converting repeating opcodes into possessified
@@ -824,7 +675,7 @@ value means there is no possessified version - in those cases the item in
question must be wrapped in ONCE brackets. The table is truncated at OP_CALLOUT
because all relevant opcodes are less than that. */
-static const pcre_uint8 opcode_possessify[] = {
+static const uint8_t opcode_possessify[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */
@@ -879,827 +730,122 @@ static const pcre_uint8 opcode_possessify[] = {
/*************************************************
-* Find an error text *
-*************************************************/
-
-/* The error texts are now all in one long string, to save on relocations. As
-some of the text is of unknown length, we can't use a table of offsets.
-Instead, just count through the strings. This is not a performance issue
-because it happens only when there has been a compilation error.
-
-Argument: the error number
-Returns: pointer to the error string
-*/
-
-static const char *
-find_error_text(int n)
-{
-const char *s = error_texts;
-for (; n > 0; n--)
- {
- while (*s++ != CHAR_NULL) {};
- if (*s == CHAR_NULL) return "Error text not found (please report)";
- }
-return s;
-}
-
-
-
-/*************************************************
-* Expand the workspace *
+* Copy compiled code *
*************************************************/
-/* This function is called during the second compiling phase, if the number of
-forward references fills the existing workspace, which is originally a block on
-the stack. A larger block is obtained from malloc() unless the ultimate limit
-has been reached or the increase will be rather small.
+/* Compiled JIT code cannot be copied, so the new compiled block has no
+associated JIT data. */
-Argument: pointer to the compile data block
-Returns: 0 if all went well, else an error number
-*/
-
-static int
-expand_workspace(compile_data *cd)
+PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
+pcre2_code_copy(const pcre2_code *code)
{
-pcre_uchar *newspace;
-int newsize = cd->workspace_size * 2;
-
-if (newsize > COMPILE_WORK_SIZE_MAX) newsize = COMPILE_WORK_SIZE_MAX;
-if (cd->workspace_size >= COMPILE_WORK_SIZE_MAX ||
- newsize - cd->workspace_size < WORK_SIZE_SAFETY_MARGIN)
- return ERR72;
-
-newspace = (PUBL(malloc))(IN_UCHARS(newsize));
-if (newspace == NULL) return ERR21;
-memcpy(newspace, cd->start_workspace, cd->workspace_size * sizeof(pcre_uchar));
-cd->hwm = (pcre_uchar *)newspace + (cd->hwm - cd->start_workspace);
-if (cd->workspace_size > COMPILE_WORK_SIZE)
- (PUBL(free))((void *)cd->start_workspace);
-cd->start_workspace = newspace;
-cd->workspace_size = newsize;
-return 0;
-}
-
+PCRE2_SIZE* ref_count;
+pcre2_code *newcode;
+if (code == NULL) return NULL;
+newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data);
+if (newcode == NULL) return NULL;
+memcpy(newcode, code, code->blocksize);
+newcode->executable_jit = NULL;
-/*************************************************
-* Check for counted repeat *
-*************************************************/
-
-/* This function is called when a '{' is encountered in a place where it might
-start a quantifier. It looks ahead to see if it really is a quantifier or not.
-It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd}
-where the ddds are digits.
-
-Arguments:
- p pointer to the first char after '{'
-
-Returns: TRUE or FALSE
-*/
+/* If the code is one that has been deserialized, increment the reference count
+in the decoded tables. */
-static BOOL
-is_counted_repeat(const pcre_uchar *p)
-{
-if (!IS_DIGIT(*p)) return FALSE;
-p++;
-while (IS_DIGIT(*p)) p++;
-if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;
-
-if (*p++ != CHAR_COMMA) return FALSE;
-if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;
-
-if (!IS_DIGIT(*p)) return FALSE;
-p++;
-while (IS_DIGIT(*p)) p++;
+if ((code->flags & PCRE2_DEREF_TABLES) != 0)
+ {
+ ref_count = (PCRE2_SIZE *)(code->tables + tables_length);
+ (*ref_count)++;
+ }
-return (*p == CHAR_RIGHT_CURLY_BRACKET);
+return newcode;
}
/*************************************************
-* Handle escapes *
+* Free compiled code *
*************************************************/
-/* This function is called when a \ has been encountered. It either returns a
-positive value for a simple escape such as \n, or 0 for a data character which
-will be placed in chptr. A backreference to group n is returned as negative n.
-When UTF-8 is enabled, a positive value greater than 255 may be returned in
-chptr. On entry, ptr is pointing at the \. On exit, it is on the final
-character of the escape sequence.
-
-Arguments:
- ptrptr points to the pattern position pointer
- chptr points to a returned data character
- errorcodeptr points to the errorcode variable
- bracount number of previous extracting brackets
- options the options bits
- isclass TRUE if inside a character class
-
-Returns: zero => a data character
- positive => a special escape sequence
- negative => a back reference
- on error, errorcodeptr is set
-*/
-
-static int
-check_escape(const pcre_uchar **ptrptr, pcre_uint32 *chptr, int *errorcodeptr,
- int bracount, int options, BOOL isclass)
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_code_free(pcre2_code *code)
{
-/* PCRE_UTF16 has the same value as PCRE_UTF8. */
-BOOL utf = (options & PCRE_UTF8) != 0;
-const pcre_uchar *ptr = *ptrptr + 1;
-pcre_uint32 c;
-int escape = 0;
-int i;
+PCRE2_SIZE* ref_count;
-GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */
-ptr--; /* Set pointer back to the last byte */
-
-/* If backslash is at the end of the pattern, it's an error. */
-
-if (c == CHAR_NULL) *errorcodeptr = ERR1;
-
-/* Non-alphanumerics are literals. For digits or letters, do an initial lookup
-in a table. A non-zero result is something that can be returned immediately.
-Otherwise further processing may be required. */
-
-#ifndef EBCDIC /* ASCII/UTF-8 coding */
-/* Not alphanumeric */
-else if (c < CHAR_0 || c > CHAR_z) {}
-else if ((i = escapes[c - CHAR_0]) != 0)
- { if (i > 0) c = (pcre_uint32)i; else escape = -i; }
-
-#else /* EBCDIC coding */
-/* Not alphanumeric */
-else if (c < CHAR_a || (!MAX_255(c) || (ebcdic_chartab[c] & 0x0E) == 0)) {}
-else if ((i = escapes[c - 0x48]) != 0) { if (i > 0) c = (pcre_uint32)i; else escape = -i; }
-#endif
-
-/* Escapes that need further processing, or are illegal. */
-
-else
+if (code != NULL)
{
- const pcre_uchar *oldptr;
- BOOL braced, negated, overflow;
- int s;
+ if (code->executable_jit != NULL)
+ PRIV(jit_free)(code->executable_jit, &code->memctl);
- switch (c)
+ if ((code->flags & PCRE2_DEREF_TABLES) != 0)
{
- /* A number of Perl escapes are not handled by PCRE. We give an explicit
- error. */
-
- case CHAR_l:
- case CHAR_L:
- *errorcodeptr = ERR37;
- break;
-
- case CHAR_u:
- if ((options & PCRE_JAVASCRIPT_COMPAT) != 0)
- {
- /* In JavaScript, \u must be followed by four hexadecimal numbers.
- Otherwise it is a lowercase u letter. */
- if (MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0
- && MAX_255(ptr[2]) && (digitab[ptr[2]] & ctype_xdigit) != 0
- && MAX_255(ptr[3]) && (digitab[ptr[3]] & ctype_xdigit) != 0
- && MAX_255(ptr[4]) && (digitab[ptr[4]] & ctype_xdigit) != 0)
- {
- c = 0;
- for (i = 0; i < 4; ++i)
- {
- register pcre_uint32 cc = *(++ptr);
-#ifndef EBCDIC /* ASCII/UTF-8 coding */
- if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */
- c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
-#else /* EBCDIC coding */
- if (cc >= CHAR_a && cc <= CHAR_z) cc += 64; /* Convert to upper case */
- c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));
-#endif
- }
-
-#if defined COMPILE_PCRE8
- if (c > (utf ? 0x10ffffU : 0xffU))
-#elif defined COMPILE_PCRE16
- if (c > (utf ? 0x10ffffU : 0xffffU))
-#elif defined COMPILE_PCRE32
- if (utf && c > 0x10ffffU)
-#endif
- {
- *errorcodeptr = ERR76;
- }
- else if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
- }
- }
- else
- *errorcodeptr = ERR37;
- break;
-
- case CHAR_U:
- /* In JavaScript, \U is an uppercase U letter. */
- if ((options & PCRE_JAVASCRIPT_COMPAT) == 0) *errorcodeptr = ERR37;
- break;
-
- /* In a character class, \g is just a literal "g". Outside a character
- class, \g must be followed by one of a number of specific things:
-
- (1) A number, either plain or braced. If positive, it is an absolute
- backreference. If negative, it is a relative backreference. This is a Perl
- 5.10 feature.
-
- (2) Perl 5.10 also supports \g{name} as a reference to a named group. This
- is part of Perl's movement towards a unified syntax for back references. As
- this is synonymous with \k{name}, we fudge it up by pretending it really
- was \k.
-
- (3) For Oniguruma compatibility we also support \g followed by a name or a
- number either in angle brackets or in single quotes. However, these are
- (possibly recursive) subroutine calls, _not_ backreferences. Just return
- the ESC_g code (cf \k). */
-
- case CHAR_g:
- if (isclass) break;
- if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE)
- {
- escape = ESC_g;
- break;
- }
-
- /* Handle the Perl-compatible cases */
-
- if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
- {
- const pcre_uchar *p;
- for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++)
- if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break;
- if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET)
- {
- escape = ESC_k;
- break;
- }
- braced = TRUE;
- ptr++;
- }
- else braced = FALSE;
-
- if (ptr[1] == CHAR_MINUS)
- {
- negated = TRUE;
- ptr++;
- }
- else negated = FALSE;
-
- /* The integer range is limited by the machine's int representation. */
- s = 0;
- overflow = FALSE;
- while (IS_DIGIT(ptr[1]))
- {
- if (s > INT_MAX / 10 - 1) /* Integer overflow */
- {
- overflow = TRUE;
- break;
- }
- s = s * 10 + (int)(*(++ptr) - CHAR_0);
- }
- if (overflow) /* Integer overflow */
- {
- while (IS_DIGIT(ptr[1]))
- ptr++;
- *errorcodeptr = ERR61;
- break;
- }
-
- if (braced && *(++ptr) != CHAR_RIGHT_CURLY_BRACKET)
- {
- *errorcodeptr = ERR57;
- break;
- }
-
- if (s == 0)
- {
- *errorcodeptr = ERR58;
- break;
- }
-
- if (negated)
- {
- if (s > bracount)
- {
- *errorcodeptr = ERR15;
- break;
- }
- s = bracount - (s - 1);
- }
-
- escape = -s;
- break;
-
- /* The handling of escape sequences consisting of a string of digits
- starting with one that is not zero is not straightforward. Perl has changed
- over the years. Nowadays \g{} for backreferences and \o{} for octal are
- recommended to avoid the ambiguities in the old syntax.
-
- Outside a character class, the digits are read as a decimal number. If the
- number is less than 8 (used to be 10), or if there are that many previous
- extracting left brackets, then it is a back reference. Otherwise, up to
- three octal digits are read to form an escaped byte. Thus \123 is likely to
- be octal 123 (cf \0123, which is octal 012 followed by the literal 3). If
- the octal value is greater than 377, the least significant 8 bits are
- taken. \8 and \9 are treated as the literal characters 8 and 9.
-
- Inside a character class, \ followed by a digit is always either a literal
- 8 or 9 or an octal number. */
-
- case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5:
- case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
-
- if (!isclass)
- {
- oldptr = ptr;
- /* The integer range is limited by the machine's int representation. */
- s = (int)(c -CHAR_0);
- overflow = FALSE;
- while (IS_DIGIT(ptr[1]))
- {
- if (s > INT_MAX / 10 - 1) /* Integer overflow */
- {
- overflow = TRUE;
- break;
- }
- s = s * 10 + (int)(*(++ptr) - CHAR_0);
- }
- if (overflow) /* Integer overflow */
- {
- while (IS_DIGIT(ptr[1]))
- ptr++;
- *errorcodeptr = ERR61;
- break;
- }
- if (s < 8 || s <= bracount) /* Check for back reference */
- {
- escape = -s;
- break;
- }
- ptr = oldptr; /* Put the pointer back and fall through */
- }
-
- /* Handle a digit following \ when the number is not a back reference. If
- the first digit is 8 or 9, Perl used to generate a binary zero byte and
- then treat the digit as a following literal. At least by Perl 5.18 this
- changed so as not to insert the binary zero. */
-
- if ((c = *ptr) >= CHAR_8) break;
-
- /* Fall through with a digit less than 8 */
-
- /* \0 always starts an octal number, but we may drop through to here with a
- larger first octal digit. The original code used just to take the least
- significant 8 bits of octal numbers (I think this is what early Perls used
- to do). Nowadays we allow for larger numbers in UTF-8 mode and 16-bit mode,
- but no more than 3 octal digits. */
-
- case CHAR_0:
- c -= CHAR_0;
- while(i++ < 2 && ptr[1] >= CHAR_0 && ptr[1] <= CHAR_7)
- c = c * 8 + *(++ptr) - CHAR_0;
-#ifdef COMPILE_PCRE8
- if (!utf && c > 0xff) *errorcodeptr = ERR51;
-#endif
- break;
-
- /* \o is a relatively new Perl feature, supporting a more general way of
- specifying character codes in octal. The only supported form is \o{ddd}. */
-
- case CHAR_o:
- if (ptr[1] != CHAR_LEFT_CURLY_BRACKET) *errorcodeptr = ERR81; else
- if (ptr[2] == CHAR_RIGHT_CURLY_BRACKET) *errorcodeptr = ERR86; else
- {
- ptr += 2;
- c = 0;
- overflow = FALSE;
- while (*ptr >= CHAR_0 && *ptr <= CHAR_7)
- {
- register pcre_uint32 cc = *ptr++;
- if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */
-#ifdef COMPILE_PCRE32
- if (c >= 0x20000000l) { overflow = TRUE; break; }
-#endif
- c = (c << 3) + cc - CHAR_0 ;
-#if defined COMPILE_PCRE8
- if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
-#elif defined COMPILE_PCRE16
- if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
-#elif defined COMPILE_PCRE32
- if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
-#endif
- }
- if (overflow)
- {
- while (*ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++;
- *errorcodeptr = ERR34;
- }
- else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
- {
- if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
- }
- else *errorcodeptr = ERR80;
- }
- break;
-
- /* \x is complicated. In JavaScript, \x must be followed by two hexadecimal
- numbers. Otherwise it is a lowercase x letter. */
-
- case CHAR_x:
- if ((options & PCRE_JAVASCRIPT_COMPAT) != 0)
- {
- if (MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0
- && MAX_255(ptr[2]) && (digitab[ptr[2]] & ctype_xdigit) != 0)
- {
- c = 0;
- for (i = 0; i < 2; ++i)
- {
- register pcre_uint32 cc = *(++ptr);
-#ifndef EBCDIC /* ASCII/UTF-8 coding */
- if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */
- c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
-#else /* EBCDIC coding */
- if (cc >= CHAR_a && cc <= CHAR_z) cc += 64; /* Convert to upper case */
- c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));
-#endif
- }
- }
- } /* End JavaScript handling */
-
- /* Handle \x in Perl's style. \x{ddd} is a character number which can be
- greater than 0xff in utf or non-8bit mode, but only if the ddd are hex
- digits. If not, { used to be treated as a data character. However, Perl
- seems to read hex digits up to the first non-such, and ignore the rest, so
- that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE
- now gives an error. */
+ /* Decoded tables belong to the codes after deserialization, and they must
+ be freed when there are no more reference to them. The *ref_count should
+ always be > 0. */
- else
+ ref_count = (PCRE2_SIZE *)(code->tables + tables_length);
+ if (*ref_count > 0)
{
- if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
- {
- ptr += 2;
- if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
- {
- *errorcodeptr = ERR86;
- break;
- }
- c = 0;
- overflow = FALSE;
- while (MAX_255(*ptr) && (digitab[*ptr] & ctype_xdigit) != 0)
- {
- register pcre_uint32 cc = *ptr++;
- if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */
-
-#ifdef COMPILE_PCRE32
- if (c >= 0x10000000l) { overflow = TRUE; break; }
-#endif
-
-#ifndef EBCDIC /* ASCII/UTF-8 coding */
- if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */
- c = (c << 4) + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
-#else /* EBCDIC coding */
- if (cc >= CHAR_a && cc <= CHAR_z) cc += 64; /* Convert to upper case */
- c = (c << 4) + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));
-#endif
-
-#if defined COMPILE_PCRE8
- if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
-#elif defined COMPILE_PCRE16
- if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
-#elif defined COMPILE_PCRE32
- if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
-#endif
- }
-
- if (overflow)
- {
- while (MAX_255(*ptr) && (digitab[*ptr] & ctype_xdigit) != 0) ptr++;
- *errorcodeptr = ERR34;
- }
-
- else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
- {
- if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
- }
-
- /* If the sequence of hex digits does not end with '}', give an error.
- We used just to recognize this construct and fall through to the normal
- \x handling, but nowadays Perl gives an error, which seems much more
- sensible, so we do too. */
-
- else *errorcodeptr = ERR79;
- } /* End of \x{} processing */
-
- /* Read a single-byte hex-defined char (up to two hex digits after \x) */
-
- else
- {
- c = 0;
- while (i++ < 2 && MAX_255(ptr[1]) && (digitab[ptr[1]] & ctype_xdigit) != 0)
- {
- pcre_uint32 cc; /* Some compilers don't like */
- cc = *(++ptr); /* ++ in initializers */
-#ifndef EBCDIC /* ASCII/UTF-8 coding */
- if (cc >= CHAR_a) cc -= 32; /* Convert to upper case */
- c = c * 16 + cc - ((cc < CHAR_A)? CHAR_0 : (CHAR_A - 10));
-#else /* EBCDIC coding */
- if (cc <= CHAR_z) cc += 64; /* Convert to upper case */
- c = c * 16 + cc - ((cc >= CHAR_0)? CHAR_0 : (CHAR_A - 10));
-#endif
- }
- } /* End of \xdd handling */
- } /* End of Perl-style \x handling */
- break;
-
- /* For \c, a following letter is upper-cased; then the 0x40 bit is flipped.
- An error is given if the byte following \c is not an ASCII character. This
- coding is ASCII-specific, but then the whole concept of \cx is
- ASCII-specific. (However, an EBCDIC equivalent has now been added.) */
-
- case CHAR_c:
- c = *(++ptr);
- if (c == CHAR_NULL)
- {
- *errorcodeptr = ERR2;
- break;
- }
-#ifndef EBCDIC /* ASCII/UTF-8 coding */
- if (c > 127) /* Excludes all non-ASCII in either mode */
- {
- *errorcodeptr = ERR68;
- break;
- }
- if (c >= CHAR_a && c <= CHAR_z) c -= 32;
- c ^= 0x40;
-#else /* EBCDIC coding */
- if (c >= CHAR_a && c <= CHAR_z) c += 64;
- if (c == CHAR_QUESTION_MARK)
- c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff;
- else
- {
- for (i = 0; i < 32; i++)
- {
- if (c == ebcdic_escape_c[i]) break;
- }
- if (i < 32) c = i; else *errorcodeptr = ERR68;
+ (*ref_count)--;
+ if (*ref_count == 0)
+ code->memctl.free((void *)code->tables, code->memctl.memory_data);
}
-#endif
- break;
-
- /* PCRE_EXTRA enables extensions to Perl in the matter of escapes. Any
- other alphanumeric following \ is an error if PCRE_EXTRA was set;
- otherwise, for Perl compatibility, it is a literal. This code looks a bit
- odd, but there used to be some cases other than the default, and there may
- be again in future, so I haven't "optimized" it. */
-
- default:
- if ((options & PCRE_EXTRA) != 0) switch(c)
- {
- default:
- *errorcodeptr = ERR3;
- break;
- }
- break;
- }
- }
-
-/* Perl supports \N{name} for character names, as well as plain \N for "not
-newline". PCRE does not support \N{name}. However, it does support
-quantification such as \N{2,3}. */
-
-if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET &&
- !is_counted_repeat(ptr+2))
- *errorcodeptr = ERR37;
-
-/* If PCRE_UCP is set, we change the values for \d etc. */
-
-if ((options & PCRE_UCP) != 0 && escape >= ESC_D && escape <= ESC_w)
- escape += (ESC_DU - ESC_D);
-
-/* Set the pointer to the final character before returning. */
-
-*ptrptr = ptr;
-*chptr = c;
-return escape;
-}
-
-
-
-#ifdef SUPPORT_UCP
-/*************************************************
-* Handle \P and \p *
-*************************************************/
-
-/* This function is called after \P or \p has been encountered, provided that
-PCRE is compiled with support for Unicode properties. On entry, ptrptr is
-pointing at the P or p. On exit, it is pointing at the final character of the
-escape sequence.
-
-Argument:
- ptrptr points to the pattern position pointer
- negptr points to a boolean that is set TRUE for negation else FALSE
- ptypeptr points to an unsigned int that is set to the type value
- pdataptr points to an unsigned int that is set to the detailed property value
- errorcodeptr points to the error code variable
-
-Returns: TRUE if the type value was found, or FALSE for an invalid type
-*/
-
-static BOOL
-get_ucp(const pcre_uchar **ptrptr, BOOL *negptr, unsigned int *ptypeptr,
- unsigned int *pdataptr, int *errorcodeptr)
-{
-pcre_uchar c;
-int i, bot, top;
-const pcre_uchar *ptr = *ptrptr;
-pcre_uchar name[32];
-
-c = *(++ptr);
-if (c == CHAR_NULL) goto ERROR_RETURN;
-
-*negptr = FALSE;
-
-/* \P or \p can be followed by a name in {}, optionally preceded by ^ for
-negation. */
-
-if (c == CHAR_LEFT_CURLY_BRACKET)
- {
- if (ptr[1] == CHAR_CIRCUMFLEX_ACCENT)
- {
- *negptr = TRUE;
- ptr++;
- }
- for (i = 0; i < (int)(sizeof(name) / sizeof(pcre_uchar)) - 1; i++)
- {
- c = *(++ptr);
- if (c == CHAR_NULL) goto ERROR_RETURN;
- if (c == CHAR_RIGHT_CURLY_BRACKET) break;
- name[i] = c;
}
- if (c != CHAR_RIGHT_CURLY_BRACKET) goto ERROR_RETURN;
- name[i] = 0;
- }
-
-/* Otherwise there is just one following character */
-
-else
- {
- name[0] = c;
- name[1] = 0;
- }
-
-*ptrptr = ptr;
-/* Search for a recognized property name using binary chop */
-
-bot = 0;
-top = PRIV(utt_size);
-
-while (bot < top)
- {
- int r;
- i = (bot + top) >> 1;
- r = STRCMP_UC_C8(name, PRIV(utt_names) + PRIV(utt)[i].name_offset);
- if (r == 0)
- {
- *ptypeptr = PRIV(utt)[i].type;
- *pdataptr = PRIV(utt)[i].value;
- return TRUE;
- }
- if (r > 0) bot = i + 1; else top = i;
+ code->memctl.free(code, code->memctl.memory_data);
}
-
-*errorcodeptr = ERR47;
-*ptrptr = ptr;
-return FALSE;
-
-ERROR_RETURN:
-*errorcodeptr = ERR46;
-*ptrptr = ptr;
-return FALSE;
}
-#endif
/*************************************************
-* Read repeat counts *
+* Insert an automatic callout point *
*************************************************/
-/* Read an item of the form {n,m} and return the values. This is called only
-after is_counted_repeat() has confirmed that a repeat-count quantifier exists,
-so the syntax is guaranteed to be correct, but we need to check the values.
+/* This function is called when the PCRE2_AUTO_CALLOUT option is set, to insert
+callout points before each pattern item.
Arguments:
- p pointer to first char after '{'
- minp pointer to int for min
- maxp pointer to int for max
- returned as -1 if no max
- errorcodeptr points to error code variable
+ code current code pointer
+ ptr current pattern pointer
+ cb general compile-time data
-Returns: pointer to '}' on success;
- current ptr on error, with errorcodeptr set non-zero
+Returns: new code pointer
*/
-static const pcre_uchar *
-read_repeat_counts(const pcre_uchar *p, int *minp, int *maxp, int *errorcodeptr)
+static PCRE2_UCHAR *
+auto_callout(PCRE2_UCHAR *code, PCRE2_SPTR ptr, compile_block *cb)
{
-int min = 0;
-int max = -1;
-
-while (IS_DIGIT(*p))
- {
- min = min * 10 + (int)(*p++ - CHAR_0);
- if (min > 65535)
- {
- *errorcodeptr = ERR5;
- return p;
- }
- }
-
-if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else
- {
- if (*(++p) != CHAR_RIGHT_CURLY_BRACKET)
- {
- max = 0;
- while(IS_DIGIT(*p))
- {
- max = max * 10 + (int)(*p++ - CHAR_0);
- if (max > 65535)
- {
- *errorcodeptr = ERR5;
- return p;
- }
- }
- if (max < min)
- {
- *errorcodeptr = ERR4;
- return p;
- }
- }
- }
-
-*minp = min;
-*maxp = max;
-return p;
+code[0] = OP_CALLOUT;
+PUT(code, 1, ptr - cb->start_pattern); /* Pattern offset */
+PUT(code, 1 + LINK_SIZE, 0); /* Default length */
+code[1 + 2*LINK_SIZE] = 255;
+return code + PRIV(OP_lengths)[OP_CALLOUT];
}
/*************************************************
-* Find first significant op code *
+* Complete a callout item *
*************************************************/
-/* This is called by several functions that scan a compiled expression looking
-for a fixed first character, or an anchoring op code etc. It skips over things
-that do not influence this. For some calls, it makes sense to skip negative
-forward and all backward assertions, and also the \b assertion; for others it
-does not.
+/* A callout item contains the length of the next item in the pattern, which
+we can't fill in till after we have reached the relevant point. This is used
+for both automatic and manual callouts.
Arguments:
- code pointer to the start of the group
- skipassert TRUE if certain assertions are to be skipped
+ previous_callout points to previous callout item
+ ptr current pattern pointer
+ cb general compile-time data
-Returns: pointer to the first significant opcode
+Returns: nothing
*/
-static const pcre_uchar*
-first_significant_code(const pcre_uchar *code, BOOL skipassert)
+static void
+complete_callout(PCRE2_UCHAR *previous_callout, PCRE2_SPTR ptr,
+ compile_block *cb)
{
-for (;;)
- {
- switch ((int)*code)
- {
- case OP_ASSERT_NOT:
- case OP_ASSERTBACK:
- case OP_ASSERTBACK_NOT:
- if (!skipassert) return code;
- do code += GET(code, 1); while (*code == OP_ALT);
- code += PRIV(OP_lengths)[*code];
- break;
-
- case OP_WORD_BOUNDARY:
- case OP_NOT_WORD_BOUNDARY:
- if (!skipassert) return code;
- /* Fall through */
-
- case OP_CALLOUT:
- case OP_CREF:
- case OP_DNCREF:
- case OP_RREF:
- case OP_DNRREF:
- case OP_DEF:
- code += PRIV(OP_lengths)[*code];
- break;
-
- default:
- return code;
- }
- }
-/* Control never reaches here */
+size_t length = (size_t)(ptr - cb->start_pattern - GET(previous_callout, 1));
+PUT(previous_callout, 1 + LINK_SIZE, length);
}
@@ -1708,39 +854,77 @@ for (;;)
* Find the fixed length of a branch *
*************************************************/
-/* Scan a branch and compute the fixed length of subject that will match it,
-if the length is fixed. This is needed for dealing with backward assertions.
-In UTF8 mode, the result is in characters rather than bytes. The branch is
+/* Scan a branch and compute the fixed length of subject that will match it, if
+the length is fixed. This is needed for dealing with lookbehind assertions. In
+UTF mode, the result is in code units rather than bytes. The branch is
temporarily terminated with OP_END when this function is called.
-This function is called when a backward assertion is encountered, so that if it
-fails, the error message can point to the correct place in the pattern.
+This function is called when a lookbehind assertion is encountered, so that if
+it fails, the error message can point to the correct place in the pattern.
However, we cannot do this when the assertion contains subroutine calls,
because they can be forward references. We solve this by remembering this case
and doing the check at the end; a flag specifies which mode we are running in.
+Lookbehind lengths are held in 16-bit fields and the maximum value is defined
+as LOOKBEHIND_MAX.
+
Arguments:
- code points to the start of the pattern (the bracket)
- utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
- atend TRUE if called when the pattern is complete
- cd the "compile data" structure
+ code points to the start of the pattern (the bracket)
+ utf TRUE in UTF mode
+ atend TRUE if called when the pattern is complete
+ cb the "compile data" structure
recurses chain of recurse_check to catch mutual recursion
-
-Returns: the fixed length,
- or -1 if there is no fixed length,
- or -2 if \C was encountered (in UTF-8 mode only)
- or -3 if an OP_RECURSE item was encountered and atend is FALSE
- or -4 if an unknown opcode was encountered (internal error)
+ countptr pointer to counter, to catch over-complexity
+
+Returns: if non-negative, the fixed length,
+ or -1 if an OP_RECURSE item was encountered and atend is FALSE
+ or -2 if there is no fixed length,
+ or -3 if \C was encountered (in UTF mode only)
+ or -4 if length is too long
+ or -5 if regex is too complicated
+ or -6 if an unknown opcode was encountered (internal error)
*/
+#define FFL_LATER (-1)
+#define FFL_NOTFIXED (-2)
+#define FFL_BACKSLASHC (-3)
+#define FFL_TOOLONG (-4)
+#define FFL_TOOCOMPLICATED (-5)
+#define FFL_UNKNOWNOP (-6)
+
static int
-find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd,
- recurse_check *recurses)
+find_fixedlength(PCRE2_UCHAR *code, BOOL utf, BOOL atend, compile_block *cb,
+ recurse_check *recurses, int *countptr)
{
-int length = -1;
+uint32_t length = 0xffffffffu; /* Unset */
+uint32_t group = 0;
+uint32_t groupinfo = 0;
recurse_check this_recurse;
-register int branchlength = 0;
-register pcre_uchar *cc = code + 1 + LINK_SIZE;
+register uint32_t branchlength = 0;
+register PCRE2_UCHAR *cc = code + 1 + LINK_SIZE;
+
+/* If this is a capturing group, we may have the answer cached, but we can only
+use this information if there are no (?| groups in the pattern, because
+otherwise group numbers are not unique. */
+
+if (*code == OP_CBRA || *code == OP_CBRAPOS || *code == OP_SCBRA ||
+ *code == OP_SCBRAPOS)
+ {
+ group = GET2(cc, 0);
+ cc += IMM2_SIZE;
+ groupinfo = cb->groupinfo[group];
+ if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0)
+ {
+ if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return FFL_NOTFIXED;
+ if ((groupinfo & GI_SET_FIXED_LENGTH) != 0)
+ return groupinfo & GI_FIXED_LENGTH_MASK;
+ }
+ }
+
+/* A large and/or complex regex can take too long to process. This can happen
+more often when (?| groups are present in the pattern. */
+
+if ((*countptr)++ > 2000) return FFL_TOOCOMPLICATED;
/* Scan along the opcodes for this branch. If we get to the end of the
branch, check the length against that of the other branches. */
@@ -1748,8 +932,10 @@ branch, check the length against that of the other branches. */
for (;;)
{
int d;
- pcre_uchar *ce, *cs;
- register pcre_uchar op = *cc;
+ PCRE2_UCHAR *ce, *cs;
+ register PCRE2_UCHAR op = *cc;
+
+ if (branchlength > LOOKBEHIND_MAX) return FFL_TOOLONG;
switch (op)
{
@@ -1763,10 +949,9 @@ for (;;)
case OP_ONCE:
case OP_ONCE_NC:
case OP_COND:
- d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd,
- recurses);
+ d = find_fixedlength(cc, utf, atend, cb, recurses, countptr);
if (d < 0) return d;
- branchlength += d;
+ branchlength += (uint32_t)d;
do cc += GET(cc, 1); while (*cc == OP_ALT);
cc += 1 + LINK_SIZE;
break;
@@ -1782,37 +967,49 @@ for (;;)
case OP_END:
case OP_ACCEPT:
case OP_ASSERT_ACCEPT:
- if (length < 0) length = branchlength;
- else if (length != branchlength) return -1;
- if (*cc != OP_ALT) return length;
+ if (length == 0xffffffffu) length = branchlength;
+ else if (length != branchlength) goto ISNOTFIXED;
+ if (*cc != OP_ALT)
+ {
+ if (group > 0)
+ {
+ groupinfo |= (uint32_t)(GI_SET_FIXED_LENGTH | length);
+ cb->groupinfo[group] = groupinfo;
+ }
+ return (int)length;
+ }
cc += 1 + LINK_SIZE;
branchlength = 0;
break;
/* A true recursion implies not fixed length, but a subroutine call may
be OK. If the subroutine is a forward reference, we can't deal with
- it until the end of the pattern, so return -3. */
+ it until the end of the pattern, so return FFL_LATER. */
case OP_RECURSE:
- if (!atend) return -3;
- cs = ce = (pcre_uchar *)cd->start_code + GET(cc, 1); /* Start subpattern */
+ if (!atend) return FFL_LATER;
+ cs = ce = (PCRE2_UCHAR *)cb->start_code + GET(cc, 1); /* Start subpattern */
do ce += GET(ce, 1); while (*ce == OP_ALT); /* End subpattern */
- if (cc > cs && cc < ce) return -1; /* Recursion */
+ if (cc > cs && cc < ce) goto ISNOTFIXED; /* Recursion */
else /* Check for mutual recursion */
{
recurse_check *r = recurses;
for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
- if (r != NULL) return -1; /* Mutual recursion */
+ if (r != NULL) goto ISNOTFIXED; /* Mutual recursion */
}
this_recurse.prev = recurses;
this_recurse.group = cs;
- d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd, &this_recurse);
+ d = find_fixedlength(cs, utf, atend, cb, &this_recurse, countptr);
if (d < 0) return d;
- branchlength += d;
+ branchlength += (uint32_t)d;
cc += 1 + LINK_SIZE;
break;
- /* Skip over assertive subpatterns */
+ /* Skip over assertive subpatterns. Note that we must increment cc by
+ 1 + LINK_SIZE at the end, not by OP_length[*cc] because in a recursive
+ situation this assertion may be the one that is ultimately being checked
+ for having a fixed length, in which case its terminating OP_KET will have
+ been temporarily replaced by OP_END. */
case OP_ASSERT:
case OP_ASSERT_NOT:
@@ -1837,7 +1034,8 @@ for (;;)
case OP_CLOSE:
case OP_COMMIT:
case OP_CREF:
- case OP_DEF:
+ case OP_FALSE:
+ case OP_TRUE:
case OP_DNCREF:
case OP_DNRREF:
case OP_DOLL:
@@ -1858,6 +1056,10 @@ for (;;)
cc += PRIV(OP_lengths)[*cc];
break;
+ case OP_CALLOUT_STR:
+ cc += GET(cc, 1 + 2*LINK_SIZE);
+ break;
+
/* Handle literal characters */
case OP_CHAR:
@@ -1866,7 +1068,7 @@ for (;;)
case OP_NOTI:
branchlength++;
cc += 2;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -1878,9 +1080,9 @@ for (;;)
case OP_EXACTI:
case OP_NOTEXACT:
case OP_NOTEXACTI:
- branchlength += (int)GET2(cc,1);
+ branchlength += GET2(cc,1);
cc += 2 + IMM2_SIZE;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -1915,17 +1117,17 @@ for (;;)
cc++;
break;
- /* The single-byte matcher isn't allowed. This only happens in UTF-8 mode;
- otherwise \C is coded as OP_ALLANY. */
+ /* The single-byte matcher isn't allowed. This only happens in UTF-8 or
+ UTF-16 mode; otherwise \C is coded as OP_ALLANY. */
case OP_ANYBYTE:
- return -2;
+ return FFL_BACKSLASHC;
/* Check a class for variable quantification */
case OP_CLASS:
case OP_NCLASS:
-#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#ifdef SUPPORT_WIDE_CHARS
case OP_XCLASS:
/* The original code caused an unsigned overflow in 64 bit systems,
so now we use a conditional statement. */
@@ -1948,13 +1150,13 @@ for (;;)
case OP_CRPOSSTAR:
case OP_CRPOSPLUS:
case OP_CRPOSQUERY:
- return -1;
+ goto ISNOTFIXED;
case OP_CRRANGE:
case OP_CRMINRANGE:
case OP_CRPOSRANGE:
- if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) return -1;
- branchlength += (int)GET2(cc,1);
+ if (GET2(cc,1) != GET2(cc,1+IMM2_SIZE)) goto ISNOTFIXED;
+ branchlength += GET2(cc,1);
cc += 1 + 2 * IMM2_SIZE;
break;
@@ -2045,328 +1247,84 @@ for (;;)
case OP_TYPEUPTO:
case OP_UPTO:
case OP_UPTOI:
- return -1;
+ goto ISNOTFIXED;
/* Catch unrecognized opcodes so that when new ones are added they
are not forgotten, as has happened in the past. */
default:
- return -4;
+ return FFL_UNKNOWNOP;
}
}
-/* Control never gets here */
-}
-
-
-
-/*************************************************
-* Scan compiled regex for specific bracket *
-*************************************************/
-
-/* This little function scans through a compiled pattern until it finds a
-capturing bracket with the given number, or, if the number is negative, an
-instance of OP_REVERSE for a lookbehind. The function is global in the C sense
-so that it can be called from pcre_study() when finding the minimum matching
-length.
+/* Control never gets here except by goto. */
-Arguments:
- code points to start of expression
- utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
- number the required bracket number or negative to find a lookbehind
-
-Returns: pointer to the opcode for the bracket, or NULL if not found
-*/
-
-const pcre_uchar *
-PRIV(find_bracket)(const pcre_uchar *code, BOOL utf, int number)
-{
-for (;;)
+ISNOTFIXED:
+if (group > 0)
{
- register pcre_uchar c = *code;
-
- if (c == OP_END) return NULL;
-
- /* XCLASS is used for classes that cannot be represented just by a bit
- map. This includes negated single high-valued characters. The length in
- the table is zero; the actual length is stored in the compiled code. */
-
- if (c == OP_XCLASS) code += GET(code, 1);
-
- /* Handle recursion */
-
- else if (c == OP_REVERSE)
- {
- if (number < 0) return (pcre_uchar *)code;
- code += PRIV(OP_lengths)[c];
- }
-
- /* Handle capturing bracket */
-
- else if (c == OP_CBRA || c == OP_SCBRA ||
- c == OP_CBRAPOS || c == OP_SCBRAPOS)
- {
- int n = (int)GET2(code, 1+LINK_SIZE);
- if (n == number) return (pcre_uchar *)code;
- code += PRIV(OP_lengths)[c];
- }
-
- /* Otherwise, we can get the item's length from the table, except that for
- repeated character types, we have to test for \p and \P, which have an extra
- two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we
- must add in its length. */
-
- else
- {
- switch(c)
- {
- case OP_TYPESTAR:
- case OP_TYPEMINSTAR:
- case OP_TYPEPLUS:
- case OP_TYPEMINPLUS:
- case OP_TYPEQUERY:
- case OP_TYPEMINQUERY:
- case OP_TYPEPOSSTAR:
- case OP_TYPEPOSPLUS:
- case OP_TYPEPOSQUERY:
- if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
- break;
-
- case OP_TYPEUPTO:
- case OP_TYPEMINUPTO:
- case OP_TYPEEXACT:
- case OP_TYPEPOSUPTO:
- if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
- code += 2;
- break;
-
- case OP_MARK:
- case OP_PRUNE_ARG:
- case OP_SKIP_ARG:
- case OP_THEN_ARG:
- code += code[1];
- break;
- }
-
- /* Add in the fixed length from the table */
-
- code += PRIV(OP_lengths)[c];
-
- /* In UTF-8 mode, opcodes that are followed by a character may be followed by
- a multi-byte character. The length in the table is a minimum, so we have to
- arrange to skip the extra bytes. */
-
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
- if (utf) switch(c)
- {
- case OP_CHAR:
- case OP_CHARI:
- case OP_NOT:
- case OP_NOTI:
- case OP_EXACT:
- case OP_EXACTI:
- case OP_NOTEXACT:
- case OP_NOTEXACTI:
- case OP_UPTO:
- case OP_UPTOI:
- case OP_NOTUPTO:
- case OP_NOTUPTOI:
- case OP_MINUPTO:
- case OP_MINUPTOI:
- case OP_NOTMINUPTO:
- case OP_NOTMINUPTOI:
- case OP_POSUPTO:
- case OP_POSUPTOI:
- case OP_NOTPOSUPTO:
- case OP_NOTPOSUPTOI:
- case OP_STAR:
- case OP_STARI:
- case OP_NOTSTAR:
- case OP_NOTSTARI:
- case OP_MINSTAR:
- case OP_MINSTARI:
- case OP_NOTMINSTAR:
- case OP_NOTMINSTARI:
- case OP_POSSTAR:
- case OP_POSSTARI:
- case OP_NOTPOSSTAR:
- case OP_NOTPOSSTARI:
- case OP_PLUS:
- case OP_PLUSI:
- case OP_NOTPLUS:
- case OP_NOTPLUSI:
- case OP_MINPLUS:
- case OP_MINPLUSI:
- case OP_NOTMINPLUS:
- case OP_NOTMINPLUSI:
- case OP_POSPLUS:
- case OP_POSPLUSI:
- case OP_NOTPOSPLUS:
- case OP_NOTPOSPLUSI:
- case OP_QUERY:
- case OP_QUERYI:
- case OP_NOTQUERY:
- case OP_NOTQUERYI:
- case OP_MINQUERY:
- case OP_MINQUERYI:
- case OP_NOTMINQUERY:
- case OP_NOTMINQUERYI:
- case OP_POSQUERY:
- case OP_POSQUERYI:
- case OP_NOTPOSQUERY:
- case OP_NOTPOSQUERYI:
- if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
- break;
- }
-#else
- (void)(utf); /* Keep compiler happy by referencing function argument */
-#endif
- }
+ groupinfo |= GI_NOT_FIXED_LENGTH;
+ cb->groupinfo[group] = groupinfo;
}
+return FFL_NOTFIXED;
}
/*************************************************
-* Scan compiled regex for recursion reference *
+* Find first significant op code *
*************************************************/
-/* This little function scans through a compiled pattern until it finds an
-instance of OP_RECURSE.
+/* This is called by several functions that scan a compiled expression looking
+for a fixed first character, or an anchoring op code etc. It skips over things
+that do not influence this. For some calls, it makes sense to skip negative
+forward and all backward assertions, and also the \b assertion; for others it
+does not.
Arguments:
- code points to start of expression
- utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
+ code pointer to the start of the group
+ skipassert TRUE if certain assertions are to be skipped
-Returns: pointer to the opcode for OP_RECURSE, or NULL if not found
+Returns: pointer to the first significant opcode
*/
-static const pcre_uchar *
-find_recurse(const pcre_uchar *code, BOOL utf)
+static const PCRE2_UCHAR*
+first_significant_code(PCRE2_SPTR code, BOOL skipassert)
{
for (;;)
{
- register pcre_uchar c = *code;
- if (c == OP_END) return NULL;
- if (c == OP_RECURSE) return code;
-
- /* XCLASS is used for classes that cannot be represented just by a bit
- map. This includes negated single high-valued characters. The length in
- the table is zero; the actual length is stored in the compiled code. */
-
- if (c == OP_XCLASS) code += GET(code, 1);
-
- /* Otherwise, we can get the item's length from the table, except that for
- repeated character types, we have to test for \p and \P, which have an extra
- two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we
- must add in its length. */
-
- else
+ switch ((int)*code)
{
- switch(c)
- {
- case OP_TYPESTAR:
- case OP_TYPEMINSTAR:
- case OP_TYPEPLUS:
- case OP_TYPEMINPLUS:
- case OP_TYPEQUERY:
- case OP_TYPEMINQUERY:
- case OP_TYPEPOSSTAR:
- case OP_TYPEPOSPLUS:
- case OP_TYPEPOSQUERY:
- if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
- break;
-
- case OP_TYPEPOSUPTO:
- case OP_TYPEUPTO:
- case OP_TYPEMINUPTO:
- case OP_TYPEEXACT:
- if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
- code += 2;
- break;
-
- case OP_MARK:
- case OP_PRUNE_ARG:
- case OP_SKIP_ARG:
- case OP_THEN_ARG:
- code += code[1];
- break;
- }
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ if (!skipassert) return code;
+ do code += GET(code, 1); while (*code == OP_ALT);
+ code += PRIV(OP_lengths)[*code];
+ break;
- /* Add in the fixed length from the table */
+ case OP_WORD_BOUNDARY:
+ case OP_NOT_WORD_BOUNDARY:
+ if (!skipassert) return code;
+ /* Fall through */
- code += PRIV(OP_lengths)[c];
+ case OP_CALLOUT:
+ case OP_CREF:
+ case OP_DNCREF:
+ case OP_RREF:
+ case OP_DNRREF:
+ case OP_FALSE:
+ case OP_TRUE:
+ code += PRIV(OP_lengths)[*code];
+ break;
- /* In UTF-8 mode, opcodes that are followed by a character may be followed
- by a multi-byte character. The length in the table is a minimum, so we have
- to arrange to skip the extra bytes. */
+ case OP_CALLOUT_STR:
+ code += GET(code, 1 + 2*LINK_SIZE);
+ break;
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
- if (utf) switch(c)
- {
- case OP_CHAR:
- case OP_CHARI:
- case OP_NOT:
- case OP_NOTI:
- case OP_EXACT:
- case OP_EXACTI:
- case OP_NOTEXACT:
- case OP_NOTEXACTI:
- case OP_UPTO:
- case OP_UPTOI:
- case OP_NOTUPTO:
- case OP_NOTUPTOI:
- case OP_MINUPTO:
- case OP_MINUPTOI:
- case OP_NOTMINUPTO:
- case OP_NOTMINUPTOI:
- case OP_POSUPTO:
- case OP_POSUPTOI:
- case OP_NOTPOSUPTO:
- case OP_NOTPOSUPTOI:
- case OP_STAR:
- case OP_STARI:
- case OP_NOTSTAR:
- case OP_NOTSTARI:
- case OP_MINSTAR:
- case OP_MINSTARI:
- case OP_NOTMINSTAR:
- case OP_NOTMINSTARI:
- case OP_POSSTAR:
- case OP_POSSTARI:
- case OP_NOTPOSSTAR:
- case OP_NOTPOSSTARI:
- case OP_PLUS:
- case OP_PLUSI:
- case OP_NOTPLUS:
- case OP_NOTPLUSI:
- case OP_MINPLUS:
- case OP_MINPLUSI:
- case OP_NOTMINPLUS:
- case OP_NOTMINPLUSI:
- case OP_POSPLUS:
- case OP_POSPLUSI:
- case OP_NOTPOSPLUS:
- case OP_NOTPOSPLUSI:
- case OP_QUERY:
- case OP_QUERYI:
- case OP_NOTQUERY:
- case OP_NOTQUERYI:
- case OP_MINQUERY:
- case OP_MINQUERYI:
- case OP_NOTMINQUERY:
- case OP_NOTMINQUERYI:
- case OP_POSQUERY:
- case OP_POSQUERYI:
- case OP_NOTPOSQUERY:
- case OP_NOTPOSQUERYI:
- if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
- break;
- }
-#else
- (void)(utf); /* Keep compiler happy by referencing function argument */
-#endif
+ default:
+ return code;
}
}
+/* Control never reaches here */
}
@@ -2376,35 +1334,77 @@ for (;;)
*************************************************/
/* This function scans through a branch of a compiled pattern to see whether it
-can match the empty string or not. It is called from could_be_empty()
-below and from compile_branch() when checking for an unlimited repeat of a
-group that can match nothing. Note that first_significant_code() skips over
-backward and negative forward assertions when its final argument is TRUE. If we
-hit an unclosed bracket, we return "empty" - this means we've struck an inner
-bracket whose current branch will already have been scanned.
+can match the empty string. It is called at the end of compiling to check the
+entire pattern, and from compile_branch() when checking for an unlimited repeat
+of a group that can match nothing. In the latter case it is called only when
+doing the real compile, not during the pre-compile that measures the size of
+the compiled pattern.
+
+Note that first_significant_code() skips over backward and negative forward
+assertions when its final argument is TRUE. If we hit an unclosed bracket, we
+return "empty" - this means we've struck an inner bracket whose current branch
+will already have been scanned.
Arguments:
code points to start of search
endcode points to where to stop
- utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode
- cd contains pointers to tables etc.
+ utf TRUE if in UTF mode
+ cb compile data
+ atend TRUE if being called to check an entire pattern
recurses chain of recurse_check to catch mutual recursion
+ countptr pointer to count to catch over-complicated pattern
-Returns: TRUE if what is matched could be empty
+Returns: 0 if what is matched cannot be empty
+ 1 if what is matched could be empty
+ -1 if the pattern is too complicated
*/
-static BOOL
-could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode,
- BOOL utf, compile_data *cd, recurse_check *recurses)
+#define CBE_NOTEMPTY 0
+#define CBE_EMPTY 1
+#define CBE_TOOCOMPLICATED (-1)
+
+
+static int
+could_be_empty_branch(PCRE2_SPTR code, PCRE2_SPTR endcode, BOOL utf,
+ compile_block *cb, BOOL atend, recurse_check *recurses, int *countptr)
{
-register pcre_uchar c;
+uint32_t group = 0;
+uint32_t groupinfo = 0;
+register PCRE2_UCHAR c;
recurse_check this_recurse;
+/* If what we are checking has already been set as "could be empty", we know
+the answer. */
+
+if (*code >= OP_SBRA && *code <= OP_SCOND) return CBE_EMPTY;
+
+/* If this is a capturing group, we may have the answer cached, but we can only
+use this information if there are no (?| groups in the pattern, because
+otherwise group numbers are not unique. */
+
+if ((cb->external_flags & PCRE2_DUPCAPUSED) == 0 &&
+ (*code == OP_CBRA || *code == OP_CBRAPOS))
+ {
+ group = GET2(code, 1 + LINK_SIZE);
+ groupinfo = cb->groupinfo[group];
+ if ((groupinfo & GI_SET_COULD_BE_EMPTY) != 0)
+ return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY;
+ }
+
+/* A large and/or complex regex can take too long to process. We have to assume
+it can match an empty string. This can happen more often when (?| groups are
+present in the pattern and the caching is disabled. Setting the cap at 1100
+allows the test for more than 1023 capturing patterns to work. */
+
+if ((*countptr)++ > 1100) return CBE_TOOCOMPLICATED;
+
+/* Scan the opcodes for this branch. */
+
for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
code < endcode;
code = first_significant_code(code + PRIV(OP_lengths)[c], TRUE))
{
- const pcre_uchar *ccode;
+ PCRE2_SPTR ccode;
c = *code;
@@ -2418,35 +1418,27 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
continue;
}
- /* For a recursion/subroutine call, if its end has been reached, which
- implies a backward reference subroutine call, we can scan it. If it's a
- forward reference subroutine call, we can't. To detect forward reference
- we have to scan up the list that is kept in the workspace. This function is
- called only when doing the real compile, not during the pre-compile that
- measures the size of the compiled pattern. */
+ /* For a recursion/subroutine call we can scan the recursion when this
+ function is called at the end, to check a complete pattern. Before then,
+ recursions just have the group number as their argument and in any case may
+ be forward references. In that situation, we return CBE_EMPTY, just in case.
+ It means that unlimited repeats of groups that contain recursions are always
+ treated as "could be empty" - which just adds a bit more processing time
+ because of the runtime check. */
if (c == OP_RECURSE)
{
- const pcre_uchar *scode = cd->start_code + GET(code, 1);
- const pcre_uchar *endgroup = scode;
+ PCRE2_SPTR scode, endgroup;
BOOL empty_branch;
- /* Test for forward reference or uncompleted reference. This is disabled
- when called to scan a completed pattern by setting cd->start_workspace to
- NULL. */
-
- if (cd->start_workspace != NULL)
- {
- const pcre_uchar *tcode;
- for (tcode = cd->start_workspace; tcode < cd->hwm; tcode += LINK_SIZE)
- if ((int)GET(tcode, 0) == (int)(code + 1 - cd->start_code)) return TRUE;
- if (GET(scode, 1) == 0) return TRUE; /* Unclosed */
- }
+ if (!atend) goto ISTRUE;
+ scode = cb->start_code + GET(code, 1);
+ endgroup = scode;
- /* If the reference is to a completed group, we need to detect whether this
- is a recursive call, as otherwise there will be an infinite loop. If it is
- a recursion, just skip over it. Simple recursions are easily detected. For
- mutual recursions we keep a chain on the stack. */
+ /* We need to detect whether this is a recursive call, as otherwise there
+ will be an infinite loop. If it is a recursion, just skip over it. Simple
+ recursions are easily detected. For mutual recursions we keep a chain on
+ the stack. */
do endgroup += GET(endgroup, 1); while (*endgroup == OP_ALT);
if (code >= scode && code <= endgroup) continue; /* Simple recursion */
@@ -2458,8 +1450,8 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
if (r != NULL) continue; /* Mutual recursion */
}
- /* Completed reference; scan the referenced group, remembering it on the
- stack chain to detect mutual recursions. */
+ /* Scan the referenced group, remembering it on the stack chain to detect
+ mutual recursions. */
empty_branch = FALSE;
this_recurse.prev = recurses;
@@ -2467,7 +1459,10 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
do
{
- if (could_be_empty_branch(scode, endcode, utf, cd, &this_recurse))
+ int rc = could_be_empty_branch(scode, endcode, utf, cb, atend,
+ &this_recurse, countptr);
+ if (rc < 0) return rc;
+ if (rc > 0)
{
empty_branch = TRUE;
break;
@@ -2476,7 +1471,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
}
while (*scode == OP_ALT);
- if (!empty_branch) return FALSE; /* All branches are non-empty */
+ if (!empty_branch) goto ISFALSE; /* All branches are non-empty */
continue;
}
@@ -2510,7 +1505,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
c == OP_COND || c == OP_SCOND)
{
BOOL empty_branch;
- if (GET(code, 1) == 0) return TRUE; /* Hit unclosed bracket */
+ if (GET(code, 1) == 0) goto ISTRUE; /* Hit unclosed bracket */
/* If a conditional group has only one branch, there is a second, implied,
empty branch, so just skip over the conditional, because it could be empty.
@@ -2523,12 +1518,17 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
empty_branch = FALSE;
do
{
- if (!empty_branch && could_be_empty_branch(code, endcode, utf, cd,
- recurses)) empty_branch = TRUE;
+ if (!empty_branch)
+ {
+ int rc = could_be_empty_branch(code, endcode, utf, cb, atend,
+ recurses, countptr);
+ if (rc < 0) return rc;
+ if (rc > 0) empty_branch = TRUE;
+ }
code += GET(code, 1);
}
while (*code == OP_ALT);
- if (!empty_branch) return FALSE; /* All branches are non-empty */
+ if (!empty_branch) goto ISFALSE; /* All branches are non-empty */
}
c = *code;
@@ -2545,7 +1545,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
actual length is stored in the compiled code, so we must update "code"
here. */
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
case OP_XCLASS:
ccode = code += GET(code, 1);
goto CHECK_CLASS_REPEAT;
@@ -2555,7 +1555,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
case OP_NCLASS:
ccode = code + PRIV(OP_lengths)[OP_CLASS];
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
CHECK_CLASS_REPEAT:
#endif
@@ -2573,12 +1573,12 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
case OP_CRPLUS: /* These repeats aren't empty */
case OP_CRMINPLUS:
case OP_CRPOSPLUS:
- return FALSE;
+ goto ISFALSE;
case OP_CRRANGE:
case OP_CRMINRANGE:
case OP_CRPOSRANGE:
- if (GET2(ccode, 1) > 0) return FALSE; /* Minimum > 0 */
+ if (GET2(ccode, 1) > 0) goto ISFALSE; /* Minimum > 0 */
break;
}
break;
@@ -2635,8 +1635,7 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
case OP_TYPEMINPLUS:
case OP_TYPEPOSPLUS:
case OP_TYPEEXACT:
-
- return FALSE;
+ goto ISFALSE;
/* These are going to continue, as they may be empty, but we have to
fudge the length for the \p and \P cases. */
@@ -2666,13 +1665,13 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
case OP_KETRMIN:
case OP_KETRPOS:
case OP_ALT:
- return TRUE;
+ goto ISTRUE;
- /* In UTF-8 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY, POSQUERY, UPTO,
- MINUPTO, and POSUPTO and their caseless and negative versions may be
- followed by a multibyte character. */
+ /* In UTF-8 or UTF-16 mode, STAR, MINSTAR, POSSTAR, QUERY, MINQUERY,
+ POSQUERY, UPTO, MINUPTO, and POSUPTO and their caseless and negative
+ versions may be followed by a multibyte character. */
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#ifdef MAYBE_UTF_MULTI
case OP_STAR:
case OP_STARI:
case OP_NOTSTAR:
@@ -2702,7 +1701,6 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
case OP_POSQUERYI:
case OP_NOTPOSQUERY:
case OP_NOTPOSQUERYI:
-
if (utf && HAS_EXTRALEN(code[1])) code += GET_EXTRALEN(code[1]);
break;
@@ -2720,10 +1718,9 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
case OP_POSUPTOI:
case OP_NOTPOSUPTO:
case OP_NOTPOSUPTOI:
-
if (utf && HAS_EXTRALEN(code[1 + IMM2_SIZE])) code += GET_EXTRALEN(code[1 + IMM2_SIZE]);
break;
-#endif
+#endif /* MAYBE_UTF_MULTI */
/* MARK, and PRUNE/SKIP/THEN with an argument must skip over the argument
string. */
@@ -2742,1147 +1739,869 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
}
}
-return TRUE;
+ISTRUE:
+groupinfo |= GI_COULD_BE_EMPTY;
+
+ISFALSE:
+if (group > 0) cb->groupinfo[group] = groupinfo | GI_SET_COULD_BE_EMPTY;
+
+return ((groupinfo & GI_COULD_BE_EMPTY) != 0)? CBE_EMPTY : CBE_NOTEMPTY;
}
/*************************************************
-* Scan compiled regex for non-emptiness *
+* Check for counted repeat *
*************************************************/
-/* This function is called to check for left recursive calls. We want to check
-the current branch of the current pattern to see if it could match the empty
-string. If it could, we must look outwards for branches at other levels,
-stopping when we pass beyond the bracket which is the subject of the recursion.
-This function is called only during the real compile, not during the
-pre-compile.
-
-Arguments:
- code points to start of the recursion
- endcode points to where to stop (current RECURSE item)
- bcptr points to the chain of current (unclosed) branch starts
- utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode
- cd pointers to tables etc
+/* This function is called when a '{' is encountered in a place where it might
+start a quantifier. It looks ahead to see if it really is a quantifier, that
+is, one of the forms {ddd} {ddd,} or {ddd,ddd} where the ddds are digits.
-Returns: TRUE if what is matched could be empty
+Argument: pointer to the first char after '{'
+Returns: TRUE or FALSE
*/
static BOOL
-could_be_empty(const pcre_uchar *code, const pcre_uchar *endcode,
- branch_chain *bcptr, BOOL utf, compile_data *cd)
+is_counted_repeat(PCRE2_SPTR p)
{
-while (bcptr != NULL && bcptr->current_branch >= code)
- {
- if (!could_be_empty_branch(bcptr->current_branch, endcode, utf, cd, NULL))
- return FALSE;
- bcptr = bcptr->outer;
- }
-return TRUE;
-}
-
-
-
-/*************************************************
-* Base opcode of repeated opcodes *
-*************************************************/
+if (!IS_DIGIT(*p)) return FALSE;
+p++;
+while (IS_DIGIT(*p)) p++;
+if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;
-/* Returns the base opcode for repeated single character type opcodes. If the
-opcode is not a repeated character type, it returns with the original value.
+if (*p++ != CHAR_COMMA) return FALSE;
+if (*p == CHAR_RIGHT_CURLY_BRACKET) return TRUE;
-Arguments: c opcode
-Returns: base opcode for the type
-*/
+if (!IS_DIGIT(*p)) return FALSE;
+p++;
+while (IS_DIGIT(*p)) p++;
-static pcre_uchar
-get_repeat_base(pcre_uchar c)
-{
-return (c > OP_TYPEPOSUPTO)? c :
- (c >= OP_TYPESTAR)? OP_TYPESTAR :
- (c >= OP_NOTSTARI)? OP_NOTSTARI :
- (c >= OP_NOTSTAR)? OP_NOTSTAR :
- (c >= OP_STARI)? OP_STARI :
- OP_STAR;
+return (*p == CHAR_RIGHT_CURLY_BRACKET);
}
-#ifdef SUPPORT_UCP
/*************************************************
-* Check a character and a property *
+* Handle escapes *
*************************************************/
-/* This function is called by check_auto_possessive() when a property item
-is adjacent to a fixed character.
+/* This function is called when a \ has been encountered. It either returns a
+positive value for a simple escape such as \d, or 0 for a data character, which
+is placed in chptr. A backreference to group n is returned as negative n. On
+entry, ptr is pointing at the \. On exit, it points the final code unit of the
+escape sequence.
+
+This function is also called from pcre2_substitute() to handle escape sequences
+in replacement strings. In this case, the cb argument is NULL, and only
+sequences that define a data character are recognised. The isclass argument is
+not relevant, but the options argument is the final value of the compiled
+pattern's options.
+
+There is one "trick" case: when a sequence such as [[:>:]] or \s in UCP mode is
+processed, it is replaced by a nested alternative sequence. If this contains a
+backslash (which is usually does), ptrend does not point to its end - it still
+points to the end of the whole pattern. However, we can detect this case
+because cb->nestptr[0] will be non-NULL. The nested sequences are all zero-
+terminated and there are only ever two levels of nesting.
Arguments:
- c the character
- ptype the property type
- pdata the data for the type
- negated TRUE if it's a negated property (\P or \p{^)
+ ptrptr points to the input position pointer
+ ptrend points to the end of the input
+ chptr points to a returned data character
+ errorcodeptr points to the errorcode variable (containing zero)
+ options the current options bits
+ isclass TRUE if inside a character class
+ cb compile data block
-Returns: TRUE if auto-possessifying is OK
+Returns: zero => a data character
+ positive => a special escape sequence
+ negative => a back reference
+ on error, errorcodeptr is set non-zero
*/
-static BOOL
-check_char_prop(pcre_uint32 c, unsigned int ptype, unsigned int pdata,
- BOOL negated)
+int
+PRIV(check_escape)(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *chptr,
+ int *errorcodeptr, uint32_t options, BOOL isclass, compile_block *cb)
{
-const pcre_uint32 *p;
-const ucd_record *prop = GET_UCD(c);
-
-switch(ptype)
- {
- case PT_LAMP:
- return (prop->chartype == ucp_Lu ||
- prop->chartype == ucp_Ll ||
- prop->chartype == ucp_Lt) == negated;
-
- case PT_GC:
- return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated;
-
- case PT_PC:
- return (pdata == prop->chartype) == negated;
-
- case PT_SC:
- return (pdata == prop->script) == negated;
-
- /* These are specials */
-
- case PT_ALNUM:
- return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated;
-
- /* Perl space used to exclude VT, but from Perl 5.18 it is included, which
- means that Perl space and POSIX space are now identical. PCRE was changed
- at release 8.34. */
+BOOL utf = (options & PCRE2_UTF) != 0;
+PCRE2_SPTR ptr = *ptrptr + 1;
+register uint32_t c, cc;
+int escape = 0;
+int i;
- case PT_SPACE: /* Perl space */
- case PT_PXSPACE: /* POSIX space */
- switch(c)
- {
- HSPACE_CASES:
- VSPACE_CASES:
- return negated;
+/* Find the end of a nested insert. */
- default:
- return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == negated;
- }
- break; /* Control never reaches here */
+if (cb != NULL && cb->nestptr[0] != NULL)
+ ptrend = ptr + PRIV(strlen)(ptr);
- case PT_WORD:
- return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
- c == CHAR_UNDERSCORE) == negated;
+/* If backslash is at the end of the string, it's an error. */
- case PT_CLIST:
- p = PRIV(ucd_caseless_sets) + prop->caseset;
- for (;;)
- {
- if (c < *p) return !negated;
- if (c == *p++) return negated;
- }
- break; /* Control never reaches here */
+if (ptr >= ptrend)
+ {
+ *errorcodeptr = ERR1;
+ return 0;
}
-return FALSE;
-}
-#endif /* SUPPORT_UCP */
-
-
-
-/*************************************************
-* Fill the character property list *
-*************************************************/
-
-/* Checks whether the code points to an opcode that can take part in auto-
-possessification, and if so, fills a list with its properties.
-
-Arguments:
- code points to start of expression
- utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode
- fcc points to case-flipping table
- list points to output list
- list[0] will be filled with the opcode
- list[1] will be non-zero if this opcode
- can match an empty character string
- list[2..7] depends on the opcode
-
-Returns: points to the start of the next opcode if *code is accepted
- NULL if *code is not accepted
-*/
+GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */
+ptr--; /* Set pointer back to the last code unit */
-static const pcre_uchar *
-get_chr_property_list(const pcre_uchar *code, BOOL utf,
- const pcre_uint8 *fcc, pcre_uint32 *list)
-{
-pcre_uchar c = *code;
-pcre_uchar base;
-const pcre_uchar *end;
-pcre_uint32 chr;
-
-#ifdef SUPPORT_UCP
-pcre_uint32 *clist_dest;
-const pcre_uint32 *clist_src;
-#else
-utf = utf; /* Suppress "unused parameter" compiler warning */
-#endif
+/* Non-alphanumerics are literals, so we just leave the value in c. An initial
+value test saves a memory lookup for code points outside the alphanumeric
+range. Otherwise, do a table lookup. A non-zero result is something that can be
+returned immediately. Otherwise further processing is required. */
-list[0] = c;
-list[1] = FALSE;
-code++;
+if (c < ESCAPES_FIRST || c > ESCAPES_LAST) {} /* Definitely literal */
-if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
+else if ((i = escapes[c - ESCAPES_FIRST]) != 0)
{
- base = get_repeat_base(c);
- c -= (base - OP_STAR);
-
- if (c == OP_UPTO || c == OP_MINUPTO || c == OP_EXACT || c == OP_POSUPTO)
- code += IMM2_SIZE;
-
- list[1] = (c != OP_PLUS && c != OP_MINPLUS && c != OP_EXACT && c != OP_POSPLUS);
-
- switch(base)
+ if (i > 0) c = (uint32_t)i; else /* Positive is a data character */
{
- case OP_STAR:
- list[0] = OP_CHAR;
- break;
-
- case OP_STARI:
- list[0] = OP_CHARI;
- break;
-
- case OP_NOTSTAR:
- list[0] = OP_NOT;
- break;
-
- case OP_NOTSTARI:
- list[0] = OP_NOTI;
- break;
-
- case OP_TYPESTAR:
- list[0] = *code;
- code++;
- break;
+ escape = -i; /* Else return a special escape */
+ if (escape == ESC_P || escape == ESC_p || escape == ESC_X)
+ cb->external_flags |= PCRE2_HASBKPORX; /* Note \P, \p, or \X */
}
- c = list[0];
}
-switch(c)
- {
- case OP_NOT_DIGIT:
- case OP_DIGIT:
- case OP_NOT_WHITESPACE:
- case OP_WHITESPACE:
- case OP_NOT_WORDCHAR:
- case OP_WORDCHAR:
- case OP_ANY:
- case OP_ALLANY:
- case OP_ANYNL:
- case OP_NOT_HSPACE:
- case OP_HSPACE:
- case OP_NOT_VSPACE:
- case OP_VSPACE:
- case OP_EXTUNI:
- case OP_EODN:
- case OP_EOD:
- case OP_DOLL:
- case OP_DOLLM:
- return code;
-
- case OP_CHAR:
- case OP_NOT:
- GETCHARINCTEST(chr, code);
- list[2] = chr;
- list[3] = NOTACHAR;
- return code;
-
- case OP_CHARI:
- case OP_NOTI:
- list[0] = (c == OP_CHARI) ? OP_CHAR : OP_NOT;
- GETCHARINCTEST(chr, code);
- list[2] = chr;
-
-#ifdef SUPPORT_UCP
- if (chr < 128 || (chr < 256 && !utf))
- list[3] = fcc[chr];
- else
- list[3] = UCD_OTHERCASE(chr);
-#elif defined SUPPORT_UTF || !defined COMPILE_PCRE8
- list[3] = (chr < 256) ? fcc[chr] : chr;
-#else
- list[3] = fcc[chr];
-#endif
+/* Escapes that need further processing, including those that are unknown.
+When called from pcre2_substitute(), only \c, \o, and \x are recognized (and \u
+when BSUX is set). */
- /* The othercase might be the same value. */
+else
+ {
+ PCRE2_SPTR oldptr;
+ BOOL braced, negated, overflow;
+ unsigned int s;
- if (chr == list[3])
- list[3] = NOTACHAR;
- else
- list[4] = NOTACHAR;
- return code;
+ /* Filter calls from pcre2_substitute(). */
-#ifdef SUPPORT_UCP
- case OP_PROP:
- case OP_NOTPROP:
- if (code[0] != PT_CLIST)
+ if (cb == NULL && c != CHAR_c && c != CHAR_o && c != CHAR_x &&
+ (c != CHAR_u || (options & PCRE2_ALT_BSUX) != 0))
{
- list[2] = code[0];
- list[3] = code[1];
- return code + 2;
+ *errorcodeptr = ERR3;
+ return 0;
}
- /* Convert only if we have enough space. */
-
- clist_src = PRIV(ucd_caseless_sets) + code[1];
- clist_dest = list + 2;
- code += 2;
-
- do {
- if (clist_dest >= list + 8)
- {
- /* Early return if there is not enough space. This should never
- happen, since all clists are shorter than 5 character now. */
- list[2] = code[0];
- list[3] = code[1];
- return code;
- }
- *clist_dest++ = *clist_src;
- }
- while(*clist_src++ != NOTACHAR);
-
- /* All characters are stored. The terminating NOTACHAR
- is copied form the clist itself. */
-
- list[0] = (c == OP_PROP) ? OP_CHAR : OP_NOT;
- return code;
-#endif
-
- case OP_NCLASS:
- case OP_CLASS:
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- case OP_XCLASS:
- if (c == OP_XCLASS)
- end = code + GET(code, 0) - 1;
- else
-#endif
- end = code + 32 / sizeof(pcre_uchar);
-
- switch(*end)
+ switch (c)
{
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- case OP_CRPOSSTAR:
- case OP_CRPOSQUERY:
- list[1] = TRUE;
- end++;
- break;
-
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRPOSPLUS:
- end++;
- break;
+ /* A number of Perl escapes are not handled by PCRE. We give an explicit
+ error. */
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- case OP_CRPOSRANGE:
- list[1] = (GET2(end, 1) == 0);
- end += 1 + 2 * IMM2_SIZE;
+ case CHAR_l:
+ case CHAR_L:
+ *errorcodeptr = ERR37;
break;
- }
- list[2] = (pcre_uint32)(end - code);
- return end;
- }
-return NULL; /* Opcode not accepted */
-}
-
-
-
-/*************************************************
-* Scan further character sets for match *
-*************************************************/
-/* Checks whether the base and the current opcode have a common character, in
-which case the base cannot be possessified.
+ /* \u is unrecognized when PCRE2_ALT_BSUX is not set. When it is treated
+ specially, \u must be followed by four hex digits. Otherwise it is a
+ lowercase u letter. */
-Arguments:
- code points to the byte code
- utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
- cd static compile data
- base_list the data list of the base opcode
-
-Returns: TRUE if the auto-possessification is possible
-*/
-
-static BOOL
-compare_opcodes(const pcre_uchar *code, BOOL utf, const compile_data *cd,
- const pcre_uint32 *base_list, const pcre_uchar *base_end, int *rec_limit)
-{
-pcre_uchar c;
-pcre_uint32 list[8];
-const pcre_uint32 *chr_ptr;
-const pcre_uint32 *ochr_ptr;
-const pcre_uint32 *list_ptr;
-const pcre_uchar *next_code;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
-const pcre_uchar *xclass_flags;
-#endif
-const pcre_uint8 *class_bitset;
-const pcre_uint8 *set1, *set2, *set_end;
-pcre_uint32 chr;
-BOOL accepted, invert_bits;
-BOOL entered_a_group = FALSE;
-
-if (*rec_limit == 0) return FALSE;
---(*rec_limit);
-
-/* Note: the base_list[1] contains whether the current opcode has greedy
-(represented by a non-zero value) quantifier. This is a different from
-other character type lists, which stores here that the character iterator
-matches to an empty string (also represented by a non-zero value). */
-
-for(;;)
- {
- /* All operations move the code pointer forward.
- Therefore infinite recursions are not possible. */
-
- c = *code;
-
- /* Skip over callouts */
-
- if (c == OP_CALLOUT)
- {
- code += PRIV(OP_lengths)[c];
- continue;
- }
+ case CHAR_u:
+ if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37; else
+ {
+ uint32_t xc;
+ if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */
+ if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */
+ cc = (cc << 4) | xc;
+ if ((xc = XDIGIT(ptr[3])) == 0xff) break; /* Not a hex digit */
+ cc = (cc << 4) | xc;
+ if ((xc = XDIGIT(ptr[4])) == 0xff) break; /* Not a hex digit */
+ c = (cc << 4) | xc;
+ ptr += 4;
+ if (utf)
+ {
+ if (c > 0x10ffffU) *errorcodeptr = ERR77;
+ else if (c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
+ }
+ else if (c > MAX_NON_UTF_CHAR) *errorcodeptr = ERR77;
+ }
+ break;
- if (c == OP_ALT)
- {
- do code += GET(code, 1); while (*code == OP_ALT);
- c = *code;
- }
+ case CHAR_U:
+ /* \U is unrecognized unless PCRE2_ALT_BSUX is set, in which case it is an
+ upper case letter. */
+ if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37;
+ break;
- switch(c)
- {
- case OP_END:
- case OP_KETRPOS:
- /* TRUE only in greedy case. The non-greedy case could be replaced by
- an OP_EXACT, but it is probably not worth it. (And note that OP_EXACT
- uses more memory, which we cannot get at this stage.) */
+ /* In a character class, \g is just a literal "g". Outside a character
+ class, \g must be followed by one of a number of specific things:
- return base_list[1] != 0;
+ (1) A number, either plain or braced. If positive, it is an absolute
+ backreference. If negative, it is a relative backreference. This is a Perl
+ 5.10 feature.
- case OP_KET:
- /* If the bracket is capturing, and referenced by an OP_RECURSE, or
- it is an atomic sub-pattern (assert, once, etc.) the non-greedy case
- cannot be converted to a possessive form. */
+ (2) Perl 5.10 also supports \g{name} as a reference to a named group. This
+ is part of Perl's movement towards a unified syntax for back references. As
+ this is synonymous with \k{name}, we fudge it up by pretending it really
+ was \k.
- if (base_list[1] == 0) return FALSE;
+ (3) For Oniguruma compatibility we also support \g followed by a name or a
+ number either in angle brackets or in single quotes. However, these are
+ (possibly recursive) subroutine calls, _not_ backreferences. Just return
+ the ESC_g code (cf \k). */
- switch(*(code - GET(code, 1)))
+ case CHAR_g:
+ if (isclass) break;
+ if (ptr[1] == CHAR_LESS_THAN_SIGN || ptr[1] == CHAR_APOSTROPHE)
{
- case OP_ASSERT:
- case OP_ASSERT_NOT:
- case OP_ASSERTBACK:
- case OP_ASSERTBACK_NOT:
- case OP_ONCE:
- case OP_ONCE_NC:
- /* Atomic sub-patterns and assertions can always auto-possessify their
- last iterator. However, if the group was entered as a result of checking
- a previous iterator, this is not possible. */
-
- return !entered_a_group;
+ escape = ESC_g;
+ break;
}
- code += PRIV(OP_lengths)[c];
- continue;
-
- case OP_ONCE:
- case OP_ONCE_NC:
- case OP_BRA:
- case OP_CBRA:
- next_code = code + GET(code, 1);
- code += PRIV(OP_lengths)[c];
+ /* Handle the Perl-compatible cases */
- while (*next_code == OP_ALT)
+ if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
{
- if (!compare_opcodes(code, utf, cd, base_list, base_end, rec_limit))
- return FALSE;
- code = next_code + 1 + LINK_SIZE;
- next_code += GET(next_code, 1);
+ PCRE2_SPTR p;
+ for (p = ptr+2; *p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET; p++)
+ if (*p != CHAR_MINUS && !IS_DIGIT(*p)) break;
+ if (*p != CHAR_NULL && *p != CHAR_RIGHT_CURLY_BRACKET)
+ {
+ escape = ESC_k;
+ break;
+ }
+ braced = TRUE;
+ ptr++;
}
+ else braced = FALSE;
- entered_a_group = TRUE;
- continue;
-
- case OP_BRAZERO:
- case OP_BRAMINZERO:
-
- next_code = code + 1;
- if (*next_code != OP_BRA && *next_code != OP_CBRA
- && *next_code != OP_ONCE && *next_code != OP_ONCE_NC) return FALSE;
-
- do next_code += GET(next_code, 1); while (*next_code == OP_ALT);
-
- /* The bracket content will be checked by the
- OP_BRA/OP_CBRA case above. */
- next_code += 1 + LINK_SIZE;
- if (!compare_opcodes(next_code, utf, cd, base_list, base_end, rec_limit))
- return FALSE;
-
- code += PRIV(OP_lengths)[c];
- continue;
-
- default:
- break;
- }
-
- /* Check for a supported opcode, and load its properties. */
-
- code = get_chr_property_list(code, utf, cd->fcc, list);
- if (code == NULL) return FALSE; /* Unsupported */
-
- /* If either opcode is a small character list, set pointers for comparing
- characters from that list with another list, or with a property. */
-
- if (base_list[0] == OP_CHAR)
- {
- chr_ptr = base_list + 2;
- list_ptr = list;
- }
- else if (list[0] == OP_CHAR)
- {
- chr_ptr = list + 2;
- list_ptr = base_list;
- }
-
- /* Character bitsets can also be compared to certain opcodes. */
-
- else if (base_list[0] == OP_CLASS || list[0] == OP_CLASS
-#ifdef COMPILE_PCRE8
- /* In 8 bit, non-UTF mode, OP_CLASS and OP_NCLASS are the same. */
- || (!utf && (base_list[0] == OP_NCLASS || list[0] == OP_NCLASS))
-#endif
- )
- {
-#ifdef COMPILE_PCRE8
- if (base_list[0] == OP_CLASS || (!utf && base_list[0] == OP_NCLASS))
-#else
- if (base_list[0] == OP_CLASS)
-#endif
- {
- set1 = (pcre_uint8 *)(base_end - base_list[2]);
- list_ptr = list;
- }
- else
+ if (ptr[1] == CHAR_MINUS)
{
- set1 = (pcre_uint8 *)(code - list[2]);
- list_ptr = base_list;
+ negated = TRUE;
+ ptr++;
}
+ else negated = FALSE;
- invert_bits = FALSE;
- switch(list_ptr[0])
+ /* The integer range is limited by the machine's int representation. */
+ s = 0;
+ overflow = FALSE;
+ while (IS_DIGIT(ptr[1]))
{
- case OP_CLASS:
- case OP_NCLASS:
- set2 = (pcre_uint8 *)
- ((list_ptr == list ? code : base_end) - list_ptr[2]);
- break;
-
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- case OP_XCLASS:
- xclass_flags = (list_ptr == list ? code : base_end) - list_ptr[2] + LINK_SIZE;
- if ((*xclass_flags & XCL_HASPROP) != 0) return FALSE;
- if ((*xclass_flags & XCL_MAP) == 0)
+ if (s > INT_MAX / 10 - 1) /* Integer overflow */
{
- /* No bits are set for characters < 256. */
- if (list[1] == 0) return TRUE;
- /* Might be an empty repeat. */
- continue;
+ overflow = TRUE;
+ break;
}
- set2 = (pcre_uint8 *)(xclass_flags + 1);
- break;
-#endif
-
- case OP_NOT_DIGIT:
- invert_bits = TRUE;
- /* Fall through */
- case OP_DIGIT:
- set2 = (pcre_uint8 *)(cd->cbits + cbit_digit);
- break;
-
- case OP_NOT_WHITESPACE:
- invert_bits = TRUE;
- /* Fall through */
- case OP_WHITESPACE:
- set2 = (pcre_uint8 *)(cd->cbits + cbit_space);
+ s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0);
+ }
+ if (overflow) /* Integer overflow */
+ {
+ while (IS_DIGIT(ptr[1])) ptr++;
+ *errorcodeptr = ERR61;
break;
+ }
- case OP_NOT_WORDCHAR:
- invert_bits = TRUE;
- /* Fall through */
- case OP_WORDCHAR:
- set2 = (pcre_uint8 *)(cd->cbits + cbit_word);
+ if (braced && *(++ptr) != CHAR_RIGHT_CURLY_BRACKET)
+ {
+ *errorcodeptr = ERR57;
break;
-
- default:
- return FALSE;
}
- /* Because the sets are unaligned, we need
- to perform byte comparison here. */
- set_end = set1 + 32;
- if (invert_bits)
+ if (s == 0)
{
- do
- {
- if ((*set1++ & ~(*set2++)) != 0) return FALSE;
- }
- while (set1 < set_end);
+ *errorcodeptr = ERR58;
+ break;
}
- else
+
+ if (negated)
{
- do
+ if (s > cb->bracount)
{
- if ((*set1++ & *set2++) != 0) return FALSE;
+ *errorcodeptr = ERR15;
+ break;
}
- while (set1 < set_end);
+ s = cb->bracount - (s - 1);
}
- if (list[1] == 0) return TRUE;
- /* Might be an empty repeat. */
- continue;
- }
+ escape = -(int)s;
+ break;
- /* Some property combinations also acceptable. Unicode property opcodes are
- processed specially; the rest can be handled with a lookup table. */
+ /* The handling of escape sequences consisting of a string of digits
+ starting with one that is not zero is not straightforward. Perl has changed
+ over the years. Nowadays \g{} for backreferences and \o{} for octal are
+ recommended to avoid the ambiguities in the old syntax.
- else
- {
- pcre_uint32 leftop, rightop;
+ Outside a character class, the digits are read as a decimal number. If the
+ number is less than 10, or if there are that many previous extracting left
+ brackets, it is a back reference. Otherwise, up to three octal digits are
+ read to form an escaped character code. Thus \123 is likely to be octal 123
+ (cf \0123, which is octal 012 followed by the literal 3).
- leftop = base_list[0];
- rightop = list[0];
+ Inside a character class, \ followed by a digit is always either a literal
+ 8 or 9 or an octal number. */
+
+ case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5:
+ case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
-#ifdef SUPPORT_UCP
- accepted = FALSE; /* Always set in non-unicode case. */
- if (leftop == OP_PROP || leftop == OP_NOTPROP)
+ if (!isclass)
{
- if (rightop == OP_EOD)
- accepted = TRUE;
- else if (rightop == OP_PROP || rightop == OP_NOTPROP)
+ oldptr = ptr;
+ /* The integer range is limited by the machine's int representation. */
+ s = c - CHAR_0;
+ overflow = FALSE;
+ while (IS_DIGIT(ptr[1]))
{
- int n;
- const pcre_uint8 *p;
- BOOL same = leftop == rightop;
- BOOL lisprop = leftop == OP_PROP;
- BOOL risprop = rightop == OP_PROP;
- BOOL bothprop = lisprop && risprop;
-
- /* There's a table that specifies how each combination is to be
- processed:
- 0 Always return FALSE (never auto-possessify)
- 1 Character groups are distinct (possessify if both are OP_PROP)
- 2 Check character categories in the same group (general or particular)
- 3 Return TRUE if the two opcodes are not the same
- ... see comments below
- */
-
- n = propposstab[base_list[2]][list[2]];
- switch(n)
+ if (s > INT_MAX / 10 - 1) /* Integer overflow */
{
- case 0: break;
- case 1: accepted = bothprop; break;
- case 2: accepted = (base_list[3] == list[3]) != same; break;
- case 3: accepted = !same; break;
-
- case 4: /* Left general category, right particular category */
- accepted = risprop && catposstab[base_list[3]][list[3]] == same;
- break;
-
- case 5: /* Right general category, left particular category */
- accepted = lisprop && catposstab[list[3]][base_list[3]] == same;
- break;
-
- /* This code is logically tricky. Think hard before fiddling with it.
- The posspropstab table has four entries per row. Each row relates to
- one of PCRE's special properties such as ALNUM or SPACE or WORD.
- Only WORD actually needs all four entries, but using repeats for the
- others means they can all use the same code below.
-
- The first two entries in each row are Unicode general categories, and
- apply always, because all the characters they include are part of the
- PCRE character set. The third and fourth entries are a general and a
- particular category, respectively, that include one or more relevant
- characters. One or the other is used, depending on whether the check
- is for a general or a particular category. However, in both cases the
- category contains more characters than the specials that are defined
- for the property being tested against. Therefore, it cannot be used
- in a NOTPROP case.
-
- Example: the row for WORD contains ucp_L, ucp_N, ucp_P, ucp_Po.
- Underscore is covered by ucp_P or ucp_Po. */
-
- case 6: /* Left alphanum vs right general category */
- case 7: /* Left space vs right general category */
- case 8: /* Left word vs right general category */
- p = posspropstab[n-6];
- accepted = risprop && lisprop ==
- (list[3] != p[0] &&
- list[3] != p[1] &&
- (list[3] != p[2] || !lisprop));
- break;
-
- case 9: /* Right alphanum vs left general category */
- case 10: /* Right space vs left general category */
- case 11: /* Right word vs left general category */
- p = posspropstab[n-9];
- accepted = lisprop && risprop ==
- (base_list[3] != p[0] &&
- base_list[3] != p[1] &&
- (base_list[3] != p[2] || !risprop));
+ overflow = TRUE;
break;
+ }
+ s = s * 10 + (unsigned int)(*(++ptr) - CHAR_0);
+ }
+ if (overflow) /* Integer overflow */
+ {
+ while (IS_DIGIT(ptr[1])) ptr++;
+ *errorcodeptr = ERR61;
+ break;
+ }
- case 12: /* Left alphanum vs right particular category */
- case 13: /* Left space vs right particular category */
- case 14: /* Left word vs right particular category */
- p = posspropstab[n-12];
- accepted = risprop && lisprop ==
- (catposstab[p[0]][list[3]] &&
- catposstab[p[1]][list[3]] &&
- (list[3] != p[3] || !lisprop));
- break;
+ /* \1 to \9 are always back references. \8x and \9x are too; \1x to \7x
+ are octal escapes if there are not that many previous captures. */
- case 15: /* Right alphanum vs left particular category */
- case 16: /* Right space vs left particular category */
- case 17: /* Right word vs left particular category */
- p = posspropstab[n-15];
- accepted = lisprop && risprop ==
- (catposstab[p[0]][base_list[3]] &&
- catposstab[p[1]][base_list[3]] &&
- (base_list[3] != p[3] || !risprop));
- break;
- }
+ if (s < 10 || *oldptr >= CHAR_8 || s <= cb->bracount)
+ {
+ escape = -(int)s; /* Indicates a back reference */
+ break;
}
+ ptr = oldptr; /* Put the pointer back and fall through */
}
- else
-#endif /* SUPPORT_UCP */
+ /* Handle a digit following \ when the number is not a back reference, or
+ we are within a character class. If the first digit is 8 or 9, Perl used to
+ generate a binary zero byte and then treat the digit as a following
+ literal. At least by Perl 5.18 this changed so as not to insert the binary
+ zero. */
- accepted = leftop >= FIRST_AUTOTAB_OP && leftop <= LAST_AUTOTAB_LEFT_OP &&
- rightop >= FIRST_AUTOTAB_OP && rightop <= LAST_AUTOTAB_RIGHT_OP &&
- autoposstab[leftop - FIRST_AUTOTAB_OP][rightop - FIRST_AUTOTAB_OP];
+ if ((c = *ptr) >= CHAR_8) break;
- if (!accepted) return FALSE;
+ /* Fall through with a digit less than 8 */
- if (list[1] == 0) return TRUE;
- /* Might be an empty repeat. */
- continue;
- }
+ /* \0 always starts an octal number, but we may drop through to here with a
+ larger first octal digit. The original code used just to take the least
+ significant 8 bits of octal numbers (I think this is what early Perls used
+ to do). Nowadays we allow for larger numbers in UTF-8 mode and 16-bit mode,
+ but no more than 3 octal digits. */
- /* Control reaches here only if one of the items is a small character list.
- All characters are checked against the other side. */
+ case CHAR_0:
+ c -= CHAR_0;
+ while(i++ < 2 && ptr[1] >= CHAR_0 && ptr[1] <= CHAR_7)
+ c = c * 8 + *(++ptr) - CHAR_0;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (!utf && c > 0xff) *errorcodeptr = ERR51;
+#endif
+ break;
- do
- {
- chr = *chr_ptr;
+ /* \o is a relatively new Perl feature, supporting a more general way of
+ specifying character codes in octal. The only supported form is \o{ddd}. */
- switch(list_ptr[0])
+ case CHAR_o:
+ if (ptr[1] != CHAR_LEFT_CURLY_BRACKET) *errorcodeptr = ERR55; else
+ if (ptr[2] == CHAR_RIGHT_CURLY_BRACKET) *errorcodeptr = ERR78; else
{
- case OP_CHAR:
- ochr_ptr = list_ptr + 2;
- do
+ ptr += 2;
+ c = 0;
+ overflow = FALSE;
+ while (*ptr >= CHAR_0 && *ptr <= CHAR_7)
{
- if (chr == *ochr_ptr) return FALSE;
- ochr_ptr++;
+ cc = *ptr++;
+ if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c >= 0x20000000l) { overflow = TRUE; break; }
+#endif
+ c = (c << 3) + (cc - CHAR_0);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+ if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
+#endif
}
- while(*ochr_ptr != NOTACHAR);
- break;
-
- case OP_NOT:
- ochr_ptr = list_ptr + 2;
- do
+ if (overflow)
{
- if (chr == *ochr_ptr)
- break;
- ochr_ptr++;
+ while (*ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++;
+ *errorcodeptr = ERR34;
}
- while(*ochr_ptr != NOTACHAR);
- if (*ochr_ptr == NOTACHAR) return FALSE; /* Not found */
- break;
+ else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
+ }
+ else *errorcodeptr = ERR64;
+ }
+ break;
- /* Note that OP_DIGIT etc. are generated only when PCRE_UCP is *not*
- set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
+ /* \x is complicated. When PCRE2_ALT_BSUX is set, \x must be followed by
+ two hexadecimal digits. Otherwise it is a lowercase x letter. */
- case OP_DIGIT:
- if (chr < 256 && (cd->ctypes[chr] & ctype_digit) != 0) return FALSE;
- break;
+ case CHAR_x:
+ if ((options & PCRE2_ALT_BSUX) != 0)
+ {
+ uint32_t xc;
+ if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */
+ if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */
+ c = (cc << 4) | xc;
+ ptr += 2;
+ } /* End PCRE2_ALT_BSUX handling */
- case OP_NOT_DIGIT:
- if (chr > 255 || (cd->ctypes[chr] & ctype_digit) == 0) return FALSE;
- break;
+ /* Handle \x in Perl's style. \x{ddd} is a character number which can be
+ greater than 0xff in UTF-8 or non-8bit mode, but only if the ddd are hex
+ digits. If not, { used to be treated as a data character. However, Perl
+ seems to read hex digits up to the first non-such, and ignore the rest, so
+ that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE
+ now gives an error. */
- case OP_WHITESPACE:
- if (chr < 256 && (cd->ctypes[chr] & ctype_space) != 0) return FALSE;
- break;
+ else
+ {
+ if (ptr[1] == CHAR_LEFT_CURLY_BRACKET)
+ {
+ ptr += 2;
+ if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ *errorcodeptr = ERR78;
+ break;
+ }
+ c = 0;
+ overflow = FALSE;
- case OP_NOT_WHITESPACE:
- if (chr > 255 || (cd->ctypes[chr] & ctype_space) == 0) return FALSE;
- break;
+ while ((cc = XDIGIT(*ptr)) != 0xff)
+ {
+ ptr++;
+ if (c == 0 && cc == 0) continue; /* Leading zeroes */
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c >= 0x10000000l) { overflow = TRUE; break; }
+#endif
+ c = (c << 4) | cc;
+ if ((utf && c > 0x10ffffU) || (!utf && c > MAX_NON_UTF_CHAR))
+ {
+ overflow = TRUE;
+ break;
+ }
+ }
- case OP_WORDCHAR:
- if (chr < 255 && (cd->ctypes[chr] & ctype_word) != 0) return FALSE;
- break;
+ if (overflow)
+ {
+ while (XDIGIT(*ptr) != 0xff) ptr++;
+ *errorcodeptr = ERR34;
+ }
+ else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ if (utf && c >= 0xd800 && c <= 0xdfff) *errorcodeptr = ERR73;
+ }
- case OP_NOT_WORDCHAR:
- if (chr > 255 || (cd->ctypes[chr] & ctype_word) == 0) return FALSE;
- break;
+ /* If the sequence of hex digits does not end with '}', give an error.
+ We used just to recognize this construct and fall through to the normal
+ \x handling, but nowadays Perl gives an error, which seems much more
+ sensible, so we do too. */
- case OP_HSPACE:
- switch(chr)
- {
- HSPACE_CASES: return FALSE;
- default: break;
- }
- break;
+ else *errorcodeptr = ERR67;
+ } /* End of \x{} processing */
- case OP_NOT_HSPACE:
- switch(chr)
- {
- HSPACE_CASES: break;
- default: return FALSE;
- }
- break;
+ /* Read a single-byte hex-defined char (up to two hex digits after \x) */
- case OP_ANYNL:
- case OP_VSPACE:
- switch(chr)
+ else
{
- VSPACE_CASES: return FALSE;
- default: break;
- }
- break;
+ c = 0;
+ if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */
+ ptr++;
+ c = cc;
+ if ((cc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */
+ ptr++;
+ c = (c << 4) | cc;
+ } /* End of \xdd handling */
+ } /* End of Perl-style \x handling */
+ break;
- case OP_NOT_VSPACE:
- switch(chr)
- {
- VSPACE_CASES: break;
- default: return FALSE;
- }
- break;
+ /* The handling of \c is different in ASCII and EBCDIC environments. In an
+ ASCII (or Unicode) environment, an error is given if the character
+ following \c is not a printable ASCII character. Otherwise, the following
+ character is upper-cased if it is a letter, and after that the 0x40 bit is
+ flipped. The result is the value of the escape.
- case OP_DOLL:
- case OP_EODN:
- switch (chr)
- {
- case CHAR_CR:
- case CHAR_LF:
- case CHAR_VT:
- case CHAR_FF:
- case CHAR_NEL:
-#ifndef EBCDIC
- case 0x2028:
- case 0x2029:
-#endif /* Not EBCDIC */
- return FALSE;
- }
- break;
+ In an EBCDIC environment the handling of \c is compatible with the
+ specification in the perlebcdic document. The following character must be
+ a letter or one of small number of special characters. These provide a
+ means of defining the character values 0-31.
- case OP_EOD: /* Can always possessify before \z */
- break;
+ For testing the EBCDIC handling of \c in an ASCII environment, recognize
+ the EBCDIC value of 'c' explicitly. */
-#ifdef SUPPORT_UCP
- case OP_PROP:
- case OP_NOTPROP:
- if (!check_char_prop(chr, list_ptr[2], list_ptr[3],
- list_ptr[0] == OP_NOTPROP))
- return FALSE;
- break;
+#if defined EBCDIC && 'a' != 0x81
+ case 0x83:
+#else
+ case CHAR_c:
#endif
- case OP_NCLASS:
- if (chr > 255) return FALSE;
- /* Fall through */
-
- case OP_CLASS:
- if (chr > 255) break;
- class_bitset = (pcre_uint8 *)
- ((list_ptr == list ? code : base_end) - list_ptr[2]);
- if ((class_bitset[chr >> 3] & (1 << (chr & 7))) != 0) return FALSE;
+ c = *(++ptr);
+ if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c);
+ if (c == CHAR_NULL && ptr >= ptrend)
+ {
+ *errorcodeptr = ERR2;
break;
+ }
+
+ /* Handle \c in an ASCII/Unicode environment. */
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- case OP_XCLASS:
- if (PRIV(xclass)(chr, (list_ptr == list ? code : base_end) -
- list_ptr[2] + LINK_SIZE, utf)) return FALSE;
+#ifndef EBCDIC /* ASCII/UTF-8 coding */
+ if (c < 32 || c > 126) /* Excludes all non-printable ASCII */
+ {
+ *errorcodeptr = ERR68;
break;
-#endif
+ }
+ c ^= 0x40;
- default:
- return FALSE;
+ /* Handle \c in an EBCDIC environment. The special case \c? is converted to
+ 255 (0xff) or 95 (0x5f) if other character suggest we are using th POSIX-BC
+ encoding. (This is the way Perl indicates that it handles \c?.) The other
+ valid sequences correspond to a list of specific characters. */
+
+#else
+ if (c == CHAR_QUESTION_MARK)
+ c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff;
+ else
+ {
+ for (i = 0; i < 32; i++)
+ {
+ if (c == ebcdic_escape_c[i]) break;
+ }
+ if (i < 32) c = i; else *errorcodeptr = ERR68;
}
+#endif /* EBCDIC */
- chr_ptr++;
- }
- while(*chr_ptr != NOTACHAR);
+ break;
- /* At least one character must be matched from this opcode. */
+ /* Any other alphanumeric following \ is an error. Perl gives an error only
+ if in warning mode, but PCRE doesn't have a warning mode. */
- if (list[1] == 0) return TRUE;
+ default:
+ *errorcodeptr = ERR3;
+ break;
+ }
}
-/* Control never reaches here. There used to be a fail-save return FALSE; here,
-but some compilers complain about an unreachable statement. */
+/* Perl supports \N{name} for character names, as well as plain \N for "not
+newline". PCRE does not support \N{name}. However, it does support
+quantification such as \N{2,3}. */
+
+if (escape == ESC_N && ptr[1] == CHAR_LEFT_CURLY_BRACKET &&
+ !is_counted_repeat(ptr+2))
+ *errorcodeptr = ERR37;
+
+/* If PCRE2_UCP is set, we change the values for \d etc. */
+
+if ((options & PCRE2_UCP) != 0 && escape >= ESC_D && escape <= ESC_w)
+ escape += (ESC_DU - ESC_D);
+/* Set the pointer to the final character before returning. */
+
+*ptrptr = ptr;
+*chptr = c;
+return escape;
}
+#ifdef SUPPORT_UNICODE
/*************************************************
-* Scan compiled regex for auto-possession *
+* Handle \P and \p *
*************************************************/
-/* Replaces single character iterations with their possessive alternatives
-if appropriate. This function modifies the compiled opcode!
+/* This function is called after \P or \p has been encountered, provided that
+PCRE2 is compiled with support for UTF and Unicode properties. On entry, the
+contents of ptrptr are pointing at the P or p. On exit, it is left pointing at
+the final code unit of the escape sequence.
Arguments:
- code points to start of the byte code
- utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
- cd static compile data
+ ptrptr the pattern position pointer
+ negptr a boolean that is set TRUE for negation else FALSE
+ ptypeptr an unsigned int that is set to the type value
+ pdataptr an unsigned int that is set to the detailed property value
+ errorcodeptr the error code variable
+ cb the compile data
-Returns: nothing
+Returns: TRUE if the type value was found, or FALSE for an invalid type
*/
-static void
-auto_possessify(pcre_uchar *code, BOOL utf, const compile_data *cd)
+static BOOL
+get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, unsigned int *ptypeptr,
+ unsigned int *pdataptr, int *errorcodeptr, compile_block *cb)
{
-register pcre_uchar c;
-const pcre_uchar *end;
-pcre_uchar *repeat_opcode;
-pcre_uint32 list[8];
-int rec_limit;
+register PCRE2_UCHAR c;
+size_t i, bot, top;
+PCRE2_SPTR ptr = *ptrptr;
+PCRE2_UCHAR name[32];
-for (;;)
+*negptr = FALSE;
+c = *(++ptr);
+
+/* \P or \p can be followed by a name in {}, optionally preceded by ^ for
+negation. */
+
+if (c == CHAR_LEFT_CURLY_BRACKET)
{
- c = *code;
+ if (ptr[1] == CHAR_CIRCUMFLEX_ACCENT)
+ {
+ *negptr = TRUE;
+ ptr++;
+ }
+ for (i = 0; i < (int)(sizeof(name) / sizeof(PCRE2_UCHAR)) - 1; i++)
+ {
+ c = *(++ptr);
+ if (c == CHAR_NULL) goto ERROR_RETURN;
+ if (c == CHAR_RIGHT_CURLY_BRACKET) break;
+ name[i] = c;
+ }
+ if (c != CHAR_RIGHT_CURLY_BRACKET) goto ERROR_RETURN;
+ name[i] = 0;
+ }
- /* When a pattern with bad UTF-8 encoding is compiled with NO_UTF_CHECK,
- it may compile without complaining, but may get into a loop here if the code
- pointer points to a bad value. This is, of course a documentated possibility,
- when NO_UTF_CHECK is set, so it isn't a bug, but we can detect this case and
- just give up on this optimization. */
+/* Otherwise there is just one following character, which must be an ASCII
+letter. */
- if (c >= OP_TABLE_LENGTH) return;
+else if (MAX_255(c) && (cb->ctypes[c] & ctype_letter) != 0)
+ {
+ name[0] = c;
+ name[1] = 0;
+ }
+else goto ERROR_RETURN;
+
+*ptrptr = ptr;
+
+/* Search for a recognized property name using binary chop. */
- if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
+bot = 0;
+top = PRIV(utt_size);
+
+while (bot < top)
+ {
+ int r;
+ i = (bot + top) >> 1;
+ r = PRIV(strcmp_c8)(name, PRIV(utt_names) + PRIV(utt)[i].name_offset);
+ if (r == 0)
{
- c -= get_repeat_base(c) - OP_STAR;
- end = (c <= OP_MINUPTO) ?
- get_chr_property_list(code, utf, cd->fcc, list) : NULL;
- list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO;
+ *ptypeptr = PRIV(utt)[i].type;
+ *pdataptr = PRIV(utt)[i].value;
+ return TRUE;
+ }
+ if (r > 0) bot = i + 1; else top = i;
+ }
+*errorcodeptr = ERR47; /* Unrecognized name */
+return FALSE;
- rec_limit = 1000;
- if (end != NULL && compare_opcodes(end, utf, cd, list, end, &rec_limit))
- {
- switch(c)
- {
- case OP_STAR:
- *code += OP_POSSTAR - OP_STAR;
- break;
+ERROR_RETURN: /* Malformed \P or \p */
+*errorcodeptr = ERR46;
+*ptrptr = ptr;
+return FALSE;
+}
+#endif
- case OP_MINSTAR:
- *code += OP_POSSTAR - OP_MINSTAR;
- break;
- case OP_PLUS:
- *code += OP_POSPLUS - OP_PLUS;
- break;
- case OP_MINPLUS:
- *code += OP_POSPLUS - OP_MINPLUS;
- break;
+/*************************************************
+* Read repeat counts *
+*************************************************/
- case OP_QUERY:
- *code += OP_POSQUERY - OP_QUERY;
- break;
+/* Read an item of the form {n,m} and return the values. This is called only
+after is_counted_repeat() has confirmed that a repeat-count quantifier exists,
+so the syntax is guaranteed to be correct, but we need to check the values.
- case OP_MINQUERY:
- *code += OP_POSQUERY - OP_MINQUERY;
- break;
+Arguments:
+ p pointer to first char after '{'
+ minp pointer to int for min
+ maxp pointer to int for max
+ returned as -1 if no max
+ errorcodeptr points to error code variable
- case OP_UPTO:
- *code += OP_POSUPTO - OP_UPTO;
- break;
+Returns: pointer to '}' on success;
+ current ptr on error, with errorcodeptr set non-zero
+*/
- case OP_MINUPTO:
- *code += OP_POSUPTO - OP_MINUPTO;
- break;
+static PCRE2_SPTR
+read_repeat_counts(PCRE2_SPTR p, int *minp, int *maxp, int *errorcodeptr)
+{
+int min = 0;
+int max = -1;
+
+while (IS_DIGIT(*p))
+ {
+ min = min * 10 + (int)(*p++ - CHAR_0);
+ if (min > 65535)
+ {
+ *errorcodeptr = ERR5;
+ return p;
+ }
+ }
+
+if (*p == CHAR_RIGHT_CURLY_BRACKET) max = min; else
+ {
+ if (*(++p) != CHAR_RIGHT_CURLY_BRACKET)
+ {
+ max = 0;
+ while(IS_DIGIT(*p))
+ {
+ max = max * 10 + (int)(*p++ - CHAR_0);
+ if (max > 65535)
+ {
+ *errorcodeptr = ERR5;
+ return p;
}
}
- c = *code;
+ if (max < min)
+ {
+ *errorcodeptr = ERR4;
+ return p;
+ }
}
- else if (c == OP_CLASS || c == OP_NCLASS || c == OP_XCLASS)
- {
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- if (c == OP_XCLASS)
- repeat_opcode = code + GET(code, 1);
- else
-#endif
- repeat_opcode = code + 1 + (32 / sizeof(pcre_uchar));
+ }
- c = *repeat_opcode;
- if (c >= OP_CRSTAR && c <= OP_CRMINRANGE)
- {
- /* end must not be NULL. */
- end = get_chr_property_list(code, utf, cd->fcc, list);
+*minp = min;
+*maxp = max;
+return p;
+}
- list[1] = (c & 1) == 0;
- rec_limit = 1000;
- if (compare_opcodes(end, utf, cd, list, end, &rec_limit))
- {
- switch (c)
- {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- *repeat_opcode = OP_CRPOSSTAR;
- break;
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- *repeat_opcode = OP_CRPOSPLUS;
- break;
+/*************************************************
+* Scan compiled regex for recursion reference *
+*************************************************/
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- *repeat_opcode = OP_CRPOSQUERY;
- break;
+/* This function scans through a compiled pattern until it finds an instance of
+OP_RECURSE.
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- *repeat_opcode = OP_CRPOSRANGE;
- break;
- }
- }
- }
- c = *code;
- }
+Arguments:
+ code points to start of expression
+ utf TRUE in UTF mode
- switch(c)
- {
- case OP_END:
- return;
+Returns: pointer to the opcode for OP_RECURSE, or NULL if not found
+*/
- case OP_TYPESTAR:
- case OP_TYPEMINSTAR:
- case OP_TYPEPLUS:
- case OP_TYPEMINPLUS:
- case OP_TYPEQUERY:
- case OP_TYPEMINQUERY:
- case OP_TYPEPOSSTAR:
- case OP_TYPEPOSPLUS:
- case OP_TYPEPOSQUERY:
- if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
- break;
+static PCRE2_SPTR
+find_recurse(PCRE2_SPTR code, BOOL utf)
+{
+for (;;)
+ {
+ register PCRE2_UCHAR c = *code;
+ if (c == OP_END) return NULL;
+ if (c == OP_RECURSE) return code;
- case OP_TYPEUPTO:
- case OP_TYPEMINUPTO:
- case OP_TYPEEXACT:
- case OP_TYPEPOSUPTO:
- if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
- code += 2;
- break;
+ /* XCLASS is used for classes that cannot be represented just by a bit map.
+ This includes negated single high-valued characters. CALLOUT_STR is used for
+ callouts with string arguments. In both cases the length in the table is
+ zero; the actual length is stored in the compiled code. */
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- case OP_XCLASS:
- code += GET(code, 1);
- break;
-#endif
+ if (c == OP_XCLASS) code += GET(code, 1);
+ else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE);
- case OP_MARK:
- case OP_PRUNE_ARG:
- case OP_SKIP_ARG:
- case OP_THEN_ARG:
- code += code[1];
- break;
- }
+ /* Otherwise, we can get the item's length from the table, except that for
+ repeated character types, we have to test for \p and \P, which have an extra
+ two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we
+ must add in its length. */
- /* Add in the fixed length from the table */
+ else
+ {
+ switch(c)
+ {
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+ break;
- code += PRIV(OP_lengths)[c];
+ case OP_TYPEPOSUPTO:
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+ code += 2;
+ break;
- /* In UTF-8 mode, opcodes that are followed by a character may be followed by
- a multi-byte character. The length in the table is a minimum, so we have to
- arrange to skip the extra bytes. */
+ case OP_MARK:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ code += code[1];
+ break;
+ }
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
- if (utf) switch(c)
- {
- case OP_CHAR:
- case OP_CHARI:
- case OP_NOT:
- case OP_NOTI:
- case OP_STAR:
- case OP_MINSTAR:
- case OP_PLUS:
- case OP_MINPLUS:
- case OP_QUERY:
- case OP_MINQUERY:
- case OP_UPTO:
- case OP_MINUPTO:
- case OP_EXACT:
- case OP_POSSTAR:
- case OP_POSPLUS:
- case OP_POSQUERY:
- case OP_POSUPTO:
- case OP_STARI:
- case OP_MINSTARI:
- case OP_PLUSI:
- case OP_MINPLUSI:
- case OP_QUERYI:
- case OP_MINQUERYI:
- case OP_UPTOI:
- case OP_MINUPTOI:
- case OP_EXACTI:
- case OP_POSSTARI:
- case OP_POSPLUSI:
- case OP_POSQUERYI:
- case OP_POSUPTOI:
- case OP_NOTSTAR:
- case OP_NOTMINSTAR:
- case OP_NOTPLUS:
- case OP_NOTMINPLUS:
- case OP_NOTQUERY:
- case OP_NOTMINQUERY:
- case OP_NOTUPTO:
- case OP_NOTMINUPTO:
- case OP_NOTEXACT:
- case OP_NOTPOSSTAR:
- case OP_NOTPOSPLUS:
- case OP_NOTPOSQUERY:
- case OP_NOTPOSUPTO:
- case OP_NOTSTARI:
- case OP_NOTMINSTARI:
- case OP_NOTPLUSI:
- case OP_NOTMINPLUSI:
- case OP_NOTQUERYI:
- case OP_NOTMINQUERYI:
- case OP_NOTUPTOI:
- case OP_NOTMINUPTOI:
- case OP_NOTEXACTI:
- case OP_NOTPOSSTARI:
- case OP_NOTPOSPLUSI:
- case OP_NOTPOSQUERYI:
- case OP_NOTPOSUPTOI:
- if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
- break;
- }
+ /* Add in the fixed length from the table */
+
+ code += PRIV(OP_lengths)[c];
+
+ /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may
+ be followed by a multi-unit character. The length in the table is a
+ minimum, so we have to arrange to skip the extra units. */
+
+#ifdef MAYBE_UTF_MULTI
+ if (utf) switch(c)
+ {
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_EXACT:
+ case OP_EXACTI:
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ case OP_UPTO:
+ case OP_UPTOI:
+ case OP_NOTUPTO:
+ case OP_NOTUPTOI:
+ case OP_MINUPTO:
+ case OP_MINUPTOI:
+ case OP_NOTMINUPTO:
+ case OP_NOTMINUPTOI:
+ case OP_POSUPTO:
+ case OP_POSUPTOI:
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+ case OP_STAR:
+ case OP_STARI:
+ case OP_NOTSTAR:
+ case OP_NOTSTARI:
+ case OP_MINSTAR:
+ case OP_MINSTARI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINSTARI:
+ case OP_POSSTAR:
+ case OP_POSSTARI:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSSTARI:
+ case OP_PLUS:
+ case OP_PLUSI:
+ case OP_NOTPLUS:
+ case OP_NOTPLUSI:
+ case OP_MINPLUS:
+ case OP_MINPLUSI:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINPLUSI:
+ case OP_POSPLUS:
+ case OP_POSPLUSI:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSPLUSI:
+ case OP_QUERY:
+ case OP_QUERYI:
+ case OP_NOTQUERY:
+ case OP_NOTQUERYI:
+ case OP_MINQUERY:
+ case OP_MINQUERYI:
+ case OP_NOTMINQUERY:
+ case OP_NOTMINQUERYI:
+ case OP_POSQUERY:
+ case OP_POSQUERYI:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSQUERYI:
+ if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+ break;
+ }
#else
- (void)(utf); /* Keep compiler happy by referencing function argument */
-#endif
+ (void)(utf); /* Keep compiler happy by referencing function argument */
+#endif /* MAYBE_UTF_MULTI */
+ }
}
}
@@ -3915,7 +2634,9 @@ when Perl does, I think.
A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not.
It seems that the appearance of a nested POSIX class supersedes an apparent
external class. For example, [:a[:digit:]b:] matches "a", "b", ":", or
-a digit.
+a digit. This is handled by returning FALSE if the start of a new group with
+the same terminator is encountered, since the next closing sequence must close
+the nested group, not the outer one.
In Perl, unescaped square brackets may also appear as part of class names. For
example, [:a[:abc]b:] gives unknown POSIX class "[:abc]b:]". However, for
@@ -3925,21 +2646,21 @@ names.
Arguments:
ptr pointer to the initial [
- endptr where to return the end pointer
+ endptr where to return a pointer to the terminating ':', '.', or '='
Returns: TRUE or FALSE
*/
static BOOL
-check_posix_syntax(const pcre_uchar *ptr, const pcre_uchar **endptr)
+check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR *endptr)
{
-pcre_uchar terminator; /* Don't combine these lines; the Solaris cc */
+PCRE2_UCHAR terminator; /* Don't combine these lines; the Solaris cc */
terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */
+
for (++ptr; *ptr != CHAR_NULL; ptr++)
{
if (*ptr == CHAR_BACKSLASH &&
- (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET ||
- ptr[1] == CHAR_BACKSLASH))
+ (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ptr[1] == CHAR_BACKSLASH))
ptr++;
else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) ||
*ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE;
@@ -3949,12 +2670,12 @@ for (++ptr; *ptr != CHAR_NULL; ptr++)
return TRUE;
}
}
+
return FALSE;
}
-
/*************************************************
* Check POSIX class name *
*************************************************/
@@ -3970,14 +2691,14 @@ Returns: a value representing the name, or -1 if unknown
*/
static int
-check_posix_name(const pcre_uchar *ptr, int len)
+check_posix_name(PCRE2_SPTR ptr, int len)
{
const char *pn = posix_names;
register int yield = 0;
while (posix_name_lengths[yield] != 0)
{
if (len == posix_name_lengths[yield] &&
- STRNCMP_UC_C8(ptr, pn, (unsigned int)len) == 0) return yield;
+ PRIV(strncmp_c8)(ptr, pn, (unsigned int)len) == 0) return yield;
pn += posix_name_lengths[yield] + 1;
yield++;
}
@@ -3985,141 +2706,16 @@ return -1;
}
-/*************************************************
-* Adjust OP_RECURSE items in repeated group *
-*************************************************/
-
-/* OP_RECURSE items contain an offset from the start of the regex to the group
-that is referenced. This means that groups can be replicated for fixed
-repetition simply by copying (because the recursion is allowed to refer to
-earlier groups that are outside the current group). However, when a group is
-optional (i.e. the minimum quantifier is zero), OP_BRAZERO or OP_SKIPZERO is
-inserted before it, after it has been compiled. This means that any OP_RECURSE
-items within it that refer to the group itself or any contained groups have to
-have their offsets adjusted. That one of the jobs of this function. Before it
-is called, the partially compiled regex must be temporarily terminated with
-OP_END.
-
-This function has been extended to cope with forward references for recursions
-and subroutine calls. It must check the list of such references for the
-group we are dealing with. If it finds that one of the recursions in the
-current group is on this list, it does not adjust the value in the reference
-(which is a group number). After the group has been scanned, all the offsets in
-the forward reference list for the group are adjusted.
-
-Arguments:
- group points to the start of the group
- adjust the amount by which the group is to be moved
- utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
- cd contains pointers to tables etc.
- save_hwm_offset the hwm forward reference offset at the start of the group
-
-Returns: nothing
-*/
-
-static void
-adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd,
- size_t save_hwm_offset)
-{
-int offset;
-pcre_uchar *hc;
-pcre_uchar *ptr = group;
-
-while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL)
- {
- for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm;
- hc += LINK_SIZE)
- {
- offset = (int)GET(hc, 0);
- if (cd->start_code + offset == ptr + 1) break;
- }
-
- /* If we have not found this recursion on the forward reference list, adjust
- the recursion's offset if it's after the start of this group. */
-
- if (hc >= cd->hwm)
- {
- offset = (int)GET(ptr, 1);
- if (cd->start_code + offset >= group) PUT(ptr, 1, offset + adjust);
- }
-
- ptr += 1 + LINK_SIZE;
- }
-
-/* Now adjust all forward reference offsets for the group. */
-
-for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm;
- hc += LINK_SIZE)
- {
- offset = (int)GET(hc, 0);
- PUT(hc, 0, offset + adjust);
- }
-}
-
-
-
-/*************************************************
-* Insert an automatic callout point *
-*************************************************/
-
-/* This function is called when the PCRE_AUTO_CALLOUT option is set, to insert
-callout points before each pattern item.
-
-Arguments:
- code current code pointer
- ptr current pattern pointer
- cd pointers to tables etc
-
-Returns: new code pointer
-*/
-
-static pcre_uchar *
-auto_callout(pcre_uchar *code, const pcre_uchar *ptr, compile_data *cd)
-{
-*code++ = OP_CALLOUT;
-*code++ = 255;
-PUT(code, 0, (int)(ptr - cd->start_pattern)); /* Pattern offset */
-PUT(code, LINK_SIZE, 0); /* Default length */
-return code + 2 * LINK_SIZE;
-}
-
-
-/*************************************************
-* Complete a callout item *
-*************************************************/
-
-/* A callout item contains the length of the next item in the pattern, which
-we can't fill in till after we have reached the relevant point. This is used
-for both automatic and manual callouts.
-
-Arguments:
- previous_callout points to previous callout item
- ptr current pattern pointer
- cd pointers to tables etc
-
-Returns: nothing
-*/
-
-static void
-complete_callout(pcre_uchar *previous_callout, const pcre_uchar *ptr, compile_data *cd)
-{
-int length = (int)(ptr - cd->start_pattern - GET(previous_callout, 2));
-PUT(previous_callout, 2 + LINK_SIZE, length);
-}
-
-
-
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
/*************************************************
* Get othercase range *
*************************************************/
-/* This function is passed the start and end of a class range, in UTF-8 mode
-with UCP support. It searches up the characters, looking for ranges of
-characters in the "other" case. Each call returns the next one, updating the
-start address. A character with multiple other cases is returned on its own
-with a special return value.
+/* This function is passed the start and end of a class range in UCT mode. It
+searches up the characters, looking for ranges of characters in the "other"
+case. Each call returns the next one, updating the start address. A character
+with multiple other cases is returned on its own with a special return value.
Arguments:
cptr points to starting character value; updated
@@ -4134,10 +2730,10 @@ Yield: -1 when no more
*/
static int
-get_othercase_range(pcre_uint32 *cptr, pcre_uint32 d, pcre_uint32 *ocptr,
- pcre_uint32 *odptr)
+get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr,
+ uint32_t *odptr)
{
-pcre_uint32 c, othercase, next;
+uint32_t c, othercase, next;
unsigned int co;
/* Find the first character that has an other case. If it has multiple other
@@ -4173,7 +2769,7 @@ for (++c; c <= d; c++)
*cptr = c; /* Rest of input range */
return 0;
}
-#endif /* SUPPORT_UCP */
+#endif /* SUPPORT_UNICODE */
@@ -4190,7 +2786,7 @@ Arguments:
classbits the bit map for characters < 256
uchardptr points to the pointer for extra data
options the options word
- cd contains pointers to tables etc.
+ cb compile data
start start of range character
end end of range character
@@ -4198,35 +2794,35 @@ Returns: the number of < 256 characters added
the pointer to extra data is updated
*/
-static int
-add_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options,
- compile_data *cd, pcre_uint32 start, pcre_uint32 end)
+static unsigned int
+add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
+ compile_block *cb, uint32_t start, uint32_t end)
{
-pcre_uint32 c;
-pcre_uint32 classbits_end = (end <= 0xff ? end : 0xff);
-int n8 = 0;
+uint32_t c;
+uint32_t classbits_end = (end <= 0xff ? end : 0xff);
+unsigned int n8 = 0;
/* If caseless matching is required, scan the range and process alternate
cases. In Unicode, there are 8-bit characters that have alternate cases that
are greater than 255 and vice-versa. Sometimes we can just extend the original
range. */
-if ((options & PCRE_CASELESS) != 0)
+if ((options & PCRE2_CASELESS) != 0)
{
-#ifdef SUPPORT_UCP
- if ((options & PCRE_UTF8) != 0)
+#ifdef SUPPORT_UNICODE
+ if ((options & PCRE2_UTF) != 0)
{
int rc;
- pcre_uint32 oc, od;
+ uint32_t oc, od;
- options &= ~PCRE_CASELESS; /* Remove for recursive calls */
+ options &= ~PCRE2_CASELESS; /* Remove for recursive calls */
c = start;
while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0)
{
/* Handle a single character that has more than one other case. */
- if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cd,
+ if (rc > 0) n8 += add_list_to_class(classbits, uchardptr, options, cb,
PRIV(ucd_caseless_sets) + rc, oc);
/* Do nothing if the other case range is within the original range. */
@@ -4243,17 +2839,17 @@ if ((options & PCRE_CASELESS) != 0)
end = od; /* Extend upwards */
if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff);
}
- else n8 += add_to_class(classbits, uchardptr, options, cd, oc, od);
+ else n8 += add_to_class(classbits, uchardptr, options, cb, oc, od);
}
}
else
-#endif /* SUPPORT_UCP */
+#endif /* SUPPORT_UNICODE */
- /* Not UTF-mode, or no UCP */
+ /* Not UTF mode */
for (c = start; c <= classbits_end; c++)
{
- SETBIT(classbits, cd->fcc[c]);
+ SETBIT(classbits, cb->fcc[c]);
n8++;
}
}
@@ -4262,19 +2858,8 @@ if ((options & PCRE_CASELESS) != 0)
length - this means that the same lists of (e.g.) horizontal spaces can be used
in all cases. */
-#if defined COMPILE_PCRE8
-#ifdef SUPPORT_UTF
- if ((options & PCRE_UTF8) == 0)
-#endif
- if (end > 0xff) end = 0xff;
-
-#elif defined COMPILE_PCRE16
-#ifdef SUPPORT_UTF
- if ((options & PCRE_UTF16) == 0)
-#endif
- if (end > 0xffff) end = 0xffff;
-
-#endif /* COMPILE_PCRE[8|16] */
+if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR)
+ end = MAX_NON_UTF_CHAR;
/* Use the bitmap for characters < 256. Otherwise use extra data.*/
@@ -4285,14 +2870,15 @@ for (c = start; c <= classbits_end; c++)
n8++;
}
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#ifdef SUPPORT_WIDE_CHARS
if (start <= 0xff) start = 0xff + 1;
if (end >= start)
{
- pcre_uchar *uchardata = *uchardptr;
-#ifdef SUPPORT_UTF
- if ((options & PCRE_UTF8) != 0) /* All UTFs use the same flag bit */
+ PCRE2_UCHAR *uchardata = *uchardptr;
+
+#ifdef SUPPORT_UNICODE
+ if ((options & PCRE2_UTF) != 0)
{
if (start < end)
{
@@ -4307,12 +2893,12 @@ if (end >= start)
}
}
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
/* Without UTF support, character values are constrained by the bit length,
and can only be > 256 for 16-bit and 32-bit libraries. */
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
{}
#else
if (start < end)
@@ -4327,17 +2913,17 @@ if (end >= start)
*uchardata++ = start;
}
#endif
-
*uchardptr = uchardata; /* Updata extra data pointer */
}
-#endif /* SUPPORT_UTF || !COMPILE_PCRE8 */
+#else
+ (void)uchardptr; /* Avoid compiler warning */
+#endif /* SUPPORT_WIDE_CHARS */
return n8; /* Number of 8-bit characters */
}
-
/*************************************************
* Add a list of characters to a class *
*************************************************/
@@ -4352,7 +2938,7 @@ Arguments:
classbits the bit map for characters < 256
uchardptr points to the pointer for extra data
options the options word
- cd contains pointers to tables etc.
+ cb contains pointers to tables etc.
p points to row of 32-bit values, terminated by NOTACHAR
except character to omit; this is used when adding lists of
case-equivalent characters to avoid including the one we
@@ -4362,18 +2948,18 @@ Returns: the number of < 256 characters added
the pointer to extra data is updated
*/
-static int
-add_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr, int options,
- compile_data *cd, const pcre_uint32 *p, unsigned int except)
+static unsigned int
+add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
+ compile_block *cb, const uint32_t *p, unsigned int except)
{
-int n8 = 0;
+unsigned int n8 = 0;
while (p[0] < NOTACHAR)
{
- int n = 0;
+ unsigned int n = 0;
if (p[0] != except)
{
while(p[n+1] == p[0] + n + 1) n++;
- n8 += add_to_class(classbits, uchardptr, options, cd, p[0], p[n]);
+ n8 += add_to_class(classbits, uchardptr, options, cb, p[0], p[n]);
}
p += n + 1;
}
@@ -4393,25 +2979,25 @@ Arguments:
classbits the bit map for characters < 256
uchardptr points to the pointer for extra data
options the options word
- cd contains pointers to tables etc.
+ cb contains pointers to tables etc.
p points to row of 32-bit values, terminated by NOTACHAR
Returns: the number of < 256 characters added
the pointer to extra data is updated
*/
-static int
-add_not_list_to_class(pcre_uint8 *classbits, pcre_uchar **uchardptr,
- int options, compile_data *cd, const pcre_uint32 *p)
+static unsigned int
+add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
+ uint32_t options, compile_block *cb, const uint32_t *p)
{
-BOOL utf = (options & PCRE_UTF8) != 0;
-int n8 = 0;
+BOOL utf = (options & PCRE2_UTF) != 0;
+unsigned int n8 = 0;
if (p[0] > 0)
- n8 += add_to_class(classbits, uchardptr, options, cd, 0, p[0] - 1);
+ n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1);
while (p[0] < NOTACHAR)
{
while (p[1] == p[0] + 1) p++;
- n8 += add_to_class(classbits, uchardptr, options, cd, p[0] + 1,
+ n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1,
(p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1);
p++;
}
@@ -4421,6 +3007,822 @@ return n8;
/*************************************************
+* Process (*VERB) name for escapes *
+*************************************************/
+
+/* This function is called when the PCRE2_ALT_VERBNAMES option is set, to
+process the characters in a verb's name argument. It is called twice, once with
+codeptr == NULL, to find out the length of the processed name, and again to put
+the name into memory.
+
+Arguments:
+ ptrptr pointer to the input pointer
+ codeptr pointer to the compiled code pointer
+ errorcodeptr pointer to the error code
+ options the options bits
+ utf TRUE if processing UTF
+ cb compile data block
+
+Returns: length of the processed name, or < 0 on error
+*/
+
+static int
+process_verb_name(PCRE2_SPTR *ptrptr, PCRE2_UCHAR **codeptr, int *errorcodeptr,
+ uint32_t options, BOOL utf, compile_block *cb)
+{
+int32_t arglen = 0;
+BOOL inescq = FALSE;
+PCRE2_SPTR ptr = *ptrptr;
+PCRE2_UCHAR *code = (codeptr == NULL)? NULL : *codeptr;
+
+for (; ptr < cb->end_pattern; ptr++)
+ {
+ uint32_t x = *ptr;
+
+ /* Skip over literals */
+
+ if (inescq)
+ {
+ if (x == CHAR_BACKSLASH && ptr[1] == CHAR_E)
+ {
+ inescq = FALSE;
+ ptr++;;
+ continue;
+ }
+ }
+
+ else /* Not a literal character */
+ {
+ if (x == CHAR_RIGHT_PARENTHESIS) break;
+
+ /* Skip over comments and whitespace in extended mode. */
+
+ if ((options & PCRE2_EXTENDED) != 0)
+ {
+ PCRE2_SPTR wscptr = ptr;
+ while (MAX_255(x) && (cb->ctypes[x] & ctype_space) != 0) x = *(++ptr);
+ if (x == CHAR_NUMBER_SIGN)
+ {
+ ptr++;
+ while (*ptr != CHAR_NULL || ptr < cb->end_pattern)
+ {
+ if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */
+ { /* IS_NEWLINE sets cb->nllen. */
+ ptr += cb->nllen;
+ break;
+ }
+ ptr++;
+#ifdef SUPPORT_UNICODE
+ if (utf) FORWARDCHAR(ptr);
+#endif
+ }
+ }
+
+ /* If we have skipped any characters, restart the loop. */
+
+ if (ptr > wscptr)
+ {
+ ptr--;
+ continue;
+ }
+ }
+
+ /* Process escapes */
+
+ if (x == '\\')
+ {
+ int rc;
+ *errorcodeptr = 0;
+ rc = PRIV(check_escape)(&ptr, cb->end_pattern, &x, errorcodeptr, options,
+ FALSE, cb);
+ *ptrptr = ptr; /* For possible error */
+ if (*errorcodeptr != 0) return -1;
+ if (rc != 0)
+ {
+ if (rc == ESC_Q)
+ {
+ inescq = TRUE;
+ continue;
+ }
+ if (rc == ESC_E) continue;
+ *errorcodeptr = ERR40;
+ return -1;
+ }
+ }
+ }
+
+ /* We have the next character in the name. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ if (code == NULL) /* Just want the length */
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ int i;
+ for (i = 0; i < PRIV(utf8_table1_size); i++)
+ if ((int)x <= PRIV(utf8_table1)[i]) break;
+ arglen += i;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ if (x > 0xffff) arglen++;
+#endif
+ }
+ else
+ {
+ PCRE2_UCHAR cbuff[8];
+ x = PRIV(ord2utf)(x, cbuff);
+ memcpy(code, cbuff, CU2BYTES(x));
+ code += x;
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Not UTF */
+ {
+ if (code != NULL) *code++ = (PCRE2_UCHAR)x;
+ }
+
+ arglen++;
+
+ if ((unsigned int)arglen > MAX_MARK)
+ {
+ *errorcodeptr = ERR76;
+ *ptrptr = ptr;
+ return -1;
+ }
+ }
+
+/* Update the pointers before returning. */
+
+*ptrptr = ptr;
+if (codeptr != NULL) *codeptr = code;
+return arglen;
+}
+
+
+
+/*************************************************
+* Macro for the next two functions *
+*************************************************/
+
+/* Both scan_for_captures() and compile_branch() use this macro to generate a
+fragment of code that reads the characters of a name and sets its length
+(checking for not being too long). Count the characters dynamically, to avoid
+the possibility of integer overflow. The same macro is used for reading *VERB
+names. */
+
+#define READ_NAME(ctype, errno, errset) \
+ namelen = 0; \
+ while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype) != 0) \
+ { \
+ ptr++; \
+ namelen++; \
+ if (namelen > MAX_NAME_SIZE) \
+ { \
+ errset = errno; \
+ goto FAILED; \
+ } \
+ }
+
+
+
+/*************************************************
+* Scan regex to identify named groups *
+*************************************************/
+
+/* This function is called first of all, to scan for named capturing groups so
+that information about them is fully available to both the compiling scans.
+It skips over everything except parenthesized items.
+
+Arguments:
+ ptrptr points to pointer to the start of the pattern
+ options compiling dynamic options
+ cb pointer to the compile data block
+
+Returns: zero on success or a non-zero error code, with pointer updated
+*/
+
+typedef struct nest_save {
+ uint16_t nest_depth;
+ uint16_t reset_group;
+ uint16_t max_group;
+ uint16_t flags;
+} nest_save;
+
+#define NSF_RESET 0x0001u
+#define NSF_EXTENDED 0x0002u
+#define NSF_DUPNAMES 0x0004u
+
+static int scan_for_captures(PCRE2_SPTR *ptrptr, uint32_t options,
+ compile_block *cb)
+{
+uint32_t c;
+uint32_t delimiter;
+uint32_t set, unset, *optset;
+uint32_t skiptoket = 0;
+uint16_t nest_depth = 0;
+int errorcode = 0;
+int escape;
+int namelen;
+int i;
+BOOL inescq = FALSE;
+BOOL isdupname;
+BOOL utf = (options & PCRE2_UTF) != 0;
+BOOL negate_class;
+PCRE2_SPTR name;
+PCRE2_SPTR start;
+PCRE2_SPTR ptr = *ptrptr;
+named_group *ng;
+nest_save *top_nest = NULL;
+nest_save *end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size);
+
+/* The size of the nest_save structure might not be a factor of the size of the
+workspace. Therefore we must round down end_nests so as to correctly avoid
+creating a nest_save that spans the end of the workspace. */
+
+end_nests = (nest_save *)((char *)end_nests -
+ ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save)));
+
+/* Now scan the pattern */
+
+for (; ptr < cb->end_pattern; ptr++)
+ {
+ c = *ptr;
+
+ /* Parenthesized groups set skiptoket when all following characters up to the
+ next closing parenthesis must be ignored. The parenthesis itself must be
+ processed (to end the nested parenthesized item). */
+
+ if (skiptoket != 0)
+ {
+ if (c != CHAR_RIGHT_PARENTHESIS) continue;
+ skiptoket = 0;
+ }
+
+ /* Skip over literals */
+
+ if (inescq)
+ {
+ if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)
+ {
+ inescq = FALSE;
+ ptr++;
+ }
+ continue;
+ }
+
+ /* Skip over # comments and whitespace in extended mode. */
+
+ if ((options & PCRE2_EXTENDED) != 0)
+ {
+ PCRE2_SPTR wscptr = ptr;
+ while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr);
+ if (c == CHAR_NUMBER_SIGN)
+ {
+ ptr++;
+ while (ptr < cb->end_pattern)
+ {
+ if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */
+ { /* IS_NEWLINE sets cb->nllen. */
+ ptr += cb->nllen;
+ break;
+ }
+ ptr++;
+#ifdef SUPPORT_UNICODE
+ if (utf) FORWARDCHAR(ptr);
+#endif
+ }
+ }
+
+ /* If we skipped any characters, restart the loop. Otherwise, we didn't see
+ a comment. */
+
+ if (ptr > wscptr)
+ {
+ ptr--;
+ continue;
+ }
+ }
+
+ /* Process the next pattern item. */
+
+ switch(c)
+ {
+ default: /* Most characters are just skipped */
+ break;
+
+ /* Skip escapes except for \Q */
+
+ case CHAR_BACKSLASH:
+ errorcode = 0;
+ escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode, options,
+ FALSE, cb);
+ if (errorcode != 0) goto FAILED;
+ if (escape == ESC_Q) inescq = TRUE;
+ break;
+
+ /* Skip a character class. The syntax is complicated so we have to
+ replicate some of what happens when a class is processed for real. */
+
+ case CHAR_LEFT_SQUARE_BRACKET:
+ if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0 ||
+ PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0)
+ {
+ ptr += 6;
+ break;
+ }
+
+ /* If the first character is '^', set the negation flag (not actually used
+ here, except to recognize only one ^) and skip it. If the first few
+ characters (either before or after ^) are \Q\E or \E we skip them too. This
+ makes for compatibility with Perl. */
+
+ negate_class = FALSE;
+ for (;;)
+ {
+ c = *(++ptr); /* First character in class */
+ if (c == CHAR_BACKSLASH)
+ {
+ if (ptr[1] == CHAR_E)
+ ptr++;
+ else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0)
+ ptr += 3;
+ else
+ break;
+ }
+ else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT)
+ negate_class = TRUE;
+ else break;
+ }
+
+ if (c == CHAR_RIGHT_SQUARE_BRACKET &&
+ (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)
+ break;
+
+ /* Loop for the contents of the class */
+
+ for (;;)
+ {
+ PCRE2_SPTR tempptr;
+
+ if (c == CHAR_NULL && ptr >= cb->end_pattern)
+ {
+ errorcode = ERR6; /* Missing terminating ']' */
+ goto FAILED;
+ }
+
+#ifdef SUPPORT_UNICODE
+ if (utf && HAS_EXTRALEN(c))
+ { /* Braces are required because the */
+ GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */
+ }
+#endif
+
+ /* Inside \Q...\E everything is literal except \E */
+
+ if (inescq)
+ {
+ if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E) /* If we are at \E */
+ {
+ inescq = FALSE; /* Reset literal state */
+ ptr++; /* Skip the 'E' */
+ }
+ goto CONTINUE_CLASS;
+ }
+
+ /* Skip POSIX class names. */
+ if (c == CHAR_LEFT_SQUARE_BRACKET &&
+ (ptr[1] == CHAR_COLON || ptr[1] == CHAR_DOT ||
+ ptr[1] == CHAR_EQUALS_SIGN) && check_posix_syntax(ptr, &tempptr))
+ {
+ ptr = tempptr + 1;
+ }
+ else if (c == CHAR_BACKSLASH)
+ {
+ errorcode = 0;
+ escape = PRIV(check_escape)(&ptr, cb->end_pattern, &c, &errorcode,
+ options, TRUE, cb);
+ if (errorcode != 0) goto FAILED;
+ if (escape == ESC_Q) inescq = TRUE;
+ }
+
+ CONTINUE_CLASS:
+ c = *(++ptr);
+ if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break;
+ } /* End of class-processing loop */
+ break;
+
+ /* This is the real work of this function - handling parentheses. */
+
+ case CHAR_LEFT_PARENTHESIS:
+ nest_depth++;
+
+ if (ptr[1] != CHAR_QUESTION_MARK)
+ {
+ if (ptr[1] != CHAR_ASTERISK)
+ {
+ if ((options & PCRE2_NO_AUTO_CAPTURE) == 0) cb->bracount++;
+ }
+
+ /* (*something) - skip over a name, and then just skip to closing ket
+ unless PCRE2_ALT_VERBNAMES is set, in which case we have to process
+ escapes in the string after a verb name terminated by a colon. */
+
+ else
+ {
+ ptr += 2;
+ while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) != 0) ptr++;
+ if (*ptr == CHAR_COLON && (options & PCRE2_ALT_VERBNAMES) != 0)
+ {
+ ptr++;
+ if (process_verb_name(&ptr, NULL, &errorcode, options, utf, cb) < 0)
+ goto FAILED;
+ }
+ else
+ {
+ while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS)
+ ptr++;
+ }
+ nest_depth--;
+ }
+ }
+
+ /* Handle (?...) groups */
+
+ else switch(ptr[2])
+ {
+ default:
+ ptr += 2;
+ if (ptr[0] == CHAR_R || /* (?R) */
+ ptr[0] == CHAR_NUMBER_SIGN || /* (?#) */
+ IS_DIGIT(ptr[0]) || /* (?n) */
+ (ptr[0] == CHAR_MINUS && IS_DIGIT(ptr[1]))) /* (?-n) */
+ {
+ skiptoket = ptr[0];
+ break;
+ }
+
+ /* Handle (?| and (?imsxJU: which are the only other valid forms. Both
+ need a new block on the nest stack. */
+
+ if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace);
+ else if (++top_nest >= end_nests)
+ {
+ errorcode = ERR84;
+ goto FAILED;
+ }
+ top_nest->nest_depth = nest_depth;
+ top_nest->flags = 0;
+ if ((options & PCRE2_EXTENDED) != 0) top_nest->flags |= NSF_EXTENDED;
+ if ((options & PCRE2_DUPNAMES) != 0) top_nest->flags |= NSF_DUPNAMES;
+
+ if (*ptr == CHAR_VERTICAL_LINE)
+ {
+ top_nest->reset_group = (uint16_t)cb->bracount;
+ top_nest->max_group = (uint16_t)cb->bracount;
+ top_nest->flags |= NSF_RESET;
+ cb->external_flags |= PCRE2_DUPCAPUSED;
+ break;
+ }
+
+ /* Scan options */
+
+ top_nest->reset_group = 0;
+ top_nest->max_group = 0;
+
+ set = unset = 0;
+ optset = &set;
+
+ /* Need only track (?x: and (?J: at this stage */
+
+ while (*ptr != CHAR_RIGHT_PARENTHESIS && *ptr != CHAR_COLON)
+ {
+ switch (*ptr++)
+ {
+ case CHAR_MINUS: optset = &unset; break;
+
+ case CHAR_x: *optset |= PCRE2_EXTENDED; break;
+
+ case CHAR_J:
+ *optset |= PCRE2_DUPNAMES;
+ cb->external_flags |= PCRE2_JCHANGED;
+ break;
+
+ case CHAR_i:
+ case CHAR_m:
+ case CHAR_s:
+ case CHAR_U:
+ break;
+
+ default:
+ errorcode = ERR11;
+ ptr--; /* Correct the offset */
+ goto FAILED;
+ }
+ }
+
+ options = (options | set) & (~unset);
+
+ /* If the options ended with ')' this is not the start of a nested
+ group with option changes, so the options change at this level. If the
+ previous level set up a nest block, discard the one we have just created.
+ Otherwise adjust it for the previous level. */
+
+ if (*ptr == CHAR_RIGHT_PARENTHESIS)
+ {
+ nest_depth--;
+ if (top_nest > (nest_save *)(cb->start_workspace) &&
+ (top_nest-1)->nest_depth == nest_depth) top_nest --;
+ else top_nest->nest_depth = nest_depth;
+ }
+ break;
+
+ /* Skip over a numerical or string argument for a callout. */
+
+ case CHAR_C:
+ ptr += 2;
+ if (ptr[1] == CHAR_RIGHT_PARENTHESIS) break;
+ if (IS_DIGIT(ptr[1]))
+ {
+ while (IS_DIGIT(ptr[1])) ptr++;
+ }
+
+ /* Handle a string argument */
+
+ else
+ {
+ ptr++;
+ delimiter = 0;
+ for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
+ {
+ if (*ptr == PRIV(callout_start_delims)[i])
+ {
+ delimiter = PRIV(callout_end_delims)[i];
+ break;
+ }
+ }
+
+ if (delimiter == 0)
+ {
+ errorcode = ERR82;
+ goto FAILED;
+ }
+
+ start = ptr;
+ do
+ {
+ if (++ptr >= cb->end_pattern)
+ {
+ errorcode = ERR81;
+ ptr = start; /* To give a more useful message */
+ goto FAILED;
+ }
+ if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2;
+ }
+ while (ptr[0] != delimiter);
+ }
+
+ /* Check terminating ) */
+
+ if (ptr[1] != CHAR_RIGHT_PARENTHESIS)
+ {
+ errorcode = ERR39;
+ ptr++;
+ goto FAILED;
+ }
+ break;
+
+ /* Conditional group */
+
+ case CHAR_LEFT_PARENTHESIS:
+ if (ptr[3] != CHAR_QUESTION_MARK) /* Not assertion or callout */
+ {
+ nest_depth++;
+ ptr += 2;
+ break;
+ }
+
+ /* Must be an assertion or a callout */
+
+ switch(ptr[4])
+ {
+ case CHAR_LESS_THAN_SIGN:
+ if (ptr[5] != CHAR_EXCLAMATION_MARK && ptr[5] != CHAR_EQUALS_SIGN)
+ goto MISSING_ASSERTION;
+ /* Fall through */
+
+ case CHAR_C:
+ case CHAR_EXCLAMATION_MARK:
+ case CHAR_EQUALS_SIGN:
+ ptr++;
+ break;
+
+ default:
+ MISSING_ASSERTION:
+ ptr += 3; /* To improve error message */
+ errorcode = ERR28;
+ goto FAILED;
+ }
+ break;
+
+ case CHAR_COLON:
+ case CHAR_GREATER_THAN_SIGN:
+ case CHAR_EQUALS_SIGN:
+ case CHAR_EXCLAMATION_MARK:
+ case CHAR_AMPERSAND:
+ case CHAR_PLUS:
+ ptr += 2;
+ break;
+
+ case CHAR_P:
+ if (ptr[3] != CHAR_LESS_THAN_SIGN)
+ {
+ ptr += 3;
+ break;
+ }
+ ptr++;
+ c = CHAR_GREATER_THAN_SIGN; /* Terminator */
+ goto DEFINE_NAME;
+
+ case CHAR_LESS_THAN_SIGN:
+ if (ptr[3] == CHAR_EQUALS_SIGN || ptr[3] == CHAR_EXCLAMATION_MARK)
+ {
+ ptr += 3;
+ break;
+ }
+ c = CHAR_GREATER_THAN_SIGN; /* Terminator */
+ goto DEFINE_NAME;
+
+ case CHAR_APOSTROPHE:
+ c = CHAR_APOSTROPHE; /* Terminator */
+
+ DEFINE_NAME:
+ name = ptr = ptr + 3;
+
+ if (*ptr == c) /* Empty name */
+ {
+ errorcode = ERR62;
+ goto FAILED;
+ }
+
+ if (IS_DIGIT(*ptr))
+ {
+ errorcode = ERR44; /* Group name must start with non-digit */
+ goto FAILED;
+ }
+
+ if (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_word) == 0)
+ {
+ errorcode = ERR24;
+ goto FAILED;
+ }
+
+ /* Advance ptr, set namelen and check its length. */
+ READ_NAME(ctype_word, ERR48, errorcode);
+
+ if (*ptr != c)
+ {
+ errorcode = ERR42;
+ goto FAILED;
+ }
+
+ if (cb->names_found >= MAX_NAME_COUNT)
+ {
+ errorcode = ERR49;
+ goto FAILED;
+ }
+
+ if (namelen + IMM2_SIZE + 1 > cb->name_entry_size)
+ cb->name_entry_size = (uint16_t)(namelen + IMM2_SIZE + 1);
+
+ /* We have a valid name for this capturing group. */
+
+ cb->bracount++;
+
+ /* Scan the list to check for duplicates. For duplicate names, if the
+ number is the same, break the loop, which causes the name to be
+ discarded; otherwise, if DUPNAMES is not set, give an error.
+ If it is set, allow the name with a different number, but continue
+ scanning in case this is a duplicate with the same number. For
+ non-duplicate names, give an error if the number is duplicated. */
+
+ isdupname = FALSE;
+ ng = cb->named_groups;
+ for (i = 0; i < cb->names_found; i++, ng++)
+ {
+ if (namelen == ng->length &&
+ PRIV(strncmp)(name, ng->name, (size_t)namelen) == 0)
+ {
+ if (ng->number == cb->bracount) break;
+ if ((options & PCRE2_DUPNAMES) == 0)
+ {
+ errorcode = ERR43;
+ goto FAILED;
+ }
+ isdupname = ng->isdup = TRUE; /* Mark as a duplicate */
+ cb->dupnames = TRUE; /* Duplicate names exist */
+ }
+ else if (ng->number == cb->bracount)
+ {
+ errorcode = ERR65;
+ goto FAILED;
+ }
+ }
+
+ if (i < cb->names_found) break; /* Ignore duplicate with same number */
+
+ /* Increase the list size if necessary */
+
+ if (cb->names_found >= cb->named_group_list_size)
+ {
+ uint32_t newsize = cb->named_group_list_size * 2;
+ named_group *newspace =
+ cb->cx->memctl.malloc(newsize * sizeof(named_group),
+ cb->cx->memctl.memory_data);
+ if (newspace == NULL)
+ {
+ errorcode = ERR21;
+ goto FAILED;
+ }
+
+ memcpy(newspace, cb->named_groups,
+ cb->named_group_list_size * sizeof(named_group));
+ if (cb->named_group_list_size > NAMED_GROUP_LIST_SIZE)
+ cb->cx->memctl.free((void *)cb->named_groups,
+ cb->cx->memctl.memory_data);
+ cb->named_groups = newspace;
+ cb->named_group_list_size = newsize;
+ }
+
+ /* Add this name to the list */
+
+ cb->named_groups[cb->names_found].name = name;
+ cb->named_groups[cb->names_found].length = (uint16_t)namelen;
+ cb->named_groups[cb->names_found].number = cb->bracount;
+ cb->named_groups[cb->names_found].isdup = (uint16_t)isdupname;
+ cb->names_found++;
+ break;
+ } /* End of (? switch */
+ break; /* End of ( handling */
+
+ /* At an alternation, reset the capture count if we are in a (?| group. */
+
+ case CHAR_VERTICAL_LINE:
+ if (top_nest != NULL && top_nest->nest_depth == nest_depth &&
+ (top_nest->flags & NSF_RESET) != 0)
+ {
+ if (cb->bracount > top_nest->max_group)
+ top_nest->max_group = (uint16_t)cb->bracount;
+ cb->bracount = top_nest->reset_group;
+ }
+ break;
+
+ /* At a right parenthesis, reset the capture count to the maximum if we
+ are in a (?| group and/or reset the extended option. */
+
+ case CHAR_RIGHT_PARENTHESIS:
+ if (top_nest != NULL && top_nest->nest_depth == nest_depth)
+ {
+ if ((top_nest->flags & NSF_RESET) != 0 &&
+ top_nest->max_group > cb->bracount)
+ cb->bracount = top_nest->max_group;
+ if ((top_nest->flags & NSF_EXTENDED) != 0) options |= PCRE2_EXTENDED;
+ else options &= ~PCRE2_EXTENDED;
+ if ((top_nest->flags & NSF_DUPNAMES) != 0) options |= PCRE2_DUPNAMES;
+ else options &= ~PCRE2_DUPNAMES;
+ if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL;
+ else top_nest--;
+ }
+ if (nest_depth == 0) /* Unmatched closing parenthesis */
+ {
+ errorcode = ERR22;
+ goto FAILED;
+ }
+ nest_depth--;
+ break;
+ }
+ }
+
+if (nest_depth == 0)
+ {
+ cb->final_bracount = cb->bracount;
+ return 0;
+ }
+
+/* We give a special error for a missing closing parentheses after (?# because
+it might otherwise be hard to see where the missing character is. */
+
+errorcode = (skiptoket == CHAR_NUMBER_SIGN)? ERR18 : ERR14;
+
+FAILED:
+*ptrptr = ptr;
+return errorcode;
+}
+
+
+
+/*************************************************
* Compile one branch *
*************************************************/
@@ -4435,13 +3837,13 @@ Arguments:
codeptr points to the pointer to the current code point
ptrptr points to the current pattern pointer
errorcodeptr points to error code variable
- firstcharptr place to put the first required character
- firstcharflagsptr place to put the first character flags, or a negative number
- reqcharptr place to put the last required character
- reqcharflagsptr place to put the last required character flags, or a negative number
+ firstcuptr place to put the first required code unit
+ firstcuflagsptr place to put the first code unit flags, or a negative number
+ reqcuptr place to put the last required code unit
+ reqcuflagsptr place to put the last required code unit flags, or a negative number
bcptr points to current branch chain
cond_depth conditional nesting depth
- cd contains pointers to tables etc.
+ cb contains pointers to tables etc.
lengthptr NULL during the real compile phase
points to length accumulator during pre-compile phase
@@ -4450,52 +3852,50 @@ Returns: TRUE on success
*/
static BOOL
-compile_branch(int *optionsptr, pcre_uchar **codeptr,
- const pcre_uchar **ptrptr, int *errorcodeptr,
- pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr,
- pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr,
+compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr,
+ PCRE2_SPTR *ptrptr, int *errorcodeptr,
+ uint32_t *firstcuptr, int32_t *firstcuflagsptr,
+ uint32_t *reqcuptr, int32_t *reqcuflagsptr,
branch_chain *bcptr, int cond_depth,
- compile_data *cd, int *lengthptr)
+ compile_block *cb, size_t *lengthptr)
{
-int repeat_type, op_type;
int repeat_min = 0, repeat_max = 0; /* To please picky compilers */
int bravalue = 0;
-int greedy_default, greedy_non_default;
-pcre_uint32 firstchar, reqchar;
-pcre_int32 firstcharflags, reqcharflags;
-pcre_uint32 zeroreqchar, zerofirstchar;
-pcre_int32 zeroreqcharflags, zerofirstcharflags;
-pcre_int32 req_caseopt, reqvary, tempreqvary;
-int options = *optionsptr; /* May change dynamically */
+uint32_t greedy_default, greedy_non_default;
+uint32_t repeat_type, op_type;
+uint32_t options = *optionsptr; /* May change dynamically */
+uint32_t firstcu, reqcu;
+int32_t firstcuflags, reqcuflags;
+uint32_t zeroreqcu, zerofirstcu;
+int32_t zeroreqcuflags, zerofirstcuflags;
+int32_t req_caseopt, reqvary, tempreqvary;
int after_manual_callout = 0;
-int length_prevgroup = 0;
-register pcre_uint32 c;
int escape;
-register pcre_uchar *code = *codeptr;
-pcre_uchar *last_code = code;
-pcre_uchar *orig_code = code;
-pcre_uchar *tempcode;
+size_t length_prevgroup = 0;
+register uint32_t c;
+register PCRE2_UCHAR *code = *codeptr;
+PCRE2_UCHAR *last_code = code;
+PCRE2_UCHAR *orig_code = code;
+PCRE2_UCHAR *tempcode;
BOOL inescq = FALSE;
-BOOL groupsetfirstchar = FALSE;
-const pcre_uchar *ptr = *ptrptr;
-const pcre_uchar *tempptr;
-const pcre_uchar *nestptr = NULL;
-pcre_uchar *previous = NULL;
-pcre_uchar *previous_callout = NULL;
-size_t item_hwm_offset = 0;
-pcre_uint8 classbits[32];
-
-/* We can fish out the UTF-8 setting once and for all into a BOOL, but we
-must not do this for other options (e.g. PCRE_EXTENDED) because they may change
+BOOL groupsetfirstcu = FALSE;
+PCRE2_SPTR ptr = *ptrptr;
+PCRE2_SPTR tempptr;
+PCRE2_UCHAR *previous = NULL;
+PCRE2_UCHAR *previous_callout = NULL;
+uint8_t classbits[32];
+
+/* We can fish out the UTF setting once and for all into a BOOL, but we must
+not do this for other options (e.g. PCRE2_EXTENDED) because they may change
dynamically as we process the pattern. */
-#ifdef SUPPORT_UTF
-/* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */
-BOOL utf = (options & PCRE_UTF8) != 0;
-#ifndef COMPILE_PCRE32
-pcre_uchar utf_chars[6];
+#ifdef SUPPORT_UNICODE
+BOOL utf = (options & PCRE2_UTF) != 0;
+#if PCRE2_CODE_UNIT_WIDTH != 32
+PCRE2_UCHAR utf_units[6]; /* For setting up multi-cu chars */
#endif
-#else
+
+#else /* No UTF support */
BOOL utf = FALSE;
#endif
@@ -4504,41 +3904,36 @@ class_uchardata always so that it can be passed to add_to_class() always,
though it will not be used in non-UTF 8-bit cases. This avoids having to supply
alternative calls for the different cases. */
-pcre_uchar *class_uchardata;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+PCRE2_UCHAR *class_uchardata;
+#ifdef SUPPORT_WIDE_CHARS
BOOL xclass;
-pcre_uchar *class_uchardata_base;
-#endif
-
-#ifdef PCRE_DEBUG
-if (lengthptr != NULL) DPRINTF((">> start branch\n"));
+PCRE2_UCHAR *class_uchardata_base;
#endif
/* Set up the default and non-default settings for greediness */
-greedy_default = ((options & PCRE_UNGREEDY) != 0);
+greedy_default = ((options & PCRE2_UNGREEDY) != 0);
greedy_non_default = greedy_default ^ 1;
-/* Initialize no first byte, no required byte. REQ_UNSET means "no char
+/* Initialize no first unit, no required unit. REQ_UNSET means "no char
matching encountered yet". It gets changed to REQ_NONE if we hit something that
-matches a non-fixed char first char; reqchar just remains unset if we never
-find one.
+matches a non-fixed first unit; reqcu just remains unset if we never find one.
When we hit a repeat whose minimum is zero, we may have to adjust these values
to take the zero repeat into account. This is implemented by setting them to
-zerofirstbyte and zeroreqchar when such a repeat is encountered. The individual
+zerofirstcu and zeroreqcu when such a repeat is encountered. The individual
item types that can be repeated set these backoff variables appropriately. */
-firstchar = reqchar = zerofirstchar = zeroreqchar = 0;
-firstcharflags = reqcharflags = zerofirstcharflags = zeroreqcharflags = REQ_UNSET;
+firstcu = reqcu = zerofirstcu = zeroreqcu = 0;
+firstcuflags = reqcuflags = zerofirstcuflags = zeroreqcuflags = REQ_UNSET;
-/* The variable req_caseopt contains either the REQ_CASELESS value
-or zero, according to the current setting of the caseless flag. The
-REQ_CASELESS leaves the lower 28 bit empty. It is added into the
-firstchar or reqchar variables to record the case status of the
-value. This is used only for ASCII characters. */
+/* The variable req_caseopt contains either the REQ_CASELESS value or zero,
+according to the current setting of the caseless flag. The REQ_CASELESS value
+leaves the lower 28 bit empty. It is added into the firstcu or reqcu variables
+to record the case status of the value. This is used only for ASCII characters.
+*/
-req_caseopt = ((options & PCRE_CASELESS) != 0)? REQ_CASELESS:0;
+req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS:0;
/* Switch on next character until the end of the branch */
@@ -4546,28 +3941,30 @@ for (;; ptr++)
{
BOOL negate_class;
BOOL should_flip_negation;
+ BOOL match_all_or_no_wide_chars;
BOOL possessive_quantifier;
BOOL is_quantifier;
BOOL is_recurse;
+ BOOL is_dupname;
BOOL reset_bracount;
int class_has_8bitchar;
int class_one_char;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#ifdef SUPPORT_WIDE_CHARS
BOOL xclass_has_prop;
#endif
- int newoptions;
- int recno;
- int refsign;
- int skipbytes;
- pcre_uint32 subreqchar, subfirstchar;
- pcre_int32 subreqcharflags, subfirstcharflags;
- int terminator;
+ int recno; /* Must be signed */
+ int refsign; /* Must be signed */
+ int terminator; /* Must be signed */
unsigned int mclength;
unsigned int tempbracount;
- pcre_uint32 ec;
- pcre_uchar mcbuffer[8];
+ uint32_t ec;
+ uint32_t newoptions;
+ uint32_t skipunits;
+ uint32_t subreqcu, subfirstcu;
+ int32_t subreqcuflags, subfirstcuflags; /* Must be signed */
+ PCRE2_UCHAR mcbuffer[8];
- /* Come here to restart the loop without advancing the pointer. */
+ /* Come here to restart the loop. */
REDO_LOOP:
@@ -4576,12 +3973,14 @@ for (;; ptr++)
c = *ptr;
/* If we are at the end of a nested substitution, revert to the outer level
- string. Nesting only happens one level deep. */
+ string. Nesting only happens one or two levels deep, and the inserted string
+ is always zero terminated. */
- if (c == CHAR_NULL && nestptr != NULL)
+ if (c == CHAR_NULL && cb->nestptr[0] != NULL)
{
- ptr = nestptr;
- nestptr = NULL;
+ ptr = cb->nestptr[0];
+ cb->nestptr[0] = cb->nestptr[1];
+ cb->nestptr[1] = NULL;
c = *ptr;
}
@@ -4590,14 +3989,11 @@ for (;; ptr++)
if (lengthptr != NULL)
{
-#ifdef PCRE_DEBUG
- if (code > cd->hwm) cd->hwm = code; /* High water info */
-#endif
- if (code > cd->start_workspace + cd->workspace_size -
+ if (code > cb->start_workspace + cb->workspace_size -
WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */
{
- *errorcodeptr = (code >= cd->start_workspace + cd->workspace_size)?
- ERR52 : ERR87;
+ *errorcodeptr = (code >= cb->start_workspace + cb->workspace_size)?
+ ERR52 : ERR86;
goto FAILED;
}
@@ -4611,15 +4007,12 @@ for (;; ptr++)
/* Paranoid check for integer overflow */
- if (OFLOW_MAX - *lengthptr < code - last_code)
+ if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code))
{
*errorcodeptr = ERR20;
goto FAILED;
}
-
- *lengthptr += (int)(code - last_code);
- DPRINTF(("length=%d added %d c=%c (0x%x)\n", *lengthptr,
- (int)(code - last_code), c, c));
+ *lengthptr += (size_t)(code - last_code);
/* If "previous" is set and it is not at the start of the work space, move
it back to there, in order to avoid filling up the work space. Otherwise,
@@ -4629,7 +4022,7 @@ for (;; ptr++)
{
if (previous > orig_code)
{
- memmove(orig_code, previous, IN_UCHARS(code - previous));
+ memmove(orig_code, previous, (size_t)CU2BYTES(code - previous));
code -= previous - orig_code;
previous = orig_code;
}
@@ -4642,19 +4035,18 @@ for (;; ptr++)
last_code = code;
}
- /* In the real compile phase, just check the workspace used by the forward
- reference list. */
-
- else if (cd->hwm > cd->start_workspace + cd->workspace_size)
- {
- *errorcodeptr = ERR52;
- goto FAILED;
- }
+ /* Before doing anything else we must handle all the special items that do
+ nothing, and which may come between an item and its quantifier. Otherwise,
+ when auto-callouts are enabled, a callout gets incorrectly inserted before
+ the quantifier is recognized. After recognizing a "do nothing" item, restart
+ the loop in case another one follows. */
- /* If in \Q...\E, check for the end; if not, we have a literal. Otherwise an
- isolated \E is ignored. */
+ /* If c is not NULL we are not at the end of the pattern. If it is NULL, we
+ may still be in the pattern with a NULL data item. In these cases, if we are
+ in \Q...\E, check for the \E that ends the literal string; if not, we have a
+ literal character. If not in \Q...\E, an isolated \E is ignored. */
- if (c != CHAR_NULL)
+ if (c != CHAR_NULL || ptr < cb->end_pattern)
{
if (c == CHAR_BACKSLASH && ptr[1] == CHAR_E)
{
@@ -4662,18 +4054,18 @@ for (;; ptr++)
ptr++;
continue;
}
- else if (inescq)
+ else if (inescq) /* Literal character */
{
if (previous_callout != NULL)
{
if (lengthptr == NULL) /* Don't attempt in pre-compile phase */
- complete_callout(previous_callout, ptr, cd);
+ complete_callout(previous_callout, ptr, cb);
previous_callout = NULL;
}
- if ((options & PCRE_AUTO_CALLOUT) != 0)
+ if ((options & PCRE2_AUTO_CALLOUT) != 0)
{
previous_callout = code;
- code = auto_callout(code, ptr, cd);
+ code = auto_callout(code, ptr, cb);
}
goto NORMAL_CHAR;
}
@@ -4690,24 +4082,24 @@ for (;; ptr++)
}
}
- /* In extended mode, skip white space and comments. */
+ /* In extended mode, skip white space and #-comments that end at newline. */
- if ((options & PCRE_EXTENDED) != 0)
+ if ((options & PCRE2_EXTENDED) != 0)
{
- const pcre_uchar *wscptr = ptr;
- while (MAX_255(c) && (cd->ctypes[c] & ctype_space) != 0) c = *(++ptr);
+ PCRE2_SPTR wscptr = ptr;
+ while (MAX_255(c) && (cb->ctypes[c] & ctype_space) != 0) c = *(++ptr);
if (c == CHAR_NUMBER_SIGN)
{
ptr++;
- while (*ptr != CHAR_NULL)
+ while (ptr < cb->end_pattern)
{
if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */
- { /* IS_NEWLINE sets cd->nllen. */
- ptr += cd->nllen;
+ { /* IS_NEWLINE sets cb->nllen. */
+ ptr += cb->nllen;
break;
}
ptr++;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf) FORWARDCHAR(ptr);
#endif
}
@@ -4719,16 +4111,14 @@ for (;; ptr++)
if (ptr > wscptr) goto REDO_LOOP;
}
- /* Skip over (?# comments. We need to do this here because we want to know if
- the next thing is a quantifier, and these comments may come between an item
- and its quantifier. */
+ /* Skip over (?# comments. */
if (c == CHAR_LEFT_PARENTHESIS && ptr[1] == CHAR_QUESTION_MARK &&
ptr[2] == CHAR_NUMBER_SIGN)
{
ptr += 3;
- while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
- if (*ptr == CHAR_NULL)
+ while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
+ if (*ptr != CHAR_RIGHT_PARENTHESIS)
{
*errorcodeptr = ERR18;
goto FAILED;
@@ -4736,30 +4126,31 @@ for (;; ptr++)
continue;
}
- /* See if the next thing is a quantifier. */
+ /* End of processing "do nothing" items. See if the next thing is a
+ quantifier. */
is_quantifier =
c == CHAR_ASTERISK || c == CHAR_PLUS || c == CHAR_QUESTION_MARK ||
- (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1));
+ (c == CHAR_LEFT_CURLY_BRACKET && is_counted_repeat(ptr+1));
- /* Fill in length of a previous callout, except when the next thing is a
- quantifier or when processing a property substitution string in UCP mode. */
+ /* Fill in length of a previous callout and create an auto callout if
+ required, except when the next thing is a quantifier or when processing a
+ property substitution string for \w etc in UCP mode. */
- if (!is_quantifier && previous_callout != NULL && nestptr == NULL &&
- after_manual_callout-- <= 0)
+ if (!is_quantifier && cb->nestptr[0] == NULL)
{
- if (lengthptr == NULL) /* Don't attempt in pre-compile phase */
- complete_callout(previous_callout, ptr, cd);
- previous_callout = NULL;
- }
-
- /* Create auto callout, except for quantifiers, or while processing property
- strings that are substituted for \w etc in UCP mode. */
+ if (previous_callout != NULL && after_manual_callout-- <= 0)
+ {
+ if (lengthptr == NULL) /* Don't attempt in pre-compile phase */
+ complete_callout(previous_callout, ptr, cb);
+ previous_callout = NULL;
+ }
- if ((options & PCRE_AUTO_CALLOUT) != 0 && !is_quantifier && nestptr == NULL)
- {
- previous_callout = code;
- code = auto_callout(code, ptr, cd);
+ if ((options & PCRE2_AUTO_CALLOUT) != 0)
+ {
+ previous_callout = code;
+ code = auto_callout(code, ptr, cb);
+ }
}
/* Process the next pattern item. */
@@ -4767,24 +4158,28 @@ for (;; ptr++)
switch(c)
{
/* ===================================================================*/
- case CHAR_NULL: /* The branch terminates at string end */
- case CHAR_VERTICAL_LINE: /* or | or ) */
+ /* The branch terminates at string end or | or ) */
+
+ case CHAR_NULL:
+ if (ptr < cb->end_pattern) goto NORMAL_CHAR; /* Zero data character */
+ /* Fall through */
+
+ case CHAR_VERTICAL_LINE:
case CHAR_RIGHT_PARENTHESIS:
- *firstcharptr = firstchar;
- *firstcharflagsptr = firstcharflags;
- *reqcharptr = reqchar;
- *reqcharflagsptr = reqcharflags;
+ *firstcuptr = firstcu;
+ *firstcuflagsptr = firstcuflags;
+ *reqcuptr = reqcu;
+ *reqcuflagsptr = reqcuflags;
*codeptr = code;
*ptrptr = ptr;
if (lengthptr != NULL)
{
- if (OFLOW_MAX - *lengthptr < code - last_code)
+ if (OFLOW_MAX - *lengthptr < (size_t)(code - last_code))
{
*errorcodeptr = ERR20;
goto FAILED;
}
- *lengthptr += (int)(code - last_code); /* To include callout length */
- DPRINTF((">> end branch\n"));
+ *lengthptr += (size_t)(code - last_code); /* To include callout length */
}
return TRUE;
@@ -4795,10 +4190,10 @@ for (;; ptr++)
case CHAR_CIRCUMFLEX_ACCENT:
previous = NULL;
- if ((options & PCRE_MULTILINE) != 0)
+ if ((options & PCRE2_MULTILINE) != 0)
{
- if (firstcharflags == REQ_UNSET)
- zerofirstcharflags = firstcharflags = REQ_NONE;
+ if (firstcuflags == REQ_UNSET)
+ zerofirstcuflags = firstcuflags = REQ_NONE;
*code++ = OP_CIRCM;
}
else *code++ = OP_CIRC;
@@ -4806,21 +4201,20 @@ for (;; ptr++)
case CHAR_DOLLAR_SIGN:
previous = NULL;
- *code++ = ((options & PCRE_MULTILINE) != 0)? OP_DOLLM : OP_DOLL;
+ *code++ = ((options & PCRE2_MULTILINE) != 0)? OP_DOLLM : OP_DOLL;
break;
/* There can never be a first char if '.' is first, whatever happens about
- repeats. The value of reqchar doesn't change either. */
+ repeats. The value of reqcu doesn't change either. */
case CHAR_DOT:
- if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
- zerofirstchar = firstchar;
- zerofirstcharflags = firstcharflags;
- zeroreqchar = reqchar;
- zeroreqcharflags = reqcharflags;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
previous = code;
- item_hwm_offset = cd->hwm - cd->start_workspace;
- *code++ = ((options & PCRE_DOTALL) != 0)? OP_ALLANY: OP_ANY;
+ *code++ = ((options & PCRE2_DOTALL) != 0)? OP_ALLANY: OP_ANY;
break;
@@ -4836,34 +4230,31 @@ for (;; ptr++)
but those above are are explicitly listed afterwards. A flag byte tells
whether the bitmap is present, and whether this is a negated class or not.
- In JavaScript compatibility mode, an isolated ']' causes an error. In
- default (Perl) mode, it is treated as a data character. */
+ An isolated ']' character is not treated specially, so is just another data
+ character. In earlier versions of PCRE that used the original API there was
+ a "JavaScript compatibility mode" in which it gave an error. However,
+ JavaScript itself has changed in this respect so there is no longer any
+ need for this special handling.
- case CHAR_RIGHT_SQUARE_BRACKET:
- if ((cd->external_options & PCRE_JAVASCRIPT_COMPAT) != 0)
- {
- *errorcodeptr = ERR64;
- goto FAILED;
- }
- goto NORMAL_CHAR;
-
- /* In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is
+ In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is
used for "start of word" and "end of word". As these are otherwise illegal
sequences, we don't break anything by recognizing them. They are replaced
- by \b(?=\w) and \b(?<=\w) respectively. Sequences like [a[:<:]] are
- erroneous and are handled by the normal code below. */
+ by \b(?=\w) and \b(?<=\w) respectively. This can only happen at the top
+ nesting level, as no other inserted sequences will contains these oddities.
+ Sequences like [a[:<:]] are erroneous and are handled by the normal code
+ below. */
case CHAR_LEFT_SQUARE_BRACKET:
- if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0)
+ if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_STARTWORD, 6) == 0)
{
- nestptr = ptr + 7;
+ cb->nestptr[0] = ptr + 7;
ptr = sub_start_of_word;
goto REDO_LOOP;
}
- if (STRNCMP_UC_C8(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0)
+ if (PRIV(strncmp_c8)(ptr+1, STRING_WEIRD_ENDWORD, 6) == 0)
{
- nestptr = ptr + 7;
+ cb->nestptr[0] = ptr + 7;
ptr = sub_end_of_word;
goto REDO_LOOP;
}
@@ -4871,7 +4262,6 @@ for (;; ptr++)
/* Handle a real character class. */
previous = code;
- item_hwm_offset = cd->hwm - cd->start_workspace;
/* PCRE supports POSIX class stuff inside a class. Perl gives an error if
they are encountered at the top level, so we'll do that too. */
@@ -4880,7 +4270,7 @@ for (;; ptr++)
ptr[1] == CHAR_EQUALS_SIGN) &&
check_posix_syntax(ptr, &tempptr))
{
- *errorcodeptr = (ptr[1] == CHAR_COLON)? ERR13 : ERR31;
+ *errorcodeptr = (ptr[1] == CHAR_COLON)? ERR12 : ERR13;
goto FAILED;
}
@@ -4896,7 +4286,7 @@ for (;; ptr++)
{
if (ptr[1] == CHAR_E)
ptr++;
- else if (STRNCMP_UC_C8(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0)
+ else if (PRIV(strncmp_c8)(ptr + 1, STR_Q STR_BACKSLASH STR_E, 3) == 0)
ptr += 3;
else
break;
@@ -4906,86 +4296,82 @@ for (;; ptr++)
else break;
}
- /* Empty classes are allowed in JavaScript compatibility mode. Otherwise,
+ /* Empty classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set. Otherwise,
an initial ']' is taken as a data character -- the code below handles
- that. In JS mode, [] must always fail, so generate OP_FAIL, whereas
- [^] must match any character, so generate OP_ALLANY. */
+ that. When empty classes are allowed, [] must always fail, so generate
+ OP_FAIL, whereas [^] must match any character, so generate OP_ALLANY. */
if (c == CHAR_RIGHT_SQUARE_BRACKET &&
- (cd->external_options & PCRE_JAVASCRIPT_COMPAT) != 0)
+ (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)
{
*code++ = negate_class? OP_ALLANY : OP_FAIL;
- if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
- zerofirstchar = firstchar;
- zerofirstcharflags = firstcharflags;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
break;
}
- /* If a class contains a negative special such as \S, we need to flip the
- negation flag at the end, so that support for characters > 255 works
- correctly (they are all included in the class). */
+ /* If a non-extended class contains a negative special such as \S, we need
+ to flip the negation flag at the end, so that support for characters > 255
+ works correctly (they are all included in the class). An extended class may
+ need to insert specific matching or non-matching code for wide characters.
+ */
- should_flip_negation = FALSE;
+ should_flip_negation = match_all_or_no_wide_chars = FALSE;
/* Extended class (xclass) will be used when characters > 255
might match. */
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#ifdef SUPPORT_WIDE_CHARS
xclass = FALSE;
class_uchardata = code + LINK_SIZE + 2; /* For XCLASS items */
class_uchardata_base = class_uchardata; /* Save the start */
#endif
/* For optimization purposes, we track some properties of the class:
- class_has_8bitchar will be non-zero if the class contains at least one <
- 256 character; class_one_char will be 1 if the class contains just one
- character; xclass_has_prop will be TRUE if unicode property checks
- are present in the class. */
+ class_has_8bitchar will be non-zero if the class contains at least one 256
+ character with a code point less than 256; class_one_char will be 1 if the
+ class contains just one character; xclass_has_prop will be TRUE if Unicode
+ property checks are present in the class. */
class_has_8bitchar = 0;
class_one_char = 0;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#ifdef SUPPORT_WIDE_CHARS
xclass_has_prop = FALSE;
#endif
- /* Initialize the 32-char bit map to all zeros. We build the map in a
- temporary bit of memory, in case the class contains fewer than two
+ /* Initialize the 256-bit (32-byte) bit map to all zeros. We build the map
+ in a temporary bit of memory, in case the class contains fewer than two
8-bit characters because in that case the compiled code doesn't use the bit
map. */
- memset(classbits, 0, 32 * sizeof(pcre_uint8));
+ memset(classbits, 0, 32 * sizeof(uint8_t));
- /* Process characters until ] is reached. By writing this as a "do" it
- means that an initial ] is taken as a data character. At the start of the
- loop, c contains the first byte of the character. */
+ /* Process characters until ] is reached. As the test is at the end of the
+ loop, an initial ] is taken as a data character. At the start of the loop,
+ c contains the first code unit of the character. If it is zero, check for
+ the end of the pattern, to allow binary zero as data. */
- if (c != CHAR_NULL) do
+ for(;;)
{
- const pcre_uchar *oldptr;
+ PCRE2_SPTR oldptr;
+#ifdef EBCDIC
+ BOOL range_is_literal = TRUE;
+#endif
-#ifdef SUPPORT_UTF
+ if (c == CHAR_NULL && ptr >= cb->end_pattern)
+ {
+ *errorcodeptr = ERR6; /* Missing terminating ']' */
+ goto FAILED;
+ }
+
+#ifdef SUPPORT_UNICODE
if (utf && HAS_EXTRALEN(c))
{ /* Braces are required because the */
GETCHARLEN(c, ptr, ptr); /* macro generates multiple statements */
}
#endif
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- /* In the pre-compile phase, accumulate the length of any extra
- data and reset the pointer. This is so that very large classes that
- contain a zillion > 255 characters no longer overwrite the work space
- (which is on the stack). We have to remember that there was XCLASS data,
- however. */
-
- if (class_uchardata > class_uchardata_base) xclass = TRUE;
-
- if (lengthptr != NULL && class_uchardata > class_uchardata_base)
- {
- *lengthptr += (int)(class_uchardata - class_uchardata_base);
- class_uchardata = class_uchardata_base;
- }
-#endif
-
/* Inside \Q...\E everything is literal except \E */
if (inescq)
@@ -4994,7 +4380,7 @@ for (;; ptr++)
{
inescq = FALSE; /* Reset literal state */
ptr++; /* Skip the 'E' */
- continue; /* Carry on with next */
+ goto CONTINUE_CLASS; /* Carry on with next char */
}
goto CHECK_RANGE; /* Could be range if \E follows */
}
@@ -5011,12 +4397,12 @@ for (;; ptr++)
{
BOOL local_negate = FALSE;
int posix_class, taboffset, tabopt;
- register const pcre_uint8 *cbits = cd->cbits;
- pcre_uint8 pbits[32];
+ register const uint8_t *cbits = cb->cbits;
+ uint8_t pbits[32];
if (ptr[1] != CHAR_COLON)
{
- *errorcodeptr = ERR31;
+ *errorcodeptr = ERR13;
goto FAILED;
}
@@ -5039,28 +4425,30 @@ for (;; ptr++)
alpha. This relies on the fact that the class table starts with
alpha, lower, upper as the first 3 entries. */
- if ((options & PCRE_CASELESS) != 0 && posix_class <= 2)
+ if ((options & PCRE2_CASELESS) != 0 && posix_class <= 2)
posix_class = 0;
- /* When PCRE_UCP is set, some of the POSIX classes are converted to
+ /* When PCRE2_UCP is set, some of the POSIX classes are converted to
different escape sequences that use Unicode properties \p or \P. Others
that are not available via \p or \P generate XCL_PROP/XCL_NOTPROP
- directly. */
+ directly. UCP support is not available unless UTF support is.*/
-#ifdef SUPPORT_UCP
- if ((options & PCRE_UCP) != 0)
+#ifdef SUPPORT_UNICODE
+ if ((options & PCRE2_UCP) != 0)
{
unsigned int ptype = 0;
int pc = posix_class + ((local_negate)? POSIX_SUBSIZE/2 : 0);
/* The posix_substitutes table specifies which POSIX classes can be
- converted to \p or \P items. */
+ converted to \p or \P items. This can only happen at top nestling
+ level, as there will never be a POSIX class in a string that is
+ substituted for something else. */
if (posix_substitutes[pc] != NULL)
{
- nestptr = tempptr + 1;
+ cb->nestptr[0] = tempptr + 1;
ptr = posix_substitutes[pc] - 1;
- continue;
+ goto CONTINUE_CLASS;
}
/* There are three other classes that generate special property calls
@@ -5077,38 +4465,33 @@ for (;; ptr++)
case PC_PUNCT:
if (ptype == 0) ptype = PT_PXPUNCT;
*class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP;
- *class_uchardata++ = ptype;
+ *class_uchardata++ = (PCRE2_UCHAR)ptype;
*class_uchardata++ = 0;
xclass_has_prop = TRUE;
ptr = tempptr + 1;
- continue;
-
- /* For the other POSIX classes (ascii, cntrl, xdigit) we are going
- to fall through to the non-UCP case and build a bit map for
- characters with code points less than 256. If we are in a negated
- POSIX class, characters with code points greater than 255 must
- either all match or all not match. In the special case where we
- have not yet generated any xclass data, and this is the final item
- in the overall class, we need do nothing: later on, the opcode
- OP_NCLASS will be used to indicate that characters greater than 255
- are acceptable. If we have already seen an xclass item or one may
- follow (we have to assume that it might if this is not the end of
- the class), explicitly list all wide codepoints, which will then
- either not match or match, depending on whether the class is or is
- not negated. */
+ goto CONTINUE_CLASS;
+
+ /* For the other POSIX classes (ascii, xdigit) we are going to fall
+ through to the non-UCP case and build a bit map for characters with
+ code points less than 256. However, if we are in a negated POSIX
+ class, characters with code points greater than 255 must either all
+ match or all not match, depending on whether the whole class is not
+ or is negated. For example, for [[:^ascii:]... they must all match,
+ whereas for [^[:^xdigit:]... they must not.
+
+ In the special case where there are no xclass items, this is
+ automatically handled by the use of OP_CLASS or OP_NCLASS, but an
+ explicit range is needed for OP_XCLASS. Setting a flag here causes
+ the range to be generated later when it is known that OP_XCLASS is
+ required. */
default:
- if (local_negate &&
- (xclass || tempptr[2] != CHAR_RIGHT_SQUARE_BRACKET))
- {
- *class_uchardata++ = XCL_RANGE;
- class_uchardata += PRIV(ord2utf)(0x100, class_uchardata);
- class_uchardata += PRIV(ord2utf)(0x10ffff, class_uchardata);
- }
+ match_all_or_no_wide_chars |= local_negate;
break;
}
}
-#endif
+#endif /* SUPPORT_UNICODE */
+
/* In the non-UCP case, or when UCP makes no difference, we build the
bit map for the POSIX class in a chunk of local store because we may be
adding and subtracting from it, and we don't want to subtract bits that
@@ -5120,7 +4503,7 @@ for (;; ptr++)
/* Copy in the first table (always present) */
memcpy(pbits, cbits + posix_class_maps[posix_class],
- 32 * sizeof(pcre_uint8));
+ 32 * sizeof(uint8_t));
/* If there is a second table, add or remove it as required. */
@@ -5130,9 +4513,9 @@ for (;; ptr++)
if (taboffset >= 0)
{
if (tabopt >= 0)
- for (c = 0; c < 32; c++) pbits[c] |= cbits[c + taboffset];
+ for (c = 0; c < 32; c++) pbits[c] |= cbits[(int)c + taboffset];
else
- for (c = 0; c < 32; c++) pbits[c] &= ~cbits[c + taboffset];
+ for (c = 0; c < 32; c++) pbits[c] &= ~cbits[(int)c + taboffset];
}
/* Now see if we need to remove any special characters. An option
@@ -5155,7 +4538,7 @@ for (;; ptr++)
class_has_8bitchar = 1;
/* Every class contains at least two characters. */
class_one_char = 2;
- continue; /* End of POSIX syntax handling */
+ goto CONTINUE_CLASS; /* End of POSIX syntax handling */
}
/* Backslash may introduce a single character, or it may introduce one
@@ -5163,16 +4546,20 @@ for (;; ptr++)
case. Inside a class (and only there) it is treated as backspace. We
assume that other escapes have more than one character in them, so
speculatively set both class_has_8bitchar and class_one_char bigger
- than one. Unrecognized escapes fall through and are either treated
- as literal characters (by default), or are faulted if
- PCRE_EXTRA is set. */
+ than one. Unrecognized escapes fall through and are faulted. */
if (c == CHAR_BACKSLASH)
{
- escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options,
- TRUE);
+ escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr,
+ options, TRUE, cb);
if (*errorcodeptr != 0) goto FAILED;
- if (escape == 0) c = ec;
+ if (escape == 0) /* Escaped single char */
+ {
+ c = ec;
+#ifdef EBCDIC
+ range_is_literal = FALSE;
+#endif
+ }
else if (escape == ESC_b) c = CHAR_BS; /* \b is backspace in a class */
else if (escape == ESC_N) /* \N is not supported in a class */
{
@@ -5186,13 +4573,13 @@ for (;; ptr++)
ptr += 2; /* avoid empty string */
}
else inescq = TRUE;
- continue;
+ goto CONTINUE_CLASS;
}
- else if (escape == ESC_E) continue; /* Ignore orphan \E */
+ else if (escape == ESC_E) goto CONTINUE_CLASS; /* Ignore orphan \E */
- else
+ else /* Handle \d-type escapes */
{
- register const pcre_uint8 *cbits = cd->cbits;
+ register const uint8_t *cbits = cb->cbits;
/* Every class contains at least two < 256 characters. */
class_has_8bitchar++;
/* Every class contains at least two characters. */
@@ -5200,35 +4587,36 @@ for (;; ptr++)
switch (escape)
{
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
case ESC_du: /* These are the values given for \d etc */
- case ESC_DU: /* when PCRE_UCP is set. We replace the */
+ case ESC_DU: /* when PCRE2_UCP is set. We replace the */
case ESC_wu: /* escape sequence with an appropriate \p */
case ESC_WU: /* or \P to test Unicode properties instead */
- case ESC_su: /* of the default ASCII testing. */
- case ESC_SU:
- nestptr = ptr;
+ case ESC_su: /* of the default ASCII testing. This might be */
+ case ESC_SU: /* a 2nd-level nesting for [[:<:]] or [[:>:]]. */
+ cb->nestptr[1] = cb->nestptr[0];
+ cb->nestptr[0] = ptr;
ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */
class_has_8bitchar--; /* Undo! */
- continue;
+ break;
#endif
case ESC_d:
for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit];
- continue;
+ break;
case ESC_D:
should_flip_negation = TRUE;
for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit];
- continue;
+ break;
case ESC_w:
for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_word];
- continue;
+ break;
case ESC_W:
should_flip_negation = TRUE;
for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_word];
- continue;
+ break;
/* Perl 5.004 onwards omitted VT from \s, but restored it at Perl
5.18. Before PCRE 8.34, we had to preserve the VT bit if it was
@@ -5239,42 +4627,42 @@ for (;; ptr++)
case ESC_s:
for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_space];
- continue;
+ break;
case ESC_S:
should_flip_negation = TRUE;
for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_space];
- continue;
+ break;
/* The rest apply in both UCP and non-UCP cases. */
case ESC_h:
- (void)add_list_to_class(classbits, &class_uchardata, options, cd,
+ (void)add_list_to_class(classbits, &class_uchardata, options, cb,
PRIV(hspace_list), NOTACHAR);
- continue;
+ break;
case ESC_H:
(void)add_not_list_to_class(classbits, &class_uchardata, options,
- cd, PRIV(hspace_list));
- continue;
+ cb, PRIV(hspace_list));
+ break;
case ESC_v:
- (void)add_list_to_class(classbits, &class_uchardata, options, cd,
+ (void)add_list_to_class(classbits, &class_uchardata, options, cb,
PRIV(vspace_list), NOTACHAR);
- continue;
+ break;
case ESC_V:
(void)add_not_list_to_class(classbits, &class_uchardata, options,
- cd, PRIV(vspace_list));
- continue;
+ cb, PRIV(vspace_list));
+ break;
case ESC_p:
case ESC_P:
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
{
BOOL negated;
unsigned int ptype = 0, pdata = 0;
- if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr))
+ if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb))
goto FAILED;
*class_uchardata++ = ((escape == ESC_p) != negated)?
XCL_PROP : XCL_NOTPROP;
@@ -5282,34 +4670,28 @@ for (;; ptr++)
*class_uchardata++ = pdata;
xclass_has_prop = TRUE;
class_has_8bitchar--; /* Undo! */
- continue;
}
+ break;
#else
*errorcodeptr = ERR45;
goto FAILED;
#endif
- /* Unrecognized escapes are faulted if PCRE is running in its
- strict mode. By default, for compatibility with Perl, they are
- treated as literals. */
+ /* Unrecognized escapes are faulted. */
default:
- if ((options & PCRE_EXTRA) != 0)
- {
- *errorcodeptr = ERR7;
- goto FAILED;
- }
- class_has_8bitchar--; /* Undo the speculative increase. */
- class_one_char -= 2; /* Undo the speculative increase. */
- c = *ptr; /* Get the final character and fall through */
- break;
+ *errorcodeptr = ERR7;
+ goto FAILED;
}
+
+ /* Handled \d-type escape */
+
+ goto CONTINUE_CLASS;
}
- /* Fall through if the escape just defined a single character (c >= 0).
- This may be greater than 256. */
+ /* Control gets here if the escape just defined a single character.
+ This is in c and may be greater than 256. */
escape = 0;
-
} /* End of backslash handling */
/* A character may be followed by '-' to form a range. However, Perl does
@@ -5327,13 +4709,13 @@ for (;; ptr++)
/* Remember if \r or \n were explicitly used */
- if (c == CHAR_CR || c == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;
+ if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;
/* Check for range */
if (!inescq && ptr[1] == CHAR_MINUS)
{
- pcre_uint32 d;
+ uint32_t d;
ptr += 2;
while (*ptr == CHAR_BACKSLASH && ptr[1] == CHAR_E) ptr += 2;
@@ -5360,14 +4742,14 @@ for (;; ptr++)
/* Otherwise, we have a potential range; pick up the next character */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{ /* Braces are required because the */
GETCHARLEN(d, ptr, ptr); /* macro generates multiple statements */
}
else
#endif
- d = *ptr; /* Not UTF-8 mode */
+ d = *ptr; /* Not UTF mode */
/* The second part of a range can be a single-character escape
sequence, but not any of the other escapes. Perl treats a hyphen as a
@@ -5380,9 +4762,12 @@ for (;; ptr++)
if (d == CHAR_BACKSLASH)
{
int descape;
- descape = check_escape(&ptr, &d, errorcodeptr, cd->bracount, options, TRUE);
+ descape = PRIV(check_escape)(&ptr, cb->end_pattern, &d,
+ errorcodeptr, options, TRUE, cb);
if (*errorcodeptr != 0) goto FAILED;
-
+#ifdef EBCDIC
+ range_is_literal = FALSE;
+#endif
/* 0 means a character was put into d; \b is backspace; any other
special causes an error. */
@@ -5390,7 +4775,7 @@ for (;; ptr++)
{
if (descape == ESC_b) d = CHAR_BS; else
{
- *errorcodeptr = ERR83;
+ *errorcodeptr = ERR50;
goto FAILED;
}
}
@@ -5403,7 +4788,7 @@ for (;; ptr++)
ptr[1] == CHAR_EQUALS_SIGN) &&
check_posix_syntax(ptr, &tempptr))
{
- *errorcodeptr = ERR83;
+ *errorcodeptr = ERR50;
goto FAILED;
}
}
@@ -5426,12 +4811,51 @@ for (;; ptr++)
/* Remember an explicit \r or \n, and add the range to the class. */
- if (d == CHAR_CR || d == CHAR_NL) cd->external_flags |= PCRE_HASCRORLF;
+ if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;
- class_has_8bitchar +=
- add_to_class(classbits, &class_uchardata, options, cd, c, d);
+ /* In an EBCDIC environment, Perl treats alphabetic ranges specially
+ because there are holes in the encoding, and simply using the range A-Z
+ (for example) would include the characters in the holes. This applies
+ only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */
+
+#ifdef EBCDIC
+ if (range_is_literal &&
+ (cb->ctypes[c] & ctype_letter) != 0 &&
+ (cb->ctypes[d] & ctype_letter) != 0 &&
+ (c <= CHAR_z) == (d <= CHAR_z))
+ {
+ uint32_t uc = (c <= CHAR_z)? 0 : 64;
+ uint32_t C = c - uc;
+ uint32_t D = d - uc;
+
+ if (C <= CHAR_i)
+ {
+ class_has_8bitchar +=
+ add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+ ((D < CHAR_i)? D : CHAR_i) + uc);
+ C = CHAR_j;
+ }
- continue; /* Go get the next char in the class */
+ if (C <= D && C <= CHAR_r)
+ {
+ class_has_8bitchar +=
+ add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+ ((D < CHAR_r)? D : CHAR_r) + uc);
+ C = CHAR_s;
+ }
+
+ if (C <= D)
+ {
+ class_has_8bitchar +=
+ add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+ D + uc);
+ }
+ }
+ else
+#endif
+ class_has_8bitchar +=
+ add_to_class(classbits, &class_uchardata, options, cb, c, d);
+ goto CONTINUE_CLASS; /* Go get the next char in the class */
}
/* Handle a single character - we can get here for a normal non-escape
@@ -5443,40 +4867,40 @@ for (;; ptr++)
CLASS_SINGLE_CHARACTER:
if (class_one_char < 2) class_one_char++;
- /* If xclass_has_prop is false and class_one_char is 1, we have the first
+ /* If class_one_char is 1 and xclass_has_prop is false, we have the first
single character in the class, and there have been no prior ranges, or
XCLASS items generated by escapes. If this is the final character in the
class, we can optimize by turning the item into a 1-character OP_CHAR[I]
if it's positive, or OP_NOT[I] if it's negative. In the positive case, it
- can cause firstchar to be set. Otherwise, there can be no first char if
+ can cause firstcu to be set. Otherwise, there can be no first char if
this item is first, whatever repeat count may follow. In the case of
- reqchar, save the previous value for reinstating. */
+ reqcu, save the previous value for reinstating. */
if (!inescq &&
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
!xclass_has_prop &&
#endif
class_one_char == 1 && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
{
ptr++;
- zeroreqchar = reqchar;
- zeroreqcharflags = reqcharflags;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
if (negate_class)
{
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
int d;
#endif
- if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
- zerofirstchar = firstchar;
- zerofirstcharflags = firstcharflags;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
- /* For caseless UTF-8 mode when UCP support is available, check
- whether this character has more than one other case. If so, generate
- a special OP_NOTPROP item instead of OP_NOTI. */
+ /* For caseless UTF mode, check whether this character has more than
+ one other case. If so, generate a special OP_NOTPROP item instead of
+ OP_NOTI. */
-#ifdef SUPPORT_UCP
- if (utf && (options & PCRE_CASELESS) != 0 &&
+#ifdef SUPPORT_UNICODE
+ if (utf && (options & PCRE2_CASELESS) != 0 &&
(d = UCD_CASESET(c)) != 0)
{
*code++ = OP_NOTPROP;
@@ -5488,13 +4912,8 @@ for (;; ptr++)
/* Char has only one other case, or UCP not available */
{
- *code++ = ((options & PCRE_CASELESS) != 0)? OP_NOTI: OP_NOT;
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
- if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
- code += PRIV(ord2utf)(c, code);
- else
-#endif
- *code++ = c;
+ *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT;
+ code += PUTCHAR(c, code);
}
/* We are finished with this character class */
@@ -5505,15 +4924,7 @@ for (;; ptr++)
/* For a single, positive character, get the value into mcbuffer, and
then we can handle this with the normal one-character code. */
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
- if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
- mclength = PRIV(ord2utf)(c, mcbuffer);
- else
-#endif
- {
- mcbuffer[0] = c;
- mclength = 1;
- }
+ mclength = PUTCHAR(c, mcbuffer);
goto ONE_CHAR;
} /* End of 1-char optimization */
@@ -5521,64 +4932,85 @@ for (;; ptr++)
has been generated. Add this character to the class. */
class_has_8bitchar +=
- add_to_class(classbits, &class_uchardata, options, cd, c, c);
- }
-
- /* Loop until ']' reached. This "while" is the end of the "do" far above.
- If we are at the end of an internal nested string, revert to the outer
- string. */
-
- while (((c = *(++ptr)) != CHAR_NULL ||
- (nestptr != NULL &&
- (ptr = nestptr, nestptr = NULL, c = *(++ptr)) != CHAR_NULL)) &&
- (c != CHAR_RIGHT_SQUARE_BRACKET || inescq));
+ add_to_class(classbits, &class_uchardata, options, cb, c, c);
- /* Check for missing terminating ']' */
+ /* Continue to the next character in the class. Closing square bracket
+ not within \Q..\E ends the class. A NULL character terminates a
+ nested substitution string, but may be a data character in the main
+ pattern (tested at the start of this loop). */
- if (c == CHAR_NULL)
- {
- *errorcodeptr = ERR6;
- goto FAILED;
- }
+ CONTINUE_CLASS:
+ c = *(++ptr);
+ if (c == CHAR_NULL && cb->nestptr[0] != NULL)
+ {
+ ptr = cb->nestptr[0];
+ cb->nestptr[0] = cb->nestptr[1];
+ cb->nestptr[1] = NULL;
+ c = *(++ptr);
+ }
- /* We will need an XCLASS if data has been placed in class_uchardata. In
- the second phase this is a sufficient test. However, in the pre-compile
- phase, class_uchardata gets emptied to prevent workspace overflow, so it
- only if the very last character in the class needs XCLASS will it contain
- anything at this point. For this reason, xclass gets set TRUE above when
- uchar_classdata is emptied, and that's why this code is the way it is here
- instead of just doing a test on class_uchardata below. */
+#ifdef SUPPORT_WIDE_CHARS
+ /* If any wide characters have been encountered, set xclass = TRUE. Then,
+ in the pre-compile phase, accumulate the length of the wide characters
+ and reset the pointer. This is so that very large classes that contain a
+ zillion wide characters do not overwrite the work space (which is on the
+ stack). */
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- if (class_uchardata > class_uchardata_base) xclass = TRUE;
+ if (class_uchardata > class_uchardata_base)
+ {
+ xclass = TRUE;
+ if (lengthptr != NULL)
+ {
+ *lengthptr += class_uchardata - class_uchardata_base;
+ class_uchardata = class_uchardata_base;
+ }
+ }
#endif
+ /* An unescaped ] ends the class */
+
+ if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break;
+ } /* End of main class-processing loop */
/* If this is the first thing in the branch, there can be no first char
- setting, whatever the repeat count. Any reqchar setting must remain
+ setting, whatever the repeat count. Any reqcu setting must remain
unchanged after any kind of repeat. */
- if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
- zerofirstchar = firstchar;
- zerofirstcharflags = firstcharflags;
- zeroreqchar = reqchar;
- zeroreqcharflags = reqcharflags;
-
- /* If there are characters with values > 255, we have to compile an
- extended class, with its own opcode, unless there was a negated special
- such as \S in the class, and PCRE_UCP is not set, because in that case all
- characters > 255 are in the class, so any that were explicitly given as
- well can be ignored. If (when there are explicit characters > 255 that must
- be listed) there are no characters < 256, we can omit the bitmap in the
- actual compiled code. */
-
-#ifdef SUPPORT_UTF
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
+
+ /* If there are characters with values > 255, or Unicode property settings
+ (\p or \P), we have to compile an extended class, with its own opcode,
+ unless there were no property settings and there was a negated special such
+ as \S in the class, and PCRE2_UCP is not set, because in that case all
+ characters > 255 are in or not in the class, so any that were explicitly
+ given as well can be ignored.
+
+ In the UCP case, if certain negated POSIX classes ([:^ascii:] or
+ [^:xdigit:]) were present in a class, we either have to match or not match
+ all wide characters (depending on whether the whole class is or is not
+ negated). This requirement is indicated by match_all_or_no_wide_chars being
+ true. We do this by including an explicit range, which works in both cases.
+
+ If, when generating an xclass, there are no characters < 256, we can omit
+ the bitmap in the actual compiled code. */
+
+#ifdef SUPPORT_WIDE_CHARS
+#ifdef SUPPORT_UNICODE
if (xclass && (xclass_has_prop || !should_flip_negation ||
- (options & PCRE_UCP) != 0))
-#elif !defined COMPILE_PCRE8
+ (options & PCRE2_UCP) != 0))
+#elif PCRE2_CODE_UNIT_WIDTH != 8
if (xclass && (xclass_has_prop || !should_flip_negation))
#endif
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
{
+ if (match_all_or_no_wide_chars)
+ {
+ *class_uchardata++ = XCL_RANGE;
+ class_uchardata += PRIV(ord2utf)(0x100, class_uchardata);
+ class_uchardata += PRIV(ord2utf)(MAX_UTF_CODE_POINT, class_uchardata);
+ }
*class_uchardata++ = XCL_END; /* Marks the end of extra data */
*code++ = OP_XCLASS;
code += LINK_SIZE;
@@ -5591,12 +5023,12 @@ for (;; ptr++)
if (class_has_8bitchar > 0)
{
*code++ |= XCL_MAP;
- memmove(code + (32 / sizeof(pcre_uchar)), code,
- IN_UCHARS(class_uchardata - code));
+ memmove(code + (32 / sizeof(PCRE2_UCHAR)), code,
+ CU2BYTES(class_uchardata - code));
if (negate_class && !xclass_has_prop)
for (c = 0; c < 32; c++) classbits[c] = ~classbits[c];
memcpy(code, classbits, 32);
- code = class_uchardata + (32 / sizeof(pcre_uchar));
+ code = class_uchardata + (32 / sizeof(PCRE2_UCHAR));
}
else code = class_uchardata;
@@ -5605,12 +5037,6 @@ for (;; ptr++)
PUT(previous, 1, (int)(code - previous));
break; /* End of class handling */
}
-
- /* Even though any XCLASS list is now discarded, we must allow for
- its memory. */
-
- if (lengthptr != NULL)
- *lengthptr += (int)(class_uchardata - class_uchardata_base);
#endif
/* If there are no characters > 255, or they are all to be included or
@@ -5626,7 +5052,7 @@ for (;; ptr++)
for (c = 0; c < 32; c++) classbits[c] = ~classbits[c];
memcpy(code, classbits, 32);
}
- code += 32 / sizeof(pcre_uchar);
+ code += 32 / sizeof(PCRE2_UCHAR);
END_CLASS:
break;
@@ -5665,10 +5091,10 @@ for (;; ptr++)
if (repeat_min == 0)
{
- firstchar = zerofirstchar; /* Adjust for zero repeat */
- firstcharflags = zerofirstcharflags;
- reqchar = zeroreqchar; /* Ditto */
- reqcharflags = zeroreqcharflags;
+ firstcu = zerofirstcu; /* Adjust for zero repeat */
+ firstcuflags = zerofirstcuflags;
+ reqcu = zeroreqcu; /* Ditto */
+ reqcuflags = zeroreqcuflags;
}
/* Remember whether this is a variable length repeat */
@@ -5687,34 +5113,34 @@ for (;; ptr++)
whitespace and comments in extended mode because Perl allows white space at
this point. */
- if ((options & PCRE_EXTENDED) != 0)
+ if ((options & PCRE2_EXTENDED) != 0)
{
- const pcre_uchar *p = ptr + 1;
+ ptr++;
for (;;)
{
- while (MAX_255(*p) && (cd->ctypes[*p] & ctype_space) != 0) p++;
- if (*p != CHAR_NUMBER_SIGN) break;
- p++;
- while (*p != CHAR_NULL)
+ while (MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype_space) != 0) ptr++;
+ if (*ptr != CHAR_NUMBER_SIGN) break;
+ ptr++;
+ while (ptr < cb->end_pattern)
{
- if (IS_NEWLINE(p)) /* For non-fixed-length newline cases, */
- { /* IS_NEWLINE sets cd->nllen. */
- p += cd->nllen;
+ if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */
+ { /* IS_NEWLINE sets cb->nllen. */
+ ptr += cb->nllen;
break;
}
- p++;
-#ifdef SUPPORT_UTF
- if (utf) FORWARDCHAR(p);
+ ptr++;
+#ifdef SUPPORT_UNICODE
+ if (utf) FORWARDCHAR(ptr);
#endif
} /* Loop for comment characters */
} /* Loop for multiple comments */
- ptr = p - 1; /* Character before the next significant one. */
+ ptr--; /* Last code unit of previous character. */
}
/* If the next character is '+', we have a possessive quantifier. This
- implies greediness, whatever the setting of the PCRE_UNGREEDY option.
+ implies greediness, whatever the setting of the PCRE2_UNGREEDY option.
If the next character is '?' this is a minimizing repeat, by default,
- but if PCRE_UNGREEDY is set, it works the other way round. We change the
+ but if PCRE2_UNGREEDY is set, it works the other way round. We change the
repeat type to the non-default. */
if (ptr[1] == CHAR_PLUS)
@@ -5730,6 +5156,10 @@ for (;; ptr++)
}
else repeat_type = greedy_default;
+ /* If the repeat is {1} we can ignore it. */
+
+ if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT;
+
/* If previous was a recursion call, wrap it in atomic brackets so that
previous becomes the atomic group. All recursions were so wrapped in the
past, but it no longer happens for non-repeated recursions. In fact, the
@@ -5738,32 +5168,22 @@ for (;; ptr++)
if (*previous == OP_RECURSE)
{
- memmove(previous + 1 + LINK_SIZE, previous, IN_UCHARS(1 + LINK_SIZE));
+ memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE));
*previous = OP_ONCE;
PUT(previous, 1, 2 + 2*LINK_SIZE);
previous[2 + 2*LINK_SIZE] = OP_KET;
PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE);
code += 2 + 2 * LINK_SIZE;
length_prevgroup = 3 + 3*LINK_SIZE;
-
- /* When actually compiling, we need to check whether this was a forward
- reference, and if so, adjust the offset. */
-
- if (lengthptr == NULL && cd->hwm >= cd->start_workspace + LINK_SIZE)
- {
- int offset = GET(cd->hwm, -LINK_SIZE);
- if (offset == previous + 1 - cd->start_code)
- PUT(cd->hwm, -LINK_SIZE, offset + 1 + LINK_SIZE);
- }
}
/* Now handle repetition for the different types of item. */
/* If previous was a character or negated character match, abolish the item
and generate a repeat item instead. If a char item has a minimum of more
- than one, ensure that it is set in reqchar - it might not be if a sequence
+ than one, ensure that it is set in reqcu - it might not be if a sequence
such as x{3} is the first thing in a branch because the x will have gone
- into firstchar instead. */
+ into firstcu instead. */
if (*previous == OP_CHAR || *previous == OP_CHARI
|| *previous == OP_NOT || *previous == OP_NOTI)
@@ -5777,31 +5197,31 @@ for (;; ptr++)
case OP_NOTI: op_type = OP_NOTSTARI - OP_STAR; break;
}
- /* Deal with UTF characters that take up more than one character. It's
+ /* Deal with UTF characters that take up more than one code unit. It's
easier to write this out separately than try to macrify it. Use c to
- hold the length of the character in bytes, plus UTF_LENGTH to flag that
- it's a length rather than a small character. */
+ hold the length of the character in code units, plus UTF_LENGTH to flag
+ that it's a length rather than a small character. */
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
- if (utf && NOT_FIRSTCHAR(code[-1]))
+#ifdef MAYBE_UTF_MULTI
+ if (utf && NOT_FIRSTCU(code[-1]))
{
- pcre_uchar *lastchar = code - 1;
+ PCRE2_UCHAR *lastchar = code - 1;
BACKCHAR(lastchar);
- c = (int)(code - lastchar); /* Length of UTF-8 character */
- memcpy(utf_chars, lastchar, IN_UCHARS(c)); /* Save the char */
- c |= UTF_LENGTH; /* Flag c as a length */
+ c = (int)(code - lastchar); /* Length of UTF character */
+ memcpy(utf_units, lastchar, CU2BYTES(c)); /* Save the char */
+ c |= UTF_LENGTH; /* Flag c as a length */
}
else
-#endif /* SUPPORT_UTF */
+#endif /* MAYBE_UTF_MULTI */
/* Handle the case of a single charater - either with no UTF support, or
- with UTF disabled, or for a single character UTF character. */
+ with UTF disabled, or for a single-code-unit UTF character. */
{
c = code[-1];
if (*previous <= OP_CHARI && repeat_min > 1)
{
- reqchar = c;
- reqcharflags = req_caseopt | cd->req_varyopt;
+ reqcu = c;
+ reqcuflags = req_caseopt | cb->req_varyopt;
}
}
@@ -5811,26 +5231,33 @@ for (;; ptr++)
/* If previous was a character type match (\d or similar), abolish it and
create a suitable repeat item. The code is shared with single-character
repeats by setting op_type to add a suitable offset into repeat_type. Note
- the the Unicode property types will be present only when SUPPORT_UCP is
+ the the Unicode property types will be present only when SUPPORT_UNICODE is
defined, but we don't wrap the little bits of code here because it just
makes it horribly messy. */
else if (*previous < OP_EODN)
{
- pcre_uchar *oldcode;
+ PCRE2_UCHAR *oldcode;
int prop_type, prop_value;
- op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */
- c = *previous;
-
- OUTPUT_SINGLE_REPEAT:
- if (*previous == OP_PROP || *previous == OP_NOTPROP)
+ op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */
+ c = *previous; /* Save previous opcode */
+ if (c == OP_PROP || c == OP_NOTPROP)
{
prop_type = previous[1];
prop_value = previous[2];
}
- else prop_type = prop_value = -1;
+ else
+ {
+ /* Come here from just above with a character in c */
+ OUTPUT_SINGLE_REPEAT:
+ prop_type = prop_value = -1;
+ }
- oldcode = code;
+ /* At this point we either have prop_type == prop_value == -1 and either
+ a code point or a character type that is not OP_[NOT]PROP in c, or we
+ have OP_[NOT]PROP in c and prop_type/prop_value not negative. */
+
+ oldcode = code; /* Save where we were */
code = previous; /* Usually overwrite previous item */
/* If the maximum is zero then the minimum must also be zero; Perl allows
@@ -5867,7 +5294,7 @@ for (;; ptr++)
*code++ = OP_PLUS + repeat_type;
else
{
- code = oldcode; /* leave previous item in place */
+ code = oldcode; /* Leave previous item in place */
if (repeat_max == 1) goto END_REPEAT;
*code++ = OP_UPTO + repeat_type;
PUT2INC(code, 0, repeat_max - 1);
@@ -5875,29 +5302,30 @@ for (;; ptr++)
}
/* The case {n,n} is just an EXACT, while the general case {n,m} is
- handled as an EXACT followed by an UPTO. */
+ handled as an EXACT followed by an UPTO or STAR or QUERY. */
else
{
*code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */
PUT2INC(code, 0, repeat_min);
- /* If the maximum is unlimited, insert an OP_STAR. Before doing so,
- we have to insert the character for the previous code. For a repeated
- Unicode property match, there are two extra bytes that define the
- required property. In UTF-8 mode, long characters have their length in
- c, with the UTF_LENGTH bit as a flag. */
+ /* Unless repeat_max equals repeat_min, fill in the data for EXACT, and
+ then generate the second opcode. In UTF mode, multi-code-unit
+ characters have their length in c, with the UTF_LENGTH bit as a flag,
+ and the code units in utf_units. For a repeated Unicode property match,
+ there are two extra values that define the required property, and c
+ never has the UTF_LENGTH bit set. */
- if (repeat_max < 0)
+ if (repeat_max != repeat_min)
{
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#ifdef MAYBE_UTF_MULTI
if (utf && (c & UTF_LENGTH) != 0)
{
- memcpy(code, utf_chars, IN_UCHARS(c & 7));
+ memcpy(code, utf_units, CU2BYTES(c & 7));
code += c & 7;
}
else
-#endif
+#endif /* MAYBE_UTF_MULTI */
{
*code++ = c;
if (prop_type >= 0)
@@ -5906,72 +5334,50 @@ for (;; ptr++)
*code++ = prop_value;
}
}
- *code++ = OP_STAR + repeat_type;
- }
- /* Else insert an UPTO if the max is greater than the min, again
- preceded by the character, for the previously inserted code. If the
- UPTO is just for 1 instance, we can use QUERY instead. */
-
- else if (repeat_max != repeat_min)
- {
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
- if (utf && (c & UTF_LENGTH) != 0)
- {
- memcpy(code, utf_chars, IN_UCHARS(c & 7));
- code += c & 7;
- }
- else
-#endif
- *code++ = c;
- if (prop_type >= 0)
- {
- *code++ = prop_type;
- *code++ = prop_value;
- }
- repeat_max -= repeat_min;
+ /* Now set up the following opcode */
- if (repeat_max == 1)
- {
- *code++ = OP_QUERY + repeat_type;
- }
- else
+ if (repeat_max < 0) *code++ = OP_STAR + repeat_type; else
{
- *code++ = OP_UPTO + repeat_type;
- PUT2INC(code, 0, repeat_max);
+ repeat_max -= repeat_min;
+ if (repeat_max == 1)
+ {
+ *code++ = OP_QUERY + repeat_type;
+ }
+ else
+ {
+ *code++ = OP_UPTO + repeat_type;
+ PUT2INC(code, 0, repeat_max);
+ }
}
}
}
- /* The character or character type itself comes last in all cases. */
+ /* Fill in the character or character type for the final opcode. */
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#ifdef MAYBE_UTF_MULTI
if (utf && (c & UTF_LENGTH) != 0)
{
- memcpy(code, utf_chars, IN_UCHARS(c & 7));
+ memcpy(code, utf_units, CU2BYTES(c & 7));
code += c & 7;
}
else
-#endif
- *code++ = c;
-
- /* For a repeated Unicode property match, there are two extra bytes that
- define the required property. */
-
-#ifdef SUPPORT_UCP
- if (prop_type >= 0)
+#endif /* MAYBEW_UTF_MULTI */
{
- *code++ = prop_type;
- *code++ = prop_value;
+ *code++ = c;
+ if (prop_type >= 0)
+ {
+ *code++ = prop_type;
+ *code++ = prop_value;
+ }
}
-#endif
}
/* If previous was a character class or a back reference, we put the repeat
stuff after it, but just skip the item if the repeat was {0,0}. */
else if (*previous == OP_CLASS || *previous == OP_NCLASS ||
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#ifdef SUPPORT_WIDE_CHARS
*previous == OP_XCLASS ||
#endif
*previous == OP_REF || *previous == OP_REFI ||
@@ -6011,14 +5417,15 @@ for (;; ptr++)
{
register int i;
int len = (int)(code - previous);
- size_t base_hwm_offset = item_hwm_offset;
- pcre_uchar *bralink = NULL;
- pcre_uchar *brazeroptr = NULL;
+ PCRE2_UCHAR *bralink = NULL;
+ PCRE2_UCHAR *brazeroptr = NULL;
- /* Repeating a DEFINE group is pointless, but Perl allows the syntax, so
- we just ignore the repeat. */
+ /* Repeating a DEFINE group (or any group where the condition is always
+ FALSE and there is only one branch) is pointless, but Perl allows the
+ syntax, so we just ignore the repeat. */
- if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_DEF)
+ if (*previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE &&
+ previous[GET(previous, 1)] != OP_ALT)
goto END_REPEAT;
/* There is no sense in actually repeating assertions. The only potential
@@ -6057,17 +5464,11 @@ for (;; ptr++)
selectively.
If the maximum is 1 or unlimited, we just have to stick in the BRAZERO
- and do no more at this point. However, we do need to adjust any
- OP_RECURSE calls inside the group that refer to the group itself or any
- internal or forward referenced group, because the offset is from the
- start of the whole regex. Temporarily terminate the pattern while doing
- this. */
+ and do no more at this point. */
if (repeat_max <= 1) /* Covers 0, 1, and unlimited */
{
- *code = OP_END;
- adjust_recurse(previous, 1, utf, cd, item_hwm_offset);
- memmove(previous + 1, previous, IN_UCHARS(len));
+ memmove(previous + 1, previous, CU2BYTES(len));
code++;
if (repeat_max == 0)
{
@@ -6083,15 +5484,12 @@ for (;; ptr++)
The first one has to be handled carefully because it's the original
copy, which has to be moved up. The remainder can be handled by code
that is common with the non-zero minimum case below. We have to
- adjust the value or repeat_max, since one less copy is required. Once
- again, we may have to adjust any OP_RECURSE calls inside the group. */
+ adjust the value or repeat_max, since one less copy is required. */
else
{
int offset;
- *code = OP_END;
- adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, item_hwm_offset);
- memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len));
+ memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len));
code += 2 + LINK_SIZE;
*previous++ = OP_BRAZERO + repeat_type;
*previous++ = OP_BRA;
@@ -6109,10 +5507,7 @@ for (;; ptr++)
/* If the minimum is greater than zero, replicate the group as many
times as necessary, and adjust the maximum to the number of subsequent
- copies that we need. If we set a first char from the group, and didn't
- set a required char, copy the latter from the former. If there are any
- forward reference subroutine calls in the group, there will be entries on
- the workspace list; replicate these with an appropriate increment. */
+ copies that we need. */
else
{
@@ -6125,7 +5520,7 @@ for (;; ptr++)
if (lengthptr != NULL)
{
- int delta = (repeat_min - 1)*length_prevgroup;
+ size_t delta = (repeat_min - 1)*length_prevgroup;
if ((INT64_OR_DOUBLE)(repeat_min - 1)*
(INT64_OR_DOUBLE)length_prevgroup >
(INT64_OR_DOUBLE)INT_MAX ||
@@ -6138,40 +5533,18 @@ for (;; ptr++)
}
/* This is compiling for real. If there is a set first byte for
- the group, and we have not yet set a "required byte", set it. Make
- sure there is enough workspace for copying forward references before
- doing the copy. */
+ the group, and we have not yet set a "required byte", set it. */
else
{
- if (groupsetfirstchar && reqcharflags < 0)
+ if (groupsetfirstcu && reqcuflags < 0)
{
- reqchar = firstchar;
- reqcharflags = firstcharflags;
+ reqcu = firstcu;
+ reqcuflags = firstcuflags;
}
-
for (i = 1; i < repeat_min; i++)
{
- pcre_uchar *hc;
- size_t this_hwm_offset = cd->hwm - cd->start_workspace;
- memcpy(code, previous, IN_UCHARS(len));
-
- while (cd->hwm > cd->start_workspace + cd->workspace_size -
- WORK_SIZE_SAFETY_MARGIN -
- (this_hwm_offset - base_hwm_offset))
- {
- *errorcodeptr = expand_workspace(cd);
- if (*errorcodeptr != 0) goto FAILED;
- }
-
- for (hc = (pcre_uchar *)cd->start_workspace + base_hwm_offset;
- hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset;
- hc += LINK_SIZE)
- {
- PUT(cd->hwm, 0, GET(hc, 0) + len);
- cd->hwm += LINK_SIZE;
- }
- base_hwm_offset = this_hwm_offset;
+ memcpy(code, previous, CU2BYTES(len));
code += len;
}
}
@@ -6198,7 +5571,7 @@ for (;; ptr++)
if (lengthptr != NULL && repeat_max > 0)
{
- int delta = repeat_max * (length_prevgroup + 1 + 2 + 2*LINK_SIZE) -
+ size_t delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) -
2 - 2*LINK_SIZE; /* Last one doesn't nest */
if ((INT64_OR_DOUBLE)repeat_max *
(INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE)
@@ -6215,9 +5588,6 @@ for (;; ptr++)
else for (i = repeat_max - 1; i >= 0; i--)
{
- pcre_uchar *hc;
- size_t this_hwm_offset = cd->hwm - cd->start_workspace;
-
*code++ = OP_BRAZERO + repeat_type;
/* All but the final copy start a new nesting, maintaining the
@@ -6232,27 +5602,7 @@ for (;; ptr++)
PUTINC(code, 0, offset);
}
- memcpy(code, previous, IN_UCHARS(len));
-
- /* Ensure there is enough workspace for forward references before
- copying them. */
-
- while (cd->hwm > cd->start_workspace + cd->workspace_size -
- WORK_SIZE_SAFETY_MARGIN -
- (this_hwm_offset - base_hwm_offset))
- {
- *errorcodeptr = expand_workspace(cd);
- if (*errorcodeptr != 0) goto FAILED;
- }
-
- for (hc = (pcre_uchar *)cd->start_workspace + base_hwm_offset;
- hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset;
- hc += LINK_SIZE)
- {
- PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1));
- cd->hwm += LINK_SIZE;
- }
- base_hwm_offset = this_hwm_offset;
+ memcpy(code, previous, CU2BYTES(len));
code += len;
}
@@ -6263,7 +5613,7 @@ for (;; ptr++)
{
int oldlinkoffset;
int offset = (int)(code - bralink + 1);
- pcre_uchar *bra = code - offset;
+ PCRE2_UCHAR *bra = code - offset;
oldlinkoffset = GET(bra, 1);
bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
*code++ = OP_KET;
@@ -6288,7 +5638,7 @@ for (;; ptr++)
conditional, we convert the BRA code to the POS form, and the KET code to
KETRPOS. (It turns out to be convenient at runtime to detect this kind of
subpattern at both the start and at the end.) The use of special opcodes
- makes it possible to reduce greatly the stack usage in pcre_exec(). If
+ makes it possible to reduce greatly the stack usage in pcre2_match(). If
the group is preceded by OP_BRAZERO, convert this to OP_BRAPOSZERO.
Then, if the minimum number of matches is 1 or 0, cancel the possessive
@@ -6299,8 +5649,8 @@ for (;; ptr++)
else
{
- pcre_uchar *ketcode = code - 1 - LINK_SIZE;
- pcre_uchar *bracode = ketcode - GET(ketcode, 1);
+ PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE;
+ PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1);
/* Convert possessive ONCE brackets to non-capturing */
@@ -6318,14 +5668,23 @@ for (;; ptr++)
else
{
- /* In the compile phase, check for empty string matching. */
+ /* In the compile phase, check whether the group could match an empty
+ string. */
if (lengthptr == NULL)
{
- pcre_uchar *scode = bracode;
+ PCRE2_UCHAR *scode = bracode;
do
{
- if (could_be_empty_branch(scode, ketcode, utf, cd, NULL))
+ int count = 0;
+ int rc = could_be_empty_branch(scode, ketcode, utf, cb, FALSE,
+ NULL, &count);
+ if (rc < 0)
+ {
+ *errorcodeptr = ERR86;
+ goto FAILED;
+ }
+ if (rc > 0)
{
*bracode += OP_SBRA - OP_BRA;
break;
@@ -6333,13 +5692,13 @@ for (;; ptr++)
scode += GET(scode, 1);
}
while (*scode == OP_ALT);
- }
- /* A conditional group with only one branch has an implicit empty
- alternative branch. */
+ /* A conditional group with only one branch has an implicit empty
+ alternative branch. */
- if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT)
- *bracode = OP_SCOND;
+ if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT)
+ *bracode = OP_SCOND;
+ }
/* Handle possessive quantifiers. */
@@ -6347,15 +5706,12 @@ for (;; ptr++)
{
/* For COND brackets, we wrap the whole thing in a possessively
repeated non-capturing bracket, because we have not invented POS
- versions of the COND opcodes. Because we are moving code along, we
- must ensure that any pending recursive references are updated. */
+ versions of the COND opcodes. */
if (*bracode == OP_COND || *bracode == OP_SCOND)
{
int nlen = (int)(code - bracode);
- *code = OP_END;
- adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, item_hwm_offset);
- memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen));
+ memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen));
code += 1 + LINK_SIZE;
nlen += 1 + LINK_SIZE;
*bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS;
@@ -6386,10 +5742,11 @@ for (;; ptr++)
}
}
- /* If previous is OP_FAIL, it was generated by an empty class [] in
- JavaScript mode. The other ways in which OP_FAIL can be generated, that is
- by (*FAIL) or (?!) set previous to NULL, which gives a "nothing to repeat"
- error above. We can just ignore the repeat in JS case. */
+ /* If previous is OP_FAIL, it was generated by an empty class []
+ (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be
+ generated, that is by (*FAIL) or (?!), set previous to NULL, which gives a
+ "nothing to repeat" error above. We can just ignore the repeat in empty
+ class case. */
else if (*previous == OP_FAIL) goto END_REPEAT;
@@ -6397,7 +5754,7 @@ for (;; ptr++)
else
{
- *errorcodeptr = ERR11;
+ *errorcodeptr = ERR10;
goto FAILED;
}
@@ -6442,7 +5799,7 @@ for (;; ptr++)
case OP_NOTEXACT:
case OP_NOTEXACTI:
tempcode += PRIV(OP_lengths)[*tempcode];
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && HAS_EXTRALEN(tempcode[-1]))
tempcode += GET_EXTRALEN(tempcode[-1]);
#endif
@@ -6453,10 +5810,10 @@ for (;; ptr++)
case OP_CLASS:
case OP_NCLASS:
- tempcode += 1 + 32/sizeof(pcre_uchar);
+ tempcode += 1 + 32/sizeof(PCRE2_UCHAR);
break;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#ifdef SUPPORT_WIDE_CHARS
case OP_XCLASS:
tempcode += GET(tempcode, 1);
break;
@@ -6482,14 +5839,11 @@ for (;; ptr++)
*tempcode = opcode_possessify[repcode];
/* For opcode without a special possessified version, wrap the item in
- ONCE brackets. Because we are moving code along, we must ensure that any
- pending recursive references are updated. */
+ ONCE brackets. */
else
{
- *code = OP_END;
- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset);
- memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
+ memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len));
code += 1 + LINK_SIZE;
len += 1 + LINK_SIZE;
tempcode[0] = OP_ONCE;
@@ -6498,104 +5852,80 @@ for (;; ptr++)
PUT(tempcode, 1, len);
}
}
-
-#ifdef NEVER
- if (len > 0) switch (*tempcode)
- {
- case OP_STAR: *tempcode = OP_POSSTAR; break;
- case OP_PLUS: *tempcode = OP_POSPLUS; break;
- case OP_QUERY: *tempcode = OP_POSQUERY; break;
- case OP_UPTO: *tempcode = OP_POSUPTO; break;
-
- case OP_STARI: *tempcode = OP_POSSTARI; break;
- case OP_PLUSI: *tempcode = OP_POSPLUSI; break;
- case OP_QUERYI: *tempcode = OP_POSQUERYI; break;
- case OP_UPTOI: *tempcode = OP_POSUPTOI; break;
-
- case OP_NOTSTAR: *tempcode = OP_NOTPOSSTAR; break;
- case OP_NOTPLUS: *tempcode = OP_NOTPOSPLUS; break;
- case OP_NOTQUERY: *tempcode = OP_NOTPOSQUERY; break;
- case OP_NOTUPTO: *tempcode = OP_NOTPOSUPTO; break;
-
- case OP_NOTSTARI: *tempcode = OP_NOTPOSSTARI; break;
- case OP_NOTPLUSI: *tempcode = OP_NOTPOSPLUSI; break;
- case OP_NOTQUERYI: *tempcode = OP_NOTPOSQUERYI; break;
- case OP_NOTUPTOI: *tempcode = OP_NOTPOSUPTOI; break;
-
- case OP_TYPESTAR: *tempcode = OP_TYPEPOSSTAR; break;
- case OP_TYPEPLUS: *tempcode = OP_TYPEPOSPLUS; break;
- case OP_TYPEQUERY: *tempcode = OP_TYPEPOSQUERY; break;
- case OP_TYPEUPTO: *tempcode = OP_TYPEPOSUPTO; break;
-
- case OP_CRSTAR: *tempcode = OP_CRPOSSTAR; break;
- case OP_CRPLUS: *tempcode = OP_CRPOSPLUS; break;
- case OP_CRQUERY: *tempcode = OP_CRPOSQUERY; break;
- case OP_CRRANGE: *tempcode = OP_CRPOSRANGE; break;
-
- /* Because we are moving code along, we must ensure that any
- pending recursive references are updated. */
-
- default:
- *code = OP_END;
- adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, item_hwm_offset);
- memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
- code += 1 + LINK_SIZE;
- len += 1 + LINK_SIZE;
- tempcode[0] = OP_ONCE;
- *code++ = OP_KET;
- PUTINC(code, 0, len);
- PUT(tempcode, 1, len);
- break;
- }
-#endif
}
/* In all case we no longer have a previous item. We also set the
- "follows varying string" flag for subsequently encountered reqchars if
+ "follows varying string" flag for subsequently encountered reqcus if
it isn't already set and we have just passed a varying length item. */
END_REPEAT:
previous = NULL;
- cd->req_varyopt |= reqvary;
+ cb->req_varyopt |= reqvary;
break;
/* ===================================================================*/
- /* Start of nested parenthesized sub-expression, or comment or lookahead or
- lookbehind or option setting or condition or all the other extended
- parenthesis forms. */
+ /* Start of nested parenthesized sub-expression, or lookahead or lookbehind
+ or option setting or condition or all the other extended parenthesis forms.
+ We must save the current high-water-mark for the forward reference list so
+ that we know where they start for this group. However, because the list may
+ be extended when there are very many forward references (usually the result
+ of a replicated inner group), we must use an offset rather than an absolute
+ address. Note that (?# comments are dealt with at the top of the loop;
+ they do not get this far. */
case CHAR_LEFT_PARENTHESIS:
ptr++;
- /* Now deal with various "verbs" that can be introduced by '*'. */
+ /* Deal with various "verbs" that can be introduced by '*'. */
if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':'
- || (MAX_255(ptr[1]) && ((cd->ctypes[ptr[1]] & ctype_letter) != 0))))
+ || (MAX_255(ptr[1]) && ((cb->ctypes[ptr[1]] & ctype_letter) != 0))))
{
int i, namelen;
int arglen = 0;
const char *vn = verbnames;
- const pcre_uchar *name = ptr + 1;
- const pcre_uchar *arg = NULL;
+ PCRE2_SPTR name = ptr + 1;
+ PCRE2_SPTR arg = NULL;
previous = NULL;
ptr++;
- while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_letter) != 0) ptr++;
- namelen = (int)(ptr - name);
+
+ /* Increment ptr, set namelen, check length */
+
+ READ_NAME(ctype_letter, ERR60, *errorcodeptr);
/* It appears that Perl allows any characters whatsoever, other than
a closing parenthesis, to appear in arguments, so we no longer insist on
- letters, digits, and underscores. */
+ letters, digits, and underscores. Perl does not, however, do any
+ interpretation within arguments, and has no means of including a closing
+ parenthesis. PCRE supports escape processing but only when it is
+ requested by an option. Note that check_escape() will not return values
+ greater than the code unit maximum when not in UTF mode. */
if (*ptr == CHAR_COLON)
{
arg = ++ptr;
- while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
- arglen = (int)(ptr - arg);
- if ((unsigned int)arglen > MAX_MARK)
+
+ if ((options & PCRE2_ALT_VERBNAMES) == 0)
{
- *errorcodeptr = ERR75;
- goto FAILED;
+ arglen = 0;
+ while (ptr < cb->end_pattern && *ptr != CHAR_RIGHT_PARENTHESIS)
+ {
+ ptr++; /* Check length as we go */
+ arglen++; /* along, to avoid the */
+ if ((unsigned int)arglen > MAX_MARK) /* possibility of overflow. */
+ {
+ *errorcodeptr = ERR76;
+ goto FAILED;
+ }
+ }
+ }
+ else
+ {
+ /* The length check is in process_verb_names() */
+ arglen = process_verb_name(&ptr, NULL, errorcodeptr, options,
+ utf, cb);
+ if (arglen < 0) goto FAILED;
}
}
@@ -6610,7 +5940,7 @@ for (;; ptr++)
for (i = 0; i < verbcount; i++)
{
if (namelen == verbs[i].len &&
- STRNCMP_UC_C8(name, vn, namelen) == 0)
+ PRIV(strncmp_c8)(name, vn, namelen) == 0)
{
int setverb;
@@ -6625,18 +5955,17 @@ for (;; ptr++)
*errorcodeptr = ERR59;
goto FAILED;
}
- cd->had_accept = TRUE;
- for (oc = cd->open_caps; oc != NULL; oc = oc->next)
+ cb->had_accept = TRUE;
+
+ /* In the first pass, just accumulate the length required;
+ otherwise hitting (*ACCEPT) inside many nested parentheses can
+ cause workspace overflow. */
+
+ for (oc = cb->open_caps; oc != NULL; oc = oc->next)
{
if (lengthptr != NULL)
{
-#ifdef COMPILE_PCRE8
- *lengthptr += 1 + IMM2_SIZE;
-#elif defined COMPILE_PCRE16
- *lengthptr += 2 + IMM2_SIZE;
-#elif defined COMPILE_PCRE32
- *lengthptr += 4 + IMM2_SIZE;
-#endif
+ *lengthptr += CU2BYTES(1) + IMM2_SIZE;
}
else
{
@@ -6645,15 +5974,15 @@ for (;; ptr++)
}
}
setverb = *code++ =
- (cd->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;
+ (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;
- /* Do not set firstchar after *ACCEPT */
- if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
+ /* Do not set firstcu after *ACCEPT */
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
}
/* Handle other cases with/without an argument */
- else if (arglen == 0)
+ else if (arglen == 0) /* There is no argument */
{
if (verbs[i].op < 0) /* Argument is mandatory */
{
@@ -6663,25 +5992,42 @@ for (;; ptr++)
setverb = *code++ = verbs[i].op;
}
- else
+ else /* An argument is present */
{
- if (verbs[i].op_arg < 0) /* Argument is forbidden */
+ if (verbs[i].op_arg < 0) /* Argument is forbidden */
{
*errorcodeptr = ERR59;
goto FAILED;
}
setverb = *code++ = verbs[i].op_arg;
- if (lengthptr != NULL) /* In pass 1 just add in the length */
- { /* to avoid potential workspace */
- *lengthptr += arglen; /* overflow. */
+
+ /* Arguments can be very long, especially in 16- and 32-bit modes,
+ and can overflow the workspace in the first pass. Instead of
+ putting the argument into memory, we just update the length counter
+ and set up an empty argument. */
+
+ if (lengthptr != NULL)
+ {
+ *lengthptr += arglen;
*code++ = 0;
}
else
{
*code++ = arglen;
- memcpy(code, arg, IN_UCHARS(arglen));
- code += arglen;
+ if ((options & PCRE2_ALT_VERBNAMES) != 0)
+ {
+ PCRE2_UCHAR *memcode = code; /* code is "register" */
+ (void)process_verb_name(&arg, &memcode, errorcodeptr, options,
+ utf, cb);
+ code = memcode;
+ }
+ else /* No argument processing */
+ {
+ memcpy(code, arg, CU2BYTES(arglen));
+ code += arglen;
+ }
}
+
*code++ = 0;
}
@@ -6689,14 +6035,14 @@ for (;; ptr++)
{
case OP_THEN:
case OP_THEN_ARG:
- cd->external_flags |= PCRE_HASTHEN;
+ cb->external_flags |= PCRE2_HASTHEN;
break;
case OP_PRUNE:
case OP_PRUNE_ARG:
case OP_SKIP:
case OP_SKIP_ARG:
- cd->had_pruneorskip = TRUE;
+ cb->had_pruneorskip = TRUE;
break;
}
@@ -6711,12 +6057,11 @@ for (;; ptr++)
goto FAILED;
}
- /* Initialize for "real" parentheses */
+ /* Initialization for "real" parentheses */
newoptions = options;
- skipbytes = 0;
+ skipunits = 0;
bravalue = OP_CBRA;
- item_hwm_offset = cd->hwm - cd->start_workspace;
reset_bracount = FALSE;
/* Deal with the extended parentheses; all are introduced by '?', and the
@@ -6724,17 +6069,19 @@ for (;; ptr++)
if (*ptr == CHAR_QUESTION_MARK)
{
- int i, set, unset, namelen;
- int *optset;
- const pcre_uchar *name;
- pcre_uchar *slot;
+ int i, count;
+ int namelen; /* Must be signed */
+ uint32_t index;
+ uint32_t set, unset, *optset;
+ named_group *ng;
+ PCRE2_SPTR name;
+ PCRE2_UCHAR *slot;
switch (*(++ptr))
{
/* ------------------------------------------------------------ */
case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */
reset_bracount = TRUE;
- cd->dupgroups = TRUE; /* Record (?| encountered */
/* Fall through */
/* ------------------------------------------------------------ */
@@ -6743,7 +6090,6 @@ for (;; ptr++)
ptr++;
break;
-
/* ------------------------------------------------------------ */
case CHAR_LEFT_PARENTHESIS:
bravalue = OP_COND; /* Conditional group */
@@ -6768,9 +6114,39 @@ for (;; ptr++)
if (ptr[1] == CHAR_QUESTION_MARK && ptr[2] == CHAR_C)
{
- for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break;
- if (ptr[i] == CHAR_RIGHT_PARENTHESIS)
- tempptr += i + 1;
+ if (IS_DIGIT(ptr[3]) || ptr[3] == CHAR_RIGHT_PARENTHESIS)
+ {
+ for (i = 3;; i++) if (!IS_DIGIT(ptr[i])) break;
+ if (ptr[i] == CHAR_RIGHT_PARENTHESIS)
+ tempptr += i + 1;
+ }
+ else
+ {
+ uint32_t delimiter = 0;
+ for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
+ {
+ if (ptr[3] == PRIV(callout_start_delims)[i])
+ {
+ delimiter = PRIV(callout_end_delims)[i];
+ break;
+ }
+ }
+ if (delimiter != 0)
+ {
+ for (i = 4; ptr + i < cb->end_pattern; i++)
+ {
+ if (ptr[i] == delimiter)
+ {
+ if (ptr[i+1] == delimiter) i++;
+ else
+ {
+ if (ptr[i+1] == CHAR_RIGHT_PARENTHESIS) tempptr += i + 2;
+ break;
+ }
+ }
+ }
+ }
+ }
/* tempptr should now be pointing to the opening parenthesis of the
assertion condition. */
@@ -6783,8 +6159,10 @@ for (;; ptr++)
}
/* For conditions that are assertions, check the syntax, and then exit
- the switch. This will take control down to where bracketed groups,
- including assertions, are processed. */
+ the switch. This will take control down to where bracketed groups
+ are processed. The assertion will be handled as part of the group,
+ but we need to identify this case because the conditional assertion may
+ not be quantifier. */
if (tempptr[1] == CHAR_QUESTION_MARK &&
(tempptr[2] == CHAR_EQUALS_SIGN ||
@@ -6793,7 +6171,7 @@ for (;; ptr++)
(tempptr[3] == CHAR_EQUALS_SIGN ||
tempptr[3] == CHAR_EXCLAMATION_MARK))))
{
- cd->iscondassert = TRUE;
+ cb->iscondassert = TRUE;
break;
}
@@ -6801,15 +6179,72 @@ for (;; ptr++)
need to skip at least 1+IMM2_SIZE bytes at the start of the group. */
code[1+LINK_SIZE] = OP_CREF;
- skipbytes = 1+IMM2_SIZE;
+ skipunits = 1+IMM2_SIZE;
refsign = -1; /* => not a number */
namelen = -1; /* => not a name; must set to avoid warning */
name = NULL; /* Always set to avoid warning */
recno = 0; /* Always set to avoid warning */
- /* Check for a test for recursion in a named group. */
+ /* Point at character after (?( */
ptr++;
+
+ /* Check for (?(VERSION[>]=n.m), which is a facility whereby indirect
+ users of PCRE2 via an application can discover which release of PCRE2
+ is being used. */
+
+ if (PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 &&
+ ptr[7] != CHAR_RIGHT_PARENTHESIS)
+ {
+ BOOL ge = FALSE;
+ int major = 0;
+ int minor = 0;
+
+ ptr += 7;
+ if (*ptr == CHAR_GREATER_THAN_SIGN)
+ {
+ ge = TRUE;
+ ptr++;
+ }
+
+ /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT
+ references its argument twice. */
+
+ if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr)))
+ {
+ *errorcodeptr = ERR79;
+ goto FAILED;
+ }
+
+ while (IS_DIGIT(*ptr)) major = major * 10 + *ptr++ - '0';
+ if (*ptr == CHAR_DOT)
+ {
+ ptr++;
+ while (IS_DIGIT(*ptr)) minor = minor * 10 + *ptr++ - '0';
+ if (minor < 10) minor *= 10;
+ }
+
+ if (*ptr != CHAR_RIGHT_PARENTHESIS || minor > 99)
+ {
+ *errorcodeptr = ERR79;
+ goto FAILED;
+ }
+
+ if (ge)
+ code[1+LINK_SIZE] = ((PCRE2_MAJOR > major) ||
+ (PCRE2_MAJOR == major && PCRE2_MINOR >= minor))?
+ OP_TRUE : OP_FALSE;
+ else
+ code[1+LINK_SIZE] = (PCRE2_MAJOR == major && PCRE2_MINOR == minor)?
+ OP_TRUE : OP_FALSE;
+
+ ptr++;
+ skipunits = 1;
+ break; /* End of condition processing */
+ }
+
+ /* Check for a test for recursion in a named group. */
+
if (*ptr == CHAR_R && ptr[1] == CHAR_AMPERSAND)
{
terminator = -1;
@@ -6856,34 +6291,33 @@ for (;; ptr++)
}
/* Otherwise we expect to read a name; anything else is an error. When
- a name is one of a number of duplicates, a different opcode is used and
- it needs more memory. Unfortunately we cannot tell whether a name is a
- duplicate in the first pass, so we have to allow for more memory. */
+ the referenced name is one of a number of duplicates, a different
+ opcode is used and it needs more memory. Unfortunately we cannot tell
+ whether this is the case in the first pass, so we have to allow for
+ more memory always. In the second pass, the additional to skipunits
+ happens later. */
else
{
if (IS_DIGIT(*ptr))
{
- *errorcodeptr = ERR84;
+ *errorcodeptr = ERR44; /* Group name must start with non-digit */
goto FAILED;
}
- if (!MAX_255(*ptr) || (cd->ctypes[*ptr] & ctype_word) == 0)
+ if (!MAX_255(*ptr) || (cb->ctypes[*ptr] & ctype_word) == 0)
{
*errorcodeptr = ERR28; /* Assertion expected */
goto FAILED;
}
- name = ptr++;
- while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0)
- {
- ptr++;
- }
- namelen = (int)(ptr - name);
- if (lengthptr != NULL) skipbytes += IMM2_SIZE;
+ name = ptr;
+ /* Increment ptr, set namelen, check length */
+ READ_NAME(ctype_word, ERR48, *errorcodeptr);
+ if (lengthptr != NULL) skipunits += IMM2_SIZE;
}
/* Check the terminator */
- if ((terminator > 0 && *ptr++ != (pcre_uchar)terminator) ||
+ if ((terminator > 0 && *ptr++ != (PCRE2_UCHAR)terminator) ||
*ptr++ != CHAR_RIGHT_PARENTHESIS)
{
ptr--; /* Error offset */
@@ -6907,24 +6341,24 @@ for (;; ptr++)
goto FAILED;
}
if (refsign != 0) recno = (refsign == CHAR_MINUS)?
- cd->bracount - recno + 1 : recno + cd->bracount;
- if (recno <= 0 || recno > cd->final_bracount)
+ (cb->bracount + 1) - recno : recno + cb->bracount;
+ if (recno <= 0 || (uint32_t)recno > cb->final_bracount)
{
*errorcodeptr = ERR15;
goto FAILED;
}
PUT2(code, 2+LINK_SIZE, recno);
- if (recno > cd->top_backref) cd->top_backref = recno;
+ if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno;
break;
}
/* Otherwise look for the name. */
- slot = cd->name_table;
- for (i = 0; i < cd->names_found; i++)
+ slot = cb->name_table;
+ for (i = 0; i < cb->names_found; i++)
{
- if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) == 0) break;
- slot += cd->name_entry_size;
+ if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0) break;
+ slot += cb->name_entry_size;
}
/* Found the named subpattern. If the name is duplicated, add one to
@@ -6932,25 +6366,27 @@ for (;; ptr++)
appropriate data values. Otherwise, just insert the unique subpattern
number. */
- if (i < cd->names_found)
+ if (i < cb->names_found)
{
- int offset = i++;
- int count = 1;
- recno = GET2(slot, 0); /* Number from first found */
- if (recno > cd->top_backref) cd->top_backref = recno;
- for (; i < cd->names_found; i++)
+ int offset = i; /* Offset of first name found */
+
+ count = 0;
+ for (;;)
{
- slot += cd->name_entry_size;
- if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) != 0 ||
- (slot+IMM2_SIZE)[namelen] != 0) break;
+ recno = GET2(slot, 0); /* Number for last found */
+ if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno;
count++;
+ if (++i >= cb->names_found) break;
+ slot += cb->name_entry_size;
+ if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) != 0 ||
+ (slot+IMM2_SIZE)[namelen] != 0) break;
}
if (count > 1)
{
PUT2(code, 2+LINK_SIZE, offset);
PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count);
- skipbytes += IMM2_SIZE;
+ skipunits += IMM2_SIZE;
code[1+LINK_SIZE]++;
}
else /* Not a duplicated name */
@@ -6981,7 +6417,7 @@ for (;; ptr++)
{
if (!IS_DIGIT(name[i]))
{
- *errorcodeptr = ERR15;
+ *errorcodeptr = ERR15; /* Non-existent subpattern */
goto FAILED;
}
if (recno > INT_MAX / 10 - 1) /* Integer overflow */
@@ -6997,12 +6433,14 @@ for (;; ptr++)
}
/* Similarly, check for the (?(DEFINE) "condition", which is always
- false. */
+ false. During compilation we set OP_DEFINE to distinguish this from
+ other OP_FALSE conditions so that it can be checked for having only one
+ branch, but after that the opcode is changed to OP_FALSE. */
- else if (namelen == 6 && STRNCMP_UC_C8(name, STRING_DEFINE, 6) == 0)
+ else if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0)
{
- code[1+LINK_SIZE] = OP_DEF;
- skipbytes = 1;
+ code[1+LINK_SIZE] = OP_DEFINE;
+ skipunits = 1;
}
/* Reference to an unidentified subpattern. */
@@ -7018,7 +6456,7 @@ for (;; ptr++)
/* ------------------------------------------------------------ */
case CHAR_EQUALS_SIGN: /* Positive lookahead */
bravalue = OP_ASSERT;
- cd->assert_depth += 1;
+ cb->assert_depth += 1;
ptr++;
break;
@@ -7040,7 +6478,7 @@ for (;; ptr++)
continue;
}
bravalue = OP_ASSERT_NOT;
- cd->assert_depth += 1;
+ cb->assert_depth += 1;
break;
@@ -7050,22 +6488,24 @@ for (;; ptr++)
{
case CHAR_EQUALS_SIGN: /* Positive lookbehind */
bravalue = OP_ASSERTBACK;
- cd->assert_depth += 1;
+ cb->assert_depth += 1;
ptr += 2;
break;
case CHAR_EXCLAMATION_MARK: /* Negative lookbehind */
bravalue = OP_ASSERTBACK_NOT;
- cd->assert_depth += 1;
+ cb->assert_depth += 1;
ptr += 2;
break;
- default: /* Could be name define, else bad */
- if (MAX_255(ptr[1]) && (cd->ctypes[ptr[1]] & ctype_word) != 0)
- goto DEFINE_NAME;
- ptr++; /* Correct offset for error */
- *errorcodeptr = ERR24;
- goto FAILED;
+ /* Must be a name definition - as the syntax was checked in the
+ pre-pass, we can assume here that it is valid. Skip over the name
+ and go to handle the numbered group. */
+
+ default:
+ while (*(++ptr) != CHAR_GREATER_THAN_SIGN);
+ ptr++;
+ goto NUMBERED_GROUP;
}
break;
@@ -7078,159 +6518,161 @@ for (;; ptr++)
/* ------------------------------------------------------------ */
- case CHAR_C: /* Callout - may be followed by digits; */
+ case CHAR_C: /* Callout */
previous_callout = code; /* Save for later completion */
after_manual_callout = 1; /* Skip one item before completing */
- *code++ = OP_CALLOUT;
- {
- int n = 0;
- ptr++;
- while(IS_DIGIT(*ptr))
- n = n * 10 + *ptr++ - CHAR_0;
- if (*ptr != CHAR_RIGHT_PARENTHESIS)
- {
- *errorcodeptr = ERR39;
- goto FAILED;
- }
- if (n > 255)
- {
- *errorcodeptr = ERR38;
- goto FAILED;
- }
- *code++ = n;
- PUT(code, 0, (int)(ptr - cd->start_pattern + 1)); /* Pattern offset */
- PUT(code, LINK_SIZE, 0); /* Default length */
- code += 2 * LINK_SIZE;
- }
- previous = NULL;
- continue;
-
-
- /* ------------------------------------------------------------ */
- case CHAR_P: /* Python-style named subpattern handling */
- if (*(++ptr) == CHAR_EQUALS_SIGN ||
- *ptr == CHAR_GREATER_THAN_SIGN) /* Reference or recursion */
- {
- is_recurse = *ptr == CHAR_GREATER_THAN_SIGN;
- terminator = CHAR_RIGHT_PARENTHESIS;
- goto NAMED_REF_OR_RECURSE;
- }
- else if (*ptr != CHAR_LESS_THAN_SIGN) /* Test for Python-style defn */
- {
- *errorcodeptr = ERR41;
- goto FAILED;
- }
- /* Fall through to handle (?P< as (?< is handled */
-
-
- /* ------------------------------------------------------------ */
- DEFINE_NAME: /* Come here from (?< handling */
- case CHAR_APOSTROPHE:
- terminator = (*ptr == CHAR_LESS_THAN_SIGN)?
- CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
- name = ++ptr;
- if (IS_DIGIT(*ptr))
- {
- *errorcodeptr = ERR84; /* Group name must start with non-digit */
- goto FAILED;
- }
- while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++;
- namelen = (int)(ptr - name);
+ ptr++; /* Character after (?C */
- /* In the pre-compile phase, do a syntax check, remember the longest
- name, and then remember the group in a vector, expanding it if
- necessary. Duplicates for the same number are skipped; other duplicates
- are checked for validity. In the actual compile, there is nothing to
- do. */
+ /* A callout may have a string argument, delimited by one of a fixed
+ number of characters, or an undelimited numerical argument, or no
+ argument, which is the same as (?C0). Different opcodes are used for
+ the two cases. */
- if (lengthptr != NULL)
+ if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr))
{
- named_group *ng;
- pcre_uint32 number = cd->bracount + 1;
+ uint32_t delimiter = 0;
- if (*ptr != (pcre_uchar)terminator)
+ for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
{
- *errorcodeptr = ERR42;
- goto FAILED;
+ if (*ptr == PRIV(callout_start_delims)[i])
+ {
+ delimiter = PRIV(callout_end_delims)[i];
+ break;
+ }
}
- if (cd->names_found >= MAX_NAME_COUNT)
+ if (delimiter == 0)
{
- *errorcodeptr = ERR49;
+ *errorcodeptr = ERR82;
goto FAILED;
}
- if (namelen + IMM2_SIZE + 1 > cd->name_entry_size)
+ /* During the pre-compile phase, we parse the string and update the
+ length. There is no need to generate any code. (In fact, the string
+ has already been parsed in the pre-pass that looks for named
+ parentheses, but it does no harm to leave this code in.) */
+
+ if (lengthptr != NULL) /* Only check the string */
{
- cd->name_entry_size = namelen + IMM2_SIZE + 1;
- if (namelen > MAX_NAME_SIZE)
+ PCRE2_SPTR start = ptr;
+ do
{
- *errorcodeptr = ERR48;
- goto FAILED;
+ if (++ptr >= cb->end_pattern)
+ {
+ *errorcodeptr = ERR81;
+ ptr = start; /* To give a more useful message */
+ goto FAILED;
+ }
+ if (ptr[0] == delimiter && ptr[1] == delimiter) ptr += 2;
}
+ while (ptr[0] != delimiter);
+
+ /* Start points to the opening delimiter, ptr points to the
+ closing delimiter. We must allow for including the delimiter and
+ for the terminating zero. Any doubled delimiters within the string
+ make this an overestimate, but it is not worth bothering about. */
+
+ (*lengthptr) += (ptr - start) + 2 + (1 + 4*LINK_SIZE);
}
- /* Scan the list to check for duplicates. For duplicate names, if the
- number is the same, break the loop, which causes the name to be
- discarded; otherwise, if DUPNAMES is not set, give an error.
- If it is set, allow the name with a different number, but continue
- scanning in case this is a duplicate with the same number. For
- non-duplicate names, give an error if the number is duplicated. */
+ /* In the real compile we can copy the string, knowing that it is
+ syntactically OK. The starting delimiter is included so that the
+ client can discover it if they want. We also pass the start offset to
+ help a script language give better error messages. */
- ng = cd->named_groups;
- for (i = 0; i < cd->names_found; i++, ng++)
+ else
{
- if (namelen == ng->length &&
- STRNCMP_UC_UC(name, ng->name, namelen) == 0)
+ PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE);
+ *callout_string++ = *ptr++;
+ PUT(code, 1 + 3*LINK_SIZE, (int)(ptr - cb->start_pattern)); /* Start offset */
+ for(;;)
{
- if (ng->number == number) break;
- if ((options & PCRE_DUPNAMES) == 0)
+ if (*ptr == delimiter)
{
- *errorcodeptr = ERR43;
- goto FAILED;
+ if (ptr[1] == delimiter) ptr++; else break;
}
- cd->dupnames = TRUE; /* Duplicate names exist */
+ *callout_string++ = *ptr++;
}
- else if (ng->number == number)
+ *callout_string++ = CHAR_NULL;
+ code[0] = OP_CALLOUT_STR;
+ PUT(code, 1, (int)(ptr + 2 - cb->start_pattern)); /* Next offset */
+ PUT(code, 1 + LINK_SIZE, 0); /* Default length */
+ PUT(code, 1 + 2*LINK_SIZE, /* Compute size */
+ (int)(callout_string - code));
+ code = callout_string;
+ }
+
+ /* Advance to what should be the closing parenthesis, which is
+ checked below. */
+
+ ptr++;
+ }
+
+ /* Handle a callout with an optional numerical argument, which must be
+ less than or equal to 255. A missing argument gives 0. */
+
+ else
+ {
+ int n = 0;
+ code[0] = OP_CALLOUT; /* Numerical callout */
+ while (IS_DIGIT(*ptr))
+ {
+ n = n * 10 + *ptr++ - CHAR_0;
+ if (n > 255)
{
- *errorcodeptr = ERR65;
+ *errorcodeptr = ERR38;
goto FAILED;
}
}
+ PUT(code, 1, (int)(ptr - cb->start_pattern + 1)); /* Next offset */
+ PUT(code, 1 + LINK_SIZE, 0); /* Default length */
+ code[1 + 2*LINK_SIZE] = n; /* Callout number */
+ code += PRIV(OP_lengths)[OP_CALLOUT];
+ }
- if (i >= cd->names_found) /* Not a duplicate with same number */
- {
- /* Increase the list size if necessary */
+ /* Both formats must have a closing parenthesis */
- if (cd->names_found >= cd->named_group_list_size)
- {
- int newsize = cd->named_group_list_size * 2;
- named_group *newspace = (PUBL(malloc))
- (newsize * sizeof(named_group));
+ if (*ptr != CHAR_RIGHT_PARENTHESIS)
+ {
+ *errorcodeptr = ERR39;
+ goto FAILED;
+ }
- if (newspace == NULL)
- {
- *errorcodeptr = ERR21;
- goto FAILED;
- }
+ /* Callouts cannot be quantified. */
- memcpy(newspace, cd->named_groups,
- cd->named_group_list_size * sizeof(named_group));
- if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE)
- (PUBL(free))((void *)cd->named_groups);
- cd->named_groups = newspace;
- cd->named_group_list_size = newsize;
- }
+ previous = NULL;
+ continue;
- cd->named_groups[cd->names_found].name = name;
- cd->named_groups[cd->names_found].length = namelen;
- cd->named_groups[cd->names_found].number = number;
- cd->names_found++;
- }
+
+ /* ------------------------------------------------------------ */
+ case CHAR_P: /* Python-style named subpattern handling */
+ if (*(++ptr) == CHAR_EQUALS_SIGN ||
+ *ptr == CHAR_GREATER_THAN_SIGN) /* Reference or recursion */
+ {
+ is_recurse = *ptr == CHAR_GREATER_THAN_SIGN;
+ terminator = CHAR_RIGHT_PARENTHESIS;
+ goto NAMED_REF_OR_RECURSE;
}
+ else if (*ptr != CHAR_LESS_THAN_SIGN) /* Test for Python-style defn */
+ {
+ *errorcodeptr = ERR41;
+ goto FAILED;
+ }
+ /* Fall through to handle (?P< as (?< is handled */
+
- ptr++; /* Move past > or ' in both passes. */
- goto NUMBERED_GROUP;
+ /* ------------------------------------------------------------ */
+ case CHAR_APOSTROPHE: /* Define a name - note fall through above */
+
+ /* The syntax was checked and the list of names was set up in the
+ pre-pass, so there is nothing to be done now except to skip over the
+ name. */
+
+ terminator = (*ptr == CHAR_LESS_THAN_SIGN)?
+ CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
+ while (*(++ptr) != (unsigned int)terminator);
+ ptr++;
+ goto NUMBERED_GROUP; /* Set up numbered group */
/* ------------------------------------------------------------ */
@@ -7249,193 +6691,115 @@ for (;; ptr++)
name = ++ptr;
if (IS_DIGIT(*ptr))
{
- *errorcodeptr = ERR84; /* Group name must start with non-digit */
+ *errorcodeptr = ERR44; /* Group name must start with non-digit */
goto FAILED;
}
- while (MAX_255(*ptr) && (cd->ctypes[*ptr] & ctype_word) != 0) ptr++;
- namelen = (int)(ptr - name);
+ /* Increment ptr, set namelen, check length */
+ READ_NAME(ctype_word, ERR48, *errorcodeptr);
- /* In the pre-compile phase, do a syntax check. We used to just set
- a dummy reference number, because it was not used in the first pass.
- However, with the change of recursive back references to be atomic,
- we have to look for the number so that this state can be identified, as
- otherwise the incorrect length is computed. If it's not a backwards
- reference, the dummy number will do. */
+ /* In the pre-compile phase, do a syntax check. */
if (lengthptr != NULL)
{
- named_group *ng;
- recno = 0;
-
if (namelen == 0)
{
*errorcodeptr = ERR62;
goto FAILED;
}
- if (*ptr != (pcre_uchar)terminator)
+ if (*ptr != (PCRE2_UCHAR)terminator)
{
*errorcodeptr = ERR42;
goto FAILED;
}
- if (namelen > MAX_NAME_SIZE)
- {
- *errorcodeptr = ERR48;
- goto FAILED;
- }
-
- /* Count named back references. */
-
- if (!is_recurse) cd->namedrefcount++;
-
- /* We have to allow for a named reference to a duplicated name (this
- cannot be determined until the second pass). This needs an extra
- 16-bit data item. */
-
- *lengthptr += IMM2_SIZE;
+ }
- /* If this is a forward reference and we are within a (?|...) group,
- the reference may end up as the number of a group which we are
- currently inside, that is, it could be a recursive reference. In the
- real compile this will be picked up and the reference wrapped with
- OP_ONCE to make it atomic, so we must space in case this occurs. */
+ /* Scan the list of names generated in the pre-pass in order to get
+ a number and whether or not this name is duplicated. */
- /* In fact, this can happen for a non-forward reference because
- another group with the same number might be created later. This
- issue is fixed "properly" in PCRE2. As PCRE1 is now in maintenance
- only mode, we finesse the bug by allowing more memory always. */
+ recno = 0;
+ is_dupname = FALSE;
+ ng = cb->named_groups;
- *lengthptr += 4 + 4*LINK_SIZE;
+ for (i = 0; i < cb->names_found; i++, ng++)
+ {
+ if (namelen == ng->length &&
+ PRIV(strncmp)(name, ng->name, namelen) == 0)
+ {
+ open_capitem *oc;
+ is_dupname = ng->isdup;
+ recno = ng->number;
- /* It is even worse than that. The current reference may be to an
- existing named group with a different number (so apparently not
- recursive) but which later on is also attached to a group with the
- current number. This can only happen if $(| has been previous
- encountered. In that case, we allow yet more memory, just in case.
- (Again, this is fixed "properly" in PCRE2. */
+ /* For a recursion, that's all that is needed. We can now go to the
+ code that handles numerical recursion. */
- if (cd->dupgroups) *lengthptr += 4 + 4*LINK_SIZE;
+ if (is_recurse) goto HANDLE_RECURSION;
- /* Otherwise, check for recursion here. The name table does not exist
- in the first pass; instead we must scan the list of names encountered
- so far in order to get the number. If the name is not found, leave
- the value of recno as 0 for a forward reference. */
+ /* For a back reference, update the back reference map and the
+ maximum back reference. Then for each group we must check to see if
+ it is recursive, that is, it is inside the group that it
+ references. A flag is set so that the group can be made atomic. */
- /* This patch (removing "else") fixes a problem when a reference is
- to multiple identically named nested groups from within the nest.
- Once again, it is not the "proper" fix, and it results in an
- over-allocation of memory. */
+ cb->backref_map |= (recno < 32)? (1u << recno) : 1;
+ if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno;
- /* else */
- {
- ng = cd->named_groups;
- for (i = 0; i < cd->names_found; i++, ng++)
+ for (oc = cb->open_caps; oc != NULL; oc = oc->next)
{
- if (namelen == ng->length &&
- STRNCMP_UC_UC(name, ng->name, namelen) == 0)
+ if (oc->number == recno)
{
- open_capitem *oc;
- recno = ng->number;
- if (is_recurse) break;
- for (oc = cd->open_caps; oc != NULL; oc = oc->next)
- {
- if (oc->number == recno)
- {
- oc->flag = TRUE;
- break;
- }
- }
+ oc->flag = TRUE;
+ break;
}
}
}
}
- /* In the real compile, search the name table. We check the name
- first, and then check that we have reached the end of the name in the
- table. That way, if the name is longer than any in the table, the
- comparison will fail without reading beyond the table entry. */
+ /* If the name was not found we have a bad reference. */
- else
+ if (recno == 0)
{
- slot = cd->name_table;
- for (i = 0; i < cd->names_found; i++)
- {
- if (STRNCMP_UC_UC(name, slot+IMM2_SIZE, namelen) == 0 &&
- slot[IMM2_SIZE+namelen] == 0)
- break;
- slot += cd->name_entry_size;
- }
-
- if (i < cd->names_found)
- {
- recno = GET2(slot, 0);
- }
- else
- {
- *errorcodeptr = ERR15;
- goto FAILED;
- }
+ *errorcodeptr = ERR15;
+ goto FAILED;
}
- /* In both phases, for recursions, we can now go to the code than
- handles numerical recursion. */
-
- if (is_recurse) goto HANDLE_RECURSION;
+ /* If a back reference name is not duplicated, we can handle it as a
+ numerical reference. */
- /* In the second pass we must see if the name is duplicated. If so, we
- generate a different opcode. */
+ if (!is_dupname) goto HANDLE_REFERENCE;
- if (lengthptr == NULL && cd->dupnames)
- {
- int count = 1;
- unsigned int index = i;
- pcre_uchar *cslot = slot + cd->name_entry_size;
+ /* If a back reference name is duplicated, we generate a different
+ opcode to a numerical back reference. In the second pass we must search
+ for the index and count in the final name table. */
- for (i++; i < cd->names_found; i++)
- {
- if (STRCMP_UC_UC(slot + IMM2_SIZE, cslot + IMM2_SIZE) != 0) break;
- count++;
- cslot += cd->name_entry_size;
- }
+ count = 0;
+ index = 0;
- if (count > 1)
+ if (lengthptr == NULL)
+ {
+ slot = cb->name_table;
+ for (i = 0; i < cb->names_found; i++)
{
- if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
- previous = code;
- item_hwm_offset = cd->hwm - cd->start_workspace;
- *code++ = ((options & PCRE_CASELESS) != 0)? OP_DNREFI : OP_DNREF;
- PUT2INC(code, 0, index);
- PUT2INC(code, 0, count);
-
- /* Process each potentially referenced group. */
-
- for (; slot < cslot; slot += cd->name_entry_size)
+ if (PRIV(strncmp)(name, slot+IMM2_SIZE, namelen) == 0 &&
+ slot[IMM2_SIZE+namelen] == 0)
{
- open_capitem *oc;
- recno = GET2(slot, 0);
- cd->backref_map |= (recno < 32)? (1 << recno) : 1;
- if (recno > cd->top_backref) cd->top_backref = recno;
-
- /* Check to see if this back reference is recursive, that it, it
- is inside the group that it references. A flag is set so that the
- group can be made atomic. */
-
- for (oc = cd->open_caps; oc != NULL; oc = oc->next)
- {
- if (oc->number == recno)
- {
- oc->flag = TRUE;
- break;
- }
- }
+ if (count == 0) index = i;
+ count++;
}
+ slot += cb->name_entry_size;
+ }
- continue; /* End of back ref handling */
+ if (count == 0)
+ {
+ *errorcodeptr = ERR15;
+ goto FAILED;
}
}
- /* First pass, or a non-duplicated name. */
-
- goto HANDLE_REFERENCE;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ previous = code;
+ *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF;
+ PUT2INC(code, 0, index);
+ PUT2INC(code, 0, count);
+ continue; /* End of back ref handling */
/* ------------------------------------------------------------ */
@@ -7454,7 +6818,6 @@ for (;; ptr++)
case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4:
case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
{
- const pcre_uchar *called;
terminator = CHAR_RIGHT_PARENTHESIS;
/* Come here from the \g<...> and \g'...' code (Oniguruma
@@ -7482,7 +6845,7 @@ for (;; ptr++)
}
recno = 0;
- while(IS_DIGIT(*ptr))
+ while (IS_DIGIT(*ptr))
{
if (recno > INT_MAX / 10 - 1) /* Integer overflow */
{
@@ -7493,7 +6856,7 @@ for (;; ptr++)
recno = recno * 10 + *ptr++ - CHAR_0;
}
- if (*ptr != (pcre_uchar)terminator)
+ if (*ptr != (PCRE2_UCHAR)terminator)
{
*errorcodeptr = ERR29;
goto FAILED;
@@ -7506,7 +6869,7 @@ for (;; ptr++)
*errorcodeptr = ERR58;
goto FAILED;
}
- recno = cd->bracount - recno + 1;
+ recno = (int)(cb->bracount + 1) - recno;
if (recno <= 0)
{
*errorcodeptr = ERR15;
@@ -7520,84 +6883,37 @@ for (;; ptr++)
*errorcodeptr = ERR58;
goto FAILED;
}
- recno += cd->bracount;
+ recno += cb->bracount;
}
- /* Come here from code above that handles a named recursion */
-
- HANDLE_RECURSION:
-
- previous = code;
- item_hwm_offset = cd->hwm - cd->start_workspace;
- called = cd->start_code;
-
- /* When we are actually compiling, find the bracket that is being
- referenced. Temporarily end the regex in case it doesn't exist before
- this point. If we end up with a forward reference, first check that
- the bracket does occur later so we can give the error (and position)
- now. Then remember this forward reference in the workspace so it can
- be filled in at the end. */
-
- if (lengthptr == NULL)
+ if ((uint32_t)recno > cb->final_bracount)
{
- *code = OP_END;
- if (recno != 0)
- called = PRIV(find_bracket)(cd->start_code, utf, recno);
-
- /* Forward reference */
-
- if (called == NULL)
- {
- if (recno > cd->final_bracount)
- {
- *errorcodeptr = ERR15;
- goto FAILED;
- }
-
- /* Fudge the value of "called" so that when it is inserted as an
- offset below, what it actually inserted is the reference number
- of the group. Then remember the forward reference. */
-
- called = cd->start_code + recno;
- if (cd->hwm >= cd->start_workspace + cd->workspace_size -
- WORK_SIZE_SAFETY_MARGIN)
- {
- *errorcodeptr = expand_workspace(cd);
- if (*errorcodeptr != 0) goto FAILED;
- }
- PUTINC(cd->hwm, 0, (int)(code + 1 - cd->start_code));
- }
-
- /* If not a forward reference, and the subpattern is still open,
- this is a recursive call. We check to see if this is a left
- recursion that could loop for ever, and diagnose that case. We
- must not, however, do this check if we are in a conditional
- subpattern because the condition might be testing for recursion in
- a pattern such as /(?(R)a+|(?R)b)/, which is perfectly valid.
- Forever loops are also detected at runtime, so those that occur in
- conditional subpatterns will be picked up then. */
-
- else if (GET(called, 1) == 0 && cond_depth <= 0 &&
- could_be_empty(called, code, bcptr, utf, cd))
- {
- *errorcodeptr = ERR40;
- goto FAILED;
- }
+ *errorcodeptr = ERR15;
+ goto FAILED;
}
- /* Insert the recursion/subroutine item. It does not have a set first
- character (relevant if it is repeated, because it will then be
- wrapped with ONCE brackets). */
+ /* Come here from code above that handles a named recursion.
+ We insert the number of the called group after OP_RECURSE. At the
+ end of compiling the pattern is scanned and these numbers are
+ replaced by offsets within the pattern. It is done like this to avoid
+ problems with forward references and adjusting offsets when groups
+ are duplicated and moved (as discovered in previous implementations).
+ Note that a recursion does not have a set first character (relevant
+ if it is repeated, because it will then be wrapped with ONCE
+ brackets). */
+ HANDLE_RECURSION:
+ previous = code;
*code = OP_RECURSE;
- PUT(code, 1, (int)(called - cd->start_code));
+ PUT(code, 1, recno);
code += 1 + LINK_SIZE;
- groupsetfirstchar = FALSE;
+ groupsetfirstcu = FALSE;
+ cb->had_recurse = TRUE;
}
/* Can't determine a first byte now */
- if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
continue;
@@ -7614,18 +6930,17 @@ for (;; ptr++)
case CHAR_MINUS: optset = &unset; break;
case CHAR_J: /* Record that it changed in the external options */
- *optset |= PCRE_DUPNAMES;
- cd->external_flags |= PCRE_JCHANGED;
+ *optset |= PCRE2_DUPNAMES;
+ cb->external_flags |= PCRE2_JCHANGED;
break;
- case CHAR_i: *optset |= PCRE_CASELESS; break;
- case CHAR_m: *optset |= PCRE_MULTILINE; break;
- case CHAR_s: *optset |= PCRE_DOTALL; break;
- case CHAR_x: *optset |= PCRE_EXTENDED; break;
- case CHAR_U: *optset |= PCRE_UNGREEDY; break;
- case CHAR_X: *optset |= PCRE_EXTRA; break;
+ case CHAR_i: *optset |= PCRE2_CASELESS; break;
+ case CHAR_m: *optset |= PCRE2_MULTILINE; break;
+ case CHAR_s: *optset |= PCRE2_DOTALL; break;
+ case CHAR_x: *optset |= PCRE2_EXTENDED; break;
+ case CHAR_U: *optset |= PCRE2_UNGREEDY; break;
- default: *errorcodeptr = ERR12;
+ default: *errorcodeptr = ERR11;
ptr--; /* Correct the offset */
goto FAILED;
}
@@ -7636,20 +6951,16 @@ for (;; ptr++)
newoptions = (options | set) & (~unset);
/* If the options ended with ')' this is not the start of a nested
- group with option changes, so the options change at this level.
- If we are not at the pattern start, reset the greedy defaults and the
- case value for firstchar and reqchar. */
+ group with option changes, so the options change at this level. They
+ must also be passed back for use in subsequent branches. Reset the
+ greedy defaults and the case value for firstcu and reqcu. */
if (*ptr == CHAR_RIGHT_PARENTHESIS)
{
- greedy_default = ((newoptions & PCRE_UNGREEDY) != 0);
- greedy_non_default = greedy_default ^ 1;
- req_caseopt = ((newoptions & PCRE_CASELESS) != 0)? REQ_CASELESS:0;
-
- /* Change options at this level, and pass them back for use
- in subsequent branches. */
-
*optionsptr = options = newoptions;
+ greedy_default = ((newoptions & PCRE2_UNGREEDY) != 0);
+ greedy_non_default = greedy_default ^ 1;
+ req_caseopt = ((newoptions & PCRE2_CASELESS) != 0)? REQ_CASELESS:0;
previous = NULL; /* This item can't be repeated */
continue; /* It is complete */
}
@@ -7664,11 +6975,11 @@ for (;; ptr++)
} /* End of switch for character following (? */
} /* End of (? handling */
- /* Opening parenthesis not followed by '*' or '?'. If PCRE_NO_AUTO_CAPTURE
+ /* Opening parenthesis not followed by '*' or '?'. If PCRE2_NO_AUTO_CAPTURE
is set, all unadorned brackets become non-capturing and behave like (?:...)
brackets. */
- else if ((options & PCRE_NO_AUTO_CAPTURE) != 0)
+ else if ((options & PCRE2_NO_AUTO_CAPTURE) != 0)
{
bravalue = OP_BRA;
}
@@ -7678,17 +6989,17 @@ for (;; ptr++)
else
{
NUMBERED_GROUP:
- cd->bracount += 1;
- PUT2(code, 1+LINK_SIZE, cd->bracount);
- skipbytes = IMM2_SIZE;
+ cb->bracount += 1;
+ PUT2(code, 1+LINK_SIZE, cb->bracount);
+ skipunits = IMM2_SIZE;
}
/* Process nested bracketed regex. First check for parentheses nested too
deeply. */
- if ((cd->parens_depth += 1) > PARENS_NEST_LIMIT)
+ if ((cb->parens_depth += 1) > (int)(cb->cx->parens_nest_limit))
{
- *errorcodeptr = ERR82;
+ *errorcodeptr = ERR19;
goto FAILED;
}
@@ -7697,25 +7008,24 @@ for (;; ptr++)
conditions (Perl also forbids these to be repeated). We copy code into a
non-register variable (tempcode) in order to be able to pass its address
because some compilers complain otherwise. At the start of a conditional
- group whose condition is an assertion, cd->iscondassert is set. We unset it
+ group whose condition is an assertion, cb->iscondassert is set. We unset it
here so as to allow assertions later in the group to be quantified. */
if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT &&
- cd->iscondassert)
+ cb->iscondassert)
{
previous = NULL;
- cd->iscondassert = FALSE;
+ cb->iscondassert = FALSE;
}
else
{
previous = code;
- item_hwm_offset = cd->hwm - cd->start_workspace;
}
*code = bravalue;
tempcode = code;
- tempreqvary = cd->req_varyopt; /* Save value before bracket */
- tempbracount = cd->bracount; /* Save value before bracket */
+ tempreqvary = cb->req_varyopt; /* Save value before bracket */
+ tempbracount = cb->bracount; /* Save value before bracket */
length_prevgroup = 0; /* Initialize for pre-compile phase */
if (!compile_regex(
@@ -7726,30 +7036,30 @@ for (;; ptr++)
(bravalue == OP_ASSERTBACK ||
bravalue == OP_ASSERTBACK_NOT), /* TRUE if back assert */
reset_bracount, /* True if (?| group */
- skipbytes, /* Skip over bracket number */
+ skipunits, /* Skip over bracket number */
cond_depth +
((bravalue == OP_COND)?1:0), /* Depth of condition subpatterns */
- &subfirstchar, /* For possible first char */
- &subfirstcharflags,
- &subreqchar, /* For possible last char */
- &subreqcharflags,
+ &subfirstcu, /* For possible first char */
+ &subfirstcuflags,
+ &subreqcu, /* For possible last char */
+ &subreqcuflags,
bcptr, /* Current branch chain */
- cd, /* Tables block */
+ cb, /* Compile data block */
(lengthptr == NULL)? NULL : /* Actual compile phase */
&length_prevgroup /* Pre-compile phase */
))
goto FAILED;
- cd->parens_depth -= 1;
+ cb->parens_depth -= 1;
/* If this was an atomic group and there are no capturing groups within it,
generate OP_ONCE_NC instead of OP_ONCE. */
- if (bravalue == OP_ONCE && cd->bracount <= tempbracount)
+ if (bravalue == OP_ONCE && cb->bracount <= tempbracount)
*code = OP_ONCE_NC;
if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT)
- cd->assert_depth -= 1;
+ cb->assert_depth -= 1;
/* At the end of compiling, code is still pointing to the start of the
group, while tempcode has been updated to point past the end of the group.
@@ -7762,7 +7072,7 @@ for (;; ptr++)
if (bravalue == OP_COND && lengthptr == NULL)
{
- pcre_uchar *tc = code;
+ PCRE2_UCHAR *tc = code;
int condcount = 0;
do {
@@ -7772,20 +7082,22 @@ for (;; ptr++)
while (*tc != OP_KET);
/* A DEFINE group is never obeyed inline (the "condition" is always
- false). It must have only one branch. */
+ false). It must have only one branch. Having checked this, change the
+ opcode to OP_FALSE. */
- if (code[LINK_SIZE+1] == OP_DEF)
+ if (code[LINK_SIZE+1] == OP_DEFINE)
{
if (condcount > 1)
{
*errorcodeptr = ERR54;
goto FAILED;
}
- bravalue = OP_DEF; /* Just a flag to suppress char handling below */
+ code[LINK_SIZE+1] = OP_FALSE;
+ bravalue = OP_DEFINE; /* Just a flag to suppress char handling below */
}
/* A "normal" conditional group. If there is just one branch, we must not
- make use of its firstchar or reqchar, because this is equivalent to an
+ make use of its firstcu or reqcu, because this is equivalent to an
empty second branch. */
else
@@ -7795,11 +7107,13 @@ for (;; ptr++)
*errorcodeptr = ERR27;
goto FAILED;
}
- if (condcount == 1) subfirstcharflags = subreqcharflags = REQ_NONE;
+ if (condcount == 1) subfirstcuflags = subreqcuflags = REQ_NONE;
}
}
- /* Error if hit end of pattern */
+ /* At the end of a group, it's an error if we hit end of pattern or
+ any non-closing parenthesis. This check also happens in the pre-scan,
+ so should not trigger here, but leave this code as an insurance. */
if (*ptr != CHAR_RIGHT_PARENTHESIS)
{
@@ -7834,73 +7148,73 @@ for (;; ptr++)
/* For a DEFINE group, required and first character settings are not
relevant. */
- if (bravalue == OP_DEF) break;
+ if (bravalue == OP_DEFINE) break;
/* Handle updating of the required and first characters for other types of
group. Update for normal brackets of all kinds, and conditions with two
branches (see code above). If the bracket is followed by a quantifier with
- zero repeat, we have to back off. Hence the definition of zeroreqchar and
- zerofirstchar outside the main loop so that they can be accessed for the
+ zero repeat, we have to back off. Hence the definition of zeroreqcu and
+ zerofirstcu outside the main loop so that they can be accessed for the
back off. */
- zeroreqchar = reqchar;
- zeroreqcharflags = reqcharflags;
- zerofirstchar = firstchar;
- zerofirstcharflags = firstcharflags;
- groupsetfirstchar = FALSE;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ groupsetfirstcu = FALSE;
if (bravalue >= OP_ONCE)
{
- /* If we have not yet set a firstchar in this branch, take it from the
+ /* If we have not yet set a firstcu in this branch, take it from the
subpattern, remembering that it was set here so that a repeat of more
- than one can replicate it as reqchar if necessary. If the subpattern has
- no firstchar, set "none" for the whole branch. In both cases, a zero
- repeat forces firstchar to "none". */
+ than one can replicate it as reqcu if necessary. If the subpattern has
+ no firstcu, set "none" for the whole branch. In both cases, a zero
+ repeat forces firstcu to "none". */
- if (firstcharflags == REQ_UNSET)
+ if (firstcuflags == REQ_UNSET && subfirstcuflags != REQ_UNSET)
{
- if (subfirstcharflags >= 0)
+ if (subfirstcuflags >= 0)
{
- firstchar = subfirstchar;
- firstcharflags = subfirstcharflags;
- groupsetfirstchar = TRUE;
+ firstcu = subfirstcu;
+ firstcuflags = subfirstcuflags;
+ groupsetfirstcu = TRUE;
}
- else firstcharflags = REQ_NONE;
- zerofirstcharflags = REQ_NONE;
+ else firstcuflags = REQ_NONE;
+ zerofirstcuflags = REQ_NONE;
}
- /* If firstchar was previously set, convert the subpattern's firstchar
- into reqchar if there wasn't one, using the vary flag that was in
+ /* If firstcu was previously set, convert the subpattern's firstcu
+ into reqcu if there wasn't one, using the vary flag that was in
existence beforehand. */
- else if (subfirstcharflags >= 0 && subreqcharflags < 0)
+ else if (subfirstcuflags >= 0 && subreqcuflags < 0)
{
- subreqchar = subfirstchar;
- subreqcharflags = subfirstcharflags | tempreqvary;
+ subreqcu = subfirstcu;
+ subreqcuflags = subfirstcuflags | tempreqvary;
}
/* If the subpattern set a required byte (or set a first byte that isn't
really the first byte - see above), set it. */
- if (subreqcharflags >= 0)
+ if (subreqcuflags >= 0)
{
- reqchar = subreqchar;
- reqcharflags = subreqcharflags;
+ reqcu = subreqcu;
+ reqcuflags = subreqcuflags;
}
}
- /* For a forward assertion, we take the reqchar, if set. This can be
+ /* For a forward assertion, we take the reqcu, if set. This can be
helpful if the pattern that follows the assertion doesn't set a different
- char. For example, it's useful for /(?=abcde).+/. We can't set firstchar
+ char. For example, it's useful for /(?=abcde).+/. We can't set firstcu
for an assertion, however because it leads to incorrect effect for patterns
- such as /(?=a)a.+/ when the "real" "a" would then become a reqchar instead
- of a firstchar. This is overcome by a scan at the end if there's no
- firstchar, looking for an asserted first char. */
+ such as /(?=a)a.+/ when the "real" "a" would then become a reqcu instead
+ of a firstcu. This is overcome by a scan at the end if there's no
+ firstcu, looking for an asserted first char. */
- else if (bravalue == OP_ASSERT && subreqcharflags >= 0)
+ else if (bravalue == OP_ASSERT && subreqcuflags >= 0)
{
- reqchar = subreqchar;
- reqcharflags = subreqcharflags;
+ reqcu = subreqcu;
+ reqcuflags = subreqcuflags;
}
break; /* End of processing '(' */
@@ -7908,15 +7222,19 @@ for (;; ptr++)
/* ===================================================================*/
/* Handle metasequences introduced by \. For ones like \d, the ESC_ values
are arranged to be the negation of the corresponding OP_values in the
- default case when PCRE_UCP is not set. For the back references, the values
+ default case when PCRE2_UCP is not set. For the back references, the values
are negative the reference number. Only back references and those types
that consume a character may be repeated. We can test for values between
ESC_b and ESC_Z for the latter; this may have to change if any new ones are
- ever created. */
+ ever created.
+
+ Note: \Q and \E are handled at the start of the character-processing loop,
+ not here. */
case CHAR_BACKSLASH:
tempptr = ptr;
- escape = check_escape(&ptr, &ec, errorcodeptr, cd->bracount, options, FALSE);
+ escape = PRIV(check_escape)(&ptr, cb->end_pattern, &ec, errorcodeptr,
+ options, FALSE, cb);
if (*errorcodeptr != 0) goto FAILED;
if (escape == 0) /* The escape coded a single character */
@@ -7926,15 +7244,15 @@ for (;; ptr++)
/* For metasequences that actually match a character, we disable the
setting of a first character if it hasn't already been set. */
- if (firstcharflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z)
- firstcharflags = REQ_NONE;
+ if (firstcuflags == REQ_UNSET && escape > ESC_b && escape < ESC_Z)
+ firstcuflags = REQ_NONE;
/* Set values to reset to if this is followed by a zero repeat. */
- zerofirstchar = firstchar;
- zerofirstcharflags = firstcharflags;
- zeroreqchar = reqchar;
- zeroreqcharflags = reqcharflags;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
/* \g<name> or \g'name' is a subroutine call by name and \g<n> or \g'n'
is a subroutine call by number (Oniguruma syntax). In fact, the value
@@ -7945,10 +7263,9 @@ for (;; ptr++)
if (escape == ESC_g)
{
- const pcre_uchar *p;
- pcre_uint32 cf;
+ PCRE2_SPTR p;
+ uint32_t cf;
- item_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */
terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
@@ -7957,7 +7274,7 @@ for (;; ptr++)
fact, because we do the check for a number below, the paths that
would actually be in error are never taken. */
- skipbytes = 0;
+ skipunits = 0;
reset_bracount = FALSE;
/* If it's not a signed or unsigned number, treat it as a name. */
@@ -7974,7 +7291,7 @@ for (;; ptr++)
p = ptr + 2;
while (IS_DIGIT(*p)) p++;
- if (*p != (pcre_uchar)terminator)
+ if (*p != (PCRE2_UCHAR)terminator)
{
*errorcodeptr = ERR57;
goto FAILED;
@@ -8001,7 +7318,7 @@ for (;; ptr++)
goto NAMED_REF_OR_RECURSE;
}
- /* Back references are handled specially; must disable firstchar if
+ /* Back references are handled specially; must disable firstcu if
not set to cope with cases like (?=(\w+))\1: which would otherwise set
':' later. */
@@ -8011,22 +7328,26 @@ for (;; ptr++)
recno = -escape;
/* Come here from named backref handling when the reference is to a
- single group (i.e. not to a duplicated name. */
+ single group (i.e. not to a duplicated name). */
HANDLE_REFERENCE:
- if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
+ if (recno > (int)cb->final_bracount)
+ {
+ *errorcodeptr = ERR15;
+ goto FAILED;
+ }
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
previous = code;
- item_hwm_offset = cd->hwm - cd->start_workspace;
- *code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF;
+ *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF;
PUT2INC(code, 0, recno);
- cd->backref_map |= (recno < 32)? (1 << recno) : 1;
- if (recno > cd->top_backref) cd->top_backref = recno;
+ cb->backref_map |= (recno < 32)? (1u << recno) : 1;
+ if ((uint32_t)recno > cb->top_backref) cb->top_backref = recno;
/* Check to see if this back reference is recursive, that it, it
is inside the group that it references. A flag is set so that the
group can be made atomic. */
- for (oc = cd->open_caps; oc != NULL; oc = oc->next)
+ for (oc = cb->open_caps; oc != NULL; oc = oc->next)
{
if (oc->number == recno)
{
@@ -8038,15 +7359,14 @@ for (;; ptr++)
/* So are Unicode property matches, if supported. */
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
else if (escape == ESC_P || escape == ESC_p)
{
BOOL negated;
unsigned int ptype = 0, pdata = 0;
- if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr))
+ if (!get_ucp(&ptr, &negated, &ptype, &pdata, errorcodeptr, cb))
goto FAILED;
previous = code;
- item_hwm_offset = cd->hwm - cd->start_workspace;
*code++ = ((escape == ESC_p) != negated)? OP_PROP : OP_NOTPROP;
*code++ = ptype;
*code++ = pdata;
@@ -8063,32 +7383,54 @@ for (;; ptr++)
}
#endif
+ /* The use of \C can be locked out. */
+
+#ifdef NEVER_BACKSLASH_C
+ else if (escape == ESC_C)
+ {
+ *errorcodeptr = ERR85;
+ goto FAILED;
+ }
+#else
+ else if (escape == ESC_C && (options & PCRE2_NEVER_BACKSLASH_C) != 0)
+ {
+ *errorcodeptr = ERR83;
+ goto FAILED;
+ }
+#endif
+
/* For the rest (including \X when Unicode properties are supported), we
can obtain the OP value by negating the escape value in the default
- situation when PCRE_UCP is not set. When it *is* set, we substitute
+ situation when PCRE2_UCP is not set. When it *is* set, we substitute
Unicode property tests. Note that \b and \B do a one-character
lookbehind, and \A also behaves as if it does. */
else
{
+ if (escape == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */
if ((escape == ESC_b || escape == ESC_B || escape == ESC_A) &&
- cd->max_lookbehind == 0)
- cd->max_lookbehind = 1;
-#ifdef SUPPORT_UCP
+ cb->max_lookbehind == 0)
+ cb->max_lookbehind = 1;
+#ifdef SUPPORT_UNICODE
if (escape >= ESC_DU && escape <= ESC_wu)
{
- nestptr = ptr + 1; /* Where to resume */
+ cb->nestptr[1] = cb->nestptr[0]; /* Back up if at 2nd level */
+ cb->nestptr[0] = ptr + 1; /* Where to resume */
ptr = substitutes[escape - ESC_DU] - 1; /* Just before substitute */
}
else
#endif
- /* In non-UTF-8 mode, we turn \C into OP_ALLANY instead of OP_ANYBYTE
- so that it works in DFA mode and in lookbehinds. */
+ /* In non-UTF mode, and for both 32-bit modes, we turn \C into
+ OP_ALLANY instead of OP_ANYBYTE so that it works in DFA mode and in
+ lookbehinds. */
{
previous = (escape > ESC_b && escape < ESC_Z)? code : NULL;
- item_hwm_offset = cd->hwm - cd->start_workspace;
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ *code++ = (escape == ESC_C)? OP_ALLANY : escape;
+#else
*code++ = (!utf && escape == ESC_C)? OP_ALLANY : escape;
+#endif
}
}
continue;
@@ -8098,16 +7440,7 @@ for (;; ptr++)
a value > 127. We set its representation in the length/buffer, and then
handle it as a data character. */
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
- if (utf && c > MAX_VALUE_FOR_SINGLE_CHAR)
- mclength = PRIV(ord2utf)(c, mcbuffer);
- else
-#endif
-
- {
- mcbuffer[0] = c;
- mclength = 1;
- }
+ mclength = PUTCHAR(c, mcbuffer);
goto ONE_CHAR;
@@ -8121,24 +7454,22 @@ for (;; ptr++)
mclength = 1;
mcbuffer[0] = c;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && HAS_EXTRALEN(c))
ACROSSCHAR(TRUE, ptr[1], mcbuffer[mclength++] = *(++ptr));
#endif
/* At this point we have the character's bytes in mcbuffer, and the length
- in mclength. When not in UTF-8 mode, the length is always 1. */
+ in mclength. When not in UTF mode, the length is always 1. */
ONE_CHAR:
previous = code;
- item_hwm_offset = cd->hwm - cd->start_workspace;
- /* For caseless UTF-8 mode when UCP support is available, check whether
- this character has more than one other case. If so, generate a special
- OP_PROP item instead of OP_CHARI. */
+ /* For caseless UTF mode, check whether this character has more than one
+ other case. If so, generate a special OP_PROP item instead of OP_CHARI. */
-#ifdef SUPPORT_UCP
- if (utf && (options & PCRE_CASELESS) != 0)
+#ifdef SUPPORT_UNICODE
+ if (utf && (options & PCRE2_CASELESS) != 0)
{
GETCHAR(c, mcbuffer);
if ((c = UCD_CASESET(c)) != 0)
@@ -8146,8 +7477,8 @@ for (;; ptr++)
*code++ = OP_PROP;
*code++ = PT_CLIST;
*code++ = c;
- if (firstcharflags == REQ_UNSET)
- firstcharflags = zerofirstcharflags = REQ_NONE;
+ if (firstcuflags == REQ_UNSET)
+ firstcuflags = zerofirstcuflags = REQ_NONE;
break;
}
}
@@ -8155,56 +7486,56 @@ for (;; ptr++)
/* Caseful matches, or not one of the multicase characters. */
- *code++ = ((options & PCRE_CASELESS) != 0)? OP_CHARI : OP_CHAR;
+ *code++ = ((options & PCRE2_CASELESS) != 0)? OP_CHARI : OP_CHAR;
for (c = 0; c < mclength; c++) *code++ = mcbuffer[c];
/* Remember if \r or \n were seen */
if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL)
- cd->external_flags |= PCRE_HASCRORLF;
+ cb->external_flags |= PCRE2_HASCRORLF;
/* Set the first and required bytes appropriately. If no previous first
byte, set it from this character, but revert to none on a zero repeat.
- Otherwise, leave the firstchar value alone, and don't change it on a zero
+ Otherwise, leave the firstcu value alone, and don't change it on a zero
repeat. */
- if (firstcharflags == REQ_UNSET)
+ if (firstcuflags == REQ_UNSET)
{
- zerofirstcharflags = REQ_NONE;
- zeroreqchar = reqchar;
- zeroreqcharflags = reqcharflags;
+ zerofirstcuflags = REQ_NONE;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
- /* If the character is more than one byte long, we can set firstchar
+ /* If the character is more than one byte long, we can set firstcu
only if it is not to be matched caselessly. */
if (mclength == 1 || req_caseopt == 0)
{
- firstchar = mcbuffer[0] | req_caseopt;
- firstchar = mcbuffer[0];
- firstcharflags = req_caseopt;
+ firstcu = mcbuffer[0] | req_caseopt;
+ firstcu = mcbuffer[0];
+ firstcuflags = req_caseopt;
if (mclength != 1)
{
- reqchar = code[-1];
- reqcharflags = cd->req_varyopt;
+ reqcu = code[-1];
+ reqcuflags = cb->req_varyopt;
}
}
- else firstcharflags = reqcharflags = REQ_NONE;
+ else firstcuflags = reqcuflags = REQ_NONE;
}
- /* firstchar was previously set; we can set reqchar only if the length is
+ /* firstcu was previously set; we can set reqcu only if the length is
1 or the matching is caseful. */
else
{
- zerofirstchar = firstchar;
- zerofirstcharflags = firstcharflags;
- zeroreqchar = reqchar;
- zeroreqcharflags = reqcharflags;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
if (mclength == 1 || req_caseopt == 0)
{
- reqchar = code[-1];
- reqcharflags = req_caseopt | cd->req_varyopt;
+ reqcu = code[-1];
+ reqcuflags = req_caseopt | cb->req_varyopt;
}
}
@@ -8212,7 +7543,6 @@ for (;; ptr++)
}
} /* end of big loop */
-
/* Control never reaches here by falling through, only by a goto for all the
error states. Pass back the position in the pattern so that it can be displayed
to the user for diagnosing the error. */
@@ -8225,7 +7555,7 @@ return FALSE;
/*************************************************
-* Compile sequence of alternatives *
+* Compile regex: a sequence of alternatives *
*************************************************/
/* On entry, ptr is pointing past the bracket character, but on return it
@@ -8242,14 +7572,14 @@ Arguments:
errorcodeptr -> pointer to error code variable
lookbehind TRUE if this is a lookbehind assertion
reset_bracount TRUE to reset the count for each branch
- skipbytes skip this many bytes at start (for brackets and OP_COND)
+ skipunits skip this many code units at start (for brackets and OP_COND)
cond_depth depth of nesting for conditional subpatterns
- firstcharptr place to put the first required character
- firstcharflagsptr place to put the first character flags, or a negative number
- reqcharptr place to put the last required character
- reqcharflagsptr place to put the last required character flags, or a negative number
+ firstcuptr place to put the first required code unit
+ firstcuflagsptr place to put the first code unit flags, or a negative number
+ reqcuptr place to put the last required code unit
+ reqcuflagsptr place to put the last required code unit flags, or a negative number
bcptr pointer to the chain of currently open branches
- cd points to the data block with tables pointers etc.
+ cb points to the data block with tables pointers etc.
lengthptr NULL during the real compile phase
points to length accumulator during pre-compile phase
@@ -8257,35 +7587,34 @@ Returns: TRUE on success
*/
static BOOL
-compile_regex(int options, pcre_uchar **codeptr, const pcre_uchar **ptrptr,
- int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, int skipbytes,
- int cond_depth,
- pcre_uint32 *firstcharptr, pcre_int32 *firstcharflagsptr,
- pcre_uint32 *reqcharptr, pcre_int32 *reqcharflagsptr,
- branch_chain *bcptr, compile_data *cd, int *lengthptr)
+compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, PCRE2_SPTR *ptrptr,
+ int *errorcodeptr, BOOL lookbehind, BOOL reset_bracount, uint32_t skipunits,
+ int cond_depth, uint32_t *firstcuptr, int32_t *firstcuflagsptr,
+ uint32_t *reqcuptr, int32_t *reqcuflagsptr, branch_chain *bcptr,
+ compile_block *cb, size_t *lengthptr)
{
-const pcre_uchar *ptr = *ptrptr;
-pcre_uchar *code = *codeptr;
-pcre_uchar *last_branch = code;
-pcre_uchar *start_bracket = code;
-pcre_uchar *reverse_count = NULL;
+PCRE2_SPTR ptr = *ptrptr;
+PCRE2_UCHAR *code = *codeptr;
+PCRE2_UCHAR *last_branch = code;
+PCRE2_UCHAR *start_bracket = code;
+PCRE2_UCHAR *reverse_count = NULL;
open_capitem capitem;
int capnumber = 0;
-pcre_uint32 firstchar, reqchar;
-pcre_int32 firstcharflags, reqcharflags;
-pcre_uint32 branchfirstchar, branchreqchar;
-pcre_int32 branchfirstcharflags, branchreqcharflags;
-int length;
+uint32_t firstcu, reqcu;
+int32_t firstcuflags, reqcuflags;
+uint32_t branchfirstcu, branchreqcu;
+int32_t branchfirstcuflags, branchreqcuflags;
+size_t length;
unsigned int orig_bracount;
unsigned int max_bracount;
branch_chain bc;
-size_t save_hwm_offset;
/* If set, call the external function that checks for stack availability. */
-if (PUBL(stack_guard) != NULL && PUBL(stack_guard)())
+if (cb->cx->stack_guard != NULL &&
+ cb->cx->stack_guard(cb->parens_depth, cb->cx->stack_guard_data))
{
- *errorcodeptr= ERR85;
+ *errorcodeptr= ERR33;
return FALSE;
}
@@ -8294,26 +7623,24 @@ if (PUBL(stack_guard) != NULL && PUBL(stack_guard)())
bc.outer = bcptr;
bc.current_branch = code;
-firstchar = reqchar = 0;
-firstcharflags = reqcharflags = REQ_UNSET;
-
-save_hwm_offset = cd->hwm - cd->start_workspace;
+firstcu = reqcu = 0;
+firstcuflags = reqcuflags = REQ_UNSET;
/* Accumulate the length for use in the pre-compile phase. Start with the
-length of the BRA and KET and any extra bytes that are required at the
+length of the BRA and KET and any extra code units that are required at the
beginning. We accumulate in a local variable to save frequent testing of
-lenthptr for NULL. We cannot do this by looking at the value of code at the
+lengthptr for NULL. We cannot do this by looking at the value of 'code' at the
start and end of each alternative, because compiled items are discarded during
the pre-compile phase so that the work space is not exceeded. */
-length = 2 + 2*LINK_SIZE + skipbytes;
+length = 2 + 2*LINK_SIZE + skipunits;
/* WARNING: If the above line is changed for any reason, you must also change
the code that abstracts option settings at the start of the pattern and makes
them global. It tests the value of length for (2 + 2*LINK_SIZE) in the
-pre-compile phase to find out whether anything has yet been compiled or not. */
+pre-compile phase to find out whether or not anything has yet been compiled.
-/* If this is a capturing subpattern, add to the chain of open capturing items
+If this is a capturing subpattern, add to the chain of open capturing items
so that we can detect them if (*ACCEPT) is encountered. This is also used to
detect groups that contain recursive back references to themselves. Note that
only OP_CBRA need be tested here; changing this opcode to one of its variants,
@@ -8323,25 +7650,26 @@ if (*code == OP_CBRA)
{
capnumber = GET2(code, 1 + LINK_SIZE);
capitem.number = capnumber;
- capitem.next = cd->open_caps;
+ capitem.next = cb->open_caps;
capitem.flag = FALSE;
- cd->open_caps = &capitem;
+ cb->open_caps = &capitem;
}
/* Offset is set zero to mark that this bracket is still open */
PUT(code, 1, 0);
-code += 1 + LINK_SIZE + skipbytes;
+code += 1 + LINK_SIZE + skipunits;
/* Loop for each alternative branch */
-orig_bracount = max_bracount = cd->bracount;
+orig_bracount = max_bracount = cb->bracount;
+
for (;;)
{
/* For a (?| group, reset the capturing bracket count so that each branch
uses the same numbers. */
- if (reset_bracount) cd->bracount = orig_bracount;
+ if (reset_bracount) cb->bracount = orig_bracount;
/* Set up dummy OP_REVERSE if lookbehind assertion */
@@ -8356,9 +7684,9 @@ for (;;)
/* Now compile the branch; in the pre-compile phase its length gets added
into the length. */
- if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstchar,
- &branchfirstcharflags, &branchreqchar, &branchreqcharflags, &bc,
- cond_depth, cd, (lengthptr == NULL)? NULL : &length))
+ if (!compile_branch(&options, &code, &ptr, errorcodeptr, &branchfirstcu,
+ &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc,
+ cond_depth, cb, (lengthptr == NULL)? NULL : &length))
{
*ptrptr = ptr;
return FALSE;
@@ -8367,96 +7695,98 @@ for (;;)
/* Keep the highest bracket count in case (?| was used and some branch
has fewer than the rest. */
- if (cd->bracount > max_bracount) max_bracount = cd->bracount;
+ if (cb->bracount > max_bracount) max_bracount = cb->bracount;
/* In the real compile phase, there is some post-processing to be done. */
if (lengthptr == NULL)
{
- /* If this is the first branch, the firstchar and reqchar values for the
+ /* If this is the first branch, the firstcu and reqcu values for the
branch become the values for the regex. */
if (*last_branch != OP_ALT)
{
- firstchar = branchfirstchar;
- firstcharflags = branchfirstcharflags;
- reqchar = branchreqchar;
- reqcharflags = branchreqcharflags;
+ firstcu = branchfirstcu;
+ firstcuflags = branchfirstcuflags;
+ reqcu = branchreqcu;
+ reqcuflags = branchreqcuflags;
}
- /* If this is not the first branch, the first char and reqchar have to
+ /* If this is not the first branch, the first char and reqcu have to
match the values from all the previous branches, except that if the
- previous value for reqchar didn't have REQ_VARY set, it can still match,
+ previous value for reqcu didn't have REQ_VARY set, it can still match,
and we set REQ_VARY for the regex. */
else
{
- /* If we previously had a firstchar, but it doesn't match the new branch,
- we have to abandon the firstchar for the regex, but if there was
- previously no reqchar, it takes on the value of the old firstchar. */
+ /* If we previously had a firstcu, but it doesn't match the new branch,
+ we have to abandon the firstcu for the regex, but if there was
+ previously no reqcu, it takes on the value of the old firstcu. */
- if (firstcharflags >= 0 &&
- (firstcharflags != branchfirstcharflags || firstchar != branchfirstchar))
+ if (firstcuflags != branchfirstcuflags || firstcu != branchfirstcu)
{
- if (reqcharflags < 0)
+ if (firstcuflags >= 0)
{
- reqchar = firstchar;
- reqcharflags = firstcharflags;
+ if (reqcuflags < 0)
+ {
+ reqcu = firstcu;
+ reqcuflags = firstcuflags;
+ }
}
- firstcharflags = REQ_NONE;
+ firstcuflags = REQ_NONE;
}
- /* If we (now or from before) have no firstchar, a firstchar from the
- branch becomes a reqchar if there isn't a branch reqchar. */
+ /* If we (now or from before) have no firstcu, a firstcu from the
+ branch becomes a reqcu if there isn't a branch reqcu. */
- if (firstcharflags < 0 && branchfirstcharflags >= 0 && branchreqcharflags < 0)
+ if (firstcuflags < 0 && branchfirstcuflags >= 0 &&
+ branchreqcuflags < 0)
{
- branchreqchar = branchfirstchar;
- branchreqcharflags = branchfirstcharflags;
+ branchreqcu = branchfirstcu;
+ branchreqcuflags = branchfirstcuflags;
}
- /* Now ensure that the reqchars match */
+ /* Now ensure that the reqcus match */
- if (((reqcharflags & ~REQ_VARY) != (branchreqcharflags & ~REQ_VARY)) ||
- reqchar != branchreqchar)
- reqcharflags = REQ_NONE;
+ if (((reqcuflags & ~REQ_VARY) != (branchreqcuflags & ~REQ_VARY)) ||
+ reqcu != branchreqcu)
+ reqcuflags = REQ_NONE;
else
{
- reqchar = branchreqchar;
- reqcharflags |= branchreqcharflags; /* To "or" REQ_VARY */
+ reqcu = branchreqcu;
+ reqcuflags |= branchreqcuflags; /* To "or" REQ_VARY */
}
}
/* If lookbehind, check that this branch matches a fixed-length string, and
put the length into the OP_REVERSE item. Temporarily mark the end of the
- branch with OP_END. If the branch contains OP_RECURSE, the result is -3
- because there may be forward references that we can't check here. Set a
- flag to cause another lookbehind check at the end. Why not do it all at the
- end? Because common, erroneous checks are picked up here and the offset of
- the problem can be shown. */
+ branch with OP_END. If the branch contains OP_RECURSE, the result is
+ FFL_LATER (a negative value) because there may be forward references that
+ we can't check here. Set a flag to cause another lookbehind check at the
+ end. Why not do it all at the end? Because common errors can be picked up
+ here and the offset of the problem can be shown. */
if (lookbehind)
{
int fixed_length;
+ int count = 0;
*code = OP_END;
- fixed_length = find_fixedlength(last_branch, (options & PCRE_UTF8) != 0,
- FALSE, cd, NULL);
- DPRINTF(("fixed length = %d\n", fixed_length));
- if (fixed_length == -3)
+ fixed_length = find_fixedlength(last_branch, (options & PCRE2_UTF) != 0,
+ FALSE, cb, NULL, &count);
+ if (fixed_length == FFL_LATER)
{
- cd->check_lookbehind = TRUE;
+ cb->check_lookbehind = TRUE;
}
else if (fixed_length < 0)
{
- *errorcodeptr = (fixed_length == -2)? ERR36 :
- (fixed_length == -4)? ERR70: ERR25;
+ *errorcodeptr = fixed_length_errors[-fixed_length];
*ptrptr = ptr;
return FALSE;
}
else
{
- if (fixed_length > cd->max_lookbehind)
- cd->max_lookbehind = fixed_length;
+ if (fixed_length > cb->max_lookbehind)
+ cb->max_lookbehind = fixed_length;
PUT(reverse_count, 0, fixed_length);
}
}
@@ -8473,10 +7803,10 @@ for (;;)
{
if (lengthptr == NULL)
{
- int branch_length = (int)(code - last_branch);
+ size_t branch_length = code - last_branch;
do
{
- int prev_length = GET(last_branch, 1);
+ size_t prev_length = GET(last_branch, 1);
PUT(last_branch, 1, branch_length);
branch_length = prev_length;
last_branch -= branch_length;
@@ -8491,19 +7821,15 @@ for (;;)
code += 1 + LINK_SIZE;
/* If it was a capturing subpattern, check to see if it contained any
- recursive back references. If so, we must wrap it in atomic brackets.
- Because we are moving code along, we must ensure that any pending recursive
- references are updated. In any event, remove the block from the chain. */
+ recursive back references. If so, we must wrap it in atomic brackets. In
+ any event, remove the block from the chain. */
if (capnumber > 0)
{
- if (cd->open_caps->flag)
+ if (cb->open_caps->flag)
{
- *code = OP_END;
- adjust_recurse(start_bracket, 1 + LINK_SIZE,
- (options & PCRE_UTF8) != 0, cd, save_hwm_offset);
memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
- IN_UCHARS(code - start_bracket));
+ CU2BYTES(code - start_bracket));
*start_bracket = OP_ONCE;
code += 1 + LINK_SIZE;
PUT(start_bracket, 1, (int)(code - start_bracket));
@@ -8512,21 +7838,21 @@ for (;;)
code += 1 + LINK_SIZE;
length += 2 + 2*LINK_SIZE;
}
- cd->open_caps = cd->open_caps->next;
+ cb->open_caps = cb->open_caps->next;
}
/* Retain the highest bracket number, in case resetting was used. */
- cd->bracount = max_bracount;
+ cb->bracount = max_bracount;
/* Set values to pass back */
*codeptr = code;
*ptrptr = ptr;
- *firstcharptr = firstchar;
- *firstcharflagsptr = firstcharflags;
- *reqcharptr = reqchar;
- *reqcharflagsptr = reqcharflags;
+ *firstcuptr = firstcu;
+ *firstcuflagsptr = firstcuflags;
+ *reqcuptr = reqcu;
+ *reqcuflagsptr = reqcuflags;
if (lengthptr != NULL)
{
if (OFLOW_MAX - *lengthptr < length)
@@ -8550,7 +7876,7 @@ for (;;)
if (lengthptr != NULL)
{
- code = *codeptr + 1 + LINK_SIZE + skipbytes;
+ code = *codeptr + 1 + LINK_SIZE + skipunits;
length += 1 + LINK_SIZE;
}
else
@@ -8561,6 +7887,8 @@ for (;;)
code += 1 + LINK_SIZE;
}
+ /* Advance past the vertical bar */
+
ptr++;
}
/* Control never reaches here */
@@ -8568,9 +7896,8 @@ for (;;)
-
/*************************************************
-* Check for anchored expression *
+* Check for anchored pattern *
*************************************************/
/* Try to find out if this is an anchored regular expression. Consider each
@@ -8600,22 +7927,22 @@ of the more common cases more precisely.
this prevents the number of characters it matches from being adjusted.
Arguments:
- code points to start of expression (the bracket)
+ code points to start of the compiled pattern
bracket_map a bitmap of which brackets we are inside while testing; this
- handles up to substring 31; after that we just have to take
- the less precise approach
- cd points to the compile data block
+ handles up to substring 31; after that we just have to take
+ the less precise approach
+ cb points to the compile data block
atomcount atomic group level
Returns: TRUE or FALSE
*/
static BOOL
-is_anchored(register const pcre_uchar *code, unsigned int bracket_map,
- compile_data *cd, int atomcount)
+is_anchored(register PCRE2_SPTR code, unsigned int bracket_map,
+ compile_block *cb, int atomcount)
{
do {
- const pcre_uchar *scode = first_significant_code(
+ PCRE2_SPTR scode = first_significant_code(
code + PRIV(OP_lengths)[*code], FALSE);
register int op = *scode;
@@ -8624,7 +7951,7 @@ do {
if (op == OP_BRA || op == OP_BRAPOS ||
op == OP_SBRA || op == OP_SBRAPOS)
{
- if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE;
+ if (!is_anchored(scode, bracket_map, cb, atomcount)) return FALSE;
}
/* Capturing brackets */
@@ -8633,34 +7960,35 @@ do {
op == OP_SCBRA || op == OP_SCBRAPOS)
{
int n = GET2(scode, 1+LINK_SIZE);
- int new_map = bracket_map | ((n < 32)? (1 << n) : 1);
- if (!is_anchored(scode, new_map, cd, atomcount)) return FALSE;
+ int new_map = bracket_map | ((n < 32)? (1u << n) : 1);
+ if (!is_anchored(scode, new_map, cb, atomcount)) return FALSE;
}
/* Positive forward assertions and conditions */
else if (op == OP_ASSERT || op == OP_COND)
{
- if (!is_anchored(scode, bracket_map, cd, atomcount)) return FALSE;
+ if (!is_anchored(scode, bracket_map, cb, atomcount)) return FALSE;
}
/* Atomic groups */
else if (op == OP_ONCE || op == OP_ONCE_NC)
{
- if (!is_anchored(scode, bracket_map, cd, atomcount + 1))
+ if (!is_anchored(scode, bracket_map, cb, atomcount + 1))
return FALSE;
}
/* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and
it isn't in brackets that are or may be referenced or inside an atomic
- group. */
+ group. There is also an option that disables auto-anchoring. */
else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR ||
op == OP_TYPEPOSSTAR))
{
- if (scode[1] != OP_ALLANY || (bracket_map & cd->backref_map) != 0 ||
- atomcount > 0 || cd->had_pruneorskip)
+ if (scode[1] != OP_ALLANY || (bracket_map & cb->backref_map) != 0 ||
+ atomcount > 0 || cb->had_pruneorskip ||
+ (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)
return FALSE;
}
@@ -8690,22 +8018,22 @@ inside atomic brackets or in a pattern that contains *PRUNE or *SKIP does not
count, because once again the assumption no longer holds.
Arguments:
- code points to start of expression (the bracket)
+ code points to start of the compiled pattern or a group
bracket_map a bitmap of which brackets we are inside while testing; this
- handles up to substring 31; after that we just have to take
- the less precise approach
- cd points to the compile data
+ handles up to substring 31; after that we just have to take
+ the less precise approach
+ cb points to the compile data
atomcount atomic group level
Returns: TRUE or FALSE
*/
static BOOL
-is_startline(const pcre_uchar *code, unsigned int bracket_map,
- compile_data *cd, int atomcount)
+is_startline(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb,
+ int atomcount)
{
do {
- const pcre_uchar *scode = first_significant_code(
+ PCRE2_SPTR scode = first_significant_code(
code + PRIV(OP_lengths)[*code], FALSE);
register int op = *scode;
@@ -8717,19 +8045,23 @@ do {
if (op == OP_COND)
{
scode += 1 + LINK_SIZE;
+
if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT];
+ else if (*scode == OP_CALLOUT_STR) scode += GET(scode, 1 + 2*LINK_SIZE);
+
switch (*scode)
{
case OP_CREF:
case OP_DNCREF:
case OP_RREF:
case OP_DNRREF:
- case OP_DEF:
case OP_FAIL:
+ case OP_FALSE:
+ case OP_TRUE:
return FALSE;
default: /* Assertion */
- if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
+ if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE;
do scode += GET(scode, 1); while (*scode == OP_ALT);
scode += 1 + LINK_SIZE;
break;
@@ -8743,7 +8075,7 @@ do {
if (op == OP_BRA || op == OP_BRAPOS ||
op == OP_SBRA || op == OP_SBRAPOS)
{
- if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
+ if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE;
}
/* Capturing brackets */
@@ -8752,34 +8084,35 @@ do {
op == OP_SCBRA || op == OP_SCBRAPOS)
{
int n = GET2(scode, 1+LINK_SIZE);
- int new_map = bracket_map | ((n < 32)? (1 << n) : 1);
- if (!is_startline(scode, new_map, cd, atomcount)) return FALSE;
+ int new_map = bracket_map | ((n < 32)? (1u << n) : 1);
+ if (!is_startline(scode, new_map, cb, atomcount)) return FALSE;
}
/* Positive forward assertions */
else if (op == OP_ASSERT)
{
- if (!is_startline(scode, bracket_map, cd, atomcount)) return FALSE;
+ if (!is_startline(scode, bracket_map, cb, atomcount)) return FALSE;
}
/* Atomic brackets */
else if (op == OP_ONCE || op == OP_ONCE_NC)
{
- if (!is_startline(scode, bracket_map, cd, atomcount + 1)) return FALSE;
+ if (!is_startline(scode, bracket_map, cb, atomcount + 1)) return FALSE;
}
/* .* means "start at start or after \n" if it isn't in atomic brackets or
brackets that may be referenced, as long as the pattern does not contain
*PRUNE or *SKIP, because these break the feature. Consider, for example,
/.*?a(*PRUNE)b/ with the subject "aab", which matches "ab", i.e. not at the
- start of a line. */
+ start of a line. There is also an option that disables this optimization. */
else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)
{
- if (scode[1] != OP_ANY || (bracket_map & cd->backref_map) != 0 ||
- atomcount > 0 || cd->had_pruneorskip)
+ if (scode[1] != OP_ANY || (bracket_map & cb->backref_map) != 0 ||
+ atomcount > 0 || cb->had_pruneorskip ||
+ (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)
return FALSE;
}
@@ -8801,42 +8134,41 @@ return TRUE;
/*************************************************
-* Check for asserted fixed first char *
+* Check for asserted fixed first code unit *
*************************************************/
-/* During compilation, the "first char" settings from forward assertions are
-discarded, because they can cause conflicts with actual literals that follow.
-However, if we end up without a first char setting for an unanchored pattern,
-it is worth scanning the regex to see if there is an initial asserted first
-char. If all branches start with the same asserted char, or with a
-non-conditional bracket all of whose alternatives start with the same asserted
-char (recurse ad lib), then we return that char, with the flags set to zero or
-REQ_CASELESS; otherwise return zero with REQ_NONE in the flags.
+/* During compilation, the "first code unit" settings from forward assertions
+are discarded, because they can cause conflicts with actual literals that
+follow. However, if we end up without a first code unit setting for an
+unanchored pattern, it is worth scanning the regex to see if there is an
+initial asserted first code unit. If all branches start with the same asserted
+code unit, or with a non-conditional bracket all of whose alternatives start
+with the same asserted code unit (recurse ad lib), then we return that code
+unit, with the flags set to zero or REQ_CASELESS; otherwise return zero with
+REQ_NONE in the flags.
Arguments:
- code points to start of expression (the bracket)
- flags points to the first char flags, or to REQ_NONE
+ code points to start of compiled pattern
+ flags points to the first code unit flags
inassert TRUE if in an assertion
-Returns: the fixed first char, or 0 with REQ_NONE in flags
+Returns: the fixed first code unit, or 0 with REQ_NONE in flags
*/
-static pcre_uint32
-find_firstassertedchar(const pcre_uchar *code, pcre_int32 *flags,
- BOOL inassert)
+static uint32_t
+find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, BOOL inassert)
{
-register pcre_uint32 c = 0;
+register uint32_t c = 0;
int cflags = REQ_NONE;
*flags = REQ_NONE;
do {
- pcre_uint32 d;
+ uint32_t d;
int dflags;
int xl = (*code == OP_CBRA || *code == OP_SCBRA ||
*code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0;
- const pcre_uchar *scode = first_significant_code(code + 1+LINK_SIZE + xl,
- TRUE);
- register pcre_uchar op = *scode;
+ PCRE2_SPTR scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE);
+ register PCRE2_UCHAR op = *scode;
switch(op)
{
@@ -8852,10 +8184,11 @@ do {
case OP_ASSERT:
case OP_ONCE:
case OP_ONCE_NC:
- d = find_firstassertedchar(scode, &dflags, op == OP_ASSERT);
+ d = find_firstassertedcu(scode, &dflags, op == OP_ASSERT);
if (dflags < 0)
return 0;
- if (cflags < 0) { c = d; cflags = dflags; } else if (c != d || cflags != dflags) return 0;
+ if (cflags < 0) { c = d; cflags = dflags; }
+ else if (c != d || cflags != dflags) return 0;
break;
case OP_EXACT:
@@ -8904,7 +8237,7 @@ name/number table, maintaining alphabetical order. Checking for permitted
and forbidden duplicates has already been done.
Arguments:
- cd the compile data block
+ cb the compile data block
name the name to add
length the length of the name
groupno the group number
@@ -8913,15 +8246,15 @@ Returns: nothing
*/
static void
-add_name(compile_data *cd, const pcre_uchar *name, int length,
+add_name_to_table(compile_block *cb, PCRE2_SPTR name, int length,
unsigned int groupno)
{
int i;
-pcre_uchar *slot = cd->name_table;
+PCRE2_UCHAR *slot = cb->name_table;
-for (i = 0; i < cd->names_found; i++)
+for (i = 0; i < cb->names_found; i++)
{
- int crc = memcmp(name, slot+IMM2_SIZE, IN_UCHARS(length));
+ int crc = memcmp(name, slot+IMM2_SIZE, CU2BYTES(length));
if (crc == 0 && slot[IMM2_SIZE+length] != 0)
crc = -1; /* Current name is a substring */
@@ -8932,598 +8265,619 @@ for (i = 0; i < cd->names_found; i++)
if (crc < 0)
{
- memmove(slot + cd->name_entry_size, slot,
- IN_UCHARS((cd->names_found - i) * cd->name_entry_size));
+ memmove(slot + cb->name_entry_size, slot,
+ CU2BYTES((cb->names_found - i) * cb->name_entry_size));
break;
}
/* Continue the loop for a later or duplicate name */
- slot += cd->name_entry_size;
+ slot += cb->name_entry_size;
}
PUT2(slot, 0, groupno);
-memcpy(slot + IMM2_SIZE, name, IN_UCHARS(length));
-slot[IMM2_SIZE + length] = 0;
-cd->names_found++;
+memcpy(slot + IMM2_SIZE, name, CU2BYTES(length));
+cb->names_found++;
+
+/* Add a terminating zero and fill the rest of the slot with zeroes so that
+the memory is all initialized. Otherwise valgrind moans about uninitialized
+memory when saving serialized compiled patterns. */
+
+memset(slot + IMM2_SIZE + length, 0,
+ CU2BYTES(cb->name_entry_size - length - IMM2_SIZE));
}
/*************************************************
-* Compile a Regular Expression *
+* External function to compile a pattern *
*************************************************/
-/* This function takes a string and returns a pointer to a block of store
-holding a compiled version of the expression. The original API for this
-function had no error code return variable; it is retained for backwards
-compatibility. The new function is given a new name.
+/* This function reads a regular expression in the form of a string and returns
+a pointer to a block of store holding a compiled version of the expression.
Arguments:
pattern the regular expression
- options various option bits
- errorcodeptr pointer to error code variable (pcre_compile2() only)
- can be NULL if you don't want a code value
- errorptr pointer to pointer to error text
- erroroffset ptr offset in pattern where error was detected
- tables pointer to character tables or NULL
+ patlen the length of the pattern, or PCRE2_ZERO_TERMINATED
+ options option bits
+ errorptr pointer to errorcode
+ erroroffset pointer to error offset
+ ccontext points to a compile context or is NULL
Returns: pointer to compiled data block, or NULL on error,
- with errorptr and erroroffset set
+ with errorcode and erroroffset set
*/
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION
-pcre_compile(const char *pattern, int options, const char **errorptr,
- int *erroroffset, const unsigned char *tables)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION
-pcre16_compile(PCRE_SPTR16 pattern, int options, const char **errorptr,
- int *erroroffset, const unsigned char *tables)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION
-pcre32_compile(PCRE_SPTR32 pattern, int options, const char **errorptr,
- int *erroroffset, const unsigned char *tables)
-#endif
+PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
+pcre2_compile(PCRE2_SPTR pattern, PCRE2_SIZE patlen, uint32_t options,
+ int *errorptr, PCRE2_SIZE *erroroffset, pcre2_compile_context *ccontext)
{
-#if defined COMPILE_PCRE8
-return pcre_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
-#elif defined COMPILE_PCRE16
-return pcre16_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
-#elif defined COMPILE_PCRE32
-return pcre32_compile2(pattern, options, NULL, errorptr, erroroffset, tables);
-#endif
-}
+BOOL utf; /* Set TRUE for UTF mode */
+pcre2_real_code *re = NULL; /* What we will return */
+compile_block cb; /* "Static" compile-time data */
+const uint8_t *tables; /* Char tables base pointer */
+PCRE2_UCHAR *code; /* Current pointer in compiled code */
+PCRE2_SPTR codestart; /* Start of compiled code */
+PCRE2_SPTR ptr; /* Current pointer in pattern */
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN pcre * PCRE_CALL_CONVENTION
-pcre_compile2(const char *pattern, int options, int *errorcodeptr,
- const char **errorptr, int *erroroffset, const unsigned char *tables)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN pcre16 * PCRE_CALL_CONVENTION
-pcre16_compile2(PCRE_SPTR16 pattern, int options, int *errorcodeptr,
- const char **errorptr, int *erroroffset, const unsigned char *tables)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN pcre32 * PCRE_CALL_CONVENTION
-pcre32_compile2(PCRE_SPTR32 pattern, int options, int *errorcodeptr,
- const char **errorptr, int *erroroffset, const unsigned char *tables)
-#endif
-{
-REAL_PCRE *re;
-int length = 1; /* For final END opcode */
-pcre_int32 firstcharflags, reqcharflags;
-pcre_uint32 firstchar, reqchar;
-pcre_uint32 limit_match = PCRE_UINT32_MAX;
-pcre_uint32 limit_recursion = PCRE_UINT32_MAX;
-int newline;
-int errorcode = 0;
-int skipatstart = 0;
-BOOL utf;
-BOOL never_utf = FALSE;
-size_t size;
-pcre_uchar *code;
-const pcre_uchar *codestart;
-const pcre_uchar *ptr;
-compile_data compile_block;
-compile_data *cd = &compile_block;
-
-/* This space is used for "compiling" into during the first phase, when we are
-computing the amount of memory that is needed. Compiled items are thrown away
-as soon as possible, so that a fairly large buffer should be sufficient for
-this purpose. The same space is used in the second phase for remembering where
-to fill in forward references to subpatterns. That may overflow, in which case
-new memory is obtained from malloc(). */
-
-pcre_uchar cworkspace[COMPILE_WORK_SIZE];
-
-/* This vector is used for remembering name groups during the pre-compile. In a
-similar way to cworkspace, it can be expanded using malloc() if necessary. */
+size_t length = 1; /* Allow or final END opcode */
+size_t usedlength; /* Actual length used */
+size_t re_blocksize; /* Size of memory block */
+int32_t firstcuflags, reqcuflags; /* Type of first/req code unit */
+uint32_t firstcu, reqcu; /* Value of first/req code unit */
+uint32_t setflags = 0; /* NL and BSR set flags */
+
+uint32_t skipatstart; /* When checking (*UTF) etc */
+uint32_t limit_match = UINT32_MAX; /* Unset match limits */
+uint32_t limit_recursion = UINT32_MAX;
+
+int newline = 0; /* Unset; can be set by the pattern */
+int bsr = 0; /* Unset; can be set by the pattern */
+int errorcode = 0; /* Initialize to avoid compiler warn */
+
+/* Comments at the head of this file explain about these variables. */
+
+PCRE2_UCHAR *copied_pattern = NULL;
+PCRE2_UCHAR stack_copied_pattern[COPIED_PATTERN_SIZE];
named_group named_groups[NAMED_GROUP_LIST_SIZE];
-/* Set this early so that early errors get offset 0. */
+/* The workspace is used in different ways in the different compiling phases.
+It needs to be 16-bit aligned for the preliminary group scan, and 32-bit
+aligned for the group information cache. */
+
+uint32_t c32workspace[C32_WORK_SIZE];
+PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c32workspace;
+
-ptr = (const pcre_uchar *)pattern;
+/* -------------- Check arguments and set up the pattern ----------------- */
-/* We can't pass back an error message if errorptr is NULL; I guess the best we
-can do is just return NULL, but we can set a code value if there is a code
-pointer. */
+/* There must be error code and offset pointers. */
-if (errorptr == NULL)
+if (errorptr == NULL || erroroffset == NULL) return NULL;
+*errorptr = ERR0;
+*erroroffset = 0;
+
+/* There must be a pattern! */
+
+if (pattern == NULL)
{
- if (errorcodeptr != NULL) *errorcodeptr = 99;
+ *errorptr = ERR16;
return NULL;
}
-*errorptr = NULL;
-if (errorcodeptr != NULL) *errorcodeptr = ERR0;
+/* Check that all undefined public option bits are zero. */
-/* However, we can give a message for this error */
-
-if (erroroffset == NULL)
+if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0)
{
- errorcode = ERR16;
- goto PCRE_EARLY_ERROR_RETURN2;
+ *errorptr = ERR17;
+ return NULL;
}
-*erroroffset = 0;
-
-/* Set up pointers to the individual character tables */
+/* A NULL compile context means "use a default context" */
-if (tables == NULL) tables = PRIV(default_tables);
-cd->lcc = tables + lcc_offset;
-cd->fcc = tables + fcc_offset;
-cd->cbits = tables + cbits_offset;
-cd->ctypes = tables + ctypes_offset;
+if (ccontext == NULL)
+ ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context));
-/* Check that all undefined public option bits are zero */
+/* A zero-terminated pattern is indicated by the special length value
+PCRE2_ZERO_TERMINATED. Otherwise, we make a copy of the pattern and add a zero,
+to ensure that it is always possible to look one code unit beyond the end of
+the pattern's characters. In both cases, check that the pattern is overlong. */
-if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0)
+if (patlen == PCRE2_ZERO_TERMINATED)
+ {
+ patlen = PRIV(strlen)(pattern);
+ if (patlen > ccontext->max_pattern_length)
+ {
+ *errorptr = ERR88;
+ return NULL;
+ }
+ }
+else
{
- errorcode = ERR17;
- goto PCRE_EARLY_ERROR_RETURN;
+ if (patlen > ccontext->max_pattern_length)
+ {
+ *errorptr = ERR88;
+ return NULL;
+ }
+ if (patlen < COPIED_PATTERN_SIZE)
+ copied_pattern = stack_copied_pattern;
+ else
+ {
+ copied_pattern = ccontext->memctl.malloc(CU2BYTES(patlen + 1),
+ ccontext->memctl.memory_data);
+ if (copied_pattern == NULL)
+ {
+ *errorptr = ERR21;
+ return NULL;
+ }
+ }
+ memcpy(copied_pattern, pattern, CU2BYTES(patlen));
+ copied_pattern[patlen] = 0;
+ pattern = copied_pattern;
}
-/* If PCRE_NEVER_UTF is set, remember it. */
+/* ------------ Initialize the "static" compile data -------------- */
+
+tables = (ccontext->tables != NULL)? ccontext->tables : PRIV(default_tables);
+
+cb.lcc = tables + lcc_offset; /* Individual */
+cb.fcc = tables + fcc_offset; /* character */
+cb.cbits = tables + cbits_offset; /* tables */
+cb.ctypes = tables + ctypes_offset;
+
+cb.assert_depth = 0;
+cb.bracount = cb.final_bracount = 0;
+cb.cx = ccontext;
+cb.dupnames = FALSE;
+cb.end_pattern = pattern + patlen;
+cb.nestptr[0] = cb.nestptr[1] = NULL;
+cb.external_flags = 0;
+cb.external_options = options;
+cb.groupinfo = c32workspace;
+cb.had_recurse = FALSE;
+cb.iscondassert = FALSE;
+cb.max_lookbehind = 0;
+cb.name_entry_size = 0;
+cb.name_table = NULL;
+cb.named_groups = named_groups;
+cb.named_group_list_size = NAMED_GROUP_LIST_SIZE;
+cb.names_found = 0;
+cb.open_caps = NULL;
+cb.parens_depth = 0;
+cb.req_varyopt = 0;
+cb.start_code = cworkspace;
+cb.start_pattern = pattern;
+cb.start_workspace = cworkspace;
+cb.workspace_size = COMPILE_WORK_SIZE;
+
+/* Maximum back reference and backref bitmap. The bitmap records up to 31 back
+references to help in deciding whether (.*) can be treated as anchored or not.
+*/
+
+cb.top_backref = 0;
+cb.backref_map = 0;
-if ((options & PCRE_NEVER_UTF) != 0) never_utf = TRUE;
+/* --------------- Start looking at the pattern --------------- */
-/* Check for global one-time settings at the start of the pattern, and remember
-the offset for later. */
+/* Check for global one-time option settings at the start of the pattern, and
+remember the offset to the actual regex. */
-cd->external_flags = 0; /* Initialize here for LIMIT_MATCH/RECURSION */
+ptr = pattern;
+skipatstart = 0;
while (ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
ptr[skipatstart+1] == CHAR_ASTERISK)
{
- int newnl = 0;
- int newbsr = 0;
+ unsigned int i;
+ for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++)
+ {
+ pso *p = pso_list + i;
-/* For completeness and backward compatibility, (*UTFn) is supported in the
-relevant libraries, but (*UTF) is generic and always supported. Note that
-PCRE_UTF8 == PCRE_UTF16 == PCRE_UTF32. */
+ if (PRIV(strncmp_c8)(ptr+skipatstart+2, (char *)(p->name), p->length) == 0)
+ {
+ uint32_t c, pp;
-#ifdef COMPILE_PCRE8
- if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF8_RIGHTPAR, 5) == 0)
- { skipatstart += 7; options |= PCRE_UTF8; continue; }
-#endif
-#ifdef COMPILE_PCRE16
- if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF16_RIGHTPAR, 6) == 0)
- { skipatstart += 8; options |= PCRE_UTF16; continue; }
-#endif
-#ifdef COMPILE_PCRE32
- if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF32_RIGHTPAR, 6) == 0)
- { skipatstart += 8; options |= PCRE_UTF32; continue; }
-#endif
+ skipatstart += p->length + 2;
+ switch(p->type)
+ {
+ case PSO_OPT:
+ cb.external_options |= p->value;
+ break;
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UTF_RIGHTPAR, 4) == 0)
- { skipatstart += 6; options |= PCRE_UTF8; continue; }
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_UCP_RIGHTPAR, 4) == 0)
- { skipatstart += 6; options |= PCRE_UCP; continue; }
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_NO_AUTO_POSSESS_RIGHTPAR, 16) == 0)
- { skipatstart += 18; options |= PCRE_NO_AUTO_POSSESS; continue; }
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_NO_START_OPT_RIGHTPAR, 13) == 0)
- { skipatstart += 15; options |= PCRE_NO_START_OPTIMIZE; continue; }
+ case PSO_FLG:
+ setflags |= p->value;
+ break;
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_MATCH_EQ, 12) == 0)
- {
- pcre_uint32 c = 0;
- int p = skipatstart + 14;
- while (isdigit(ptr[p]))
- {
- if (c > PCRE_UINT32_MAX / 10 - 1) break; /* Integer overflow */
- c = c*10 + ptr[p++] - CHAR_0;
- }
- if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break;
- if (c < limit_match)
- {
- limit_match = c;
- cd->external_flags |= PCRE_MLSET;
- }
- skipatstart = p;
- continue;
- }
+ case PSO_NL:
+ newline = p->value;
+ setflags |= PCRE2_NL_SET;
+ break;
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LIMIT_RECURSION_EQ, 16) == 0)
- {
- pcre_uint32 c = 0;
- int p = skipatstart + 18;
- while (isdigit(ptr[p]))
- {
- if (c > PCRE_UINT32_MAX / 10 - 1) break; /* Integer overflow check */
- c = c*10 + ptr[p++] - CHAR_0;
- }
- if (ptr[p++] != CHAR_RIGHT_PARENTHESIS) break;
- if (c < limit_recursion)
- {
- limit_recursion = c;
- cd->external_flags |= PCRE_RLSET;
+ case PSO_BSR:
+ bsr = p->value;
+ setflags |= PCRE2_BSR_SET;
+ break;
+
+ case PSO_LIMM:
+ case PSO_LIMR:
+ c = 0;
+ pp = skipatstart;
+ if (!IS_DIGIT(ptr[pp]))
+ {
+ errorcode = ERR60;
+ ptr += pp;
+ goto HAD_ERROR;
+ }
+ while (IS_DIGIT(ptr[pp]))
+ {
+ if (c > UINT32_MAX / 10 - 1) break; /* Integer overflow */
+ c = c*10 + (ptr[pp++] - CHAR_0);
+ }
+ if (ptr[pp++] != CHAR_RIGHT_PARENTHESIS)
+ {
+ errorcode = ERR60;
+ ptr += pp;
+ goto HAD_ERROR;
+ }
+ if (p->type == PSO_LIMM) limit_match = c;
+ else limit_recursion = c;
+ skipatstart += pp - skipatstart;
+ break;
+ }
+ break; /* Out of the table scan loop */
}
- skipatstart = p;
- continue;
}
-
- if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_CR_RIGHTPAR, 3) == 0)
- { skipatstart += 5; newnl = PCRE_NEWLINE_CR; }
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_LF_RIGHTPAR, 3) == 0)
- { skipatstart += 5; newnl = PCRE_NEWLINE_LF; }
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_CRLF_RIGHTPAR, 5) == 0)
- { skipatstart += 7; newnl = PCRE_NEWLINE_CR + PCRE_NEWLINE_LF; }
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_ANY_RIGHTPAR, 4) == 0)
- { skipatstart += 6; newnl = PCRE_NEWLINE_ANY; }
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_ANYCRLF_RIGHTPAR, 8) == 0)
- { skipatstart += 10; newnl = PCRE_NEWLINE_ANYCRLF; }
-
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_BSR_ANYCRLF_RIGHTPAR, 12) == 0)
- { skipatstart += 14; newbsr = PCRE_BSR_ANYCRLF; }
- else if (STRNCMP_UC_C8(ptr+skipatstart+2, STRING_BSR_UNICODE_RIGHTPAR, 12) == 0)
- { skipatstart += 14; newbsr = PCRE_BSR_UNICODE; }
-
- if (newnl != 0)
- options = (options & ~PCRE_NEWLINE_BITS) | newnl;
- else if (newbsr != 0)
- options = (options & ~(PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) | newbsr;
- else break;
+ if (i >= sizeof(pso_list)/sizeof(pso)) break; /* Out of pso loop */
}
-/* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */
-utf = (options & PCRE_UTF8) != 0;
-if (utf && never_utf)
- {
- errorcode = ERR78;
- goto PCRE_EARLY_ERROR_RETURN2;
- }
+/* End of pattern-start options; advance to start of real regex. */
-/* Can't support UTF unless PCRE has been compiled to include the code. The
-return of an error code from PRIV(valid_utf)() is a new feature, introduced in
-release 8.13. It is passed back from pcre_[dfa_]exec(), but at the moment is
-not used here. */
+ptr += skipatstart;
-#ifdef SUPPORT_UTF
-if (utf && (options & PCRE_NO_UTF8_CHECK) == 0 &&
- (errorcode = PRIV(valid_utf)((PCRE_PUCHAR)pattern, -1, erroroffset)) != 0)
- {
-#if defined COMPILE_PCRE8
- errorcode = ERR44;
-#elif defined COMPILE_PCRE16
- errorcode = ERR74;
-#elif defined COMPILE_PCRE32
- errorcode = ERR77;
-#endif
- goto PCRE_EARLY_ERROR_RETURN2;
- }
-#else
-if (utf)
+/* Can't support UTF or UCP unless PCRE2 has been compiled with UTF support. */
+
+#ifndef SUPPORT_UNICODE
+if ((cb.external_options & (PCRE2_UTF|PCRE2_UCP)) != 0)
{
errorcode = ERR32;
- goto PCRE_EARLY_ERROR_RETURN;
+ goto HAD_ERROR;
}
#endif
-/* Can't support UCP unless PCRE has been compiled to include the code. */
+/* Check UTF. We have the original options in 'options', with that value as
+modified by (*UTF) etc in cb->external_options. */
-#ifndef SUPPORT_UCP
-if ((options & PCRE_UCP) != 0)
+utf = (cb.external_options & PCRE2_UTF) != 0;
+if (utf)
{
- errorcode = ERR67;
- goto PCRE_EARLY_ERROR_RETURN;
+ if ((options & PCRE2_NEVER_UTF) != 0)
+ {
+ errorcode = ERR74;
+ goto HAD_ERROR;
+ }
+ if ((options & PCRE2_NO_UTF_CHECK) == 0 &&
+ (errorcode = PRIV(valid_utf)(pattern, patlen, erroroffset)) != 0)
+ goto HAD_UTF_ERROR;
}
-#endif
-/* Check validity of \R options. */
+/* Check UCP lockout. */
-if ((options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) ==
- (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE))
+if ((cb.external_options & (PCRE2_UCP|PCRE2_NEVER_UCP)) ==
+ (PCRE2_UCP|PCRE2_NEVER_UCP))
{
- errorcode = ERR56;
- goto PCRE_EARLY_ERROR_RETURN;
+ errorcode = ERR75;
+ goto HAD_ERROR;
}
-/* Handle different types of newline. The three bits give seven cases. The
-current code allows for fixed one- or two-byte sequences, plus "any" and
-"anycrlf". */
+/* Process the BSR setting. */
-switch (options & PCRE_NEWLINE_BITS)
- {
- case 0: newline = NEWLINE; break; /* Build-time default */
- case PCRE_NEWLINE_CR: newline = CHAR_CR; break;
- case PCRE_NEWLINE_LF: newline = CHAR_NL; break;
- case PCRE_NEWLINE_CR+
- PCRE_NEWLINE_LF: newline = (CHAR_CR << 8) | CHAR_NL; break;
- case PCRE_NEWLINE_ANY: newline = -1; break;
- case PCRE_NEWLINE_ANYCRLF: newline = -2; break;
- default: errorcode = ERR56; goto PCRE_EARLY_ERROR_RETURN;
- }
+if (bsr == 0) bsr = ccontext->bsr_convention;
-if (newline == -2)
- {
- cd->nltype = NLTYPE_ANYCRLF;
- }
-else if (newline < 0)
+/* Process the newline setting. */
+
+if (newline == 0) newline = ccontext->newline_convention;
+cb.nltype = NLTYPE_FIXED;
+switch(newline)
{
- cd->nltype = NLTYPE_ANY;
+ case PCRE2_NEWLINE_CR:
+ cb.nllen = 1;
+ cb.nl[0] = CHAR_CR;
+ break;
+
+ case PCRE2_NEWLINE_LF:
+ cb.nllen = 1;
+ cb.nl[0] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_CRLF:
+ cb.nllen = 2;
+ cb.nl[0] = CHAR_CR;
+ cb.nl[1] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_ANY:
+ cb.nltype = NLTYPE_ANY;
+ break;
+
+ case PCRE2_NEWLINE_ANYCRLF:
+ cb.nltype = NLTYPE_ANYCRLF;
+ break;
+
+ default:
+ errorcode = ERR56;
+ goto HAD_ERROR;
}
-else
+
+/* Before we do anything else, do a pre-scan of the pattern in order to
+discover the named groups and their numerical equivalents, so that this
+information is always available for the remaining processing. */
+
+errorcode = scan_for_captures(&ptr, cb.external_options, &cb);
+if (errorcode != 0) goto HAD_ERROR;
+
+/* For obscure debugging this code can be enabled. */
+
+#if 0
{
- cd->nltype = NLTYPE_FIXED;
- if (newline > 255)
- {
- cd->nllen = 2;
- cd->nl[0] = (newline >> 8) & 255;
- cd->nl[1] = newline & 255;
- }
- else
+ int i;
+ named_group *ng = cb.named_groups;
+ fprintf(stderr, "+++Captures: %d\n", cb.final_bracount);
+ for (i = 0; i < cb.names_found; i++, ng++)
{
- cd->nllen = 1;
- cd->nl[0] = newline;
+ fprintf(stderr, "+++%3d %.*s\n", ng->number, ng->length, ng->name);
}
}
+#endif
-/* Maximum back reference and backref bitmap. The bitmap records up to 31 back
-references to help in deciding whether (.*) can be treated as anchored or not.
-*/
+/* Reset current bracket count to zero and current pointer to the start of the
+pattern. */
-cd->top_backref = 0;
-cd->backref_map = 0;
+cb.bracount = 0;
+ptr = pattern + skipatstart;
-/* Reflect pattern for debugging output */
+/* Pretend to compile the pattern while actually just accumulating the amount
+of memory required in the 'length' variable. This behaviour is triggered by
+passing a non-NULL final argument to compile_regex(). We pass a block of
+workspace (cworkspace) for it to compile parts of the pattern into; the
+compiled code is discarded when it is no longer needed, so hopefully this
+workspace will never overflow, though there is a test for its doing so.
-DPRINTF(("------------------------------------------------------------------\n"));
-#ifdef PCRE_DEBUG
-print_puchar(stdout, (PCRE_PUCHAR)pattern);
-#endif
-DPRINTF(("\n"));
-
-/* Pretend to compile the pattern while actually just accumulating the length
-of memory required. This behaviour is triggered by passing a non-NULL final
-argument to compile_regex(). We pass a block of workspace (cworkspace) for it
-to compile parts of the pattern into; the compiled code is discarded when it is
-no longer needed, so hopefully this workspace will never overflow, though there
-is a test for its doing so. */
-
-cd->bracount = cd->final_bracount = 0;
-cd->names_found = 0;
-cd->name_entry_size = 0;
-cd->name_table = NULL;
-cd->dupnames = FALSE;
-cd->dupgroups = FALSE;
-cd->namedrefcount = 0;
-cd->start_code = cworkspace;
-cd->hwm = cworkspace;
-cd->iscondassert = FALSE;
-cd->start_workspace = cworkspace;
-cd->workspace_size = COMPILE_WORK_SIZE;
-cd->named_groups = named_groups;
-cd->named_group_list_size = NAMED_GROUP_LIST_SIZE;
-cd->start_pattern = (const pcre_uchar *)pattern;
-cd->end_pattern = (const pcre_uchar *)(pattern + STRLEN_UC((const pcre_uchar *)pattern));
-cd->req_varyopt = 0;
-cd->parens_depth = 0;
-cd->assert_depth = 0;
-cd->max_lookbehind = 0;
-cd->external_options = options;
-cd->open_caps = NULL;
-
-/* Now do the pre-compile. On error, errorcode will be set non-zero, so we
-don't need to look at the result of the function here. The initial options have
-been put into the cd block so that they can be changed if an option setting is
-found within the regex right at the beginning. Bringing initial option settings
-outside can help speed up starting point checks. */
+On error, errorcode will be set non-zero, so we don't need to look at the
+result of the function. The initial options have been put into the cb block so
+that they can be changed if an option setting is found within the regex right
+at the beginning. Bringing initial option settings outside can help speed up
+starting point checks. We still have to pass a separate options variable (the
+first argument) because that may change as the pattern is processed. */
-ptr += skipatstart;
code = cworkspace;
*code = OP_BRA;
-(void)compile_regex(cd->external_options, &code, &ptr, &errorcode, FALSE,
- FALSE, 0, 0, &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL,
- cd, &length);
-if (errorcode != 0) goto PCRE_EARLY_ERROR_RETURN;
-
-DPRINTF(("end pre-compile: length=%d workspace=%d\n", length,
- (int)(cd->hwm - cworkspace)));
+(void)compile_regex(cb.external_options, &code, &ptr, &errorcode, FALSE,
+ FALSE, 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL,
+ &cb, &length);
+if (errorcode != 0) goto HAD_ERROR;
if (length > MAX_PATTERN_SIZE)
{
errorcode = ERR20;
- goto PCRE_EARLY_ERROR_RETURN;
+ goto HAD_ERROR;
}
-/* Compute the size of the data block for storing the compiled pattern. Integer
-overflow should no longer be possible because nowadays we limit the maximum
-value of cd->names_found and cd->name_entry_size. */
-
-size = sizeof(REAL_PCRE) +
- (length + cd->names_found * cd->name_entry_size) * sizeof(pcre_uchar);
-
-/* Get the memory. */
+/* Compute the size of, and then get and initialize, the data block for storing
+the compiled pattern and names table. Integer overflow should no longer be
+possible because nowadays we limit the maximum value of cb.names_found and
+cb.name_entry_size. */
-re = (REAL_PCRE *)(PUBL(malloc))(size);
+re_blocksize = sizeof(pcre2_real_code) +
+ CU2BYTES(length + cb.names_found * cb.name_entry_size);
+re = (pcre2_real_code *)
+ ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data);
if (re == NULL)
{
errorcode = ERR21;
- goto PCRE_EARLY_ERROR_RETURN;
+ goto HAD_ERROR;
}
-/* Put in the magic number, and save the sizes, initial options, internal
-flags, and character table pointer. NULL is used for the default character
-tables. The nullpad field is at the end; it's there to help in the case when a
-regex compiled on a system with 4-byte pointers is run on another with 8-byte
-pointers. */
-
+re->memctl = ccontext->memctl;
+re->tables = tables;
+re->executable_jit = NULL;
+memset(re->start_bitmap, 0, 32 * sizeof(uint8_t));
+re->blocksize = re_blocksize;
re->magic_number = MAGIC_NUMBER;
-re->size = (int)size;
-re->options = cd->external_options;
-re->flags = cd->external_flags;
+re->compile_options = options;
+re->overall_options = cb.external_options;
+re->flags = PCRE2_CODE_UNIT_WIDTH/8 | cb.external_flags | setflags;
re->limit_match = limit_match;
re->limit_recursion = limit_recursion;
-re->first_char = 0;
-re->req_char = 0;
-re->name_table_offset = sizeof(REAL_PCRE) / sizeof(pcre_uchar);
-re->name_entry_size = cd->name_entry_size;
-re->name_count = cd->names_found;
-re->ref_count = 0;
-re->tables = (tables == PRIV(default_tables))? NULL : tables;
-re->nullpad = NULL;
-#ifdef COMPILE_PCRE32
-re->dummy = 0;
-#else
-re->dummy1 = re->dummy2 = re->dummy3 = 0;
-#endif
-
-/* The starting points of the name/number translation table and of the code are
-passed around in the compile data block. The start/end pattern and initial
-options are already set from the pre-compile phase, as is the name_entry_size
-field. Reset the bracket count and the names_found field. Also reset the hwm
-field; this time it's used for remembering forward references to subpatterns.
-*/
-
-cd->final_bracount = cd->bracount; /* Save for checking forward references */
-cd->parens_depth = 0;
-cd->assert_depth = 0;
-cd->bracount = 0;
-cd->max_lookbehind = 0;
-cd->name_table = (pcre_uchar *)re + re->name_table_offset;
-codestart = cd->name_table + re->name_entry_size * re->name_count;
-cd->start_code = codestart;
-cd->hwm = (pcre_uchar *)(cd->start_workspace);
-cd->iscondassert = FALSE;
-cd->req_varyopt = 0;
-cd->had_accept = FALSE;
-cd->had_pruneorskip = FALSE;
-cd->check_lookbehind = FALSE;
-cd->open_caps = NULL;
+re->first_codeunit = 0;
+re->last_codeunit = 0;
+re->bsr_convention = bsr;
+re->newline_convention = newline;
+re->max_lookbehind = 0;
+re->minlength = 0;
+re->top_bracket = 0;
+re->top_backref = 0;
+re->name_entry_size = cb.name_entry_size;
+re->name_count = cb.names_found;
+
+/* The basic block is immediately followed by the name table, and the compiled
+code follows after that. */
+
+codestart = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)) +
+ re->name_entry_size * re->name_count;
+
+/* Workspace is needed to remember information about numbered groups: whether a
+group can match an empty string and what its fixed length is. This is done to
+avoid the possibility of recursive references causing very long compile times
+when checking these features. Unnumbered groups do not have this exposure since
+they cannot be referenced. We use an indexed vector for this purpose. If there
+are sufficiently few groups, it can be the c32workspace vector, as set up
+above. Otherwise we have to get/free a special vector. The vector must be
+initialized to zero. */
+
+if (cb.final_bracount >= C32_WORK_SIZE)
+ {
+ cb.groupinfo = ccontext->memctl.malloc(
+ (cb.final_bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data);
+ if (cb.groupinfo == NULL)
+ {
+ errorcode = ERR21;
+ goto HAD_ERROR;
+ }
+ }
+memset(cb.groupinfo, 0, (cb.final_bracount + 1) * sizeof(uint32_t));
+
+/* Update the compile data block for the actual compile. The starting points of
+the name/number translation table and of the code are passed around in the
+compile data block. The start/end pattern and initial options are already set
+from the pre-compile phase, as is the name_entry_size field. Reset the bracket
+count and the names_found field. */
+
+cb.parens_depth = 0;
+cb.assert_depth = 0;
+cb.bracount = 0;
+cb.max_lookbehind = 0;
+cb.name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code));
+cb.start_code = codestart;
+cb.iscondassert = FALSE;
+cb.req_varyopt = 0;
+cb.had_accept = FALSE;
+cb.had_pruneorskip = FALSE;
+cb.check_lookbehind = FALSE;
+cb.open_caps = NULL;
/* If any named groups were found, create the name/number table from the list
-created in the first pass. */
+created in the pre-pass. */
-if (cd->names_found > 0)
+if (cb.names_found > 0)
{
- int i = cd->names_found;
- named_group *ng = cd->named_groups;
- cd->names_found = 0;
+ int i = cb.names_found;
+ named_group *ng = cb.named_groups;
+ cb.names_found = 0;
for (; i > 0; i--, ng++)
- add_name(cd, ng->name, ng->length, ng->number);
- if (cd->named_group_list_size > NAMED_GROUP_LIST_SIZE)
- (PUBL(free))((void *)cd->named_groups);
+ add_name_to_table(&cb, ng->name, ng->length, ng->number);
}
/* Set up a starting, non-extracting bracket, then compile the expression. On
error, errorcode will be set non-zero, so we don't need to look at the result
of the function here. */
-ptr = (const pcre_uchar *)pattern + skipatstart;
-code = (pcre_uchar *)codestart;
+ptr = pattern + skipatstart;
+code = (PCRE2_UCHAR *)codestart;
*code = OP_BRA;
-(void)compile_regex(re->options, &code, &ptr, &errorcode, FALSE, FALSE, 0, 0,
- &firstchar, &firstcharflags, &reqchar, &reqcharflags, NULL, cd, NULL);
-re->top_bracket = cd->bracount;
-re->top_backref = cd->top_backref;
-re->max_lookbehind = cd->max_lookbehind;
-re->flags = cd->external_flags | PCRE_MODE;
-
-if (cd->had_accept)
- {
- reqchar = 0; /* Must disable after (*ACCEPT) */
- reqcharflags = REQ_NONE;
- }
+(void)compile_regex(re->overall_options, &code, &ptr, &errorcode, FALSE, FALSE,
+ 0, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL);
-/* If not reached end of pattern on success, there's an excess bracket. */
+re->top_bracket = cb.bracount;
+re->top_backref = cb.top_backref;
+re->max_lookbehind = cb.max_lookbehind;
-if (errorcode == 0 && *ptr != CHAR_NULL) errorcode = ERR22;
+if (cb.had_accept)
+ {
+ reqcu = 0; /* Must disable after (*ACCEPT) */
+ reqcuflags = REQ_NONE;
+ }
-/* Fill in the terminating state and check for disastrous overflow, but
-if debugging, leave the test till after things are printed out. */
+/* Fill in the final opcode and check for disastrous overflow. If no overflow,
+but the estimated length exceeds the really used length, adjust the value of
+re->blocksize, and if valgrind support is configured, mark the extra allocated
+memory as unaddressable, so that any out-of-bound reads can be detected. */
*code++ = OP_END;
-
-#ifndef PCRE_DEBUG
-if (code - codestart > length) errorcode = ERR23;
-#endif
-
+usedlength = code - codestart;
+if (usedlength > length) errorcode = ERR23; else
+ {
+ re->blocksize -= CU2BYTES(length - usedlength);
#ifdef SUPPORT_VALGRIND
-/* If the estimated length exceeds the really used length, mark the extra
-allocated memory as unaddressable, so that any out-of-bound reads can be
-detected. */
-VALGRIND_MAKE_MEM_NOACCESS(code, (length - (code - codestart)) * sizeof(pcre_uchar));
+ VALGRIND_MAKE_MEM_NOACCESS(code, CU2BYTES(length - usedlength));
#endif
+ }
+
+/* Scan the pattern for recursion/subroutine calls and convert the group
+numbers into offsets. Maintain a small cache so that repeated groups containing
+recursions are efficiently handled. */
-/* Fill in any forward references that are required. There may be repeated
-references; optimize for them, as searching a large regex takes time. */
+#define RSCAN_CACHE_SIZE 8
-if (cd->hwm > cd->start_workspace)
+if (errorcode == 0 && cb.had_recurse)
{
- int prev_recno = -1;
- const pcre_uchar *groupptr = NULL;
- while (errorcode == 0 && cd->hwm > cd->start_workspace)
+ PCRE2_UCHAR *rcode;
+ PCRE2_SPTR rgroup;
+ int ccount = 0;
+ int start = RSCAN_CACHE_SIZE;
+ recurse_cache rc[RSCAN_CACHE_SIZE];
+
+ for (rcode = (PCRE2_UCHAR *)find_recurse(codestart, utf);
+ rcode != NULL;
+ rcode = (PCRE2_UCHAR *)find_recurse(rcode + 1 + LINK_SIZE, utf))
{
- int offset, recno;
- cd->hwm -= LINK_SIZE;
- offset = GET(cd->hwm, 0);
+ int i, p, recno;
- /* Check that the hwm handling hasn't gone wrong. This whole area is
- rewritten in PCRE2 because there are some obscure cases. */
-
- if (offset == 0 || codestart[offset-1] != OP_RECURSE)
+ recno = (int)GET(rcode, 1);
+ if (recno == 0) rgroup = codestart; else
{
- errorcode = ERR10;
- break;
- }
+ PCRE2_SPTR search_from = codestart;
+ rgroup = NULL;
+ for (i = 0, p = start; i < ccount; i++, p = (p + 1) & 7)
+ {
+ if (recno == rc[p].recno)
+ {
+ rgroup = rc[p].group;
+ break;
+ }
- recno = GET(codestart, offset);
- if (recno != prev_recno)
- {
- groupptr = PRIV(find_bracket)(codestart, utf, recno);
- prev_recno = recno;
+ /* Group n+1 must always start to the right of group n, so we can save
+ search time below when the new group number is greater than any of the
+ previously found groups. */
+
+ if (recno > rc[p].recno) search_from = rc[p].group;
+ }
+
+ if (rgroup == NULL)
+ {
+ rgroup = PRIV(find_bracket)(search_from, utf, recno);
+ if (rgroup == NULL)
+ {
+ errorcode = ERR53;
+ break;
+ }
+ if (--start < 0) start = RSCAN_CACHE_SIZE - 1;
+ rc[start].recno = recno;
+ rc[start].group = rgroup;
+ if (ccount < RSCAN_CACHE_SIZE) ccount++;
+ }
}
- if (groupptr == NULL) errorcode = ERR53;
- else PUT(((pcre_uchar *)codestart), offset, (int)(groupptr - codestart));
+
+ PUT(rcode, 1, rgroup - codestart);
}
}
-/* If the workspace had to be expanded, free the new memory. Set the pointer to
-NULL to indicate that forward references have been filled in. */
+/* In rare debugging situations we sometimes need to look at the compiled code
+at this stage. */
-if (cd->workspace_size > COMPILE_WORK_SIZE)
- (PUBL(free))((void *)cd->start_workspace);
-cd->start_workspace = NULL;
-
-/* Give an error if there's back reference to a non-existent capturing
-subpattern. */
-
-if (errorcode == 0 && re->top_backref > re->top_bracket) errorcode = ERR15;
+#ifdef CALL_PRINTINT
+pcre2_printint(re, stderr, TRUE);
+fprintf(stderr, "Length=%lu Used=%lu\n", length, usedlength);
+#endif
-/* Unless disabled, check whether any single character iterators can be
-auto-possessified. The function overwrites the appropriate opcode values, so
-the type of the pointer must be cast. NOTE: the intermediate variable "temp" is
-used in this code because at least one compiler gives a warning about loss of
-"const" attribute if the cast (pcre_uchar *)codestart is used directly in the
-function call. */
+/* After a successful compile, give an error if there's back reference to a
+non-existent capturing subpattern. Then, unless disabled, check whether any
+single character iterators can be auto-possessified. The function overwrites
+the appropriate opcode values, so the type of the pointer must be cast. NOTE:
+the intermediate variable "temp" is used in this code because at least one
+compiler gives a warning about loss of "const" attribute if the cast
+(PCRE2_UCHAR *)codestart is used directly in the function call. */
-if (errorcode == 0 && (options & PCRE_NO_AUTO_POSSESS) == 0)
+if (errorcode == 0)
{
- pcre_uchar *temp = (pcre_uchar *)codestart;
- auto_possessify(temp, utf, cd);
+ if (re->top_backref > re->top_bracket) errorcode = ERR15;
+ else if ((re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0)
+ {
+ PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart;
+ if (PRIV(auto_possessify)(temp, utf, &cb) != 0) errorcode = ERR80;
+ }
}
/* If there were any lookbehind assertions that contained OP_RECURSE
@@ -9534,216 +8888,194 @@ OP_RECURSE that are not fixed length get a diagnosic with a useful offset. The
exceptional ones forgo this. We scan the pattern to check that they are fixed
length, and set their lengths. */
-if (errorcode == 0 && cd->check_lookbehind)
+if (errorcode == 0 && cb.check_lookbehind)
{
- pcre_uchar *cc = (pcre_uchar *)codestart;
+ PCRE2_UCHAR *cc = (PCRE2_UCHAR *)codestart;
/* Loop, searching for OP_REVERSE items, and process those that do not have
their length set. (Actually, it will also re-process any that have a length
of zero, but that is a pathological case, and it does no harm.) When we find
- one, we temporarily terminate the branch it is in while we scan it. */
+ one, we temporarily terminate the branch it is in while we scan it. Note that
+ calling find_bracket() with a negative group number returns a pointer to the
+ OP_REVERSE item, not the actual lookbehind. */
- for (cc = (pcre_uchar *)PRIV(find_bracket)(codestart, utf, -1);
+ for (cc = (PCRE2_UCHAR *)PRIV(find_bracket)(codestart, utf, -1);
cc != NULL;
- cc = (pcre_uchar *)PRIV(find_bracket)(cc, utf, -1))
+ cc = (PCRE2_UCHAR *)PRIV(find_bracket)(cc, utf, -1))
{
if (GET(cc, 1) == 0)
{
int fixed_length;
- pcre_uchar *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE);
+ int count = 0;
+ PCRE2_UCHAR *be = cc - 1 - LINK_SIZE + GET(cc, -LINK_SIZE);
int end_op = *be;
*be = OP_END;
- fixed_length = find_fixedlength(cc, (re->options & PCRE_UTF8) != 0, TRUE,
- cd, NULL);
+ fixed_length = find_fixedlength(cc, utf, TRUE, &cb, NULL, &count);
*be = end_op;
- DPRINTF(("fixed length = %d\n", fixed_length));
if (fixed_length < 0)
{
- errorcode = (fixed_length == -2)? ERR36 :
- (fixed_length == -4)? ERR70 : ERR25;
+ errorcode = fixed_length_errors[-fixed_length];
break;
}
- if (fixed_length > cd->max_lookbehind) cd->max_lookbehind = fixed_length;
+ if (fixed_length > cb.max_lookbehind) cb.max_lookbehind = fixed_length;
PUT(cc, 1, fixed_length);
}
cc += 1 + LINK_SIZE;
}
+
+ /* The previous value of the maximum lookbehind was transferred to the
+ compiled regex block above. We could have updated this value in the loop
+ above, but keep the two values in step, just in case some later code below
+ uses the cb value. */
+
+ re->max_lookbehind = cb.max_lookbehind;
}
-/* Failed to compile, or error while post-processing */
+/* Failed to compile, or error while post-processing. Earlier errors get here
+via the dreaded goto. */
if (errorcode != 0)
{
- (PUBL(free))(re);
- PCRE_EARLY_ERROR_RETURN:
- *erroroffset = (int)(ptr - (const pcre_uchar *)pattern);
- PCRE_EARLY_ERROR_RETURN2:
- *errorptr = find_error_text(errorcode);
- if (errorcodeptr != NULL) *errorcodeptr = errorcode;
- return NULL;
+ HAD_ERROR:
+ *erroroffset = (int)(ptr - pattern);
+ HAD_UTF_ERROR:
+ *errorptr = errorcode;
+ pcre2_code_free(re);
+ re = NULL;
+ goto EXIT;
}
-/* If the anchored option was not passed, set the flag if we can determine that
-the pattern is anchored by virtue of ^ characters or \A or anything else, such
-as starting with non-atomic .* when DOTALL is set and there are no occurrences
-of *PRUNE or *SKIP.
+/* Successful compile. If the anchored option was not passed, set it if
+we can determine that the pattern is anchored by virtue of ^ characters or \A
+or anything else, such as starting with non-atomic .* when DOTALL is set and
+there are no occurrences of *PRUNE or *SKIP (though there is an option to
+disable this case). */
+
+if ((re->overall_options & PCRE2_ANCHORED) == 0 &&
+ is_anchored(codestart, 0, &cb, 0))
+ re->overall_options |= PCRE2_ANCHORED;
-Otherwise, if we know what the first byte has to be, save it, because that
-speeds up unanchored matches no end. If not, see if we can set the
-PCRE_STARTLINE flag. This is helpful for multiline matches when all branches
-start with ^. and also when all branches start with non-atomic .* for
-non-DOTALL matches when *PRUNE and SKIP are not present. */
+/* If the pattern is still not anchored and we do not have a first code unit,
+see if there is one that is asserted (these are not saved during the compile
+because they can cause conflicts with actual literals that follow). This code
+need not be obeyed if PCRE2_NO_START_OPTIMIZE is set, as the data it would
+create will not be used. */
-if ((re->options & PCRE_ANCHORED) == 0)
+if ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0)
{
- if (is_anchored(codestart, 0, cd, 0)) re->options |= PCRE_ANCHORED;
- else
- {
- if (firstcharflags < 0)
- firstchar = find_firstassertedchar(codestart, &firstcharflags, FALSE);
- if (firstcharflags >= 0) /* Remove caseless flag for non-caseable chars */
- {
-#if defined COMPILE_PCRE8
- re->first_char = firstchar & 0xff;
-#elif defined COMPILE_PCRE16
- re->first_char = firstchar & 0xffff;
-#elif defined COMPILE_PCRE32
- re->first_char = firstchar;
-#endif
- if ((firstcharflags & REQ_CASELESS) != 0)
- {
-#if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
- /* We ignore non-ASCII first chars in 8 bit mode. */
- if (utf)
- {
- if (re->first_char < 128)
- {
- if (cd->fcc[re->first_char] != re->first_char)
- re->flags |= PCRE_FCH_CASELESS;
- }
- else if (UCD_OTHERCASE(re->first_char) != re->first_char)
- re->flags |= PCRE_FCH_CASELESS;
- }
- else
-#endif
- if (MAX_255(re->first_char)
- && cd->fcc[re->first_char] != re->first_char)
- re->flags |= PCRE_FCH_CASELESS;
- }
+ if (firstcuflags < 0)
+ firstcu = find_firstassertedcu(codestart, &firstcuflags, FALSE);
- re->flags |= PCRE_FIRSTSET;
- }
+ /* Save the data for a first code unit. */
- else if (is_startline(codestart, 0, cd, 0)) re->flags |= PCRE_STARTLINE;
- }
- }
+ if (firstcuflags >= 0)
+ {
+ re->first_codeunit = firstcu;
+ re->flags |= PCRE2_FIRSTSET;
-/* For an anchored pattern, we use the "required byte" only if it follows a
-variable length item in the regex. Remove the caseless flag for non-caseable
-bytes. */
+ /* Handle caseless first code units. */
-if (reqcharflags >= 0 &&
- ((re->options & PCRE_ANCHORED) == 0 || (reqcharflags & REQ_VARY) != 0))
- {
-#if defined COMPILE_PCRE8
- re->req_char = reqchar & 0xff;
-#elif defined COMPILE_PCRE16
- re->req_char = reqchar & 0xffff;
-#elif defined COMPILE_PCRE32
- re->req_char = reqchar;
-#endif
- if ((reqcharflags & REQ_CASELESS) != 0)
- {
-#if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
- /* We ignore non-ASCII first chars in 8 bit mode. */
- if (utf)
+ if ((firstcuflags & REQ_CASELESS) != 0)
{
- if (re->req_char < 128)
+ if (firstcu < 128 || (!utf && firstcu < 255))
{
- if (cd->fcc[re->req_char] != re->req_char)
- re->flags |= PCRE_RCH_CASELESS;
+ if (cb.fcc[firstcu] != firstcu) re->flags |= PCRE2_FIRSTCASELESS;
}
- else if (UCD_OTHERCASE(re->req_char) != re->req_char)
- re->flags |= PCRE_RCH_CASELESS;
- }
- else
+
+ /* The first code unit is > 128 in UTF mode, or > 255 otherwise. In
+ 8-bit UTF mode, codepoints in the range 128-255 are introductory code
+ points and cannot have another case. In 16-bit and 32-bit modes, we can
+ check wide characters when UTF (and therefore UCP) is supported. */
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ else if (firstcu <= MAX_UTF_CODE_POINT &&
+ UCD_OTHERCASE(firstcu) != firstcu)
+ re->flags |= PCRE2_FIRSTCASELESS;
#endif
- if (MAX_255(re->req_char) && cd->fcc[re->req_char] != re->req_char)
- re->flags |= PCRE_RCH_CASELESS;
+ }
}
- re->flags |= PCRE_REQCHSET;
- }
-
-/* Print out the compiled data if debugging is enabled. This is never the
-case when building a production library. */
+ /* When there is no first code unit, see if we can set the PCRE2_STARTLINE
+ flag. This is helpful for multiline matches when all branches start with ^
+ and also when all branches start with non-atomic .* for non-DOTALL matches
+ when *PRUNE and SKIP are not present. (There is an option that disables this
+ case.) */
-#ifdef PCRE_DEBUG
-printf("Length = %d top_bracket = %d top_backref = %d\n",
- length, re->top_bracket, re->top_backref);
+ else if (is_startline(codestart, 0, &cb, 0)) re->flags |= PCRE2_STARTLINE;
+ }
-printf("Options=%08x\n", re->options);
+/* Handle the "required code unit", if one is set. In the case of an anchored
+pattern, do this only if it follows a variable length item in the pattern.
+Again, skip this if PCRE2_NO_START_OPTIMIZE is set. */
-if ((re->flags & PCRE_FIRSTSET) != 0)
+if (reqcuflags >= 0 &&
+ ((re->overall_options & (PCRE2_ANCHORED|PCRE2_NO_START_OPTIMIZE)) == 0 ||
+ (reqcuflags & REQ_VARY) != 0))
{
- pcre_uchar ch = re->first_char;
- const char *caseless =
- ((re->flags & PCRE_FCH_CASELESS) == 0)? "" : " (caseless)";
- if (PRINTABLE(ch)) printf("First char = %c%s\n", ch, caseless);
- else printf("First char = \\x%02x%s\n", ch, caseless);
- }
+ re->last_codeunit = reqcu;
+ re->flags |= PCRE2_LASTSET;
-if ((re->flags & PCRE_REQCHSET) != 0)
- {
- pcre_uchar ch = re->req_char;
- const char *caseless =
- ((re->flags & PCRE_RCH_CASELESS) == 0)? "" : " (caseless)";
- if (PRINTABLE(ch)) printf("Req char = %c%s\n", ch, caseless);
- else printf("Req char = \\x%02x%s\n", ch, caseless);
- }
+ /* Handle caseless required code units as for first code units (above). */
-#if defined COMPILE_PCRE8
-pcre_printint((pcre *)re, stdout, TRUE);
-#elif defined COMPILE_PCRE16
-pcre16_printint((pcre *)re, stdout, TRUE);
-#elif defined COMPILE_PCRE32
-pcre32_printint((pcre *)re, stdout, TRUE);
+ if ((reqcuflags & REQ_CASELESS) != 0)
+ {
+ if (reqcu < 128 || (!utf && reqcu < 255))
+ {
+ if (cb.fcc[reqcu] != reqcu) re->flags |= PCRE2_LASTCASELESS;
+ }
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ else if (reqcu <= MAX_UTF_CODE_POINT && UCD_OTHERCASE(reqcu) != reqcu)
+ re->flags |= PCRE2_LASTCASELESS;
#endif
-
-/* This check is done here in the debugging case so that the code that
-was compiled can be seen. */
-
-if (code - codestart > length)
- {
- (PUBL(free))(re);
- *errorptr = find_error_text(ERR23);
- *erroroffset = ptr - (pcre_uchar *)pattern;
- if (errorcodeptr != NULL) *errorcodeptr = ERR23;
- return NULL;
+ }
}
-#endif /* PCRE_DEBUG */
/* Check for a pattern than can match an empty string, so that this information
can be provided to applications. */
do
{
- if (could_be_empty_branch(codestart, code, utf, cd, NULL))
+ int count = 0;
+ int rc = could_be_empty_branch(codestart, code, utf, &cb, TRUE, NULL, &count);
+ if (rc < 0)
+ {
+ errorcode = ERR86;
+ goto HAD_ERROR;
+ }
+ if (rc > 0)
{
- re->flags |= PCRE_MATCH_EMPTY;
+ re->flags |= PCRE2_MATCH_EMPTY;
break;
}
codestart += GET(codestart, 1);
}
while (*codestart == OP_ALT);
-#if defined COMPILE_PCRE8
-return (pcre *)re;
-#elif defined COMPILE_PCRE16
-return (pcre16 *)re;
-#elif defined COMPILE_PCRE32
-return (pcre32 *)re;
-#endif
+/* Finally, unless PCRE2_NO_START_OPTIMIZE is set, study the compiled pattern
+to set up information such as a bitmap of starting code units and a minimum
+matching length. */
+
+if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 &&
+ PRIV(study)(re) != 0)
+ {
+ errorcode = ERR31;
+ goto HAD_ERROR;
+ }
+
+/* Control ends up here in all cases. If memory was obtained for a
+zero-terminated copy of the pattern, remember to free it before returning. Also
+free the list of named groups if a larger one had to be obtained, and likewise
+the group information vector. */
+
+EXIT:
+if (copied_pattern != stack_copied_pattern)
+ ccontext->memctl.free(copied_pattern, ccontext->memctl.memory_data);
+if (cb.named_group_list_size > NAMED_GROUP_LIST_SIZE)
+ ccontext->memctl.free((void *)cb.named_groups, ccontext->memctl.memory_data);
+if (cb.groupinfo != c32workspace)
+ ccontext->memctl.free((void *)cb.groupinfo, ccontext->memctl.memory_data);
+
+return re; /* Will be NULL after an error */
}
-/* End of pcre_compile.c */
+/* End of pcre2_compile.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_config.c b/src/3rdparty/pcre2/src/pcre2_config.c
new file mode 100644
index 0000000000..e99272f577
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_config.c
@@ -0,0 +1,218 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Save the configured link size, which is in bytes. In 16-bit and 32-bit modes
+its value gets changed by pcre2_internal.h to be in code units. */
+
+static int configured_link_size = LINK_SIZE;
+
+#include "pcre2_internal.h"
+
+/* These macros are the standard way of turning unquoted text into C strings.
+They allow macros like PCRE2_MAJOR to be defined without quotes, which is
+convenient for user programs that want to test their values. */
+
+#define STRING(a) # a
+#define XSTRING(s) STRING(s)
+
+
+/*************************************************
+* Return info about what features are configured *
+*************************************************/
+
+/* If where is NULL, the length of memory required is returned.
+
+Arguments:
+ what what information is required
+ where where to put the information
+
+Returns: 0 if a numerical value is returned
+ >= 0 if a string value
+ PCRE2_ERROR_BADOPTION if "where" not recognized
+ or JIT target requested when JIT not enabled
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_config(uint32_t what, void *where)
+{
+if (where == NULL) /* Requests a length */
+ {
+ switch(what)
+ {
+ default:
+ return PCRE2_ERROR_BADOPTION;
+
+ case PCRE2_CONFIG_BSR:
+ case PCRE2_CONFIG_JIT:
+ case PCRE2_CONFIG_LINKSIZE:
+ case PCRE2_CONFIG_MATCHLIMIT:
+ case PCRE2_CONFIG_NEWLINE:
+ case PCRE2_CONFIG_PARENSLIMIT:
+ case PCRE2_CONFIG_RECURSIONLIMIT:
+ case PCRE2_CONFIG_STACKRECURSE:
+ case PCRE2_CONFIG_UNICODE:
+ return sizeof(uint32_t);
+
+ /* These are handled below */
+
+ case PCRE2_CONFIG_JITTARGET:
+ case PCRE2_CONFIG_UNICODE_VERSION:
+ case PCRE2_CONFIG_VERSION:
+ break;
+ }
+ }
+
+switch (what)
+ {
+ default:
+ return PCRE2_ERROR_BADOPTION;
+
+ case PCRE2_CONFIG_BSR:
+#ifdef BSR_ANYCRLF
+ *((uint32_t *)where) = PCRE2_BSR_ANYCRLF;
+#else
+ *((uint32_t *)where) = PCRE2_BSR_UNICODE;
+#endif
+ break;
+
+ case PCRE2_CONFIG_JIT:
+#ifdef SUPPORT_JIT
+ *((uint32_t *)where) = 1;
+#else
+ *((uint32_t *)where) = 0;
+#endif
+ break;
+
+ case PCRE2_CONFIG_JITTARGET:
+#ifdef SUPPORT_JIT
+ {
+ const char *v = PRIV(jit_get_target)();
+ return (int)(1 + ((where == NULL)?
+ strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
+ }
+#else
+ return PCRE2_ERROR_BADOPTION;
+#endif
+
+ case PCRE2_CONFIG_LINKSIZE:
+ *((uint32_t *)where) = (uint32_t)configured_link_size;
+ break;
+
+ case PCRE2_CONFIG_MATCHLIMIT:
+ *((uint32_t *)where) = MATCH_LIMIT;
+ break;
+
+ case PCRE2_CONFIG_NEWLINE:
+ *((uint32_t *)where) = NEWLINE_DEFAULT;
+ break;
+
+ case PCRE2_CONFIG_PARENSLIMIT:
+ *((uint32_t *)where) = PARENS_NEST_LIMIT;
+ break;
+
+ case PCRE2_CONFIG_RECURSIONLIMIT:
+ *((uint32_t *)where) = MATCH_LIMIT_RECURSION;
+ break;
+
+ case PCRE2_CONFIG_STACKRECURSE:
+#ifdef HEAP_MATCH_RECURSE
+ *((uint32_t *)where) = 0;
+#else
+ *((uint32_t *)where) = 1;
+#endif
+ break;
+
+ case PCRE2_CONFIG_UNICODE_VERSION:
+ {
+#if defined SUPPORT_UNICODE
+ const char *v = PRIV(unicode_version);
+#else
+ const char *v = "Unicode not supported";
+#endif
+ return (int)(1 + ((where == NULL)?
+ strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
+ }
+ break;
+
+ case PCRE2_CONFIG_UNICODE:
+#if defined SUPPORT_UNICODE
+ *((uint32_t *)where) = 1;
+#else
+ *((uint32_t *)where) = 0;
+#endif
+ break;
+
+ /* The hackery in setting "v" below is to cope with the case when
+ PCRE2_PRERELEASE is set to an empty string (which it is for real releases).
+ If the second alternative is used in this case, it does not leave a space
+ before the date. On the other hand, if all four macros are put into a single
+ XSTRING when PCRE2_PRERELEASE is not empty, an unwanted space is inserted.
+ There are problems using an "obvious" approach like this:
+
+ XSTRING(PCRE2_MAJOR) "." XSTRING(PCRE_MINOR)
+ XSTRING(PCRE2_PRERELEASE) " " XSTRING(PCRE_DATE)
+
+ because, when PCRE2_PRERELEASE is empty, this leads to an attempted expansion
+ of STRING(). The C standard states: "If (before argument substitution) any
+ argument consists of no preprocessing tokens, the behavior is undefined." It
+ turns out the gcc treats this case as a single empty string - which is what
+ we really want - but Visual C grumbles about the lack of an argument for the
+ macro. Unfortunately, both are within their rights. As there seems to be no
+ way to test for a macro's value being empty at compile time, we have to
+ resort to a runtime test. */
+
+ case PCRE2_CONFIG_VERSION:
+ {
+ const char *v = (XSTRING(Z PCRE2_PRERELEASE)[1] == 0)?
+ XSTRING(PCRE2_MAJOR.PCRE2_MINOR PCRE2_DATE) :
+ XSTRING(PCRE2_MAJOR.PCRE2_MINOR) XSTRING(PCRE2_PRERELEASE PCRE2_DATE);
+ return (int)(1 + ((where == NULL)?
+ strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
+ }
+ }
+
+return 0;
+}
+
+/* End of pcre2_config.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_context.c b/src/3rdparty/pcre2/src/pcre2_context.c
new file mode 100644
index 0000000000..ae050fe92c
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_context.c
@@ -0,0 +1,391 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+* Default malloc/free functions *
+*************************************************/
+
+/* Ignore the "user data" argument in each case. */
+
+static void *default_malloc(size_t size, void *data)
+{
+(void)data;
+return malloc(size);
+}
+
+
+static void default_free(void *block, void *data)
+{
+(void)data;
+free(block);
+}
+
+
+
+/*************************************************
+* Get a block and save memory control *
+*************************************************/
+
+/* This internal function is called to get a block of memory in which the
+memory control data is to be stored at the start for future use.
+
+Arguments:
+ size amount of memory required
+ memctl pointer to a memctl block or NULL
+
+Returns: pointer to memory or NULL on failure
+*/
+
+extern void *
+PRIV(memctl_malloc)(size_t size, pcre2_memctl *memctl)
+{
+pcre2_memctl *newmemctl;
+void *yield = (memctl == NULL)? malloc(size) :
+ memctl->malloc(size, memctl->memory_data);
+if (yield == NULL) return NULL;
+newmemctl = (pcre2_memctl *)yield;
+if (memctl == NULL)
+ {
+ newmemctl->malloc = default_malloc;
+ newmemctl->free = default_free;
+ newmemctl->memory_data = NULL;
+ }
+else *newmemctl = *memctl;
+return yield;
+}
+
+
+
+/*************************************************
+* Create and initialize contexts *
+*************************************************/
+
+/* Initializing for compile and match contexts is done in separate, private
+functions so that these can be called from functions such as pcre2_compile()
+when an external context is not supplied. The initializing functions have an
+option to set up default memory management. */
+
+PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION
+pcre2_general_context_create(void *(*private_malloc)(size_t, void *),
+ void (*private_free)(void *, void *), void *memory_data)
+{
+pcre2_general_context *gcontext;
+if (private_malloc == NULL) private_malloc = default_malloc;
+if (private_free == NULL) private_free = default_free;
+gcontext = private_malloc(sizeof(pcre2_real_general_context), memory_data);
+if (gcontext == NULL) return NULL;
+gcontext->memctl.malloc = private_malloc;
+gcontext->memctl.free = private_free;
+gcontext->memctl.memory_data = memory_data;
+return gcontext;
+}
+
+
+/* A default compile context is set up to save having to initialize at run time
+when no context is supplied to the compile function. */
+
+const pcre2_compile_context PRIV(default_compile_context) = {
+ { default_malloc, default_free, NULL }, /* Default memory handling */
+ NULL, /* Stack guard */
+ NULL, /* Stack guard data */
+ PRIV(default_tables), /* Character tables */
+ PCRE2_UNSET, /* Max pattern length */
+ BSR_DEFAULT, /* Backslash R default */
+ NEWLINE_DEFAULT, /* Newline convention */
+ PARENS_NEST_LIMIT }; /* As it says */
+
+/* The create function copies the default into the new memory, but must
+override the default memory handling functions if a gcontext was provided. */
+
+PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION
+pcre2_compile_context_create(pcre2_general_context *gcontext)
+{
+pcre2_compile_context *ccontext = PRIV(memctl_malloc)(
+ sizeof(pcre2_real_compile_context), (pcre2_memctl *)gcontext);
+if (ccontext == NULL) return NULL;
+*ccontext = PRIV(default_compile_context);
+if (gcontext != NULL)
+ *((pcre2_memctl *)ccontext) = *((pcre2_memctl *)gcontext);
+return ccontext;
+}
+
+
+/* A default match context is set up to save having to initialize at run time
+when no context is supplied to a match function. */
+
+const pcre2_match_context PRIV(default_match_context) = {
+ { default_malloc, default_free, NULL },
+#ifdef HEAP_MATCH_RECURSE
+ { default_malloc, default_free, NULL },
+#endif
+#ifdef SUPPORT_JIT
+ NULL,
+ NULL,
+#endif
+ NULL,
+ NULL,
+ PCRE2_UNSET, /* Offset limit */
+ MATCH_LIMIT,
+ MATCH_LIMIT_RECURSION };
+
+/* The create function copies the default into the new memory, but must
+override the default memory handling functions if a gcontext was provided. */
+
+PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION
+pcre2_match_context_create(pcre2_general_context *gcontext)
+{
+pcre2_match_context *mcontext = PRIV(memctl_malloc)(
+ sizeof(pcre2_real_match_context), (pcre2_memctl *)gcontext);
+if (mcontext == NULL) return NULL;
+*mcontext = PRIV(default_match_context);
+if (gcontext != NULL)
+ *((pcre2_memctl *)mcontext) = *((pcre2_memctl *)gcontext);
+return mcontext;
+}
+
+
+/*************************************************
+* Context copy functions *
+*************************************************/
+
+PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION
+pcre2_general_context_copy(pcre2_general_context *gcontext)
+{
+pcre2_general_context *new =
+ gcontext->memctl.malloc(sizeof(pcre2_real_general_context),
+ gcontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, gcontext, sizeof(pcre2_real_general_context));
+return new;
+}
+
+
+PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION
+pcre2_compile_context_copy(pcre2_compile_context *ccontext)
+{
+pcre2_compile_context *new =
+ ccontext->memctl.malloc(sizeof(pcre2_real_compile_context),
+ ccontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, ccontext, sizeof(pcre2_real_compile_context));
+return new;
+}
+
+
+PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION
+pcre2_match_context_copy(pcre2_match_context *mcontext)
+{
+pcre2_match_context *new =
+ mcontext->memctl.malloc(sizeof(pcre2_real_match_context),
+ mcontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, mcontext, sizeof(pcre2_real_match_context));
+return new;
+}
+
+
+
+/*************************************************
+* Context free functions *
+*************************************************/
+
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_general_context_free(pcre2_general_context *gcontext)
+{
+if (gcontext != NULL)
+ gcontext->memctl.free(gcontext, gcontext->memctl.memory_data);
+}
+
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_compile_context_free(pcre2_compile_context *ccontext)
+{
+if (ccontext != NULL)
+ ccontext->memctl.free(ccontext, ccontext->memctl.memory_data);
+}
+
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_match_context_free(pcre2_match_context *mcontext)
+{
+if (mcontext != NULL)
+ mcontext->memctl.free(mcontext, mcontext->memctl.memory_data);
+}
+
+
+
+
+/*************************************************
+* Set values in contexts *
+*************************************************/
+
+/* All these functions return 0 for success or PCRE2_ERROR_BADDATA if invalid
+data is given. Only some of the functions are able to test the validity of the
+data. */
+
+
+/* ------------ Compile contexts ------------ */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_character_tables(pcre2_compile_context *ccontext,
+ const unsigned char *tables)
+{
+ccontext->tables = tables;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_bsr(pcre2_compile_context *ccontext, uint32_t value)
+{
+switch(value)
+ {
+ case PCRE2_BSR_ANYCRLF:
+ case PCRE2_BSR_UNICODE:
+ ccontext->bsr_convention = value;
+ return 0;
+
+ default:
+ return PCRE2_ERROR_BADDATA;
+ }
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_max_pattern_length(pcre2_compile_context *ccontext, PCRE2_SIZE length)
+{
+ccontext->max_pattern_length = length;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_newline(pcre2_compile_context *ccontext, uint32_t newline)
+{
+switch(newline)
+ {
+ case PCRE2_NEWLINE_CR:
+ case PCRE2_NEWLINE_LF:
+ case PCRE2_NEWLINE_CRLF:
+ case PCRE2_NEWLINE_ANY:
+ case PCRE2_NEWLINE_ANYCRLF:
+ ccontext->newline_convention = newline;
+ return 0;
+
+ default:
+ return PCRE2_ERROR_BADDATA;
+ }
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_parens_nest_limit(pcre2_compile_context *ccontext, uint32_t limit)
+{
+ccontext->parens_nest_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_compile_recursion_guard(pcre2_compile_context *ccontext,
+ int (*guard)(uint32_t, void *), void *user_data)
+{
+ccontext->stack_guard = guard;
+ccontext->stack_guard_data = user_data;
+return 0;
+}
+
+
+/* ------------ Match contexts ------------ */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_callout(pcre2_match_context *mcontext,
+ int (*callout)(pcre2_callout_block *, void *), void *callout_data)
+{
+mcontext->callout = callout;
+mcontext->callout_data = callout_data;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_match_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+mcontext->match_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_offset_limit(pcre2_match_context *mcontext, PCRE2_SIZE limit)
+{
+mcontext->offset_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_recursion_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+mcontext->recursion_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_recursion_memory_management(pcre2_match_context *mcontext,
+ void *(*mymalloc)(size_t, void *), void (*myfree)(void *, void *),
+ void *mydata)
+{
+#ifdef HEAP_MATCH_RECURSE
+mcontext->stack_memctl.malloc = mymalloc;
+mcontext->stack_memctl.free = myfree;
+mcontext->stack_memctl.memory_data = mydata;
+#else
+(void)mcontext;
+(void)mymalloc;
+(void)myfree;
+(void)mydata;
+#endif
+return 0;
+}
+
+/* End of pcre2_context.c */
diff --git a/src/3rdparty/pcre/pcre_dfa_exec.c b/src/3rdparty/pcre2/src/pcre2_dfa_match.c
index 170ce6a001..12b31b1b36 100644
--- a/src/3rdparty/pcre/pcre_dfa_exec.c
+++ b/src/3rdparty/pcre2/src/pcre2_dfa_match.c
@@ -3,11 +3,11 @@
*************************************************/
/* PCRE is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language (but see
-below for why this module is different).
+and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2014 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,8 @@ POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
-/* This module contains the external function pcre_dfa_exec(), which is an
+
+/* This module contains the external function pcre2_dfa_match(), which is an
alternative matching function that uses a sort of DFA algorithm (not a true
FSM). This is NOT Perl-compatible, but it has advantages in certain
applications. */
@@ -64,28 +65,27 @@ on the stack. It did give a 13% improvement with one specially constructed
pattern for certain subject strings, but on other strings and on many of the
simpler patterns in the test suite it did worse. The major problem, I think,
was the extra time to initialize the index. This had to be done for each call
-of internal_dfa_exec(). (The supplied patch used a static vector, initialized
+of internal_dfa_match(). (The supplied patch used a static vector, initialized
only once - I suspect this was the cause of the problems with the tests.)
Overall, I concluded that the gains in some cases did not outweigh the losses
in others, so I abandoned this code. */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#define NLBLOCK md /* Block containing newline information */
+#define NLBLOCK mb /* Block containing newline information */
#define PSSTART start_subject /* Field containing processed string start */
#define PSEND end_subject /* Field containing processed string end */
-#include "pcre_internal.h"
-
+#include "pcre2_internal.h"
-/* For use to indent debugging output */
-
-#define SP " "
+#define PUBLIC_DFA_MATCH_OPTIONS \
+ (PCRE2_ANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
+ PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \
+ PCRE2_PARTIAL_SOFT|PCRE2_DFA_SHORTEST|PCRE2_DFA_RESTART)
/*************************************************
@@ -112,7 +112,7 @@ small value. Non-zero values in the table are the offsets from the opcode where
the character is to be found. ***NOTE*** If the start of this table is
modified, the three tables that follow must also be modified. */
-static const pcre_uint8 coptable[] = {
+static const uint8_t coptable[] = {
0, /* End */
0, 0, 0, 0, 0, /* \A, \G, \K, \B, \b */
0, 0, 0, 0, 0, 0, /* \D, \d, \S, \s, \W, \w */
@@ -161,6 +161,7 @@ static const pcre_uint8 coptable[] = {
0, /* DNREFI */
0, /* RECURSE */
0, /* CALLOUT */
+ 0, /* CALLOUT_STR */
0, /* Alt */
0, /* Ket */
0, /* KetRmax */
@@ -176,12 +177,12 @@ static const pcre_uint8 coptable[] = {
0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */
0, 0, /* CREF, DNCREF */
0, 0, /* RREF, DNRREF */
- 0, /* DEF */
+ 0, 0, /* FALSE, TRUE */
0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */
0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */
0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */
0, 0, 0, 0, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */
- 0, 0 /* CLOSE, SKIPZERO */
+ 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */
};
/* This table identifies those opcodes that inspect a character. It is used to
@@ -189,7 +190,7 @@ remember the fact that a character could have been inspected when the end of
the subject is reached. ***NOTE*** If the start of this table is modified, the
two tables that follow must also be modified. */
-static const pcre_uint8 poptable[] = {
+static const uint8_t poptable[] = {
0, /* End */
0, 0, 0, 1, 1, /* \A, \G, \K, \B, \b */
1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */
@@ -233,6 +234,7 @@ static const pcre_uint8 poptable[] = {
0, /* DNREFI */
0, /* RECURSE */
0, /* CALLOUT */
+ 0, /* CALLOUT_STR */
0, /* Alt */
0, /* Ket */
0, /* KetRmax */
@@ -248,18 +250,18 @@ static const pcre_uint8 poptable[] = {
0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */
0, 0, /* CREF, DNCREF */
0, 0, /* RREF, DNRREF */
- 0, /* DEF */
+ 0, 0, /* FALSE, TRUE */
0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */
0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */
0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */
0, 0, 0, 0, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */
- 0, 0 /* CLOSE, SKIPZERO */
+ 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */
};
/* These 2 tables allow for compact code for testing for \D, \d, \S, \s, \W,
and \w */
-static const pcre_uint8 toptable1[] = {
+static const uint8_t toptable1[] = {
0, 0, 0, 0, 0, 0,
ctype_digit, ctype_digit,
ctype_space, ctype_space,
@@ -267,7 +269,7 @@ static const pcre_uint8 toptable1[] = {
0, 0 /* OP_ANY, OP_ALLANY */
};
-static const pcre_uint8 toptable2[] = {
+static const uint8_t toptable2[] = {
0, 0, 0, 0, 0, 0,
ctype_digit, 0,
ctype_space, 0,
@@ -282,7 +284,7 @@ entirely of ints because the working vector we are passed, and which we put
these structures in, is a vector of ints. */
typedef struct stateblock {
- int offset; /* Offset to opcode */
+ int offset; /* Offset to opcode (-ve has meaning) */
int count; /* Count for repeats */
int data; /* Some use extra data */
} stateblock;
@@ -290,39 +292,9 @@ typedef struct stateblock {
#define INTS_PER_STATEBLOCK (int)(sizeof(stateblock)/sizeof(int))
-#ifdef PCRE_DEBUG
-/*************************************************
-* Print character string *
-*************************************************/
-
-/* Character string printing function for debugging.
-
-Arguments:
- p points to string
- length number of bytes
- f where to print
-
-Returns: nothing
-*/
-
-static void
-pchars(const pcre_uchar *p, int length, FILE *f)
-{
-pcre_uint32 c;
-while (length-- > 0)
- {
- if (isprint(c = *(p++)))
- fprintf(f, "%c", c);
- else
- fprintf(f, "\\x{%02x}", c);
- }
-}
-#endif
-
-
/*************************************************
-* Execute a Regular Expression - DFA engine *
+* Match a Regular Expression - DFA engine *
*************************************************/
/* This internal function applies a compiled pattern to a subject string,
@@ -331,7 +303,7 @@ external one, possibly multiple times if the pattern is not anchored. The
function calls itself recursively for some kinds of subpattern.
Arguments:
- md the match_data block with fixed information
+ mb the match_data block with fixed information
this_start_code the opening bracket of this subexpression's code
current_subject where we currently are in the subject string
start_offset start offset in the subject string
@@ -355,9 +327,8 @@ for the current character, one for the following character). */
next_active_state->offset = (x); \
next_active_state->count = (y); \
next_active_state++; \
- DPRINTF(("%.*sADD_ACTIVE(%d,%d)\n", rlevel*2-2, SP, (x), (y))); \
} \
- else return PCRE_ERROR_DFA_WSSIZE
+ else return PCRE2_ERROR_DFA_WSSIZE
#define ADD_ACTIVE_DATA(x,y,z) \
if (active_count++ < wscount) \
@@ -366,9 +337,8 @@ for the current character, one for the following character). */
next_active_state->count = (y); \
next_active_state->data = (z); \
next_active_state++; \
- DPRINTF(("%.*sADD_ACTIVE_DATA(%d,%d,%d)\n", rlevel*2-2, SP, (x), (y), (z))); \
} \
- else return PCRE_ERROR_DFA_WSSIZE
+ else return PCRE2_ERROR_DFA_WSSIZE
#define ADD_NEW(x,y) \
if (new_count++ < wscount) \
@@ -376,9 +346,8 @@ for the current character, one for the following character). */
next_new_state->offset = (x); \
next_new_state->count = (y); \
next_new_state++; \
- DPRINTF(("%.*sADD_NEW(%d,%d)\n", rlevel*2-2, SP, (x), (y))); \
} \
- else return PCRE_ERROR_DFA_WSSIZE
+ else return PCRE2_ERROR_DFA_WSSIZE
#define ADD_NEW_DATA(x,y,z) \
if (new_count++ < wscount) \
@@ -387,21 +356,19 @@ for the current character, one for the following character). */
next_new_state->count = (y); \
next_new_state->data = (z); \
next_new_state++; \
- DPRINTF(("%.*sADD_NEW_DATA(%d,%d,%d) line %d\n", rlevel*2-2, SP, \
- (x), (y), (z), __LINE__)); \
} \
- else return PCRE_ERROR_DFA_WSSIZE
+ else return PCRE2_ERROR_DFA_WSSIZE
/* And now, here is the code */
static int
-internal_dfa_exec(
- dfa_match_data *md,
- const pcre_uchar *this_start_code,
- const pcre_uchar *current_subject,
- int start_offset,
- int *offsets,
- int offsetcount,
+internal_dfa_match(
+ dfa_match_block *mb,
+ PCRE2_SPTR this_start_code,
+ PCRE2_SPTR current_subject,
+ PCRE2_SIZE start_offset,
+ PCRE2_SIZE *offsets,
+ uint32_t offsetcount,
int *workspace,
int wscount,
int rlevel)
@@ -409,23 +376,24 @@ internal_dfa_exec(
stateblock *active_states, *new_states, *temp_states;
stateblock *next_active_state, *next_new_state;
-const pcre_uint8 *ctypes, *lcc, *fcc;
-const pcre_uchar *ptr;
-const pcre_uchar *end_code, *first_op;
+const uint8_t *ctypes, *lcc, *fcc;
+PCRE2_SPTR ptr;
+PCRE2_SPTR end_code;
+PCRE2_SPTR first_op;
dfa_recursion_info new_recursive;
int active_count, new_count, match_count;
-/* Some fields in the md block are frequently referenced, so we load them into
+/* Some fields in the mb block are frequently referenced, so we load them into
independent variables in the hope that this will perform better. */
-const pcre_uchar *start_subject = md->start_subject;
-const pcre_uchar *end_subject = md->end_subject;
-const pcre_uchar *start_code = md->start_code;
+PCRE2_SPTR start_subject = mb->start_subject;
+PCRE2_SPTR end_subject = mb->end_subject;
+PCRE2_SPTR start_code = mb->start_code;
-#ifdef SUPPORT_UTF
-BOOL utf = (md->poptions & PCRE_UTF8) != 0;
+#ifdef SUPPORT_UNICODE
+BOOL utf = (mb->poptions & PCRE2_UTF) != 0;
#else
BOOL utf = FALSE;
#endif
@@ -433,21 +401,17 @@ BOOL utf = FALSE;
BOOL reset_could_continue = FALSE;
rlevel++;
-offsetcount &= (-2);
+offsetcount &= (uint32_t)(-2); /* Round down */
wscount -= 2;
wscount = (wscount - (wscount % (INTS_PER_STATEBLOCK * 2))) /
(2 * INTS_PER_STATEBLOCK);
-DPRINTF(("\n%.*s---------------------\n"
- "%.*sCall to internal_dfa_exec f=%d\n",
- rlevel*2-2, SP, rlevel*2-2, SP, rlevel));
+ctypes = mb->tables + ctypes_offset;
+lcc = mb->tables + lcc_offset;
+fcc = mb->tables + fcc_offset;
-ctypes = md->tables + ctypes_offset;
-lcc = md->tables + lcc_offset;
-fcc = md->tables + fcc_offset;
-
-match_count = PCRE_ERROR_NOMATCH; /* A negative number */
+match_count = PCRE2_ERROR_NOMATCH; /* A negative number */
active_states = (stateblock *)(workspace + 2);
next_new_state = new_states = active_states + wscount;
@@ -469,13 +433,13 @@ move back, and set up each alternative appropriately. */
if (*first_op == OP_REVERSE)
{
- int max_back = 0;
- int gone_back;
+ size_t max_back = 0;
+ size_t gone_back;
end_code = this_start_code;
do
{
- int back = GET(end_code, 2+LINK_SIZE);
+ size_t back = (size_t)GET(end_code, 2+LINK_SIZE);
if (back > max_back) max_back = back;
end_code += GET(end_code, 1);
}
@@ -484,7 +448,7 @@ if (*first_op == OP_REVERSE)
/* If we can't go back the amount required for the longest lookbehind
pattern, go back as far as we can; some alternatives may still be viable. */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
/* In character mode we have to step back character by character */
if (utf)
@@ -502,26 +466,26 @@ if (*first_op == OP_REVERSE)
/* In byte-mode we can do this quickly. */
{
- gone_back = (current_subject - max_back < start_subject)?
- (int)(current_subject - start_subject) : max_back;
+ size_t current_offset = (size_t)(current_subject - start_subject);
+ gone_back = (current_offset < max_back)? current_offset : max_back;
current_subject -= gone_back;
}
/* Save the earliest consulted character */
- if (current_subject < md->start_used_ptr)
- md->start_used_ptr = current_subject;
+ if (current_subject < mb->start_used_ptr)
+ mb->start_used_ptr = current_subject;
/* Now we can process the individual branches. */
end_code = this_start_code;
do
{
- int back = GET(end_code, 2+LINK_SIZE);
+ size_t back = (size_t)GET(end_code, 2+LINK_SIZE);
if (back <= gone_back)
{
int bstate = (int)(end_code - start_code + 2 + 2*LINK_SIZE);
- ADD_NEW_DATA(-bstate, 0, gone_back - back);
+ ADD_NEW_DATA(-bstate, 0, (int)(gone_back - back));
}
end_code += GET(end_code, 1);
}
@@ -540,12 +504,12 @@ else
/* Restarting */
- if (rlevel == 1 && (md->moptions & PCRE_DFA_RESTART) != 0)
+ if (rlevel == 1 && (mb->moptions & PCRE2_DFA_RESTART) != 0)
{
do { end_code += GET(end_code, 1); } while (*end_code == OP_ALT);
new_count = workspace[1];
if (!workspace[0])
- memcpy(new_states, active_states, new_count * sizeof(stateblock));
+ memcpy(new_states, active_states, (size_t)new_count * sizeof(stateblock));
}
/* Not restarting */
@@ -568,8 +532,6 @@ else
workspace[0] = 0; /* Bit indicating which vector is current */
-DPRINTF(("%.*sEnd state = %d\n", rlevel*2-2, SP, (int)(end_code - start_code)));
-
/* Loop for scanning the subject */
ptr = current_subject;
@@ -577,12 +539,14 @@ for (;;)
{
int i, j;
int clen, dlen;
- pcre_uint32 c, d;
+ uint32_t c, d;
int forced_fail = 0;
BOOL partial_newline = FALSE;
BOOL could_continue = reset_could_continue;
reset_could_continue = FALSE;
+ if (ptr > mb->last_used_ptr) mb->last_used_ptr = ptr;
+
/* Make the new state list into the active state list and empty the
new state list. */
@@ -595,17 +559,6 @@ for (;;)
workspace[0] ^= 1; /* Remember for the restarting feature */
workspace[1] = active_count;
-#ifdef PCRE_DEBUG
- printf("%.*sNext character: rest of subject = \"", rlevel*2-2, SP);
- pchars(ptr, STRLEN_UC(ptr), stdout);
- printf("\"\n");
-
- printf("%.*sActive states: ", rlevel*2-2, SP);
- for (i = 0; i < active_count; i++)
- printf("%d/%d ", active_states[i].offset, active_states[i].count);
- printf("\n");
-#endif
-
/* Set the pointers for adding new states */
next_active_state = active_states + active_count;
@@ -618,11 +571,11 @@ for (;;)
if (ptr < end_subject)
{
clen = 1; /* Number of data items in the character */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
GETCHARLENTEST(c, ptr, clen);
#else
c = *ptr;
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
}
else
{
@@ -639,18 +592,12 @@ for (;;)
{
stateblock *current_state = active_states + i;
BOOL caseless = FALSE;
- const pcre_uchar *code;
+ PCRE2_SPTR code;
+ uint32_t codevalue;
int state_offset = current_state->offset;
- int codevalue, rrc;
+ int rrc;
int count;
-#ifdef PCRE_DEBUG
- printf ("%.*sProcessing state %d c=", rlevel*2-2, SP, state_offset);
- if (clen == 0) printf("EOL\n");
- else if (c > 32 && c < 127) printf("'%c'\n", c);
- else printf("0x%02x\n", c);
-#endif
-
/* A negative offset is a special case meaning "hold off going to this
(negated) state until the number of characters in the data field have
been skipped". If the could_continue flag was passed over from a previous
@@ -660,7 +607,6 @@ for (;;)
{
if (current_state->data > 0)
{
- DPRINTF(("%.*sSkipping this character\n", rlevel*2-2, SP));
ADD_NEW_DATA(state_offset, current_state->count,
current_state->data - 1);
if (could_continue) reset_could_continue = TRUE;
@@ -680,10 +626,7 @@ for (;;)
{
if (active_states[j].offset == state_offset &&
active_states[j].count == current_state->count)
- {
- DPRINTF(("%.*sDuplicate state: skipped\n", rlevel*2-2, SP));
goto NEXT_ACTIVE_STATE;
- }
}
/* The state offset is the offset to the opcode */
@@ -711,15 +654,15 @@ for (;;)
if (coptable[codevalue] > 0)
{
dlen = 1;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf) { GETCHARLEN(d, (code + coptable[codevalue]), dlen); } else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
d = code[coptable[codevalue]];
if (codevalue >= OP_TYPESTAR)
{
switch(d)
{
- case OP_ANYBYTE: return PCRE_ERROR_DFA_UITEM;
+ case OP_ANYBYTE: return PCRE2_ERROR_DFA_UITEM;
case OP_NOTPROP:
case OP_PROP: codevalue += OP_PROP_EXTRA; break;
case OP_ANYNL: codevalue += OP_ANYNL_EXTRA; break;
@@ -764,7 +707,7 @@ for (;;)
using recursive calls. Thus, it never adds any new states.
At the end of the (sub)pattern, unless we have an empty string and
- PCRE_NOTEMPTY is set, or PCRE_NOTEMPTY_ATSTART is set and we are at the
+ PCRE2_NOTEMPTY is set, or PCRE2_NOTEMPTY_ATSTART is set and we are at the
start of the subject, save the match data, shifting up all previous
matches so we always have the longest first. */
@@ -777,35 +720,28 @@ for (;;)
ADD_ACTIVE(state_offset + 1 + LINK_SIZE, 0);
if (codevalue != OP_KET)
{
- ADD_ACTIVE(state_offset - GET(code, 1), 0);
+ ADD_ACTIVE(state_offset - (int)GET(code, 1), 0);
}
}
else
{
if (ptr > current_subject ||
- ((md->moptions & PCRE_NOTEMPTY) == 0 &&
- ((md->moptions & PCRE_NOTEMPTY_ATSTART) == 0 ||
- current_subject > start_subject + md->start_offset)))
+ ((mb->moptions & PCRE2_NOTEMPTY) == 0 &&
+ ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) == 0 ||
+ current_subject > start_subject + mb->start_offset)))
{
if (match_count < 0) match_count = (offsetcount >= 2)? 1 : 0;
- else if (match_count > 0 && ++match_count * 2 > offsetcount)
+ else if (match_count > 0 && ++match_count * 2 > (int)offsetcount)
match_count = 0;
- count = ((match_count == 0)? offsetcount : match_count * 2) - 2;
- if (count > 0) memmove(offsets + 2, offsets, count * sizeof(int));
+ count = ((match_count == 0)? (int)offsetcount : match_count * 2) - 2;
+ if (count > 0) memmove(offsets + 2, offsets,
+ (size_t)count * sizeof(PCRE2_SIZE));
if (offsetcount >= 2)
{
- offsets[0] = (int)(current_subject - start_subject);
- offsets[1] = (int)(ptr - start_subject);
- DPRINTF(("%.*sSet matched string = \"%.*s\"\n", rlevel*2-2, SP,
- offsets[1] - offsets[0], (char *)current_subject));
- }
- if ((md->moptions & PCRE_DFA_SHORTEST) != 0)
- {
- DPRINTF(("%.*sEnd of internal_dfa_exec %d: returning %d\n"
- "%.*s---------------------\n\n", rlevel*2-2, SP, rlevel,
- match_count, rlevel*2-2, SP));
- return match_count;
+ offsets[0] = (PCRE2_SIZE)(current_subject - start_subject);
+ offsets[1] = (PCRE2_SIZE)(ptr - start_subject);
}
+ if ((mb->moptions & PCRE2_DFA_SHORTEST) != 0) return match_count;
}
}
break;
@@ -861,14 +797,15 @@ for (;;)
/*-----------------------------------------------------------------*/
case OP_CIRC:
- if (ptr == start_subject && (md->moptions & PCRE_NOTBOL) == 0)
+ if (ptr == start_subject && (mb->moptions & PCRE2_NOTBOL) == 0)
{ ADD_ACTIVE(state_offset + 1, 0); }
break;
/*-----------------------------------------------------------------*/
case OP_CIRCM:
- if ((ptr == start_subject && (md->moptions & PCRE_NOTBOL) == 0) ||
- (ptr != end_subject && WAS_NEWLINE(ptr)))
+ if ((ptr == start_subject && (mb->moptions & PCRE2_NOTBOL) == 0) ||
+ ((ptr != end_subject || (mb->poptions & PCRE2_ALT_CIRCUMFLEX) != 0 )
+ && WAS_NEWLINE(ptr)))
{ ADD_ACTIVE(state_offset + 1, 0); }
break;
@@ -876,7 +813,7 @@ for (;;)
case OP_EOD:
if (ptr >= end_subject)
{
- if ((md->moptions & PCRE_PARTIAL_HARD) != 0)
+ if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
could_continue = TRUE;
else { ADD_ACTIVE(state_offset + 1, 0); }
}
@@ -903,8 +840,8 @@ for (;;)
case OP_ANY:
if (clen > 0 && !IS_NEWLINE(ptr))
{
- if (ptr + 1 >= md->end_subject &&
- (md->moptions & (PCRE_PARTIAL_HARD)) != 0 &&
+ if (ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
@@ -926,30 +863,30 @@ for (;;)
/*-----------------------------------------------------------------*/
case OP_EODN:
- if (clen == 0 && (md->moptions & PCRE_PARTIAL_HARD) != 0)
+ if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
could_continue = TRUE;
- else if (clen == 0 || (IS_NEWLINE(ptr) && ptr == end_subject - md->nllen))
+ else if (clen == 0 || (IS_NEWLINE(ptr) && ptr == end_subject - mb->nllen))
{ ADD_ACTIVE(state_offset + 1, 0); }
break;
/*-----------------------------------------------------------------*/
case OP_DOLL:
- if ((md->moptions & PCRE_NOTEOL) == 0)
+ if ((mb->moptions & PCRE2_NOTEOL) == 0)
{
- if (clen == 0 && (md->moptions & PCRE_PARTIAL_HARD) != 0)
+ if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
could_continue = TRUE;
else if (clen == 0 ||
- ((md->poptions & PCRE_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr) &&
- (ptr == end_subject - md->nllen)
+ ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr) &&
+ (ptr == end_subject - mb->nllen)
))
{ ADD_ACTIVE(state_offset + 1, 0); }
- else if (ptr + 1 >= md->end_subject &&
- (md->moptions & (PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT)) != 0 &&
+ else if (ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
{
- if ((md->moptions & PCRE_PARTIAL_HARD) != 0)
+ if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
{
reset_could_continue = TRUE;
ADD_NEW_DATA(-(state_offset + 1), 0, 1);
@@ -961,20 +898,20 @@ for (;;)
/*-----------------------------------------------------------------*/
case OP_DOLLM:
- if ((md->moptions & PCRE_NOTEOL) == 0)
+ if ((mb->moptions & PCRE2_NOTEOL) == 0)
{
- if (clen == 0 && (md->moptions & PCRE_PARTIAL_HARD) != 0)
+ if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
could_continue = TRUE;
else if (clen == 0 ||
- ((md->poptions & PCRE_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr)))
+ ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr)))
{ ADD_ACTIVE(state_offset + 1, 0); }
- else if (ptr + 1 >= md->end_subject &&
- (md->moptions & (PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT)) != 0 &&
+ else if (ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
{
- if ((md->moptions & PCRE_PARTIAL_HARD) != 0)
+ if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
{
reset_could_continue = TRUE;
ADD_NEW_DATA(-(state_offset + 1), 0, 1);
@@ -1013,18 +950,18 @@ for (;;)
if (ptr > start_subject)
{
- const pcre_uchar *temp = ptr - 1;
- if (temp < md->start_used_ptr) md->start_used_ptr = temp;
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+ PCRE2_SPTR temp = ptr - 1;
+ if (temp < mb->start_used_ptr) mb->start_used_ptr = temp;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (utf) { BACKCHAR(temp); }
#endif
GETCHARTEST(d, temp);
-#ifdef SUPPORT_UCP
- if ((md->poptions & PCRE_UCP) != 0)
+#ifdef SUPPORT_UNICODE
+ if ((mb->poptions & PCRE2_UCP) != 0)
{
if (d == '_') left_word = TRUE; else
{
- int cat = UCD_CATEGORY(d);
+ uint32_t cat = UCD_CATEGORY(d);
left_word = (cat == ucp_L || cat == ucp_N);
}
}
@@ -1036,12 +973,20 @@ for (;;)
if (clen > 0)
{
-#ifdef SUPPORT_UCP
- if ((md->poptions & PCRE_UCP) != 0)
+ if (ptr >= mb->last_used_ptr)
+ {
+ PCRE2_SPTR temp = ptr + 1;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (utf) { FORWARDCHARTEST(temp, mb->end_subject); }
+#endif
+ mb->last_used_ptr = temp;
+ }
+#ifdef SUPPORT_UNICODE
+ if ((mb->poptions & PCRE2_UCP) != 0)
{
if (c == '_') right_word = TRUE; else
{
- int cat = UCD_CATEGORY(c);
+ uint32_t cat = UCD_CATEGORY(c);
right_word = (cat == ucp_L || cat == ucp_N);
}
}
@@ -1062,13 +1007,13 @@ for (;;)
if the support is in the binary; otherwise a compile-time error occurs.
*/
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
case OP_PROP:
case OP_NOTPROP:
if (clen > 0)
{
BOOL OK;
- const pcre_uint32 *cp;
+ const uint32_t *cp;
const ucd_record * prop = GET_UCD(c);
switch(code[1])
{
@@ -1167,8 +1112,8 @@ for (;;)
if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
if (clen > 0)
{
- if (d == OP_ANY && ptr + 1 >= md->end_subject &&
- (md->moptions & (PCRE_PARTIAL_HARD)) != 0 &&
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
@@ -1198,8 +1143,8 @@ for (;;)
ADD_ACTIVE(state_offset + 2, 0);
if (clen > 0)
{
- if (d == OP_ANY && ptr + 1 >= md->end_subject &&
- (md->moptions & (PCRE_PARTIAL_HARD)) != 0 &&
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
@@ -1228,8 +1173,8 @@ for (;;)
ADD_ACTIVE(state_offset + 2, 0);
if (clen > 0)
{
- if (d == OP_ANY && ptr + 1 >= md->end_subject &&
- (md->moptions & (PCRE_PARTIAL_HARD)) != 0 &&
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
@@ -1256,8 +1201,8 @@ for (;;)
count = current_state->count; /* Number already matched */
if (clen > 0)
{
- if (d == OP_ANY && ptr + 1 >= md->end_subject &&
- (md->moptions & (PCRE_PARTIAL_HARD)) != 0 &&
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
@@ -1285,8 +1230,8 @@ for (;;)
count = current_state->count; /* Number already matched */
if (clen > 0)
{
- if (d == OP_ANY && ptr + 1 >= md->end_subject &&
- (md->moptions & (PCRE_PARTIAL_HARD)) != 0 &&
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
@@ -1317,7 +1262,7 @@ for (;;)
argument. It keeps the code above fast for the other cases. The argument
is in the d variable. */
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
case OP_PROP_EXTRA + OP_TYPEPLUS:
case OP_PROP_EXTRA + OP_TYPEMINPLUS:
case OP_PROP_EXTRA + OP_TYPEPOSPLUS:
@@ -1326,7 +1271,7 @@ for (;;)
if (clen > 0)
{
BOOL OK;
- const pcre_uint32 *cp;
+ const uint32_t *cp;
const ucd_record * prop = GET_UCD(c);
switch(code[2])
{
@@ -1426,8 +1371,8 @@ for (;;)
if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
if (clen > 0)
{
- int lgb, rgb;
- const pcre_uchar *nptr = ptr + clen;
+ uint32_t lgb, rgb;
+ PCRE2_SPTR nptr = ptr + clen;
int ncount = 0;
if (count > 0 && codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS)
{
@@ -1440,7 +1385,7 @@ for (;;)
dlen = 1;
if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); }
rgb = UCD_GRAPHBREAK(d);
- if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break;
+ if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break;
ncount++;
lgb = rgb;
nptr += dlen;
@@ -1469,7 +1414,7 @@ for (;;)
case 0x2028:
case 0x2029:
#endif /* Not EBCDIC */
- if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break;
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
goto ANYNL01;
case CHAR_CR:
@@ -1560,7 +1505,7 @@ for (;;)
break;
/*-----------------------------------------------------------------*/
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
case OP_PROP_EXTRA + OP_TYPEQUERY:
case OP_PROP_EXTRA + OP_TYPEMINQUERY:
case OP_PROP_EXTRA + OP_TYPEPOSQUERY:
@@ -1578,7 +1523,7 @@ for (;;)
if (clen > 0)
{
BOOL OK;
- const pcre_uint32 *cp;
+ const uint32_t *cp;
const ucd_record * prop = GET_UCD(c);
switch(code[2])
{
@@ -1687,8 +1632,8 @@ for (;;)
ADD_ACTIVE(state_offset + 2, 0);
if (clen > 0)
{
- int lgb, rgb;
- const pcre_uchar *nptr = ptr + clen;
+ uint32_t lgb, rgb;
+ PCRE2_SPTR nptr = ptr + clen;
int ncount = 0;
if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR ||
codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY)
@@ -1702,7 +1647,7 @@ for (;;)
dlen = 1;
if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); }
rgb = UCD_GRAPHBREAK(d);
- if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break;
+ if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break;
ncount++;
lgb = rgb;
nptr += dlen;
@@ -1738,7 +1683,7 @@ for (;;)
case 0x2028:
case 0x2029:
#endif /* Not EBCDIC */
- if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break;
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
goto ANYNL02;
case CHAR_CR:
@@ -1844,7 +1789,7 @@ for (;;)
break;
/*-----------------------------------------------------------------*/
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
case OP_PROP_EXTRA + OP_TYPEEXACT:
case OP_PROP_EXTRA + OP_TYPEUPTO:
case OP_PROP_EXTRA + OP_TYPEMINUPTO:
@@ -1855,7 +1800,7 @@ for (;;)
if (clen > 0)
{
BOOL OK;
- const pcre_uint32 *cp;
+ const uint32_t *cp;
const ucd_record * prop = GET_UCD(c);
switch(code[1 + IMM2_SIZE + 1])
{
@@ -1959,8 +1904,8 @@ for (;;)
count = current_state->count; /* Number already matched */
if (clen > 0)
{
- int lgb, rgb;
- const pcre_uchar *nptr = ptr + clen;
+ uint32_t lgb, rgb;
+ PCRE2_SPTR nptr = ptr + clen;
int ncount = 0;
if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO)
{
@@ -1973,12 +1918,12 @@ for (;;)
dlen = 1;
if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); }
rgb = UCD_GRAPHBREAK(d);
- if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break;
+ if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break;
ncount++;
lgb = rgb;
nptr += dlen;
}
- if (nptr >= end_subject && (md->moptions & PCRE_PARTIAL_HARD) != 0)
+ if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
reset_could_continue = TRUE;
if (++count >= (int)GET2(code, 1))
{ ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); }
@@ -2008,7 +1953,7 @@ for (;;)
case 0x2028:
case 0x2029:
#endif /* Not EBCDIC */
- if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break;
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
goto ANYNL03;
case CHAR_CR:
@@ -2122,7 +2067,7 @@ for (;;)
case OP_CHARI:
if (clen == 0) break;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
if (c == d) { ADD_NEW(state_offset + dlen + 1, 0); } else
@@ -2131,19 +2076,12 @@ for (;;)
if (c < 128)
othercase = fcc[c];
else
- /* If we have Unicode property support, we can use it to test the
- other case of the character. */
-#ifdef SUPPORT_UCP
othercase = UCD_OTHERCASE(c);
-#else
- othercase = NOTACHAR;
-#endif
-
if (d == othercase) { ADD_NEW(state_offset + dlen + 1, 0); }
}
}
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
/* Not UTF mode */
{
if (TABLE_GET(c, lcc, c) == TABLE_GET(d, lcc, d))
@@ -2152,7 +2090,7 @@ for (;;)
break;
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
/*-----------------------------------------------------------------*/
/* This is a tricky one because it can match more than one character.
Find out how many characters to skip, and then set up a negative state
@@ -2161,8 +2099,8 @@ for (;;)
case OP_EXTUNI:
if (clen > 0)
{
- int lgb, rgb;
- const pcre_uchar *nptr = ptr + clen;
+ uint32_t lgb, rgb;
+ PCRE2_SPTR nptr = ptr + clen;
int ncount = 0;
lgb = UCD_GRAPHBREAK(c);
while (nptr < end_subject)
@@ -2170,12 +2108,12 @@ for (;;)
dlen = 1;
if (!utf) d = *nptr; else { GETCHARLEN(d, nptr, dlen); }
rgb = UCD_GRAPHBREAK(d);
- if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break;
+ if ((PRIV(ucp_gbtable)[lgb] & (1u << rgb)) == 0) break;
ncount++;
lgb = rgb;
nptr += dlen;
}
- if (nptr >= end_subject && (md->moptions & PCRE_PARTIAL_HARD) != 0)
+ if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
reset_could_continue = TRUE;
ADD_NEW_DATA(-(state_offset + 1), 0, ncount);
}
@@ -2197,7 +2135,7 @@ for (;;)
case 0x2028:
case 0x2029:
#endif /* Not EBCDIC */
- if ((md->moptions & PCRE_BSR_ANYCRLF) != 0) break;
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
case CHAR_LF:
ADD_NEW(state_offset + 1, 0);
@@ -2207,7 +2145,7 @@ for (;;)
if (ptr + 1 >= end_subject)
{
ADD_NEW(state_offset + 1, 0);
- if ((md->moptions & PCRE_PARTIAL_HARD) != 0)
+ if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
reset_could_continue = TRUE;
}
else if (UCHAR21TEST(ptr + 1) == CHAR_LF)
@@ -2288,15 +2226,11 @@ for (;;)
if (clen > 0)
{
unsigned int otherd;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && d >= 128)
- {
-#ifdef SUPPORT_UCP
otherd = UCD_OTHERCASE(d);
-#endif /* SUPPORT_UCP */
- }
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
otherd = TABLE_GET(d, fcc, d);
if (c != d && c != otherd)
{ ADD_NEW(state_offset + dlen + 1, 0); }
@@ -2324,18 +2258,14 @@ for (;;)
if (count > 0) { ADD_ACTIVE(state_offset + dlen + 1, 0); }
if (clen > 0)
{
- pcre_uint32 otherd = NOTACHAR;
+ uint32_t otherd = NOTACHAR;
if (caseless)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && d >= 128)
- {
-#ifdef SUPPORT_UCP
otherd = UCD_OTHERCASE(d);
-#endif /* SUPPORT_UCP */
- }
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
otherd = TABLE_GET(d, fcc, d);
}
if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
@@ -2371,18 +2301,14 @@ for (;;)
ADD_ACTIVE(state_offset + dlen + 1, 0);
if (clen > 0)
{
- pcre_uint32 otherd = NOTACHAR;
+ uint32_t otherd = NOTACHAR;
if (caseless)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && d >= 128)
- {
-#ifdef SUPPORT_UCP
otherd = UCD_OTHERCASE(d);
-#endif /* SUPPORT_UCP */
- }
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
otherd = TABLE_GET(d, fcc, d);
}
if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
@@ -2416,18 +2342,14 @@ for (;;)
ADD_ACTIVE(state_offset + dlen + 1, 0);
if (clen > 0)
{
- pcre_uint32 otherd = NOTACHAR;
+ uint32_t otherd = NOTACHAR;
if (caseless)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && d >= 128)
- {
-#ifdef SUPPORT_UCP
otherd = UCD_OTHERCASE(d);
-#endif /* SUPPORT_UCP */
- }
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
otherd = TABLE_GET(d, fcc, d);
}
if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
@@ -2453,18 +2375,14 @@ for (;;)
count = current_state->count; /* Number already matched */
if (clen > 0)
{
- pcre_uint32 otherd = NOTACHAR;
+ uint32_t otherd = NOTACHAR;
if (caseless)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && d >= 128)
- {
-#ifdef SUPPORT_UCP
otherd = UCD_OTHERCASE(d);
-#endif /* SUPPORT_UCP */
- }
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
otherd = TABLE_GET(d, fcc, d);
}
if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
@@ -2497,18 +2415,14 @@ for (;;)
count = current_state->count; /* Number already matched */
if (clen > 0)
{
- pcre_uint32 otherd = NOTACHAR;
+ uint32_t otherd = NOTACHAR;
if (caseless)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && d >= 128)
- {
-#ifdef SUPPORT_UCP
otherd = UCD_OTHERCASE(d);
-#endif /* SUPPORT_UCP */
- }
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
otherd = TABLE_GET(d, fcc, d);
}
if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
@@ -2536,18 +2450,18 @@ for (;;)
{
BOOL isinclass = FALSE;
int next_state_offset;
- const pcre_uchar *ecode;
+ PCRE2_SPTR ecode;
/* For a simple class, there is always just a 32-byte table, and we
can set isinclass from it. */
if (codevalue != OP_XCLASS)
{
- ecode = code + 1 + (32 / sizeof(pcre_uchar));
+ ecode = code + 1 + (32 / sizeof(PCRE2_UCHAR));
if (clen > 0)
{
isinclass = (c > 255)? (codevalue == OP_NCLASS) :
- ((((pcre_uint8 *)(code + 1))[c/8] & (1 << (c&7))) != 0);
+ ((((uint8_t *)(code + 1))[c/8] & (1 << (c&7))) != 0);
}
}
@@ -2659,25 +2573,25 @@ for (;;)
case OP_ASSERTBACK:
case OP_ASSERTBACK_NOT:
{
+ PCRE2_SPTR endasscode = code + GET(code, 1);
+ PCRE2_SIZE local_offsets[2];
int rc;
- int local_offsets[2];
int local_workspace[1000];
- const pcre_uchar *endasscode = code + GET(code, 1);
while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
- rc = internal_dfa_exec(
- md, /* static match data */
+ rc = internal_dfa_match(
+ mb, /* static match data */
code, /* this subexpression's code */
ptr, /* where we currently are */
- (int)(ptr - start_subject), /* start offset */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
local_offsets, /* offset vector */
- sizeof(local_offsets)/sizeof(int), /* size of same */
+ sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
rlevel); /* function recursion level */
- if (rc == PCRE_ERROR_DFA_UITEM) return rc;
+ if (rc == PCRE2_ERROR_DFA_UITEM) return rc;
if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK))
{ ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); }
}
@@ -2687,44 +2601,59 @@ for (;;)
case OP_COND:
case OP_SCOND:
{
- int local_offsets[1000];
+ PCRE2_SIZE local_offsets[1000];
int local_workspace[1000];
- int codelink = GET(code, 1);
- int condcode;
+ int codelink = (int)GET(code, 1);
+ PCRE2_UCHAR condcode;
/* Because of the way auto-callout works during compile, a callout item
is inserted between OP_COND and an assertion condition. This does not
happen for the other conditions. */
- if (code[LINK_SIZE+1] == OP_CALLOUT)
+ if (code[LINK_SIZE + 1] == OP_CALLOUT
+ || code[LINK_SIZE + 1] == OP_CALLOUT_STR)
{
+ PCRE2_SIZE callout_length = (code[LINK_SIZE + 1] == OP_CALLOUT)?
+ (PCRE2_SIZE)PRIV(OP_lengths)[OP_CALLOUT] :
+ (PCRE2_SIZE)GET(code, 2 + 3*LINK_SIZE);
+
rrc = 0;
- if (PUBL(callout) != NULL)
+ if (mb->callout != NULL)
{
- PUBL(callout_block) cb;
- cb.version = 1; /* Version 1 of the callout block */
- cb.callout_number = code[LINK_SIZE+2];
- cb.offset_vector = offsets;
-#if defined COMPILE_PCRE8
- cb.subject = (PCRE_SPTR)start_subject;
-#elif defined COMPILE_PCRE16
- cb.subject = (PCRE_SPTR16)start_subject;
-#elif defined COMPILE_PCRE32
- cb.subject = (PCRE_SPTR32)start_subject;
-#endif
- cb.subject_length = (int)(end_subject - start_subject);
- cb.start_match = (int)(current_subject - start_subject);
- cb.current_position = (int)(ptr - start_subject);
- cb.pattern_position = GET(code, LINK_SIZE + 3);
- cb.next_item_length = GET(code, 3 + 2*LINK_SIZE);
+ pcre2_callout_block cb;
+ cb.version = 1;
cb.capture_top = 1;
- cb.capture_last = -1;
- cb.callout_data = md->callout_data;
+ cb.capture_last = 0;
+ cb.offset_vector = offsets;
cb.mark = NULL; /* No (*MARK) support */
- if ((rrc = (*PUBL(callout))(&cb)) < 0) return rrc; /* Abandon */
+ cb.subject = start_subject;
+ cb.subject_length = (PCRE2_SIZE)(end_subject - start_subject);
+ cb.start_match = (PCRE2_SIZE)(current_subject - start_subject);
+ cb.current_position = (PCRE2_SIZE)(ptr - start_subject);
+ cb.pattern_position = GET(code, LINK_SIZE + 2);
+ cb.next_item_length = GET(code, LINK_SIZE + 2 + LINK_SIZE);
+
+ if (code[LINK_SIZE + 1] == OP_CALLOUT)
+ {
+ cb.callout_number = code[2 + 3*LINK_SIZE];
+ cb.callout_string_offset = 0;
+ cb.callout_string = NULL;
+ cb.callout_string_length = 0;
+ }
+ else
+ {
+ cb.callout_number = 0;
+ cb.callout_string_offset = GET(code, 2 + 4*LINK_SIZE);
+ cb.callout_string = code + (2 + 5*LINK_SIZE) + 1;
+ cb.callout_string_length =
+ callout_length - (1 + 4*LINK_SIZE) - 2;
+ }
+
+ if ((rrc = (mb->callout)(&cb, mb->callout_data)) < 0)
+ return rrc; /* Abandon */
}
if (rrc > 0) break; /* Fail this thread */
- code += PRIV(OP_lengths)[OP_CALLOUT]; /* Skip callout data */
+ code += callout_length; /* Skip callout data */
}
condcode = code[LINK_SIZE+1];
@@ -2734,23 +2663,28 @@ for (;;)
if (condcode == OP_CREF || condcode == OP_DNCREF ||
condcode == OP_DNRREF)
- return PCRE_ERROR_DFA_UCOND;
+ return PCRE2_ERROR_DFA_UCOND;
/* The DEFINE condition is always false, and the assertion (?!) is
converted to OP_FAIL. */
- if (condcode == OP_DEF || condcode == OP_FAIL)
+ if (condcode == OP_FALSE || condcode == OP_FAIL)
{ ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
+ /* There is also an always-true condition */
+
+ else if (condcode == OP_TRUE)
+ { ADD_ACTIVE(state_offset + LINK_SIZE + 2 + IMM2_SIZE, 0); }
+
/* The only supported version of OP_RREF is for the value RREF_ANY,
which means "test if in any recursion". We can't test for specifically
recursed groups. */
else if (condcode == OP_RREF)
{
- int value = GET2(code, LINK_SIZE + 2);
- if (value != RREF_ANY) return PCRE_ERROR_DFA_UCOND;
- if (md->recursive != NULL)
+ unsigned int value = GET2(code, LINK_SIZE + 2);
+ if (value != RREF_ANY) return PCRE2_ERROR_DFA_UCOND;
+ if (mb->recursive != NULL)
{ ADD_ACTIVE(state_offset + LINK_SIZE + 2 + IMM2_SIZE, 0); }
else { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
}
@@ -2760,23 +2694,23 @@ for (;;)
else
{
int rc;
- const pcre_uchar *asscode = code + LINK_SIZE + 1;
- const pcre_uchar *endasscode = asscode + GET(asscode, 1);
+ PCRE2_SPTR asscode = code + LINK_SIZE + 1;
+ PCRE2_SPTR endasscode = asscode + GET(asscode, 1);
while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
- rc = internal_dfa_exec(
- md, /* fixed match data */
+ rc = internal_dfa_match(
+ mb, /* fixed match data */
asscode, /* this subexpression's code */
ptr, /* where we currently are */
- (int)(ptr - start_subject), /* start offset */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
local_offsets, /* offset vector */
- sizeof(local_offsets)/sizeof(int), /* size of same */
+ sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
rlevel); /* function recursion level */
- if (rc == PCRE_ERROR_DFA_UITEM) return rc;
+ if (rc == PCRE2_ERROR_DFA_UITEM) return rc;
if ((rc >= 0) ==
(condcode == OP_ASSERT || condcode == OP_ASSERTBACK))
{ ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); }
@@ -2790,50 +2724,45 @@ for (;;)
case OP_RECURSE:
{
dfa_recursion_info *ri;
- int local_offsets[1000];
+ PCRE2_SIZE local_offsets[1000];
int local_workspace[1000];
- const pcre_uchar *callpat = start_code + GET(code, 1);
- int recno = (callpat == md->start_code)? 0 :
+ PCRE2_SPTR callpat = start_code + GET(code, 1);
+ uint32_t recno = (callpat == mb->start_code)? 0 :
GET2(callpat, 1 + LINK_SIZE);
int rc;
- DPRINTF(("%.*sStarting regex recursion\n", rlevel*2-2, SP));
-
/* Check for repeating a recursion without advancing the subject
pointer. This should catch convoluted mutual recursions. (Some simple
cases are caught at compile time.) */
- for (ri = md->recursive; ri != NULL; ri = ri->prevrec)
+ for (ri = mb->recursive; ri != NULL; ri = ri->prevrec)
if (recno == ri->group_num && ptr == ri->subject_position)
- return PCRE_ERROR_RECURSELOOP;
+ return PCRE2_ERROR_RECURSELOOP;
/* Remember this recursion and where we started it so as to
catch infinite loops. */
new_recursive.group_num = recno;
new_recursive.subject_position = ptr;
- new_recursive.prevrec = md->recursive;
- md->recursive = &new_recursive;
+ new_recursive.prevrec = mb->recursive;
+ mb->recursive = &new_recursive;
- rc = internal_dfa_exec(
- md, /* fixed match data */
+ rc = internal_dfa_match(
+ mb, /* fixed match data */
callpat, /* this subexpression's code */
ptr, /* where we currently are */
- (int)(ptr - start_subject), /* start offset */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
local_offsets, /* offset vector */
- sizeof(local_offsets)/sizeof(int), /* size of same */
+ sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
rlevel); /* function recursion level */
- md->recursive = new_recursive.prevrec; /* Done this recursion */
-
- DPRINTF(("%.*sReturn from regex recursion: rc=%d\n", rlevel*2-2, SP,
- rc));
+ mb->recursive = new_recursive.prevrec; /* Done this recursion */
/* Ran out of internal offsets */
- if (rc == 0) return PCRE_ERROR_DFA_RECURSE;
+ if (rc == 0) return PCRE2_ERROR_DFA_RECURSE;
/* For each successful matched substring, set up the next state with a
count of characters to skip before trying it. Note that the count is in
@@ -2843,18 +2772,19 @@ for (;;)
{
for (rc = rc*2 - 2; rc >= 0; rc -= 2)
{
- int charcount = local_offsets[rc+1] - local_offsets[rc];
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+ PCRE2_SIZE charcount = local_offsets[rc+1] - local_offsets[rc];
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (utf)
{
- const pcre_uchar *p = start_subject + local_offsets[rc];
- const pcre_uchar *pp = start_subject + local_offsets[rc+1];
- while (p < pp) if (NOT_FIRSTCHAR(*p++)) charcount--;
+ PCRE2_SPTR p = start_subject + local_offsets[rc];
+ PCRE2_SPTR pp = start_subject + local_offsets[rc+1];
+ while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--;
}
#endif
if (charcount > 0)
{
- ADD_NEW_DATA(-(state_offset + LINK_SIZE + 1), 0, (charcount - 1));
+ ADD_NEW_DATA(-(state_offset + LINK_SIZE + 1), 0,
+ (int)(charcount - 1));
}
else
{
@@ -2862,7 +2792,7 @@ for (;;)
}
}
}
- else if (rc != PCRE_ERROR_NOMATCH) return rc;
+ else if (rc != PCRE2_ERROR_NOMATCH) return rc;
}
break;
@@ -2873,8 +2803,8 @@ for (;;)
case OP_SCBRAPOS:
case OP_BRAPOSZERO:
{
- int charcount, matched_count;
- const pcre_uchar *local_ptr = ptr;
+ PCRE2_SIZE charcount, matched_count;
+ PCRE2_SPTR local_ptr = ptr;
BOOL allow_zero;
if (codevalue == OP_BRAPOSZERO)
@@ -2889,16 +2819,16 @@ for (;;)
for (matched_count = 0;; matched_count++)
{
- int local_offsets[2];
+ PCRE2_SIZE local_offsets[2];
int local_workspace[1000];
- int rc = internal_dfa_exec(
- md, /* fixed match data */
+ int rc = internal_dfa_match(
+ mb, /* fixed match data */
code, /* this subexpression's code */
local_ptr, /* where we currently are */
- (int)(ptr - start_subject), /* start offset */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
local_offsets, /* offset vector */
- sizeof(local_offsets)/sizeof(int), /* size of same */
+ sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
rlevel); /* function recursion level */
@@ -2907,7 +2837,7 @@ for (;;)
if (rc < 0)
{
- if (rc != PCRE_ERROR_NOMATCH) return rc;
+ if (rc != PCRE2_ERROR_NOMATCH) return rc;
break;
}
@@ -2924,7 +2854,7 @@ for (;;)
if (matched_count > 0 || allow_zero)
{
- const pcre_uchar *end_subpattern = code;
+ PCRE2_SPTR end_subpattern = code;
int next_state_offset;
do { end_subpattern += GET(end_subpattern, 1); }
@@ -2945,13 +2875,13 @@ for (;;)
}
else
{
- const pcre_uchar *p = ptr;
- const pcre_uchar *pp = local_ptr;
- charcount = (int)(pp - p);
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
- if (utf) while (p < pp) if (NOT_FIRSTCHAR(*p++)) charcount--;
+ PCRE2_SPTR p = ptr;
+ PCRE2_SPTR pp = local_ptr;
+ charcount = (PCRE2_SIZE)(pp - p);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (utf) while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--;
#endif
- ADD_NEW_DATA(-next_state_offset, 0, (charcount - 1));
+ ADD_NEW_DATA(-next_state_offset, 0, (int)(charcount - 1));
}
}
}
@@ -2961,24 +2891,24 @@ for (;;)
case OP_ONCE:
case OP_ONCE_NC:
{
- int local_offsets[2];
+ PCRE2_SIZE local_offsets[2];
int local_workspace[1000];
- int rc = internal_dfa_exec(
- md, /* fixed match data */
+ int rc = internal_dfa_match(
+ mb, /* fixed match data */
code, /* this subexpression's code */
ptr, /* where we currently are */
- (int)(ptr - start_subject), /* start offset */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
local_offsets, /* offset vector */
- sizeof(local_offsets)/sizeof(int), /* size of same */
+ sizeof(local_offsets)/sizeof(PCRE2_SIZE), /* size of same */
local_workspace, /* workspace vector */
sizeof(local_workspace)/sizeof(int), /* size of same */
rlevel); /* function recursion level */
if (rc >= 0)
{
- const pcre_uchar *end_subpattern = code;
- int charcount = local_offsets[1] - local_offsets[0];
+ PCRE2_SPTR end_subpattern = code;
+ PCRE2_SIZE charcount = local_offsets[1] - local_offsets[0];
int next_state_offset, repeat_state_offset;
do { end_subpattern += GET(end_subpattern, 1); }
@@ -3030,20 +2960,20 @@ for (;;)
}
else
{
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (utf)
{
- const pcre_uchar *p = start_subject + local_offsets[0];
- const pcre_uchar *pp = start_subject + local_offsets[1];
- while (p < pp) if (NOT_FIRSTCHAR(*p++)) charcount--;
+ PCRE2_SPTR p = start_subject + local_offsets[0];
+ PCRE2_SPTR pp = start_subject + local_offsets[1];
+ while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--;
}
#endif
- ADD_NEW_DATA(-next_state_offset, 0, (charcount - 1));
+ ADD_NEW_DATA(-next_state_offset, 0, (int)(charcount - 1));
if (repeat_state_offset >= 0)
- { ADD_NEW_DATA(-repeat_state_offset, 0, (charcount - 1)); }
+ { ADD_NEW_DATA(-repeat_state_offset, 0, (int)(charcount - 1)); }
}
}
- else if (rc != PCRE_ERROR_NOMATCH) return rc;
+ else if (rc != PCRE2_ERROR_NOMATCH) return rc;
}
break;
@@ -3052,39 +2982,55 @@ for (;;)
/* Handle callouts */
case OP_CALLOUT:
- rrc = 0;
- if (PUBL(callout) != NULL)
+ case OP_CALLOUT_STR:
{
- PUBL(callout_block) cb;
- cb.version = 1; /* Version 1 of the callout block */
- cb.callout_number = code[1];
- cb.offset_vector = offsets;
-#if defined COMPILE_PCRE8
- cb.subject = (PCRE_SPTR)start_subject;
-#elif defined COMPILE_PCRE16
- cb.subject = (PCRE_SPTR16)start_subject;
-#elif defined COMPILE_PCRE32
- cb.subject = (PCRE_SPTR32)start_subject;
-#endif
- cb.subject_length = (int)(end_subject - start_subject);
- cb.start_match = (int)(current_subject - start_subject);
- cb.current_position = (int)(ptr - start_subject);
- cb.pattern_position = GET(code, 2);
- cb.next_item_length = GET(code, 2 + LINK_SIZE);
- cb.capture_top = 1;
- cb.capture_last = -1;
- cb.callout_data = md->callout_data;
- cb.mark = NULL; /* No (*MARK) support */
- if ((rrc = (*PUBL(callout))(&cb)) < 0) return rrc; /* Abandon */
+ unsigned int callout_length = (*code == OP_CALLOUT)
+ ? PRIV(OP_lengths)[OP_CALLOUT] : GET(code, 1 + 2*LINK_SIZE);
+ rrc = 0;
+
+ if (mb->callout != NULL)
+ {
+ pcre2_callout_block cb;
+ cb.version = 1;
+ cb.capture_top = 1;
+ cb.capture_last = 0;
+ cb.offset_vector = offsets;
+ cb.mark = NULL; /* No (*MARK) support */
+ cb.subject = start_subject;
+ cb.subject_length = (PCRE2_SIZE)(end_subject - start_subject);
+ cb.start_match = (PCRE2_SIZE)(current_subject - start_subject);
+ cb.current_position = (PCRE2_SIZE)(ptr - start_subject);
+ cb.pattern_position = GET(code, 1);
+ cb.next_item_length = GET(code, 1 + LINK_SIZE);
+
+ if (*code == OP_CALLOUT)
+ {
+ cb.callout_number = code[1 + 2*LINK_SIZE];
+ cb.callout_string_offset = 0;
+ cb.callout_string = NULL;
+ cb.callout_string_length = 0;
+ }
+ else
+ {
+ cb.callout_number = 0;
+ cb.callout_string_offset = GET(code, 1 + 3*LINK_SIZE);
+ cb.callout_string = code + (1 + 4*LINK_SIZE) + 1;
+ cb.callout_string_length =
+ callout_length - (1 + 4*LINK_SIZE) - 2;
+ }
+
+ if ((rrc = (mb->callout)(&cb, mb->callout_data)) < 0)
+ return rrc; /* Abandon */
+ }
+ if (rrc == 0)
+ { ADD_ACTIVE(state_offset + (int)callout_length, 0); }
}
- if (rrc == 0)
- { ADD_ACTIVE(state_offset + PRIV(OP_lengths)[OP_CALLOUT], 0); }
break;
/* ========================================================================== */
default: /* Unsupported opcode */
- return PCRE_ERROR_DFA_UITEM;
+ return PCRE2_ERROR_DFA_UITEM;
}
NEXT_ACTIVE_STATE: continue;
@@ -3110,22 +3056,19 @@ for (;;)
could_continue && /* Some could go on, and */
forced_fail != workspace[1] && /* Not all forced fail & */
( /* either... */
- (md->moptions & PCRE_PARTIAL_HARD) != 0 /* Hard partial */
+ (mb->moptions & PCRE2_PARTIAL_HARD) != 0 /* Hard partial */
|| /* or... */
- ((md->moptions & PCRE_PARTIAL_SOFT) != 0 && /* Soft partial and */
+ ((mb->moptions & PCRE2_PARTIAL_SOFT) != 0 && /* Soft partial and */
match_count < 0) /* no matches */
) && /* And... */
(
partial_newline || /* Either partial NL */
( /* or ... */
ptr >= end_subject && /* End of subject and */
- ptr > md->start_used_ptr) /* Inspected non-empty string */
+ ptr > mb->start_used_ptr) /* Inspected non-empty string */
)
)
- match_count = PCRE_ERROR_PARTIAL;
- DPRINTF(("%.*sEnd of internal_dfa_exec %d: returning %d\n"
- "%.*s---------------------\n\n", rlevel*2-2, SP, rlevel, match_count,
- rlevel*2-2, SP));
+ match_count = PCRE2_ERROR_PARTIAL;
break; /* In effect, "return", but see the comment below */
}
@@ -3145,285 +3088,288 @@ return match_count;
-
/*************************************************
-* Execute a Regular Expression - DFA engine *
+* Match a pattern using the DFA algorithm *
*************************************************/
-/* This external function applies a compiled re to a subject string using a DFA
-engine. This function calls the internal function multiple times if the pattern
-is not anchored.
+/* This function matches a compiled pattern to a subject string, using the
+alternate matching algorithm that finds all matches at once.
Arguments:
- argument_re points to the compiled expression
- extra_data points to extra data or is NULL
- subject points to the subject string
- length length of subject string (may contain binary zeros)
- start_offset where to start in the subject string
- options option bits
- offsets vector of match offsets
- offsetcount size of same
- workspace workspace vector
- wscount size of same
-
-Returns: > 0 => number of match offset pairs placed in offsets
- = 0 => offsets overflowed; longest matches are present
- -1 => failed to match
- < -1 => some kind of unexpected problem
+ code points to the compiled pattern
+ subject subject string
+ length length of subject string
+ startoffset where to start matching in the subject
+ options option bits
+ match_data points to a match data structure
+ gcontext points to a match context
+ workspace pointer to workspace
+ wscount size of workspace
+
+Returns: > 0 => number of match offset pairs placed in offsets
+ = 0 => offsets overflowed; longest matches are present
+ -1 => failed to match
+ < -1 => some kind of unexpected problem
*/
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_dfa_exec(const pcre *argument_re, const pcre_extra *extra_data,
- const char *subject, int length, int start_offset, int options, int *offsets,
- int offsetcount, int *workspace, int wscount)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_dfa_exec(const pcre16 *argument_re, const pcre16_extra *extra_data,
- PCRE_SPTR16 subject, int length, int start_offset, int options, int *offsets,
- int offsetcount, int *workspace, int wscount)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_dfa_exec(const pcre32 *argument_re, const pcre32_extra *extra_data,
- PCRE_SPTR32 subject, int length, int start_offset, int options, int *offsets,
- int offsetcount, int *workspace, int wscount)
-#endif
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_dfa_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+ PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+ pcre2_match_context *mcontext, int *workspace, size_t wscount)
{
-REAL_PCRE *re = (REAL_PCRE *)argument_re;
-dfa_match_data match_block;
-dfa_match_data *md = &match_block;
-BOOL utf, anchored, startline, firstline;
-const pcre_uchar *current_subject, *end_subject;
-const pcre_study_data *study = NULL;
-
-const pcre_uchar *req_char_ptr;
-const pcre_uint8 *start_bits = NULL;
-BOOL has_first_char = FALSE;
-BOOL has_req_char = FALSE;
-pcre_uchar first_char = 0;
-pcre_uchar first_char2 = 0;
-pcre_uchar req_char = 0;
-pcre_uchar req_char2 = 0;
-int newline;
+const pcre2_real_code *re = (const pcre2_real_code *)code;
-/* Plausibility checks */
+PCRE2_SPTR start_match;
+PCRE2_SPTR end_subject;
+PCRE2_SPTR bumpalong_limit;
+PCRE2_SPTR req_cu_ptr;
-if ((options & ~PUBLIC_DFA_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION;
-if (re == NULL || subject == NULL || workspace == NULL ||
- (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL;
-if (offsetcount < 0) return PCRE_ERROR_BADCOUNT;
-if (wscount < 20) return PCRE_ERROR_DFA_WSSIZE;
-if (length < 0) return PCRE_ERROR_BADLENGTH;
-if (start_offset < 0 || start_offset > length) return PCRE_ERROR_BADOFFSET;
+BOOL utf, anchored, startline, firstline;
-/* Check that the first field in the block is the magic number. If it is not,
-return with PCRE_ERROR_BADMAGIC. However, if the magic number is equal to
-REVERSED_MAGIC_NUMBER we return with PCRE_ERROR_BADENDIANNESS, which
-means that the pattern is likely compiled with different endianness. */
+BOOL has_first_cu = FALSE;
+BOOL has_req_cu = FALSE;
+PCRE2_UCHAR first_cu = 0;
+PCRE2_UCHAR first_cu2 = 0;
+PCRE2_UCHAR req_cu = 0;
+PCRE2_UCHAR req_cu2 = 0;
-if (re->magic_number != MAGIC_NUMBER)
- return re->magic_number == REVERSED_MAGIC_NUMBER?
- PCRE_ERROR_BADENDIANNESS:PCRE_ERROR_BADMAGIC;
-if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
+const uint8_t *start_bits = NULL;
-/* If restarting after a partial match, do some sanity checks on the contents
-of the workspace. */
+/* We need to have mb pointing to a match block, because the IS_NEWLINE macro
+is used below, and it expects NLBLOCK to be defined as a pointer. */
-if ((options & PCRE_DFA_RESTART) != 0)
- {
- if ((workspace[0] & (-2)) != 0 || workspace[1] < 1 ||
- workspace[1] > (wscount - 2)/INTS_PER_STATEBLOCK)
- return PCRE_ERROR_DFA_BADRESTART;
- }
+dfa_match_block actual_match_block;
+dfa_match_block *mb = &actual_match_block;
-/* Set up study, callout, and table data */
+/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
+subject string. */
-md->tables = re->tables;
-md->callout_data = NULL;
+if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
-if (extra_data != NULL)
- {
- unsigned long int flags = extra_data->flags;
- if ((flags & PCRE_EXTRA_STUDY_DATA) != 0)
- study = (const pcre_study_data *)extra_data->study_data;
- if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0) return PCRE_ERROR_DFA_UMLIMIT;
- if ((flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) != 0)
- return PCRE_ERROR_DFA_UMLIMIT;
- if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0)
- md->callout_data = extra_data->callout_data;
- if ((flags & PCRE_EXTRA_TABLES) != 0)
- md->tables = extra_data->tables;
- }
+/* Plausibility checks */
-/* Set some local values */
+if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
+if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL)
+ return PCRE2_ERROR_NULL;
+if (wscount < 20) return PCRE2_ERROR_DFA_WSSIZE;
+if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
-current_subject = (const pcre_uchar *)subject + start_offset;
-end_subject = (const pcre_uchar *)subject + length;
-req_char_ptr = current_subject - 1;
+/* Check that the first field in the block is the magic number. If it is not,
+return with PCRE2_ERROR_BADMAGIC. */
-#ifdef SUPPORT_UTF
-/* PCRE_UTF(16|32) have the same value as PCRE_UTF8. */
-utf = (re->options & PCRE_UTF8) != 0;
-#else
-utf = FALSE;
-#endif
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
-anchored = (options & (PCRE_ANCHORED|PCRE_DFA_RESTART)) != 0 ||
- (re->options & PCRE_ANCHORED) != 0;
+/* Check the code unit width. */
-/* The remaining fixed data for passing around. */
+if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
+ return PCRE2_ERROR_BADMODE;
-md->start_code = (const pcre_uchar *)argument_re +
- re->name_table_offset + re->name_count * re->name_entry_size;
-md->start_subject = (const pcre_uchar *)subject;
-md->end_subject = end_subject;
-md->start_offset = start_offset;
-md->moptions = options;
-md->poptions = re->options;
+/* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the
+options variable for this function. Users of PCRE2 who are not calling the
+function directly would like to have a way of setting these flags, in the same
+way that they can set pcre2_compile() flags like PCRE2_NO_AUTOPOSSESS with
+constructions like (*NO_AUTOPOSSESS). To enable this, (*NOTEMPTY) and
+(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which can now be
+transferred to the options for this function. The bits are guaranteed to be
+adjacent, but do not have the same values. This bit of Boolean trickery assumes
+that the match-time bits are not more significant than the flag bits. If by
+accident this is not the case, a compile-time division by zero error will
+occur. */
-/* If the BSR option is not set at match time, copy what was set
-at compile time. */
+#define FF (PCRE2_NOTEMPTY_SET|PCRE2_NE_ATST_SET)
+#define OO (PCRE2_NOTEMPTY|PCRE2_NOTEMPTY_ATSTART)
+options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1)));
+#undef FF
+#undef OO
-if ((md->moptions & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) == 0)
+/* If restarting after a partial match, do some sanity checks on the contents
+of the workspace. */
+
+if ((options & PCRE2_DFA_RESTART) != 0)
{
- if ((re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) != 0)
- md->moptions |= re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE);
-#ifdef BSR_ANYCRLF
- else md->moptions |= PCRE_BSR_ANYCRLF;
-#endif
+ if ((workspace[0] & (-2)) != 0 || workspace[1] < 1 ||
+ workspace[1] > (int)((wscount - 2)/INTS_PER_STATEBLOCK))
+ return PCRE2_ERROR_DFA_BADRESTART;
}
-/* Handle different types of newline. The three bits give eight cases. If
-nothing is set at run time, whatever was used at compile time applies. */
+/* Set some local values */
-switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options : (pcre_uint32)options) &
- PCRE_NEWLINE_BITS)
- {
- case 0: newline = NEWLINE; break; /* Compile-time default */
- case PCRE_NEWLINE_CR: newline = CHAR_CR; break;
- case PCRE_NEWLINE_LF: newline = CHAR_NL; break;
- case PCRE_NEWLINE_CR+
- PCRE_NEWLINE_LF: newline = (CHAR_CR << 8) | CHAR_NL; break;
- case PCRE_NEWLINE_ANY: newline = -1; break;
- case PCRE_NEWLINE_ANYCRLF: newline = -2; break;
- default: return PCRE_ERROR_BADNEWLINE;
- }
+utf = (re->overall_options & PCRE2_UTF) != 0;
+start_match = subject + start_offset;
+end_subject = subject + length;
+req_cu_ptr = start_match - 1;
+anchored = (options & (PCRE2_ANCHORED|PCRE2_DFA_RESTART)) != 0 ||
+ (re->overall_options & PCRE2_ANCHORED) != 0;
-if (newline == -2)
- {
- md->nltype = NLTYPE_ANYCRLF;
- }
-else if (newline < 0)
+/* The "must be at the start of a line" flags are used in a loop when finding
+where to start. */
+
+startline = (re->flags & PCRE2_STARTLINE) != 0;
+firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+bumpalong_limit = end_subject;
+
+/* Get data from the match context, if present, and fill in the fields in the
+match block. It is an error to set an offset limit without setting the flag at
+compile time. */
+
+if (mcontext == NULL)
{
- md->nltype = NLTYPE_ANY;
+ mb->callout = NULL;
+ mb->memctl = re->memctl;
}
else
{
- md->nltype = NLTYPE_FIXED;
- if (newline > 255)
+ if (mcontext->offset_limit != PCRE2_UNSET)
{
- md->nllen = 2;
- md->nl[0] = (newline >> 8) & 255;
- md->nl[1] = newline & 255;
- }
- else
- {
- md->nllen = 1;
- md->nl[0] = newline;
+ if ((re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0)
+ return PCRE2_ERROR_BADOFFSETLIMIT;
+ bumpalong_limit = subject + mcontext->offset_limit;
}
+ mb->callout = mcontext->callout;
+ mb->callout_data = mcontext->callout_data;
+ mb->memctl = mcontext->memctl;
+ }
+
+mb->start_code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) +
+ re->name_count * re->name_entry_size;
+mb->tables = re->tables;
+mb->start_subject = subject;
+mb->end_subject = end_subject;
+mb->start_offset = start_offset;
+mb->moptions = options;
+mb->poptions = re->overall_options;
+
+/* Process the \R and newline settings. */
+
+mb->bsr_convention = re->bsr_convention;
+mb->nltype = NLTYPE_FIXED;
+switch(re->newline_convention)
+ {
+ case PCRE2_NEWLINE_CR:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_CR;
+ break;
+
+ case PCRE2_NEWLINE_LF:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_CRLF:
+ mb->nllen = 2;
+ mb->nl[0] = CHAR_CR;
+ mb->nl[1] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_ANY:
+ mb->nltype = NLTYPE_ANY;
+ break;
+
+ case PCRE2_NEWLINE_ANYCRLF:
+ mb->nltype = NLTYPE_ANYCRLF;
+ break;
+
+ default: return PCRE2_ERROR_INTERNAL;
}
-/* Check a UTF-8 string if required. Unfortunately there's no way of passing
-back the character offset. */
+/* Check a UTF string for validity if required. For 8-bit and 16-bit strings,
+we must also check that a starting offset does not point into the middle of a
+multiunit character. We check only the portion of the subject that is going to
+be inspected during matching - from the offset minus the maximum back reference
+to the given length. This saves time when a small part of a large subject is
+being matched by the use of a starting offset. Note that the maximum lookbehind
+is a number of characters, not code units. */
-#ifdef SUPPORT_UTF
-if (utf && (options & PCRE_NO_UTF8_CHECK) == 0)
+#ifdef SUPPORT_UNICODE
+if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
{
- int erroroffset;
- int errorcode = PRIV(valid_utf)((pcre_uchar *)subject, length, &erroroffset);
- if (errorcode != 0)
+ PCRE2_SPTR check_subject = start_match; /* start_match includes offset */
+
+ if (start_offset > 0)
{
- if (offsetcount >= 2)
+#if PCRE2_CODE_UNIT_WIDTH != 32
+ unsigned int i;
+ if (start_match < end_subject && NOT_FIRSTCU(*start_match))
+ return PCRE2_ERROR_BADUTFOFFSET;
+ for (i = re->max_lookbehind; i > 0 && check_subject > subject; i--)
{
- offsets[0] = erroroffset;
- offsets[1] = errorcode;
+ check_subject--;
+ while (check_subject > subject &&
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ (*check_subject & 0xc0) == 0x80)
+#else /* 16-bit */
+ (*check_subject & 0xfc00) == 0xdc00)
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ check_subject--;
}
-#if defined COMPILE_PCRE8
- return (errorcode <= PCRE_UTF8_ERR5 && (options & PCRE_PARTIAL_HARD) != 0) ?
- PCRE_ERROR_SHORTUTF8 : PCRE_ERROR_BADUTF8;
-#elif defined COMPILE_PCRE16
- return (errorcode <= PCRE_UTF16_ERR1 && (options & PCRE_PARTIAL_HARD) != 0) ?
- PCRE_ERROR_SHORTUTF16 : PCRE_ERROR_BADUTF16;
-#elif defined COMPILE_PCRE32
- return PCRE_ERROR_BADUTF32;
-#endif
+#else /* In the 32-bit library, one code unit equals one character. */
+ check_subject -= re->max_lookbehind;
+ if (check_subject < subject) check_subject = subject;
+#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
}
-#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16
- if (start_offset > 0 && start_offset < length &&
- NOT_FIRSTCHAR(((PCRE_PUCHAR)subject)[start_offset]))
- return PCRE_ERROR_BADUTF8_OFFSET;
-#endif
- }
-#endif
-
-/* If the exec call supplied NULL for tables, use the inbuilt ones. This
-is a feature that makes it possible to save compiled regex and re-use them
-in other programs later. */
-if (md->tables == NULL) md->tables = PRIV(default_tables);
+ /* Validate the relevant portion of the subject. After an error, adjust the
+ offset to be an absolute offset in the whole string. */
-/* The "must be at the start of a line" flags are used in a loop when finding
-where to start. */
-
-startline = (re->flags & PCRE_STARTLINE) != 0;
-firstline = (re->options & PCRE_FIRSTLINE) != 0;
+ match_data->rc = PRIV(valid_utf)(check_subject,
+ length - (PCRE2_SIZE)(check_subject - subject), &(match_data->startchar));
+ if (match_data->rc != 0)
+ {
+ match_data->startchar += (PCRE2_SIZE)(check_subject - subject);
+ return match_data->rc;
+ }
+ }
+#endif /* SUPPORT_UNICODE */
-/* Set up the first character to match, if available. The first_byte value is
-never set for an anchored regular expression, but the anchoring may be forced
-at run time, so we have to test for anchoring. The first char may be unset for
-an unanchored pattern, of course. If there's no first char and the pattern was
-studied, there may be a bitmap of possible first characters. */
+/* Set up the first code unit to match, if available. The first_codeunit value
+is never set for an anchored regular expression, but the anchoring may be
+forced at run time, so we have to test for anchoring. The first code unit may
+be unset for an unanchored pattern, of course. If there's no first code unit
+there may be a bitmap of possible first characters. */
if (!anchored)
{
- if ((re->flags & PCRE_FIRSTSET) != 0)
+ if ((re->flags & PCRE2_FIRSTSET) != 0)
{
- has_first_char = TRUE;
- first_char = first_char2 = (pcre_uchar)(re->first_char);
- if ((re->flags & PCRE_FCH_CASELESS) != 0)
+ has_first_cu = TRUE;
+ first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit);
+ if ((re->flags & PCRE2_FIRSTCASELESS) != 0)
{
- first_char2 = TABLE_GET(first_char, md->tables + fcc_offset, first_char);
-#if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
- if (utf && first_char > 127)
- first_char2 = UCD_OTHERCASE(first_char);
+ first_cu2 = TABLE_GET(first_cu, mb->tables + fcc_offset, first_cu);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (utf && first_cu > 127)
+ first_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(first_cu);
#endif
}
}
else
- {
- if (!startline && study != NULL &&
- (study->flags & PCRE_STUDY_MAPPED) != 0)
- start_bits = study->start_bits;
- }
+ if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0)
+ start_bits = re->start_bitmap;
}
/* For anchored or unanchored matches, there may be a "last known required
character" set. */
-if ((re->flags & PCRE_REQCHSET) != 0)
+if ((re->flags & PCRE2_LASTSET) != 0)
{
- has_req_char = TRUE;
- req_char = req_char2 = (pcre_uchar)(re->req_char);
- if ((re->flags & PCRE_RCH_CASELESS) != 0)
+ has_req_cu = TRUE;
+ req_cu = req_cu2 = (PCRE2_UCHAR)(re->last_codeunit);
+ if ((re->flags & PCRE2_LASTCASELESS) != 0)
{
- req_char2 = TABLE_GET(req_char, md->tables + fcc_offset, req_char);
-#if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
- if (utf && req_char > 127)
- req_char2 = UCD_OTHERCASE(req_char);
+ req_cu2 = TABLE_GET(req_cu, mb->tables + fcc_offset, req_cu);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (utf && req_cu > 127) req_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(req_cu);
#endif
}
}
+/* Fill in fields that are always returned in the match data. */
+
+match_data->code = re;
+match_data->subject = subject;
+match_data->mark = NULL;
+match_data->matchedby = PCRE2_MATCHEDBY_DFA_INTERPRETER;
+
/* Call the main matching function, looping for a non-anchored regex after a
failed match. If not restarting, perform certain optimizations at the start of
a match. */
@@ -3432,22 +3378,32 @@ for (;;)
{
int rc;
- if ((options & PCRE_DFA_RESTART) == 0)
+ /* ----------------- Start of match optimizations ---------------- */
+
+ /* There are some optimizations that avoid running the match if a known
+ starting point is not found, or if a known later code unit is not present.
+ However, there is an option (settable at compile time) that disables
+ these, for testing and for ensuring that all callouts do actually occur.
+ The optimizations must also be avoided when restarting a DFA match. */
+
+ if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 &&
+ (options & PCRE2_DFA_RESTART) == 0)
{
- const pcre_uchar *save_end_subject = end_subject;
+ PCRE2_SPTR save_end_subject = end_subject;
/* If firstline is TRUE, the start of the match is constrained to the first
- line of a multiline string. Implement this by temporarily adjusting
- end_subject so that we stop scanning at a newline. If the match fails at
- the newline, later code breaks this loop. */
+ line of a multiline string. That is, the match must be before or at the
+ first newline. Implement this by temporarily adjusting end_subject so that
+ we stop the optimization scans at a newline. If the match fails at the
+ newline, later code breaks this loop. */
if (firstline)
{
- PCRE_PUCHAR t = current_subject;
-#ifdef SUPPORT_UTF
+ PCRE2_SPTR t = start_match;
+#ifdef SUPPORT_UNICODE
if (utf)
{
- while (t < md->end_subject && !IS_NEWLINE(t))
+ while (t < mb->end_subject && !IS_NEWLINE(t))
{
t++;
ACROSSCHAR(t < end_subject, *t, t++);
@@ -3455,82 +3411,71 @@ for (;;)
}
else
#endif
- while (t < md->end_subject && !IS_NEWLINE(t)) t++;
+ while (t < mb->end_subject && !IS_NEWLINE(t)) t++;
end_subject = t;
}
- /* There are some optimizations that avoid running the match if a known
- starting point is not found. However, there is an option that disables
- these, for testing and for ensuring that all callouts do actually occur.
- The option can be set in the regex by (*NO_START_OPT) or passed in
- match-time options. */
+ /* Advance to a unique first code unit if there is one. */
- if (((options | re->options) & PCRE_NO_START_OPTIMIZE) == 0)
+ if (has_first_cu)
{
- /* Advance to a known first pcre_uchar (i.e. data item) */
-
- if (has_first_char)
- {
- if (first_char != first_char2)
- {
- pcre_uchar csc;
- while (current_subject < end_subject &&
- (csc = UCHAR21TEST(current_subject)) != first_char && csc != first_char2)
- current_subject++;
- }
- else
- while (current_subject < end_subject &&
- UCHAR21TEST(current_subject) != first_char)
- current_subject++;
- }
+ PCRE2_UCHAR smc;
+ if (first_cu != first_cu2)
+ while (start_match < end_subject &&
+ (smc = UCHAR21TEST(start_match)) != first_cu && smc != first_cu2)
+ start_match++;
+ else
+ while (start_match < end_subject && UCHAR21TEST(start_match) != first_cu)
+ start_match++;
+ }
- /* Or to just after a linebreak for a multiline match if possible */
+ /* Or to just after a linebreak for a multiline match */
- else if (startline)
+ else if (startline)
+ {
+ if (start_match > mb->start_subject + start_offset)
{
- if (current_subject > md->start_subject + start_offset)
+#ifdef SUPPORT_UNICODE
+ if (utf)
{
-#ifdef SUPPORT_UTF
- if (utf)
+ while (start_match < end_subject && !WAS_NEWLINE(start_match))
{
- while (current_subject < end_subject &&
- !WAS_NEWLINE(current_subject))
- {
- current_subject++;
- ACROSSCHAR(current_subject < end_subject, *current_subject,
- current_subject++);
- }
+ start_match++;
+ ACROSSCHAR(start_match < end_subject, *start_match,
+ start_match++);
}
- else
-#endif
- while (current_subject < end_subject && !WAS_NEWLINE(current_subject))
- current_subject++;
-
- /* If we have just passed a CR and the newline option is ANY or
- ANYCRLF, and we are now at a LF, advance the match position by one
- more character. */
-
- if (UCHAR21TEST(current_subject - 1) == CHAR_CR &&
- (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) &&
- current_subject < end_subject &&
- UCHAR21TEST(current_subject) == CHAR_NL)
- current_subject++;
}
+ else
+#endif
+ while (start_match < end_subject && !WAS_NEWLINE(start_match))
+ start_match++;
+
+ /* If we have just passed a CR and the newline option is ANY or
+ ANYCRLF, and we are now at a LF, advance the match position by one more
+ code unit. */
+
+ if (start_match[-1] == CHAR_CR &&
+ (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) &&
+ start_match < end_subject &&
+ UCHAR21TEST(start_match) == CHAR_NL)
+ start_match++;
}
+ }
- /* Advance to a non-unique first pcre_uchar after study */
+ /* Or to a non-unique first code unit if any have been identified. The
+ bitmap contains only 256 bits. When code units are 16 or 32 bits wide, all
+ code units greater than 254 set the 255 bit. */
- else if (start_bits != NULL)
+ else if (start_bits != NULL)
+ {
+ while (start_match < end_subject)
{
- while (current_subject < end_subject)
- {
- register pcre_uint32 c = UCHAR21TEST(current_subject);
-#ifndef COMPILE_PCRE8
- if (c > 255) c = 255;
+ register uint32_t c = UCHAR21TEST(start_match);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ if (c > 255) c = 255;
#endif
- if ((start_bits[c/8] & (1 << (c&7))) != 0) break;
- current_subject++;
- }
+ if ((start_bits[c/8] & (1 << (c&7))) != 0) break;
+ start_match++;
}
}
@@ -3538,137 +3483,142 @@ for (;;)
end_subject = save_end_subject;
- /* The following two optimizations are disabled for partial matching or if
- disabling is explicitly requested (and of course, by the test above, this
- code is not obeyed when restarting after a partial match). */
+ /* The following two optimizations are disabled for partial matching. */
- if (((options | re->options) & PCRE_NO_START_OPTIMIZE) == 0 &&
- (options & (PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT)) == 0)
+ if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0)
{
- /* If the pattern was studied, a minimum subject length may be set. This
- is a lower bound; no actual string of that length may actually match the
- pattern. Although the value is, strictly, in characters, we treat it as
- in pcre_uchar units to avoid spending too much time in this optimization.
- */
+ /* The minimum matching length is a lower bound; no actual string of that
+ length may actually match the pattern. Although the value is, strictly,
+ in characters, we treat it as code units to avoid spending too much time
+ in this optimization. */
- if (study != NULL && (study->flags & PCRE_STUDY_MINLEN) != 0 &&
- (pcre_uint32)(end_subject - current_subject) < study->minlength)
- return PCRE_ERROR_NOMATCH;
+ if (end_subject - start_match < re->minlength) return PCRE2_ERROR_NOMATCH;
- /* If req_char is set, we know that that pcre_uchar must appear in the
- subject for the match to succeed. If the first pcre_uchar is set,
- req_char must be later in the subject; otherwise the test starts at the
- match point. This optimization can save a huge amount of work in patterns
- with nested unlimited repeats that aren't going to match. Writing
- separate code for cased/caseless versions makes it go faster, as does
- using an autoincrement and backing off on a match.
+ /* If req_cu is set, we know that that code unit must appear in the
+ subject for the match to succeed. If the first code unit is set, req_cu
+ must be later in the subject; otherwise the test starts at the match
+ point. This optimization can save a huge amount of backtracking in
+ patterns with nested unlimited repeats that aren't going to match.
+ Writing separate code for cased/caseless versions makes it go faster, as
+ does using an autoincrement and backing off on a match.
HOWEVER: when the subject string is very, very long, searching to its end
can take a long time, and give bad performance on quite ordinary
- patterns. This showed up when somebody was matching /^C/ on a 32-megabyte
- string... so we don't do this when the string is sufficiently long. */
+ patterns. This showed up when somebody was matching something like
+ /^\d+C/ on a 32-megabyte string... so we don't do this when the string is
+ sufficiently long. */
- if (has_req_char && end_subject - current_subject < REQ_BYTE_MAX)
+ if (has_req_cu && end_subject - start_match < REQ_CU_MAX)
{
- register PCRE_PUCHAR p = current_subject + (has_first_char? 1:0);
+ register PCRE2_SPTR p = start_match + (has_first_cu? 1:0);
/* We don't need to repeat the search if we haven't yet reached the
place we found it at last time. */
- if (p > req_char_ptr)
+ if (p > req_cu_ptr)
{
- if (req_char != req_char2)
+ if (req_cu != req_cu2)
{
while (p < end_subject)
{
- register pcre_uint32 pp = UCHAR21INCTEST(p);
- if (pp == req_char || pp == req_char2) { p--; break; }
+ register uint32_t pp = UCHAR21INCTEST(p);
+ if (pp == req_cu || pp == req_cu2) { p--; break; }
}
}
else
{
while (p < end_subject)
{
- if (UCHAR21INCTEST(p) == req_char) { p--; break; }
+ if (UCHAR21INCTEST(p) == req_cu) { p--; break; }
}
}
- /* If we can't find the required pcre_uchar, break the matching loop,
- which will cause a return or PCRE_ERROR_NOMATCH. */
+ /* If we can't find the required code unit, break the matching loop,
+ forcing a match failure. */
if (p >= end_subject) break;
- /* If we have found the required pcre_uchar, save the point where we
+ /* If we have found the required code unit, save the point where we
found it, so that we don't search again next time round the loop if
- the start hasn't passed this point yet. */
+ the start hasn't passed this code unit yet. */
- req_char_ptr = p;
+ req_cu_ptr = p;
}
}
}
- } /* End of optimizations that are done when not restarting */
+ }
- /* OK, now we can do the business */
+ /* ------------ End of start of match optimizations ------------ */
+
+ /* Give no match if we have passed the bumpalong limit. */
- md->start_used_ptr = current_subject;
- md->recursive = NULL;
+ if (start_match > bumpalong_limit) break;
- rc = internal_dfa_exec(
- md, /* fixed match data */
- md->start_code, /* this subexpression's code */
- current_subject, /* where we currently are */
- start_offset, /* start offset in subject */
- offsets, /* offset vector */
- offsetcount, /* size of same */
- workspace, /* workspace vector */
- wscount, /* size of same */
- 0); /* function recurse level */
+ /* OK, now we can do the business */
+
+ mb->start_used_ptr = start_match;
+ mb->last_used_ptr = start_match;
+ mb->recursive = NULL;
+
+ rc = internal_dfa_match(
+ mb, /* fixed match data */
+ mb->start_code, /* this subexpression's code */
+ start_match, /* where we currently are */
+ start_offset, /* start offset in subject */
+ match_data->ovector, /* offset vector */
+ (uint32_t)match_data->oveccount * 2, /* actual size of same */
+ workspace, /* workspace vector */
+ (int)wscount, /* size of same */
+ 0); /* function recurse level */
/* Anything other than "no match" means we are done, always; otherwise, carry
on only if not anchored. */
- if (rc != PCRE_ERROR_NOMATCH || anchored)
+ if (rc != PCRE2_ERROR_NOMATCH || anchored)
{
- if (rc == PCRE_ERROR_PARTIAL && offsetcount >= 2)
+ if (rc == PCRE2_ERROR_PARTIAL && match_data->oveccount > 0)
{
- offsets[0] = (int)(md->start_used_ptr - (PCRE_PUCHAR)subject);
- offsets[1] = (int)(end_subject - (PCRE_PUCHAR)subject);
- if (offsetcount > 2)
- offsets[2] = (int)(current_subject - (PCRE_PUCHAR)subject);
+ match_data->ovector[0] = (PCRE2_SIZE)(start_match - subject);
+ match_data->ovector[1] = (PCRE2_SIZE)(end_subject - subject);
}
+ match_data->leftchar = (PCRE2_SIZE)(mb->start_used_ptr - subject);
+ match_data->rightchar = (PCRE2_SIZE)( mb->last_used_ptr - subject);
+ match_data->startchar = (PCRE2_SIZE)(start_match - subject);
+ match_data->rc = rc;
return rc;
}
/* Advance to the next subject character unless we are at the end of a line
and firstline is set. */
- if (firstline && IS_NEWLINE(current_subject)) break;
- current_subject++;
-#ifdef SUPPORT_UTF
+ if (firstline && IS_NEWLINE(start_match)) break;
+ start_match++;
+#ifdef SUPPORT_UNICODE
if (utf)
{
- ACROSSCHAR(current_subject < end_subject, *current_subject,
- current_subject++);
+ ACROSSCHAR(start_match < end_subject, *start_match,
+ start_match++);
}
#endif
- if (current_subject > end_subject) break;
+ if (start_match > end_subject) break;
/* If we have just passed a CR and we are now at a LF, and the pattern does
not contain any explicit matches for \r or \n, and the newline option is CRLF
or ANY or ANYCRLF, advance the match position by one more character. */
- if (UCHAR21TEST(current_subject - 1) == CHAR_CR &&
- current_subject < end_subject &&
- UCHAR21TEST(current_subject) == CHAR_NL &&
- (re->flags & PCRE_HASCRORLF) == 0 &&
- (md->nltype == NLTYPE_ANY ||
- md->nltype == NLTYPE_ANYCRLF ||
- md->nllen == 2))
- current_subject++;
+ if (UCHAR21TEST(start_match - 1) == CHAR_CR &&
+ start_match < end_subject &&
+ UCHAR21TEST(start_match) == CHAR_NL &&
+ (re->flags & PCRE2_HASCRORLF) == 0 &&
+ (mb->nltype == NLTYPE_ANY ||
+ mb->nltype == NLTYPE_ANYCRLF ||
+ mb->nllen == 2))
+ start_match++;
} /* "Bumpalong" loop */
-return PCRE_ERROR_NOMATCH;
+
+return PCRE2_ERROR_NOMATCH;
}
-/* End of pcre_dfa_exec.c */
+/* End of pcre2_dfa_match.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_error.c b/src/3rdparty/pcre2/src/pcre2_error.c
new file mode 100644
index 0000000000..77fd5f4124
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_error.c
@@ -0,0 +1,322 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#define STRING(a) # a
+#define XSTRING(s) STRING(s)
+
+/* The texts of compile-time error messages. Compile-time error numbers start
+at COMPILE_ERROR_BASE (100).
+
+This used to be a table of strings, but in order to reduce the number of
+relocations needed when a shared library is loaded dynamically, it is now one
+long string. We cannot use a table of offsets, because the lengths of inserts
+such as XSTRING(MAX_NAME_SIZE) are not known. Instead,
+pcre2_get_error_message() counts through to the one it wants - this isn't a
+performance issue because these strings are used only when there is an error.
+
+Each substring ends with \0 to insert a null character. This includes the final
+substring, so that the whole string ends with \0\0, which can be detected when
+counting through. */
+
+static const unsigned char compile_error_texts[] =
+ "no error\0"
+ "\\ at end of pattern\0"
+ "\\c at end of pattern\0"
+ "unrecognized character follows \\\0"
+ "numbers out of order in {} quantifier\0"
+ /* 5 */
+ "number too big in {} quantifier\0"
+ "missing terminating ] for character class\0"
+ "invalid escape sequence in character class\0"
+ "range out of order in character class\0"
+ "quantifier does not follow a repeatable item\0"
+ /* 10 */
+ "internal error: unexpected repeat\0"
+ "unrecognized character after (? or (?-\0"
+ "POSIX named classes are supported only within a class\0"
+ "POSIX collating elements are not supported\0"
+ "missing closing parenthesis\0"
+ /* 15 */
+ "reference to non-existent subpattern\0"
+ "pattern passed as NULL\0"
+ "unrecognised compile-time option bit(s)\0"
+ "missing ) after (?# comment\0"
+ "parentheses are too deeply nested\0"
+ /* 20 */
+ "regular expression is too large\0"
+ "failed to allocate heap memory\0"
+ "unmatched closing parenthesis\0"
+ "internal error: code overflow\0"
+ "letter or underscore expected after (?< or (?'\0"
+ /* 25 */
+ "lookbehind assertion is not fixed length\0"
+ "malformed number or name after (?(\0"
+ "conditional group contains more than two branches\0"
+ "assertion expected after (?( or (?(?C)\0"
+ "(?R or (?[+-]digits must be followed by )\0"
+ /* 30 */
+ "unknown POSIX class name\0"
+ "internal error in pcre2_study(): should not occur\0"
+ "this version of PCRE2 does not have Unicode support\0"
+ "parentheses are too deeply nested (stack check)\0"
+ "character code point value in \\x{} or \\o{} is too large\0"
+ /* 35 */
+ "invalid condition (?(0)\0"
+ "\\C is not allowed in a lookbehind assertion in UTF-" XSTRING(PCRE2_CODE_UNIT_WIDTH) " mode\0"
+ "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u\0"
+ "number after (?C is greater than 255\0"
+ "closing parenthesis for (?C expected\0"
+ /* 40 */
+ "invalid escape sequence in (*VERB) name\0"
+ "unrecognized character after (?P\0"
+ "syntax error in subpattern name (missing terminator)\0"
+ "two named subpatterns have the same name (PCRE2_DUPNAMES not set)\0"
+ "group name must start with a non-digit\0"
+ /* 45 */
+ "this version of PCRE2 does not have support for \\P, \\p, or \\X\0"
+ "malformed \\P or \\p sequence\0"
+ "unknown property name after \\P or \\p\0"
+ "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)\0"
+ "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0"
+ /* 50 */
+ "invalid range in character class\0"
+ "octal value is greater than \\377 in 8-bit non-UTF-8 mode\0"
+ "internal error: overran compiling workspace\0"
+ "internal error: previously-checked referenced subpattern not found\0"
+ "DEFINE group contains more than one branch\0"
+ /* 55 */
+ "missing opening brace after \\o\0"
+ "internal error: unknown newline setting\0"
+ "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0"
+ "a numbered reference must not be zero\0"
+ "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0"
+ /* 60 */
+ "(*VERB) not recognized or malformed\0"
+ "number is too big\0"
+ "subpattern name expected\0"
+ "digit expected after (?+\0"
+ "non-octal character in \\o{} (closing brace missing?)\0"
+ /* 65 */
+ "different names for subpatterns of the same number are not allowed\0"
+ "(*MARK) must have an argument\0"
+ "non-hex character in \\x{} (closing brace missing?)\0"
+#ifndef EBCDIC
+ "\\c must be followed by a printable ASCII character\0"
+#else
+ "\\c must be followed by a letter or one of [\\]^_?\0"
+#endif
+ "\\k is not followed by a braced, angle-bracketed, or quoted name\0"
+ /* 70 */
+ "internal error: unknown opcode in find_fixedlength()\0"
+ "\\N is not supported in a class\0"
+ "SPARE ERROR\0"
+ "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)\0"
+ "using UTF is disabled by the application\0"
+ /* 75 */
+ "using UCP is disabled by the application\0"
+ "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0"
+ "character code point value in \\u.... sequence is too large\0"
+ "digits missing in \\x{} or \\o{}\0"
+ "syntax error in (?(VERSION condition\0"
+ /* 80 */
+ "internal error: unknown opcode in auto_possessify()\0"
+ "missing terminating delimiter for callout with string argument\0"
+ "unrecognized string delimiter follows (?C\0"
+ "using \\C is disabled by the application\0"
+ "(?| and/or (?J: or (?x: parentheses are too deeply nested\0"
+ /* 85 */
+ "using \\C is disabled in this PCRE2 library\0"
+ "regular expression is too complicated\0"
+ "lookbehind assertion is too long\0"
+ "pattern string is longer than the limit set by the application\0"
+ ;
+
+/* Match-time and UTF error texts are in the same format. */
+
+static const unsigned char match_error_texts[] =
+ "no error\0"
+ "no match\0"
+ "partial match\0"
+ "UTF-8 error: 1 byte missing at end\0"
+ "UTF-8 error: 2 bytes missing at end\0"
+ /* 5 */
+ "UTF-8 error: 3 bytes missing at end\0"
+ "UTF-8 error: 4 bytes missing at end\0"
+ "UTF-8 error: 5 bytes missing at end\0"
+ "UTF-8 error: byte 2 top bits not 0x80\0"
+ "UTF-8 error: byte 3 top bits not 0x80\0"
+ /* 10 */
+ "UTF-8 error: byte 4 top bits not 0x80\0"
+ "UTF-8 error: byte 5 top bits not 0x80\0"
+ "UTF-8 error: byte 6 top bits not 0x80\0"
+ "UTF-8 error: 5-byte character is not allowed (RFC 3629)\0"
+ "UTF-8 error: 6-byte character is not allowed (RFC 3629)\0"
+ /* 15 */
+ "UTF-8 error: code points greater than 0x10ffff are not defined\0"
+ "UTF-8 error: code points 0xd800-0xdfff are not defined\0"
+ "UTF-8 error: overlong 2-byte sequence\0"
+ "UTF-8 error: overlong 3-byte sequence\0"
+ "UTF-8 error: overlong 4-byte sequence\0"
+ /* 20 */
+ "UTF-8 error: overlong 5-byte sequence\0"
+ "UTF-8 error: overlong 6-byte sequence\0"
+ "UTF-8 error: isolated byte with 0x80 bit set\0"
+ "UTF-8 error: illegal byte (0xfe or 0xff)\0"
+ "UTF-16 error: missing low surrogate at end\0"
+ /* 25 */
+ "UTF-16 error: invalid low surrogate\0"
+ "UTF-16 error: isolated low surrogate\0"
+ "UTF-32 error: code points 0xd800-0xdfff are not defined\0"
+ "UTF-32 error: code points greater than 0x10ffff are not defined\0"
+ "bad data value\0"
+ /* 30 */
+ "patterns do not all use the same character tables\0"
+ "magic number missing\0"
+ "pattern compiled in wrong mode: 8/16/32-bit error\0"
+ "bad offset value\0"
+ "bad option value\0"
+ /* 35 */
+ "invalid replacement string\0"
+ "bad offset into UTF string\0"
+ "callout error code\0" /* Never returned by PCRE2 itself */
+ "invalid data in workspace for DFA restart\0"
+ "too much recursion for DFA matching\0"
+ /* 40 */
+ "backreference condition or recursion test is not supported for DFA matching\0"
+ "function is not supported for DFA matching\0"
+ "pattern contains an item that is not supported for DFA matching\0"
+ "workspace size exceeded in DFA matching\0"
+ "internal error - pattern overwritten?\0"
+ /* 45 */
+ "bad JIT option\0"
+ "JIT stack limit reached\0"
+ "match limit exceeded\0"
+ "no more memory\0"
+ "unknown substring\0"
+ /* 50 */
+ "non-unique substring name\0"
+ "NULL argument passed\0"
+ "nested recursion at the same subject position\0"
+ "recursion limit exceeded\0"
+ "requested value is not available\0"
+ /* 55 */
+ "requested value is not set\0"
+ "offset limit set without PCRE2_USE_OFFSET_LIMIT\0"
+ "bad escape sequence in replacement string\0"
+ "expected closing curly bracket in replacement string\0"
+ "bad substitution in replacement string\0"
+ /* 60 */
+ "match with end before start is not supported\0"
+ "too many replacements (more than INT_MAX)\0"
+ "bad serialized data\0"
+ ;
+
+
+/*************************************************
+* Return error message *
+*************************************************/
+
+/* This function copies an error message into a buffer whose units are of an
+appropriate width. Error numbers are positive for compile-time errors, and
+negative for match-time errors (except for UTF errors), but the numbers are all
+distinct.
+
+Arguments:
+ enumber error number
+ buffer where to put the message (zero terminated)
+ size size of the buffer
+
+Returns: length of message if all is well
+ negative on error
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_get_error_message(int enumber, PCRE2_UCHAR *buffer, size_t size)
+{
+const unsigned char *message;
+size_t i;
+int n;
+
+if (size == 0) return PCRE2_ERROR_NOMEMORY;
+
+if (enumber >= COMPILE_ERROR_BASE) /* Compile error */
+ {
+ message = compile_error_texts;
+ n = enumber - COMPILE_ERROR_BASE;
+ }
+else if (enumber < 0) /* Match or UTF error */
+ {
+ message = match_error_texts;
+ n = -enumber;
+ }
+else /* Invalid error number */
+ {
+ message = (unsigned char *)"\0"; /* Empty message list */
+ n = 1;
+ }
+
+for (; n > 0; n--)
+ {
+ while (*message++ != CHAR_NULL) {};
+ if (*message == CHAR_NULL) return PCRE2_ERROR_BADDATA;
+ }
+
+for (i = 0; *message != 0; i++)
+ {
+ if (i >= size - 1)
+ {
+ buffer[i] = 0; /* Terminate partial message */
+ return PCRE2_ERROR_NOMEMORY;
+ }
+ buffer[i] = *message++;
+ }
+
+buffer[i] = 0;
+return (int)i;
+}
+
+/* End of pcre2_error.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_find_bracket.c b/src/3rdparty/pcre2/src/pcre2_find_bracket.c
new file mode 100644
index 0000000000..803e719765
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_find_bracket.c
@@ -0,0 +1,218 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains a single function that scans through a compiled pattern
+until it finds a capturing bracket with the given number, or, if the number is
+negative, an instance of OP_REVERSE for a lookbehind. The function is called
+from pcre2_compile.c and also from pcre2_study.c when finding the minimum
+matching length. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+* Scan compiled regex for specific bracket *
+*************************************************/
+
+/*
+Arguments:
+ code points to start of expression
+ utf TRUE in UTF mode
+ number the required bracket number or negative to find a lookbehind
+
+Returns: pointer to the opcode for the bracket, or NULL if not found
+*/
+
+PCRE2_SPTR
+PRIV(find_bracket)(PCRE2_SPTR code, BOOL utf, int number)
+{
+for (;;)
+ {
+ register PCRE2_UCHAR c = *code;
+
+ if (c == OP_END) return NULL;
+
+ /* XCLASS is used for classes that cannot be represented just by a bit map.
+ This includes negated single high-valued characters. CALLOUT_STR is used for
+ callouts with string arguments. In both cases the length in the table is
+ zero; the actual length is stored in the compiled code. */
+
+ if (c == OP_XCLASS) code += GET(code, 1);
+ else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE);
+
+ /* Handle lookbehind */
+
+ else if (c == OP_REVERSE)
+ {
+ if (number < 0) return (PCRE2_UCHAR *)code;
+ code += PRIV(OP_lengths)[c];
+ }
+
+ /* Handle capturing bracket */
+
+ else if (c == OP_CBRA || c == OP_SCBRA ||
+ c == OP_CBRAPOS || c == OP_SCBRAPOS)
+ {
+ int n = (int)GET2(code, 1+LINK_SIZE);
+ if (n == number) return (PCRE2_UCHAR *)code;
+ code += PRIV(OP_lengths)[c];
+ }
+
+ /* Otherwise, we can get the item's length from the table, except that for
+ repeated character types, we have to test for \p and \P, which have an extra
+ two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we
+ must add in its length. */
+
+ else
+ {
+ switch(c)
+ {
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+ break;
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSUPTO:
+ if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+ code += 2;
+ break;
+
+ case OP_MARK:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ code += code[1];
+ break;
+ }
+
+ /* Add in the fixed length from the table */
+
+ code += PRIV(OP_lengths)[c];
+
+ /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may be
+ followed by a multi-byte character. The length in the table is a minimum, so
+ we have to arrange to skip the extra bytes. */
+
+#ifdef MAYBE_UTF_MULTI
+ if (utf) switch(c)
+ {
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_EXACT:
+ case OP_EXACTI:
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ case OP_UPTO:
+ case OP_UPTOI:
+ case OP_NOTUPTO:
+ case OP_NOTUPTOI:
+ case OP_MINUPTO:
+ case OP_MINUPTOI:
+ case OP_NOTMINUPTO:
+ case OP_NOTMINUPTOI:
+ case OP_POSUPTO:
+ case OP_POSUPTOI:
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+ case OP_STAR:
+ case OP_STARI:
+ case OP_NOTSTAR:
+ case OP_NOTSTARI:
+ case OP_MINSTAR:
+ case OP_MINSTARI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINSTARI:
+ case OP_POSSTAR:
+ case OP_POSSTARI:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSSTARI:
+ case OP_PLUS:
+ case OP_PLUSI:
+ case OP_NOTPLUS:
+ case OP_NOTPLUSI:
+ case OP_MINPLUS:
+ case OP_MINPLUSI:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINPLUSI:
+ case OP_POSPLUS:
+ case OP_POSPLUSI:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSPLUSI:
+ case OP_QUERY:
+ case OP_QUERYI:
+ case OP_NOTQUERY:
+ case OP_NOTQUERYI:
+ case OP_MINQUERY:
+ case OP_MINQUERYI:
+ case OP_NOTMINQUERY:
+ case OP_NOTMINQUERYI:
+ case OP_POSQUERY:
+ case OP_POSQUERYI:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSQUERYI:
+ if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+ break;
+ }
+#else
+ (void)(utf); /* Keep compiler happy by referencing function argument */
+#endif /* MAYBE_UTF_MULTI */
+ }
+ }
+}
+
+/* End of pcre2_find_bracket.c */
diff --git a/src/3rdparty/pcre/pcre_internal.h b/src/3rdparty/pcre2/src/pcre2_internal.h
index 2923b29f82..56908708aa 100644
--- a/src/3rdparty/pcre/pcre_internal.h
+++ b/src/3rdparty/pcre2/src/pcre2_internal.h
@@ -2,12 +2,12 @@
* Perl-Compatible Regular Expressions *
*************************************************/
-
-/* PCRE is a library of functions to support regular expressions whose syntax
+/* PCRE2 is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2016 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -38,72 +38,17 @@ POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
-/* This header contains definitions that are shared between the different
-modules, but which are not relevant to the exported API. This includes some
-functions whose names all begin with "_pcre_", "_pcre16_" or "_pcre32_"
-depending on the PRIV macro. */
-
-#ifndef PCRE_INTERNAL_H
-#define PCRE_INTERNAL_H
-
-/* Define PCRE_DEBUG to get debugging output on stdout. */
-
-#if 0
-#define PCRE_DEBUG
-#endif
-
-/* PCRE is compiled as an 8 bit library if it is not requested otherwise. */
-
-#if !defined COMPILE_PCRE16 && !defined COMPILE_PCRE32
-#define COMPILE_PCRE8
-#endif
-
-/* If SUPPORT_UCP is defined, SUPPORT_UTF must also be defined. The
-"configure" script ensures this, but not everybody uses "configure". */
-
-#if defined SUPPORT_UCP && !(defined SUPPORT_UTF)
-#define SUPPORT_UTF 1
-#endif
-
-/* We define SUPPORT_UTF if SUPPORT_UTF8 is enabled for compatibility
-reasons with existing code. */
-
-#if defined SUPPORT_UTF8 && !(defined SUPPORT_UTF)
-#define SUPPORT_UTF 1
-#endif
-
-/* Fixme: SUPPORT_UTF8 should be eventually disappear from the code.
-Until then we define it if SUPPORT_UTF is defined. */
-
-#if defined SUPPORT_UTF && !(defined SUPPORT_UTF8)
-#define SUPPORT_UTF8 1
-#endif
-
-/* We do not support both EBCDIC and UTF-8/16/32 at the same time. The "configure"
-script prevents both being selected, but not everybody uses "configure". */
-
-#if defined EBCDIC && defined SUPPORT_UTF
-#error The use of both EBCDIC and SUPPORT_UTF is not supported.
-#endif
-
-/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
-inline, and there are *still* stupid compilers about that don't like indented
-pre-processor statements, or at least there were when I first wrote this. After
-all, it had only been about 10 years then...
+/* We do not support both EBCDIC and Unicode at the same time. The "configure"
+script prevents both being selected, but not everybody uses "configure". EBCDIC
+is only supported for the 8-bit library, but the check for this has to be later
+in this file, because the first part is not width-dependent, and is included by
+pcre2test.c with CODE_UNIT_WIDTH == 0. */
-It turns out that the Mac Debugging.h header also defines the macro DPRINTF, so
-be absolutely sure we get our version. */
-
-#undef DPRINTF
-#ifdef PCRE_DEBUG
-#define DPRINTF(p) printf p
-#else
-#define DPRINTF(p) /* Nothing */
+#if defined EBCDIC && defined SUPPORT_UNICODE
+#error The use of both EBCDIC and SUPPORT_UNICODE is not supported.
#endif
-
-/* Standard C headers plus the external interface definition. The only time
-setjmp and stdarg are used is when NO_RECURSE is set. */
+/* Standard C headers */
#include <ctype.h>
#include <limits.h>
@@ -112,65 +57,91 @@ setjmp and stdarg are used is when NO_RECURSE is set. */
#include <stdlib.h>
#include <string.h>
+/* Macros to make boolean values more obvious. The #ifndef is to pacify
+compiler warnings in environments where these macros are defined elsewhere.
+Unfortunately, there is no way to do the same for the typedef. */
+
+typedef int BOOL;
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
/* Valgrind (memcheck) support */
#ifdef SUPPORT_VALGRIND
#include <valgrind/memcheck.h>
#endif
+/* Older versions of MSVC lack snprintf(). This define allows for
+warning/error-free compilation and testing with MSVC compilers back to at least
+MSVC 10/2010. Except for VC6 (which is missing some fundamentals and fails). */
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define snprintf _snprintf
+#endif
+
/* When compiling a DLL for Windows, the exported symbols have to be declared
using some MS magic. I found some useful information on this web page:
http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the
information there, using __declspec(dllexport) without "extern" we have a
definition; with "extern" we have a declaration. The settings here override the
-setting in pcre.h (which is included below); it defines only PCRE_EXP_DECL,
+setting in pcre2.h (which is included below); it defines only PCRE2_EXP_DECL,
which is all that is needed for applications (they just import the symbols). We
use:
- PCRE_EXP_DECL for declarations
- PCRE_EXP_DEFN for definitions of exported functions
- PCRE_EXP_DATA_DEFN for definitions of exported variables
-
-The reason for the two DEFN macros is that in non-Windows environments, one
-does not want to have "extern" before variable definitions because it leads to
-compiler warnings. So we distinguish between functions and variables. In
-Windows, the two should always be the same.
+ PCRE2_EXP_DECL for declarations
+ PCRE2_EXP_DEFN for definitions
-The reason for wrapping this in #ifndef PCRE_EXP_DECL is so that pcretest,
+The reason for wrapping this in #ifndef PCRE2_EXP_DECL is so that pcre2test,
which is an application, but needs to import this file in order to "peek" at
-internals, can #include pcre.h first to get an application's-eye view.
+internals, can #include pcre2.h first to get an application's-eye view.
In principle, people compiling for non-Windows, non-Unix-like (i.e. uncommon,
special-purpose environments) might want to stick other stuff in front of
-exported symbols. That's why, in the non-Windows case, we set PCRE_EXP_DEFN and
-PCRE_EXP_DATA_DEFN only if they are not already set. */
+exported symbols. That's why, in the non-Windows case, we set PCRE2_EXP_DEFN
+only if it is not already set. */
-#ifndef PCRE_EXP_DECL
+#ifndef PCRE2_EXP_DECL
# ifdef _WIN32
-# ifndef PCRE_STATIC
-# define PCRE_EXP_DECL extern __declspec(dllexport)
-# define PCRE_EXP_DEFN __declspec(dllexport)
-# define PCRE_EXP_DATA_DEFN __declspec(dllexport)
+# ifndef PCRE2_STATIC
+# define PCRE2_EXP_DECL extern __declspec(dllexport)
+# define PCRE2_EXP_DEFN __declspec(dllexport)
# else
-# define PCRE_EXP_DECL extern
-# define PCRE_EXP_DEFN
-# define PCRE_EXP_DATA_DEFN
+# define PCRE2_EXP_DECL extern
+# define PCRE2_EXP_DEFN
# endif
# else
# ifdef __cplusplus
-# define PCRE_EXP_DECL extern "C"
+# define PCRE2_EXP_DECL extern "C"
# else
-# define PCRE_EXP_DECL extern
+# define PCRE2_EXP_DECL extern
# endif
-# ifndef PCRE_EXP_DEFN
-# define PCRE_EXP_DEFN PCRE_EXP_DECL
-# endif
-# ifndef PCRE_EXP_DATA_DEFN
-# define PCRE_EXP_DATA_DEFN
+# ifndef PCRE2_EXP_DEFN
+# define PCRE2_EXP_DEFN PCRE2_EXP_DECL
# endif
# endif
#endif
+/* Include the public PCRE2 header and the definitions of UCP character
+property values. This must follow the setting of PCRE2_EXP_DECL above. */
+
+#include "pcre2.h"
+#include "pcre2_ucp.h"
+
+/* When PCRE2 is compiled as a C++ library, the subject pointer can be replaced
+with a custom type. This makes it possible, for example, to allow pcre2_match()
+to process subject strings that are discontinuous by using a smart pointer
+class. It must always be possible to inspect all of the subject string in
+pcre2_match() because of the way it backtracks. */
+
+/* WARNING: This is as yet untested for PCRE2. */
+
+#ifdef CUSTOM_SUBJECT_PTR
+#undef PCRE2_SPTR
+#define PCRE2_SPTR CUSTOM_SUBJECT_PTR
+#endif
+
/* When compiling with the MSVC compiler, it is sometimes necessary to include
a "calling convention" before exported function names. (This is secondhand
information; I know nothing about MSVC myself). For example, something like
@@ -178,50 +149,14 @@ information; I know nothing about MSVC myself). For example, something like
void __cdecl function(....)
might be needed. In order so make this easy, all the exported functions have
-PCRE_CALL_CONVENTION just before their names. It is rarely needed; if not
+PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not
set, we ensure here that it has no effect. */
-#ifndef PCRE_CALL_CONVENTION
-#define PCRE_CALL_CONVENTION
+#ifndef PCRE2_CALL_CONVENTION
+#define PCRE2_CALL_CONVENTION
#endif
-/* We need to have types that specify unsigned 8, 16 and 32-bit integers. We
-cannot determine these outside the compilation (e.g. by running a program as
-part of "configure") because PCRE is often cross-compiled for use on other
-systems. Instead we make use of the maximum sizes that are available at
-preprocessor time in standard C environments. */
-
-typedef unsigned char pcre_uint8;
-
-#if USHRT_MAX == 65535
-typedef unsigned short pcre_uint16;
-typedef short pcre_int16;
-#define PCRE_UINT16_MAX USHRT_MAX
-#define PCRE_INT16_MAX SHRT_MAX
-#elif UINT_MAX == 65535
-typedef unsigned int pcre_uint16;
-typedef int pcre_int16;
-#define PCRE_UINT16_MAX UINT_MAX
-#define PCRE_INT16_MAX INT_MAX
-#else
-#error Cannot determine a type for 16-bit integers
-#endif
-
-#if UINT_MAX == 4294967295U
-typedef unsigned int pcre_uint32;
-typedef int pcre_int32;
-#define PCRE_UINT32_MAX UINT_MAX
-#define PCRE_INT32_MAX INT_MAX
-#elif ULONG_MAX == 4294967295UL
-typedef unsigned long int pcre_uint32;
-typedef long int pcre_int32;
-#define PCRE_UINT32_MAX ULONG_MAX
-#define PCRE_INT32_MAX LONG_MAX
-#else
-#error Cannot determine a type for 32-bit integers
-#endif
-
-/* When checking for integer overflow in pcre_compile(), we need to handle
+/* When checking for integer overflow in pcre2_compile(), we need to handle
large integers. If a 64-bit integer type is available, we can use that.
Otherwise we have to cast to double, which of course requires floating point
arithmetic. Handle this by defining a macro for the appropriate type. If
@@ -241,128 +176,8 @@ by "configure". */
#define INT64_OR_DOUBLE double
#endif
-/* All character handling must be done as unsigned characters. Otherwise there
-are problems with top-bit-set characters and functions such as isspace().
-However, we leave the interface to the outside world as char * or short *,
-because that should make things easier for callers. This character type is
-called pcre_uchar.
-
-The IN_UCHARS macro multiply its argument with the byte size of the current
-pcre_uchar type. Useful for memcpy and such operations, whose require the
-byte size of their input/output buffers.
-
-The MAX_255 macro checks whether its pcre_uchar input is less than 256.
-
-The TABLE_GET macro is designed for accessing elements of tables whose contain
-exactly 256 items. When the character is able to contain more than 256
-items, some check is needed before accessing these tables.
-*/
-
-#if defined COMPILE_PCRE8
-
-typedef unsigned char pcre_uchar;
-#define IN_UCHARS(x) (x)
-#define MAX_255(c) 1
-#define TABLE_GET(c, table, default) ((table)[c])
-
-#elif defined COMPILE_PCRE16
-
-#if USHRT_MAX != 65535
-/* This is a warning message. Change PCRE_UCHAR16 to a 16 bit data type in
-pcre.h(.in) and disable (comment out) this message. */
-#error Warning: PCRE_UCHAR16 is not a 16 bit data type.
-#endif
-
-typedef pcre_uint16 pcre_uchar;
-#define UCHAR_SHIFT (1)
-#define IN_UCHARS(x) ((x) * 2)
-#define MAX_255(c) ((c) <= 255u)
-#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default))
-
-#elif defined COMPILE_PCRE32
-
-typedef pcre_uint32 pcre_uchar;
-#define UCHAR_SHIFT (2)
-#define IN_UCHARS(x) ((x) * 4)
-#define MAX_255(c) ((c) <= 255u)
-#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default))
-
-#else
-#error Unsupported compiling mode
-#endif /* COMPILE_PCRE[8|16|32] */
-
-/* This is an unsigned int value that no character can ever have. UTF-8
-characters only go up to 0x7fffffff (though Unicode doesn't go beyond
-0x0010ffff). */
-
-#define NOTACHAR 0xffffffff
-
-/* PCRE is able to support several different kinds of newline (CR, LF, CRLF,
-"any" and "anycrlf" at present). The following macros are used to package up
-testing for newlines. NLBLOCK, PSSTART, and PSEND are defined in the various
-modules to indicate in which datablock the parameters exist, and what the
-start/end of string field names are. */
-
-#define NLTYPE_FIXED 0 /* Newline is a fixed length string */
-#define NLTYPE_ANY 1 /* Newline is any Unicode line ending */
-#define NLTYPE_ANYCRLF 2 /* Newline is CR, LF, or CRLF */
-
-/* This macro checks for a newline at the given position */
-
-#define IS_NEWLINE(p) \
- ((NLBLOCK->nltype != NLTYPE_FIXED)? \
- ((p) < NLBLOCK->PSEND && \
- PRIV(is_newline)((p), NLBLOCK->nltype, NLBLOCK->PSEND, \
- &(NLBLOCK->nllen), utf)) \
- : \
- ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \
- UCHAR21TEST(p) == NLBLOCK->nl[0] && \
- (NLBLOCK->nllen == 1 || UCHAR21TEST(p+1) == NLBLOCK->nl[1]) \
- ) \
- )
-
-/* This macro checks for a newline immediately preceding the given position */
-
-#define WAS_NEWLINE(p) \
- ((NLBLOCK->nltype != NLTYPE_FIXED)? \
- ((p) > NLBLOCK->PSSTART && \
- PRIV(was_newline)((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \
- &(NLBLOCK->nllen), utf)) \
- : \
- ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \
- UCHAR21TEST(p - NLBLOCK->nllen) == NLBLOCK->nl[0] && \
- (NLBLOCK->nllen == 1 || UCHAR21TEST(p - NLBLOCK->nllen + 1) == NLBLOCK->nl[1]) \
- ) \
- )
-
-/* When PCRE is compiled as a C++ library, the subject pointer can be replaced
-with a custom type. This makes it possible, for example, to allow pcre_exec()
-to process subject strings that are discontinuous by using a smart pointer
-class. It must always be possible to inspect all of the subject string in
-pcre_exec() because of the way it backtracks. Two macros are required in the
-normal case, for sign-unspecified and unsigned char pointers. The former is
-used for the external interface and appears in pcre.h, which is why its name
-must begin with PCRE_. */
-
-#ifdef CUSTOM_SUBJECT_PTR
-#define PCRE_PUCHAR CUSTOM_SUBJECT_PTR
-#else
-#define PCRE_PUCHAR const pcre_uchar *
-#endif
-
-/* Include the public PCRE header and the definitions of UCP character property
-values. */
-
-#include "pcre.h"
-#include "ucp.h"
-
-#ifdef COMPILE_PCRE32
-/* Assert that the public PCRE_UCHAR32 is a 32-bit type */
-typedef int __assert_pcre_uchar32_size[sizeof(PCRE_UCHAR32) == 4 ? 1 : -1];
-#endif
-
/* When compiling for use with the Virtual Pascal compiler, these functions
-need to have their names changed. PCRE must be compiled with the -DVPCOMPAT
+need to have their names changed. PCRE2 must be compiled with the -DVPCOMPAT
option on the command line. */
#ifdef VPCOMPAT
@@ -385,7 +200,7 @@ neither (there some non-Unix environments where this is the case). */
#define memmove(a, b, c) bcopy(b, a, c)
#else /* HAVE_BCOPY */
static void *
-pcre_memmove(void *d, const void *s, size_t n)
+pcre2_memmove(void *d, const void *s, size_t n)
{
size_t i;
unsigned char *dest = (unsigned char *)d;
@@ -403,249 +218,87 @@ else
return (void *)(dest - n);
}
}
-#define memmove(a, b, c) pcre_memmove(a, b, c)
+#define memmove(a, b, c) pcre2_memmove(a, b, c)
#endif /* not HAVE_BCOPY */
#endif /* not HAVE_MEMMOVE */
#endif /* not VPCOMPAT */
+/* External (in the C sense) functions and tables that are private to the
+libraries are always referenced using the PRIV macro. This makes it possible
+for pcre2test.c to include some of the source files from the libraries using a
+different PRIV definition to avoid name clashes. It also makes it clear in the
+code that a non-static object is being referenced. */
-/* PCRE keeps offsets in its compiled code as 2-byte quantities (always stored
-in big-endian order) by default. These are used, for example, to link from the
-start of a subpattern to its alternatives and its end. The use of 2 bytes per
-offset limits the size of the compiled regex to around 64K, which is big enough
-for almost everybody. However, I received a request for an even bigger limit.
-For this reason, and also to make the code easier to maintain, the storing and
-loading of offsets from the byte string is now handled by the macros that are
-defined here.
-
-The macros are controlled by the value of LINK_SIZE. This defaults to 2 in
-the config.h file, but can be overridden by using -D on the command line. This
-is automated on Unix systems via the "configure" command. */
-
-#if defined COMPILE_PCRE8
-
-#if LINK_SIZE == 2
-
-#define PUT(a,n,d) \
- (a[n] = (d) >> 8), \
- (a[(n)+1] = (d) & 255)
-
-#define GET(a,n) \
- (((a)[n] << 8) | (a)[(n)+1])
-
-#define MAX_PATTERN_SIZE (1 << 16)
-
-
-#elif LINK_SIZE == 3
-
-#define PUT(a,n,d) \
- (a[n] = (d) >> 16), \
- (a[(n)+1] = (d) >> 8), \
- (a[(n)+2] = (d) & 255)
-
-#define GET(a,n) \
- (((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2])
-
-#define MAX_PATTERN_SIZE (1 << 24)
-
-
-#elif LINK_SIZE == 4
-
-#define PUT(a,n,d) \
- (a[n] = (d) >> 24), \
- (a[(n)+1] = (d) >> 16), \
- (a[(n)+2] = (d) >> 8), \
- (a[(n)+3] = (d) & 255)
-
-#define GET(a,n) \
- (((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3])
-
-/* Keep it positive */
-#define MAX_PATTERN_SIZE (1 << 30)
-
-#else
-#error LINK_SIZE must be either 2, 3, or 4
+#ifndef PRIV
+#define PRIV(name) _pcre2_##name
#endif
-#elif defined COMPILE_PCRE16
+/* This is an unsigned int value that no UTF character can ever have, as
+Unicode doesn't go beyond 0x0010ffff. */
-#if LINK_SIZE == 2
-
-/* Redefine LINK_SIZE as a multiple of sizeof(pcre_uchar) */
-#undef LINK_SIZE
-#define LINK_SIZE 1
-
-#define PUT(a,n,d) \
- (a[n] = (d))
-
-#define GET(a,n) \
- (a[n])
-
-#define MAX_PATTERN_SIZE (1 << 16)
+#define NOTACHAR 0xffffffff
-#elif LINK_SIZE == 3 || LINK_SIZE == 4
+/* This is the largest valid UTF/Unicode code point. */
-/* Redefine LINK_SIZE as a multiple of sizeof(pcre_uchar) */
-#undef LINK_SIZE
-#define LINK_SIZE 2
+#define MAX_UTF_CODE_POINT 0x10ffff
-#define PUT(a,n,d) \
- (a[n] = (d) >> 16), \
- (a[(n)+1] = (d) & 65535)
+/* Compile-time positive error numbers (all except UTF errors, which are
+negative) start at this value. It should probably never be changed, in case
+some application is checking for specific numbers. There is a copy of this
+#define in pcre2posix.c (which now no longer includes this file). Ideally, a
+way of having a single definition should be found, but as the number is
+unlikely to change, this is not a pressing issue. The original reason for
+having a base other than 0 was to keep the absolute values of compile-time and
+run-time error numbers numerically different, but in the event the code does
+not rely on this. */
-#define GET(a,n) \
- (((a)[n] << 16) | (a)[(n)+1])
+#define COMPILE_ERROR_BASE 100
-/* Keep it positive */
-#define MAX_PATTERN_SIZE (1 << 30)
+/* Define the default BSR convention. */
+#ifdef BSR_ANYCRLF
+#define BSR_DEFAULT PCRE2_BSR_ANYCRLF
#else
-#error LINK_SIZE must be either 2, 3, or 4
+#define BSR_DEFAULT PCRE2_BSR_UNICODE
#endif
-#elif defined COMPILE_PCRE32
-
-/* Only supported LINK_SIZE is 4 */
-/* Redefine LINK_SIZE as a multiple of sizeof(pcre_uchar) */
-#undef LINK_SIZE
-#define LINK_SIZE 1
-
-#define PUT(a,n,d) \
- (a[n] = (d))
-
-#define GET(a,n) \
- (a[n])
-
-/* Keep it positive */
-#define MAX_PATTERN_SIZE (1 << 30)
-
-#else
-#error Unsupported compiling mode
-#endif /* COMPILE_PCRE[8|16|32] */
-
-/* Convenience macro defined in terms of the others */
-
-#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE
-
-
-/* PCRE uses some other 2-byte quantities that do not change when the size of
-offsets changes. There are used for repeat counts and for other things such as
-capturing parenthesis numbers in back references. */
-
-#if defined COMPILE_PCRE8
-
-#define IMM2_SIZE 2
-
-#define PUT2(a,n,d) \
- a[n] = (d) >> 8; \
- a[(n)+1] = (d) & 255
-
-/* For reasons that I do not understand, the expression in this GET2 macro is
-treated by gcc as a signed expression, even when a is declared as unsigned. It
-seems that any kind of arithmetic results in a signed value. */
-
-#define GET2(a,n) \
- (unsigned int)(((a)[n] << 8) | (a)[(n)+1])
-
-#elif defined COMPILE_PCRE16
-
-#define IMM2_SIZE 1
-
-#define PUT2(a,n,d) \
- a[n] = d
-
-#define GET2(a,n) \
- a[n]
-
-#elif defined COMPILE_PCRE32
-
-#define IMM2_SIZE 1
-
-#define PUT2(a,n,d) \
- a[n] = d
-#define GET2(a,n) \
- a[n]
+/* ---------------- Basic UTF-8 macros ---------------- */
-#else
-#error Unsupported compiling mode
-#endif /* COMPILE_PCRE[8|16|32] */
-
-#define PUT2INC(a,n,d) PUT2(a,n,d), a += IMM2_SIZE
+/* These UTF-8 macros are always defined because they are used in pcre2test for
+handling wide characters in 16-bit and 32-bit modes, even if an 8-bit library
+is not supported. */
-/* The maximum length of a MARK name is currently one data unit; it may be
-changed in future to be a fixed number of bytes or to depend on LINK_SIZE. */
-
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
-#define MAX_MARK ((1u << 16) - 1)
-#else
-#define MAX_MARK ((1u << 8) - 1)
-#endif
-
-/* There is a proposed future special "UTF-21" mode, in which only the lowest
-21 bits of a 32-bit character are interpreted as UTF, with the remaining 11
-high-order bits available to the application for other uses. In preparation for
-the future implementation of this mode, there are macros that load a data item
-and, if in this special mode, mask it to 21 bits. These macros all have names
-starting with UCHAR21. In all other modes, including the normal 32-bit
-library, the macros all have the same simple definitions. When the new mode is
-implemented, it is expected that these definitions will be varied appropriately
-using #ifdef when compiling the library that supports the special mode. */
-
-#define UCHAR21(eptr) (*(eptr))
-#define UCHAR21TEST(eptr) (*(eptr))
-#define UCHAR21INC(eptr) (*(eptr)++)
-#define UCHAR21INCTEST(eptr) (*(eptr)++)
-
-/* When UTF encoding is being used, a character is no longer just a single
-byte in 8-bit mode or a single short in 16-bit mode. The macros for character
-handling generate simple sequences when used in the basic mode, and more
-complicated ones for UTF characters. GETCHARLENTEST and other macros are not
-used when UTF is not supported. To make sure they can never even appear when
-UTF support is omitted, we don't even define them. */
-
-#ifndef SUPPORT_UTF
-
-/* #define MAX_VALUE_FOR_SINGLE_CHAR */
-/* #define HAS_EXTRALEN(c) */
-/* #define GET_EXTRALEN(c) */
-/* #define NOT_FIRSTCHAR(c) */
-#define GETCHAR(c, eptr) c = *eptr;
-#define GETCHARTEST(c, eptr) c = *eptr;
-#define GETCHARINC(c, eptr) c = *eptr++;
-#define GETCHARINCTEST(c, eptr) c = *eptr++;
-#define GETCHARLEN(c, eptr, len) c = *eptr;
-/* #define GETCHARLENTEST(c, eptr, len) */
-/* #define BACKCHAR(eptr) */
-/* #define FORWARDCHAR(eptr) */
-/* #define ACROSSCHAR(condition, eptr, action) */
-
-#else /* SUPPORT_UTF */
-
-/* Tests whether the code point needs extra characters to decode. */
+/* Tests whether a UTF-8 code point needs extra bytes to decode. */
#define HASUTF8EXTRALEN(c) ((c) >= 0xc0)
+/* The following macros were originally written in the form of loops that used
+data from the tables whose names start with PRIV(utf8_table). They were
+rewritten by a user so as not to use loops, because in some environments this
+gives a significant performance advantage, and it seems never to do any harm.
+*/
+
/* Base macro to pick up the remaining bytes of a UTF-8 character, not
advancing the pointer. */
#define GETUTF8(c, eptr) \
{ \
- if ((c & 0x20) == 0) \
- c = ((c & 0x1f) << 6) | (eptr[1] & 0x3f); \
- else if ((c & 0x10) == 0) \
- c = ((c & 0x0f) << 12) | ((eptr[1] & 0x3f) << 6) | (eptr[2] & 0x3f); \
- else if ((c & 0x08) == 0) \
- c = ((c & 0x07) << 18) | ((eptr[1] & 0x3f) << 12) | \
- ((eptr[2] & 0x3f) << 6) | (eptr[3] & 0x3f); \
- else if ((c & 0x04) == 0) \
- c = ((c & 0x03) << 24) | ((eptr[1] & 0x3f) << 18) | \
- ((eptr[2] & 0x3f) << 12) | ((eptr[3] & 0x3f) << 6) | \
- (eptr[4] & 0x3f); \
+ if ((c & 0x20u) == 0) \
+ c = ((c & 0x1fu) << 6) | (eptr[1] & 0x3fu); \
+ else if ((c & 0x10u) == 0) \
+ c = ((c & 0x0fu) << 12) | ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \
+ else if ((c & 0x08u) == 0) \
+ c = ((c & 0x07u) << 18) | ((eptr[1] & 0x3fu) << 12) | \
+ ((eptr[2] & 0x3fu) << 6) | (eptr[3] & 0x3fu); \
+ else if ((c & 0x04u) == 0) \
+ c = ((c & 0x03u) << 24) | ((eptr[1] & 0x3fu) << 18) | \
+ ((eptr[2] & 0x3fu) << 12) | ((eptr[3] & 0x3fu) << 6) | \
+ (eptr[4] & 0x3fu); \
else \
- c = ((c & 0x01) << 30) | ((eptr[1] & 0x3f) << 24) | \
- ((eptr[2] & 0x3f) << 18) | ((eptr[3] & 0x3f) << 12) | \
- ((eptr[4] & 0x3f) << 6) | (eptr[5] & 0x3f); \
+ c = ((c & 0x01u) << 30) | ((eptr[1] & 0x3fu) << 24) | \
+ ((eptr[2] & 0x3fu) << 18) | ((eptr[3] & 0x3fu) << 12) | \
+ ((eptr[4] & 0x3fu) << 6) | (eptr[5] & 0x3fu); \
}
/* Base macro to pick up the remaining bytes of a UTF-8 character, advancing
@@ -653,315 +306,73 @@ the pointer. */
#define GETUTF8INC(c, eptr) \
{ \
- if ((c & 0x20) == 0) \
- c = ((c & 0x1f) << 6) | (*eptr++ & 0x3f); \
- else if ((c & 0x10) == 0) \
+ if ((c & 0x20u) == 0) \
+ c = ((c & 0x1fu) << 6) | (*eptr++ & 0x3fu); \
+ else if ((c & 0x10u) == 0) \
{ \
- c = ((c & 0x0f) << 12) | ((*eptr & 0x3f) << 6) | (eptr[1] & 0x3f); \
+ c = ((c & 0x0fu) << 12) | ((*eptr & 0x3fu) << 6) | (eptr[1] & 0x3fu); \
eptr += 2; \
} \
- else if ((c & 0x08) == 0) \
+ else if ((c & 0x08u) == 0) \
{ \
- c = ((c & 0x07) << 18) | ((*eptr & 0x3f) << 12) | \
- ((eptr[1] & 0x3f) << 6) | (eptr[2] & 0x3f); \
+ c = ((c & 0x07u) << 18) | ((*eptr & 0x3fu) << 12) | \
+ ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \
eptr += 3; \
} \
- else if ((c & 0x04) == 0) \
+ else if ((c & 0x04u) == 0) \
{ \
- c = ((c & 0x03) << 24) | ((*eptr & 0x3f) << 18) | \
- ((eptr[1] & 0x3f) << 12) | ((eptr[2] & 0x3f) << 6) | \
- (eptr[3] & 0x3f); \
+ c = ((c & 0x03u) << 24) | ((*eptr & 0x3fu) << 18) | \
+ ((eptr[1] & 0x3fu) << 12) | ((eptr[2] & 0x3fu) << 6) | \
+ (eptr[3] & 0x3fu); \
eptr += 4; \
} \
else \
{ \
- c = ((c & 0x01) << 30) | ((*eptr & 0x3f) << 24) | \
- ((eptr[1] & 0x3f) << 18) | ((eptr[2] & 0x3f) << 12) | \
- ((eptr[3] & 0x3f) << 6) | (eptr[4] & 0x3f); \
+ c = ((c & 0x01u) << 30) | ((*eptr & 0x3fu) << 24) | \
+ ((eptr[1] & 0x3fu) << 18) | ((eptr[2] & 0x3fu) << 12) | \
+ ((eptr[3] & 0x3fu) << 6) | (eptr[4] & 0x3fu); \
eptr += 5; \
} \
}
-#if defined COMPILE_PCRE8
-
-/* These macros were originally written in the form of loops that used data
-from the tables whose names start with PRIV(utf8_table). They were rewritten by
-a user so as not to use loops, because in some environments this gives a
-significant performance advantage, and it seems never to do any harm. */
-
-/* Tells the biggest code point which can be encoded as a single character. */
-
-#define MAX_VALUE_FOR_SINGLE_CHAR 127
-
-/* Tests whether the code point needs extra characters to decode. */
-
-#define HAS_EXTRALEN(c) ((c) >= 0xc0)
-
-/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
-Otherwise it has an undefined behaviour. */
-
-#define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3f])
-
-/* Returns TRUE, if the given character is not the first character
-of a UTF sequence. */
-
-#define NOT_FIRSTCHAR(c) (((c) & 0xc0) == 0x80)
-
-/* Get the next UTF-8 character, not advancing the pointer. This is called when
-we know we are in UTF-8 mode. */
-
-#define GETCHAR(c, eptr) \
- c = *eptr; \
- if (c >= 0xc0) GETUTF8(c, eptr);
-
-/* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the
-pointer. */
-
-#define GETCHARTEST(c, eptr) \
- c = *eptr; \
- if (utf && c >= 0xc0) GETUTF8(c, eptr);
-
-/* Get the next UTF-8 character, advancing the pointer. This is called when we
-know we are in UTF-8 mode. */
-
-#define GETCHARINC(c, eptr) \
- c = *eptr++; \
- if (c >= 0xc0) GETUTF8INC(c, eptr);
-
-/* Get the next character, testing for UTF-8 mode, and advancing the pointer.
-This is called when we don't know if we are in UTF-8 mode. */
-
-#define GETCHARINCTEST(c, eptr) \
- c = *eptr++; \
- if (utf && c >= 0xc0) GETUTF8INC(c, eptr);
-
/* Base macro to pick up the remaining bytes of a UTF-8 character, not
advancing the pointer, incrementing the length. */
#define GETUTF8LEN(c, eptr, len) \
{ \
- if ((c & 0x20) == 0) \
+ if ((c & 0x20u) == 0) \
{ \
- c = ((c & 0x1f) << 6) | (eptr[1] & 0x3f); \
+ c = ((c & 0x1fu) << 6) | (eptr[1] & 0x3fu); \
len++; \
} \
- else if ((c & 0x10) == 0) \
+ else if ((c & 0x10u) == 0) \
{ \
- c = ((c & 0x0f) << 12) | ((eptr[1] & 0x3f) << 6) | (eptr[2] & 0x3f); \
+ c = ((c & 0x0fu) << 12) | ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \
len += 2; \
} \
- else if ((c & 0x08) == 0) \
+ else if ((c & 0x08u) == 0) \
{\
- c = ((c & 0x07) << 18) | ((eptr[1] & 0x3f) << 12) | \
- ((eptr[2] & 0x3f) << 6) | (eptr[3] & 0x3f); \
+ c = ((c & 0x07u) << 18) | ((eptr[1] & 0x3fu) << 12) | \
+ ((eptr[2] & 0x3fu) << 6) | (eptr[3] & 0x3fu); \
len += 3; \
} \
- else if ((c & 0x04) == 0) \
+ else if ((c & 0x04u) == 0) \
{ \
- c = ((c & 0x03) << 24) | ((eptr[1] & 0x3f) << 18) | \
- ((eptr[2] & 0x3f) << 12) | ((eptr[3] & 0x3f) << 6) | \
- (eptr[4] & 0x3f); \
+ c = ((c & 0x03u) << 24) | ((eptr[1] & 0x3fu) << 18) | \
+ ((eptr[2] & 0x3fu) << 12) | ((eptr[3] & 0x3fu) << 6) | \
+ (eptr[4] & 0x3fu); \
len += 4; \
} \
else \
{\
- c = ((c & 0x01) << 30) | ((eptr[1] & 0x3f) << 24) | \
- ((eptr[2] & 0x3f) << 18) | ((eptr[3] & 0x3f) << 12) | \
- ((eptr[4] & 0x3f) << 6) | (eptr[5] & 0x3f); \
+ c = ((c & 0x01u) << 30) | ((eptr[1] & 0x3fu) << 24) | \
+ ((eptr[2] & 0x3fu) << 18) | ((eptr[3] & 0x3fu) << 12) | \
+ ((eptr[4] & 0x3fu) << 6) | (eptr[5] & 0x3fu); \
len += 5; \
} \
}
-/* Get the next UTF-8 character, not advancing the pointer, incrementing length
-if there are extra bytes. This is called when we know we are in UTF-8 mode. */
-
-#define GETCHARLEN(c, eptr, len) \
- c = *eptr; \
- if (c >= 0xc0) GETUTF8LEN(c, eptr, len);
-
-/* Get the next UTF-8 character, testing for UTF-8 mode, not advancing the
-pointer, incrementing length if there are extra bytes. This is called when we
-do not know if we are in UTF-8 mode. */
-
-#define GETCHARLENTEST(c, eptr, len) \
- c = *eptr; \
- if (utf && c >= 0xc0) GETUTF8LEN(c, eptr, len);
-
-/* If the pointer is not at the start of a character, move it back until
-it is. This is called only in UTF-8 mode - we don't put a test within the macro
-because almost all calls are already within a block of UTF-8 only code. */
-
-#define BACKCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr--
-
-/* Same as above, just in the other direction. */
-#define FORWARDCHAR(eptr) while((*eptr & 0xc0) == 0x80) eptr++
-
-/* Same as above, but it allows a fully customizable form. */
-#define ACROSSCHAR(condition, eptr, action) \
- while((condition) && ((eptr) & 0xc0) == 0x80) action
-
-#elif defined COMPILE_PCRE16
-
-/* Tells the biggest code point which can be encoded as a single character. */
-
-#define MAX_VALUE_FOR_SINGLE_CHAR 65535
-
-/* Tests whether the code point needs extra characters to decode. */
-
-#define HAS_EXTRALEN(c) (((c) & 0xfc00) == 0xd800)
-
-/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
-Otherwise it has an undefined behaviour. */
-
-#define GET_EXTRALEN(c) 1
-
-/* Returns TRUE, if the given character is not the first character
-of a UTF sequence. */
-
-#define NOT_FIRSTCHAR(c) (((c) & 0xfc00) == 0xdc00)
-
-/* Base macro to pick up the low surrogate of a UTF-16 character, not
-advancing the pointer. */
-
-#define GETUTF16(c, eptr) \
- { c = (((c & 0x3ff) << 10) | (eptr[1] & 0x3ff)) + 0x10000; }
-
-/* Get the next UTF-16 character, not advancing the pointer. This is called when
-we know we are in UTF-16 mode. */
-
-#define GETCHAR(c, eptr) \
- c = *eptr; \
- if ((c & 0xfc00) == 0xd800) GETUTF16(c, eptr);
-
-/* Get the next UTF-16 character, testing for UTF-16 mode, and not advancing the
-pointer. */
-
-#define GETCHARTEST(c, eptr) \
- c = *eptr; \
- if (utf && (c & 0xfc00) == 0xd800) GETUTF16(c, eptr);
-
-/* Base macro to pick up the low surrogate of a UTF-16 character, advancing
-the pointer. */
-
-#define GETUTF16INC(c, eptr) \
- { c = (((c & 0x3ff) << 10) | (*eptr++ & 0x3ff)) + 0x10000; }
-
-/* Get the next UTF-16 character, advancing the pointer. This is called when we
-know we are in UTF-16 mode. */
-
-#define GETCHARINC(c, eptr) \
- c = *eptr++; \
- if ((c & 0xfc00) == 0xd800) GETUTF16INC(c, eptr);
-
-/* Get the next character, testing for UTF-16 mode, and advancing the pointer.
-This is called when we don't know if we are in UTF-16 mode. */
-
-#define GETCHARINCTEST(c, eptr) \
- c = *eptr++; \
- if (utf && (c & 0xfc00) == 0xd800) GETUTF16INC(c, eptr);
-
-/* Base macro to pick up the low surrogate of a UTF-16 character, not
-advancing the pointer, incrementing the length. */
-
-#define GETUTF16LEN(c, eptr, len) \
- { c = (((c & 0x3ff) << 10) | (eptr[1] & 0x3ff)) + 0x10000; len++; }
-
-/* Get the next UTF-16 character, not advancing the pointer, incrementing
-length if there is a low surrogate. This is called when we know we are in
-UTF-16 mode. */
-
-#define GETCHARLEN(c, eptr, len) \
- c = *eptr; \
- if ((c & 0xfc00) == 0xd800) GETUTF16LEN(c, eptr, len);
-
-/* Get the next UTF-816character, testing for UTF-16 mode, not advancing the
-pointer, incrementing length if there is a low surrogate. This is called when
-we do not know if we are in UTF-16 mode. */
-
-#define GETCHARLENTEST(c, eptr, len) \
- c = *eptr; \
- if (utf && (c & 0xfc00) == 0xd800) GETUTF16LEN(c, eptr, len);
-
-/* If the pointer is not at the start of a character, move it back until
-it is. This is called only in UTF-16 mode - we don't put a test within the
-macro because almost all calls are already within a block of UTF-16 only
-code. */
-
-#define BACKCHAR(eptr) if ((*eptr & 0xfc00) == 0xdc00) eptr--
-
-/* Same as above, just in the other direction. */
-#define FORWARDCHAR(eptr) if ((*eptr & 0xfc00) == 0xdc00) eptr++
-
-/* Same as above, but it allows a fully customizable form. */
-#define ACROSSCHAR(condition, eptr, action) \
- if ((condition) && ((eptr) & 0xfc00) == 0xdc00) action
-
-#elif defined COMPILE_PCRE32
-
-/* These are trivial for the 32-bit library, since all UTF-32 characters fit
-into one pcre_uchar unit. */
-#define MAX_VALUE_FOR_SINGLE_CHAR (0x10ffffu)
-#define HAS_EXTRALEN(c) (0)
-#define GET_EXTRALEN(c) (0)
-#define NOT_FIRSTCHAR(c) (0)
-
-/* Get the next UTF-32 character, not advancing the pointer. This is called when
-we know we are in UTF-32 mode. */
-
-#define GETCHAR(c, eptr) \
- c = *(eptr);
-
-/* Get the next UTF-32 character, testing for UTF-32 mode, and not advancing the
-pointer. */
-
-#define GETCHARTEST(c, eptr) \
- c = *(eptr);
-
-/* Get the next UTF-32 character, advancing the pointer. This is called when we
-know we are in UTF-32 mode. */
-
-#define GETCHARINC(c, eptr) \
- c = *((eptr)++);
-
-/* Get the next character, testing for UTF-32 mode, and advancing the pointer.
-This is called when we don't know if we are in UTF-32 mode. */
-
-#define GETCHARINCTEST(c, eptr) \
- c = *((eptr)++);
-
-/* Get the next UTF-32 character, not advancing the pointer, not incrementing
-length (since all UTF-32 is of length 1). This is called when we know we are in
-UTF-32 mode. */
-
-#define GETCHARLEN(c, eptr, len) \
- GETCHAR(c, eptr)
-
-/* Get the next UTF-32character, testing for UTF-32 mode, not advancing the
-pointer, not incrementing the length (since all UTF-32 is of length 1).
-This is called when we do not know if we are in UTF-32 mode. */
-
-#define GETCHARLENTEST(c, eptr, len) \
- GETCHARTEST(c, eptr)
-
-/* If the pointer is not at the start of a character, move it back until
-it is. This is called only in UTF-32 mode - we don't put a test within the
-macro because almost all calls are already within a block of UTF-32 only
-code.
-These are all no-ops since all UTF-32 characters fit into one pcre_uchar. */
-
-#define BACKCHAR(eptr) do { } while (0)
-
-/* Same as above, just in the other direction. */
-#define FORWARDCHAR(eptr) do { } while (0)
-
-/* Same as above, but it allows a fully customizable form. */
-#define ACROSSCHAR(condition, eptr, action) do { } while (0)
-
-#else
-#error Unsupported compiling mode
-#endif /* COMPILE_PCRE[8|16|32] */
-
-#endif /* SUPPORT_UTF */
+/* --------------- Whitespace macros ---------------- */
/* Tests for Unicode horizontal and vertical whitespace characters must check a
number of different values. Using a switch statement for this generates the
@@ -970,19 +381,24 @@ interpreter code where this happens. In order to ensure that all the case lists
remain in step, we use macros so that there is only one place where the lists
are defined.
-These values are also required as lists in pcre_compile.c when processing \h,
-\H, \v and \V in a character class. The lists are defined in pcre_tables.c, but
-macros that define the values are here so that all the definitions are
+These values are also required as lists in pcre2_compile.c when processing \h,
+\H, \v and \V in a character class. The lists are defined in pcre2_tables.c,
+but macros that define the values are here so that all the definitions are
together. The lists must be in ascending character order, terminated by
NOTACHAR (which is 0xffffffff).
Any changes should ensure that the various macros are kept in step with each
-other. NOTE: The values also appear in pcre_jit_compile.c. */
+other. NOTE: The values also appear in pcre2_jit_compile.c. */
-/* ------ ASCII/Unicode environments ------ */
+/* -------------- ASCII/Unicode environments -------------- */
#ifndef EBCDIC
+/* Character U+180E (Mongolian Vowel Separator) is not included in the list of
+spaces in the Unicode file PropList.txt, and Perl does not recognize it as a
+space. However, in many other sources it is listed as a space and has been in
+PCRE (both APIs) for a long time. */
+
#define HSPACE_LIST \
CHAR_HT, CHAR_SPACE, CHAR_NBSP, \
0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, \
@@ -1034,7 +450,7 @@ other. NOTE: The values also appear in pcre_jit_compile.c. */
VSPACE_BYTE_CASES: \
VSPACE_MULTIBYTE_CASES
-/* ------ EBCDIC environments ------ */
+/* -------------- EBCDIC environments -------------- */
#else
#define HSPACE_LIST CHAR_HT, CHAR_SPACE, CHAR_NBSP, NOTACHAR
@@ -1064,106 +480,129 @@ other. NOTE: The values also appear in pcre_jit_compile.c. */
#define VSPACE_CASES VSPACE_BYTE_CASES
#endif /* EBCDIC */
-/* ------ End of whitespace macros ------ */
-
-
-
-/* Private flags containing information about the compiled regex. They used to
-live at the top end of the options word, but that got almost full, so they were
-moved to a 16-bit flags word - which got almost full, so now they are in a
-32-bit flags word. From release 8.00, PCRE_NOPARTIAL is unused, as the
-restrictions on partial matching have been lifted. It remains for backwards
-compatibility. */
-
-#define PCRE_MODE8 0x00000001 /* compiled in 8 bit mode */
-#define PCRE_MODE16 0x00000002 /* compiled in 16 bit mode */
-#define PCRE_MODE32 0x00000004 /* compiled in 32 bit mode */
-#define PCRE_FIRSTSET 0x00000010 /* first_char is set */
-#define PCRE_FCH_CASELESS 0x00000020 /* caseless first char */
-#define PCRE_REQCHSET 0x00000040 /* req_byte is set */
-#define PCRE_RCH_CASELESS 0x00000080 /* caseless requested char */
-#define PCRE_STARTLINE 0x00000100 /* start after \n for multiline */
-#define PCRE_NOPARTIAL 0x00000200 /* can't use partial with this regex */
-#define PCRE_JCHANGED 0x00000400 /* j option used in regex */
-#define PCRE_HASCRORLF 0x00000800 /* explicit \r or \n in pattern */
-#define PCRE_HASTHEN 0x00001000 /* pattern contains (*THEN) */
-#define PCRE_MLSET 0x00002000 /* match limit set by regex */
-#define PCRE_RLSET 0x00004000 /* recursion limit set by regex */
-#define PCRE_MATCH_EMPTY 0x00008000 /* pattern can match empty string */
-
-#if defined COMPILE_PCRE8
-#define PCRE_MODE PCRE_MODE8
-#elif defined COMPILE_PCRE16
-#define PCRE_MODE PCRE_MODE16
-#elif defined COMPILE_PCRE32
-#define PCRE_MODE PCRE_MODE32
-#endif
-#define PCRE_MODE_MASK (PCRE_MODE8 | PCRE_MODE16 | PCRE_MODE32)
-
-/* Flags for the "extra" block produced by pcre_study(). */
+/* -------------- End of whitespace macros -------------- */
-#define PCRE_STUDY_MAPPED 0x0001 /* a map of starting chars exists */
-#define PCRE_STUDY_MINLEN 0x0002 /* a minimum length field exists */
-/* Masks for identifying the public options that are permitted at compile
-time, run time, or study time, respectively. */
+/* PCRE2 is able to support several different kinds of newline (CR, LF, CRLF,
+"any" and "anycrlf" at present). The following macros are used to package up
+testing for newlines. NLBLOCK, PSSTART, and PSEND are defined in the various
+modules to indicate in which datablock the parameters exist, and what the
+start/end of string field names are. */
-#define PCRE_NEWLINE_BITS (PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|PCRE_NEWLINE_ANY| \
- PCRE_NEWLINE_ANYCRLF)
+#define NLTYPE_FIXED 0 /* Newline is a fixed length string */
+#define NLTYPE_ANY 1 /* Newline is any Unicode line ending */
+#define NLTYPE_ANYCRLF 2 /* Newline is CR, LF, or CRLF */
-#define PUBLIC_COMPILE_OPTIONS \
- (PCRE_CASELESS|PCRE_EXTENDED|PCRE_ANCHORED|PCRE_MULTILINE| \
- PCRE_DOTALL|PCRE_DOLLAR_ENDONLY|PCRE_EXTRA|PCRE_UNGREEDY|PCRE_UTF8| \
- PCRE_NO_AUTO_CAPTURE|PCRE_NO_AUTO_POSSESS| \
- PCRE_NO_UTF8_CHECK|PCRE_AUTO_CALLOUT|PCRE_FIRSTLINE| \
- PCRE_DUPNAMES|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE| \
- PCRE_JAVASCRIPT_COMPAT|PCRE_UCP|PCRE_NO_START_OPTIMIZE|PCRE_NEVER_UTF)
+/* This macro checks for a newline at the given position */
-#define PUBLIC_EXEC_OPTIONS \
- (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NOTEMPTY_ATSTART| \
- PCRE_NO_UTF8_CHECK|PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT|PCRE_NEWLINE_BITS| \
- PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE|PCRE_NO_START_OPTIMIZE)
+#define IS_NEWLINE(p) \
+ ((NLBLOCK->nltype != NLTYPE_FIXED)? \
+ ((p) < NLBLOCK->PSEND && \
+ PRIV(is_newline)((p), NLBLOCK->nltype, NLBLOCK->PSEND, \
+ &(NLBLOCK->nllen), utf)) \
+ : \
+ ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \
+ UCHAR21TEST(p) == NLBLOCK->nl[0] && \
+ (NLBLOCK->nllen == 1 || UCHAR21TEST(p+1) == NLBLOCK->nl[1]) \
+ ) \
+ )
-#define PUBLIC_DFA_EXEC_OPTIONS \
- (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|PCRE_NOTEMPTY_ATSTART| \
- PCRE_NO_UTF8_CHECK|PCRE_PARTIAL_HARD|PCRE_PARTIAL_SOFT|PCRE_DFA_SHORTEST| \
- PCRE_DFA_RESTART|PCRE_NEWLINE_BITS|PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE| \
- PCRE_NO_START_OPTIMIZE)
+/* This macro checks for a newline immediately preceding the given position */
-#define PUBLIC_STUDY_OPTIONS \
- (PCRE_STUDY_JIT_COMPILE|PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE| \
- PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE|PCRE_STUDY_EXTRA_NEEDED)
+#define WAS_NEWLINE(p) \
+ ((NLBLOCK->nltype != NLTYPE_FIXED)? \
+ ((p) > NLBLOCK->PSSTART && \
+ PRIV(was_newline)((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \
+ &(NLBLOCK->nllen), utf)) \
+ : \
+ ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \
+ UCHAR21TEST(p - NLBLOCK->nllen) == NLBLOCK->nl[0] && \
+ (NLBLOCK->nllen == 1 || UCHAR21TEST(p - NLBLOCK->nllen + 1) == NLBLOCK->nl[1]) \
+ ) \
+ )
-#define PUBLIC_JIT_EXEC_OPTIONS \
- (PCRE_NO_UTF8_CHECK|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY|\
- PCRE_NOTEMPTY_ATSTART|PCRE_PARTIAL_SOFT|PCRE_PARTIAL_HARD)
+/* Private flags containing information about the compiled pattern. The first
+three must not be changed, because whichever is set is actually the number of
+bytes in a code unit in that mode. */
+
+#define PCRE2_MODE8 0x00000001 /* compiled in 8 bit mode */
+#define PCRE2_MODE16 0x00000002 /* compiled in 16 bit mode */
+#define PCRE2_MODE32 0x00000004 /* compiled in 32 bit mode */
+#define PCRE2_FIRSTSET 0x00000010 /* first_code unit is set */
+#define PCRE2_FIRSTCASELESS 0x00000020 /* caseless first code unit */
+#define PCRE2_FIRSTMAPSET 0x00000040 /* bitmap of first code units is set */
+#define PCRE2_LASTSET 0x00000080 /* last code unit is set */
+#define PCRE2_LASTCASELESS 0x00000100 /* caseless last code unit */
+#define PCRE2_STARTLINE 0x00000200 /* start after \n for multiline */
+#define PCRE2_JCHANGED 0x00000400 /* j option used in pattern */
+#define PCRE2_HASCRORLF 0x00000800 /* explicit \r or \n in pattern */
+#define PCRE2_HASTHEN 0x00001000 /* pattern contains (*THEN) */
+#define PCRE2_MATCH_EMPTY 0x00002000 /* pattern can match empty string */
+#define PCRE2_BSR_SET 0x00004000 /* BSR was set in the pattern */
+#define PCRE2_NL_SET 0x00008000 /* newline was set in the pattern */
+#define PCRE2_NOTEMPTY_SET 0x00010000 /* (*NOTEMPTY) used ) keep */
+#define PCRE2_NE_ATST_SET 0x00020000 /* (*NOTEMPTY_ATSTART) used) together */
+#define PCRE2_DEREF_TABLES 0x00040000 /* release character tables */
+#define PCRE2_NOJIT 0x00080000 /* (*NOJIT) used */
+#define PCRE2_HASBKPORX 0x00100000 /* contains \P, \p, or \X */
+#define PCRE2_DUPCAPUSED 0x00200000 /* contains (?| */
+#define PCRE2_HASBKC 0x00400000 /* contains \C */
+
+#define PCRE2_MODE_MASK (PCRE2_MODE8 | PCRE2_MODE16 | PCRE2_MODE32)
+
+/* Values for the matchedby field in a match data block. */
+
+enum { PCRE2_MATCHEDBY_INTERPRETER, /* pcre2_match() */
+ PCRE2_MATCHEDBY_DFA_INTERPRETER, /* pcre2_dfa_match() */
+ PCRE2_MATCHEDBY_JIT }; /* pcre2_jit_match() */
/* Magic number to provide a small check against being handed junk. */
#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */
-/* This variable is used to detect a loaded regular expression
-in different endianness. */
+/* The maximum remaining length of subject we are prepared to search for a
+req_unit match. */
-#define REVERSED_MAGIC_NUMBER 0x45524350UL /* 'ERCP' */
+#define REQ_CU_MAX 1000
-/* The maximum remaining length of subject we are prepared to search for a
-req_byte match. */
+/* Offsets for the bitmap tables in the cbits set of tables. Each table
+contains a set of bits for a class map. Some classes are built by combining
+these tables. */
-#define REQ_BYTE_MAX 1000
+#define cbit_space 0 /* [:space:] or \s */
+#define cbit_xdigit 32 /* [:xdigit:] */
+#define cbit_digit 64 /* [:digit:] or \d */
+#define cbit_upper 96 /* [:upper:] */
+#define cbit_lower 128 /* [:lower:] */
+#define cbit_word 160 /* [:word:] or \w */
+#define cbit_graph 192 /* [:graph:] */
+#define cbit_print 224 /* [:print:] */
+#define cbit_punct 256 /* [:punct:] */
+#define cbit_cntrl 288 /* [:cntrl:] */
+#define cbit_length 320 /* Length of the cbits table */
-/* Miscellaneous definitions. The #ifndef is to pacify compiler warnings in
-environments where these macros are defined elsewhere. Unfortunately, there
-is no way to do the same for the typedef. */
+/* Bit definitions for entries in the ctypes table. */
-typedef int BOOL;
+#define ctype_space 0x01
+#define ctype_letter 0x02
+#define ctype_digit 0x04
+#define ctype_xdigit 0x08
+#define ctype_word 0x10 /* alphanumeric or '_' */
+#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
+/* Offsets of the various tables from the base tables pointer, and
+total length of the tables. */
+
+#define lcc_offset 0 /* Lower case */
+#define fcc_offset 256 /* Flip case */
+#define cbits_offset 512 /* Character classes */
+#define ctypes_offset (cbits_offset + cbit_length) /* Character types */
+#define tables_length (ctypes_offset + 256)
-/* If PCRE is to support UTF-8 on EBCDIC platforms, we cannot use normal
+
+/* -------------------- Character and string names ------------------------ */
+
+/* If PCRE2 is to support UTF-8 on EBCDIC platforms, we cannot use normal
character constants like '*' because the compiler would emit their EBCDIC code,
which is different from their ASCII/UTF-8 code. Instead we define macros for
the characters so that they always use the ASCII/UTF-8 code when UTF-8 support
@@ -1171,19 +610,19 @@ is enabled. When UTF-8 support is not enabled, the definitions use character
literals. Both character and string versions of each character are needed, and
there are some longer strings as well.
-This means that, on EBCDIC platforms, the PCRE library can handle either
+This means that, on EBCDIC platforms, the PCRE2 library can handle either
EBCDIC, or UTF-8, but not both. To support both in the same compiled library
-would need different lookups depending on whether PCRE_UTF8 was set or not.
+would need different lookups depending on whether PCRE2_UTF was set or not.
This would make it impossible to use characters in switch/case statements,
which would reduce performance. For a theoretical use (which nobody has asked
for) in a minority area (EBCDIC platforms), this is not sensible. Any
application that did need both could compile two versions of the library, using
macros to give the functions distinct names. */
-#ifndef SUPPORT_UTF
+#ifndef SUPPORT_UNICODE
/* UTF-8 support is not enabled; use the platform-dependent character literals
-so that PCRE works in both ASCII and EBCDIC environments, but only in non-UTF
+so that PCRE2 works in both ASCII and EBCDIC environments, but only in non-UTF
mode. Newline characters are problematic in EBCDIC. Though it has CR and LF
characters, a common practice has been to use its NL (0x15) character as the
line terminator in C-like processing environments. However, sometimes the LF
@@ -1191,7 +630,7 @@ line terminator in C-like processing environments. However, sometimes the LF
http://unicode.org/standard/reports/tr13/tr13-5.html
-PCRE defaults EBCDIC NL to 0x15, but has a build-time option to select 0x25
+PCRE2 defaults EBCDIC NL to 0x15, but has a build-time option to select 0x25
instead. Whichever is *not* chosen is defined as NEL.
In both ASCII and EBCDIC environments, CHAR_NL and CHAR_LF are synonyms for the
@@ -1216,7 +655,7 @@ same code point. */
#define CHAR_ESC '\047'
#define CHAR_DEL '\007'
-#define CHAR_NBSP '\x41'
+#define CHAR_NBSP ((unsigned char)'\x41')
#define STR_ESC "\047"
#define STR_DEL "\007"
@@ -1475,27 +914,33 @@ a positive value. */
#define STRING_xdigit "xdigit"
#define STRING_DEFINE "DEFINE"
+#define STRING_VERSION "VERSION"
#define STRING_WEIRD_STARTWORD "[:<:]]"
#define STRING_WEIRD_ENDWORD "[:>:]]"
-#define STRING_CR_RIGHTPAR "CR)"
-#define STRING_LF_RIGHTPAR "LF)"
-#define STRING_CRLF_RIGHTPAR "CRLF)"
-#define STRING_ANY_RIGHTPAR "ANY)"
-#define STRING_ANYCRLF_RIGHTPAR "ANYCRLF)"
-#define STRING_BSR_ANYCRLF_RIGHTPAR "BSR_ANYCRLF)"
-#define STRING_BSR_UNICODE_RIGHTPAR "BSR_UNICODE)"
-#define STRING_UTF8_RIGHTPAR "UTF8)"
-#define STRING_UTF16_RIGHTPAR "UTF16)"
-#define STRING_UTF32_RIGHTPAR "UTF32)"
-#define STRING_UTF_RIGHTPAR "UTF)"
-#define STRING_UCP_RIGHTPAR "UCP)"
-#define STRING_NO_AUTO_POSSESS_RIGHTPAR "NO_AUTO_POSSESS)"
-#define STRING_NO_START_OPT_RIGHTPAR "NO_START_OPT)"
-#define STRING_LIMIT_MATCH_EQ "LIMIT_MATCH="
-#define STRING_LIMIT_RECURSION_EQ "LIMIT_RECURSION="
-
-#else /* SUPPORT_UTF */
+#define STRING_CR_RIGHTPAR "CR)"
+#define STRING_LF_RIGHTPAR "LF)"
+#define STRING_CRLF_RIGHTPAR "CRLF)"
+#define STRING_ANY_RIGHTPAR "ANY)"
+#define STRING_ANYCRLF_RIGHTPAR "ANYCRLF)"
+#define STRING_BSR_ANYCRLF_RIGHTPAR "BSR_ANYCRLF)"
+#define STRING_BSR_UNICODE_RIGHTPAR "BSR_UNICODE)"
+#define STRING_UTF8_RIGHTPAR "UTF8)"
+#define STRING_UTF16_RIGHTPAR "UTF16)"
+#define STRING_UTF32_RIGHTPAR "UTF32)"
+#define STRING_UTF_RIGHTPAR "UTF)"
+#define STRING_UCP_RIGHTPAR "UCP)"
+#define STRING_NO_AUTO_POSSESS_RIGHTPAR "NO_AUTO_POSSESS)"
+#define STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR "NO_DOTSTAR_ANCHOR)"
+#define STRING_NO_JIT_RIGHTPAR "NO_JIT)"
+#define STRING_NO_START_OPT_RIGHTPAR "NO_START_OPT)"
+#define STRING_NOTEMPTY_RIGHTPAR "NOTEMPTY)"
+#define STRING_NOTEMPTY_ATSTART_RIGHTPAR "NOTEMPTY_ATSTART)"
+#define STRING_LIMIT_MATCH_EQ "LIMIT_MATCH="
+#define STRING_LIMIT_RECURSION_EQ "LIMIT_RECURSION="
+#define STRING_MARK "MARK"
+
+#else /* SUPPORT_UNICODE */
/* UTF-8 support is enabled; always use UTF-8 (=ASCII) character codes. This
works in both modes non-EBCDIC platforms, and on EBCDIC platforms in UTF-8 mode
@@ -1742,56 +1187,37 @@ only. */
#define STRING_xdigit STR_x STR_d STR_i STR_g STR_i STR_t
#define STRING_DEFINE STR_D STR_E STR_F STR_I STR_N STR_E
+#define STRING_VERSION STR_V STR_E STR_R STR_S STR_I STR_O STR_N
#define STRING_WEIRD_STARTWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_LESS_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET
#define STRING_WEIRD_ENDWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_GREATER_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET
-#define STRING_CR_RIGHTPAR STR_C STR_R STR_RIGHT_PARENTHESIS
-#define STRING_LF_RIGHTPAR STR_L STR_F STR_RIGHT_PARENTHESIS
-#define STRING_CRLF_RIGHTPAR STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
-#define STRING_ANY_RIGHTPAR STR_A STR_N STR_Y STR_RIGHT_PARENTHESIS
-#define STRING_ANYCRLF_RIGHTPAR STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
-#define STRING_BSR_ANYCRLF_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
-#define STRING_BSR_UNICODE_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS
-#define STRING_UTF8_RIGHTPAR STR_U STR_T STR_F STR_8 STR_RIGHT_PARENTHESIS
-#define STRING_UTF16_RIGHTPAR STR_U STR_T STR_F STR_1 STR_6 STR_RIGHT_PARENTHESIS
-#define STRING_UTF32_RIGHTPAR STR_U STR_T STR_F STR_3 STR_2 STR_RIGHT_PARENTHESIS
-#define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_RIGHT_PARENTHESIS
-#define STRING_UCP_RIGHTPAR STR_U STR_C STR_P STR_RIGHT_PARENTHESIS
-#define STRING_NO_AUTO_POSSESS_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_A STR_U STR_T STR_O STR_UNDERSCORE STR_P STR_O STR_S STR_S STR_E STR_S STR_S STR_RIGHT_PARENTHESIS
-#define STRING_NO_START_OPT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_S STR_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS
-#define STRING_LIMIT_MATCH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_M STR_A STR_T STR_C STR_H STR_EQUALS_SIGN
-#define STRING_LIMIT_RECURSION_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_R STR_E STR_C STR_U STR_R STR_S STR_I STR_O STR_N STR_EQUALS_SIGN
-
-#endif /* SUPPORT_UTF */
-
-/* Escape items that are just an encoding of a particular data value. */
-
-#ifndef ESC_a
-#define ESC_a CHAR_BEL
-#endif
-
-#ifndef ESC_e
-#define ESC_e CHAR_ESC
-#endif
-
-#ifndef ESC_f
-#define ESC_f CHAR_FF
-#endif
-
-#ifndef ESC_n
-#define ESC_n CHAR_LF
-#endif
-
-#ifndef ESC_r
-#define ESC_r CHAR_CR
-#endif
-
-/* We can't officially use ESC_t because it is a POSIX reserved identifier
-(presumably because of all the others like size_t). */
-
-#ifndef ESC_tee
-#define ESC_tee CHAR_HT
-#endif
+#define STRING_CR_RIGHTPAR STR_C STR_R STR_RIGHT_PARENTHESIS
+#define STRING_LF_RIGHTPAR STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_CRLF_RIGHTPAR STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_ANY_RIGHTPAR STR_A STR_N STR_Y STR_RIGHT_PARENTHESIS
+#define STRING_ANYCRLF_RIGHTPAR STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_BSR_ANYCRLF_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_BSR_UNICODE_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS
+#define STRING_UTF8_RIGHTPAR STR_U STR_T STR_F STR_8 STR_RIGHT_PARENTHESIS
+#define STRING_UTF16_RIGHTPAR STR_U STR_T STR_F STR_1 STR_6 STR_RIGHT_PARENTHESIS
+#define STRING_UTF32_RIGHTPAR STR_U STR_T STR_F STR_3 STR_2 STR_RIGHT_PARENTHESIS
+#define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_RIGHT_PARENTHESIS
+#define STRING_UCP_RIGHTPAR STR_U STR_C STR_P STR_RIGHT_PARENTHESIS
+#define STRING_NO_AUTO_POSSESS_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_A STR_U STR_T STR_O STR_UNDERSCORE STR_P STR_O STR_S STR_S STR_E STR_S STR_S STR_RIGHT_PARENTHESIS
+#define STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_D STR_O STR_T STR_S STR_T STR_A STR_R STR_UNDERSCORE STR_A STR_N STR_C STR_H STR_O STR_R STR_RIGHT_PARENTHESIS
+#define STRING_NO_JIT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_J STR_I STR_T STR_RIGHT_PARENTHESIS
+#define STRING_NO_START_OPT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_S STR_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS
+#define STRING_NOTEMPTY_RIGHTPAR STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_RIGHT_PARENTHESIS
+#define STRING_NOTEMPTY_ATSTART_RIGHTPAR STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_UNDERSCORE STR_A STR_T STR_S STR_T STR_A STR_R STR_T STR_RIGHT_PARENTHESIS
+#define STRING_LIMIT_MATCH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_M STR_A STR_T STR_C STR_H STR_EQUALS_SIGN
+#define STRING_LIMIT_RECURSION_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_R STR_E STR_C STR_U STR_R STR_S STR_I STR_O STR_N STR_EQUALS_SIGN
+#define STRING_MARK STR_M STR_A STR_R STR_K
+
+#endif /* SUPPORT_UNICODE */
+
+/* -------------------- End of character and string names -------------------*/
+
+/* -------------------- Definitions for compiled patterns -------------------*/
/* Codes for different types of Unicode property */
@@ -1809,7 +1235,7 @@ only. */
#define PT_TABSIZE 11 /* Size of square table for autopossessify tests */
/* The following special properties are used only in XCLASS items, when POSIX
-classes are specified and PCRE_UCP is set - in other words, for Unicode
+classes are specified and PCRE2_UCP is set - in other words, for Unicode
handling of these classes. They are not available via the \p or \P escapes like
those in the above list, and so they do not take part in the autopossessifying
table. */
@@ -1831,16 +1257,49 @@ contain characters with values greater than 255. */
#define XCL_PROP 3 /* Unicode property (2-byte property code follows) */
#define XCL_NOTPROP 4 /* Unicode inverted property (ditto) */
+/* Escape items that are just an encoding of a particular data value. These
+appear in the escapes[] table in pcre2_compile.c as positive numbers. */
+
+#ifndef ESC_a
+#define ESC_a CHAR_BEL
+#endif
+
+#ifndef ESC_e
+#define ESC_e CHAR_ESC
+#endif
+
+#ifndef ESC_f
+#define ESC_f CHAR_FF
+#endif
+
+#ifndef ESC_n
+#define ESC_n CHAR_LF
+#endif
+
+#ifndef ESC_r
+#define ESC_r CHAR_CR
+#endif
+
+/* We can't officially use ESC_t because it is a POSIX reserved identifier
+(presumably because of all the others like size_t). */
+
+#ifndef ESC_tee
+#define ESC_tee CHAR_HT
+#endif
+
/* These are escaped items that aren't just an encoding of a particular data
value such as \n. They must have non-zero values, as check_escape() returns 0
-for a data character. Also, they must appear in the same order as in the
-opcode definitions below, up to ESC_z. There's a dummy for OP_ALLANY because it
-corresponds to "." in DOTALL mode rather than an escape sequence. It is also
-used for [^] in JavaScript compatibility mode, and for \C in non-utf mode. In
-non-DOTALL mode, "." behaves like \N.
+for a data character. In the escapes[] table in pcre2_compile.c their values
+are negated in order to distinguish them from data values.
+
+They must appear here in the same order as in the opcode definitions below, up
+to ESC_z. There's a dummy for OP_ALLANY because it corresponds to "." in DOTALL
+mode rather than an escape sequence. It is also used for [^] in JavaScript
+compatibility mode, and for \C in non-utf mode. In non-DOTALL mode, "." behaves
+like \N.
The special values ESC_DU, ESC_du, etc. are used instead of ESC_D, ESC_d, etc.
-when PCRE_UCP is set and replacement of \d etc by \p sequences is required.
+when PCRE2_UCP is set and replacement of \d etc by \p sequences is required.
They must be contiguous, and remain in order so that the replacements can be
looked up from a table.
@@ -1865,12 +1324,12 @@ enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s,
Starting from 1 (i.e. after OP_END), the values up to OP_EOD must correspond in
order to the list of escapes immediately above. Furthermore, values up to
OP_DOLLM must not be changed without adjusting the table called autoposstab in
-pcre_compile.c
+pcre2_auto_possess.c
Whenever this list is updated, the two macro definitions that follow must be
updated to match. The possessification table called "opcode_possessify" in
-pcre_compile.c must also be updated, and also the tables called "coptable"
-and "poptable" in pcre_dfa_exec.c.
+pcre2_compile.c must also be updated, and also the tables called "coptable"
+and "poptable" in pcre2_dfa_match.c.
****** NOTE NOTE NOTE ******/
@@ -2054,94 +1513,103 @@ enum {
OP_DNREFI, /* 116 Match a duplicate name backref, caselessly */
OP_RECURSE, /* 117 Match a numbered subpattern (possibly recursive) */
OP_CALLOUT, /* 118 Call out to external function if provided */
+ OP_CALLOUT_STR, /* 119 Call out with string argument */
- OP_ALT, /* 119 Start of alternation */
- OP_KET, /* 120 End of group that doesn't have an unbounded repeat */
- OP_KETRMAX, /* 121 These two must remain together and in this */
- OP_KETRMIN, /* 122 order. They are for groups the repeat for ever. */
- OP_KETRPOS, /* 123 Possessive unlimited repeat. */
+ OP_ALT, /* 120 Start of alternation */
+ OP_KET, /* 121 End of group that doesn't have an unbounded repeat */
+ OP_KETRMAX, /* 122 These two must remain together and in this */
+ OP_KETRMIN, /* 123 order. They are for groups the repeat for ever. */
+ OP_KETRPOS, /* 124 Possessive unlimited repeat. */
/* The assertions must come before BRA, CBRA, ONCE, and COND, and the four
asserts must remain in order. */
- OP_REVERSE, /* 124 Move pointer back - used in lookbehind assertions */
- OP_ASSERT, /* 125 Positive lookahead */
- OP_ASSERT_NOT, /* 126 Negative lookahead */
- OP_ASSERTBACK, /* 127 Positive lookbehind */
- OP_ASSERTBACK_NOT, /* 128 Negative lookbehind */
+ OP_REVERSE, /* 125 Move pointer back - used in lookbehind assertions */
+ OP_ASSERT, /* 126 Positive lookahead */
+ OP_ASSERT_NOT, /* 127 Negative lookahead */
+ OP_ASSERTBACK, /* 128 Positive lookbehind */
+ OP_ASSERTBACK_NOT, /* 129 Negative lookbehind */
/* ONCE, ONCE_NC, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come immediately
after the assertions, with ONCE first, as there's a test for >= ONCE for a
subpattern that isn't an assertion. The POS versions must immediately follow
the non-POS versions in each case. */
- OP_ONCE, /* 129 Atomic group, contains captures */
- OP_ONCE_NC, /* 130 Atomic group containing no captures */
- OP_BRA, /* 131 Start of non-capturing bracket */
- OP_BRAPOS, /* 132 Ditto, with unlimited, possessive repeat */
- OP_CBRA, /* 133 Start of capturing bracket */
- OP_CBRAPOS, /* 134 Ditto, with unlimited, possessive repeat */
- OP_COND, /* 135 Conditional group */
+ OP_ONCE, /* 130 Atomic group, contains captures */
+ OP_ONCE_NC, /* 131 Atomic group containing no captures */
+ OP_BRA, /* 132 Start of non-capturing bracket */
+ OP_BRAPOS, /* 133 Ditto, with unlimited, possessive repeat */
+ OP_CBRA, /* 134 Start of capturing bracket */
+ OP_CBRAPOS, /* 135 Ditto, with unlimited, possessive repeat */
+ OP_COND, /* 136 Conditional group */
/* These five must follow the previous five, in the same order. There's a
check for >= SBRA to distinguish the two sets. */
- OP_SBRA, /* 136 Start of non-capturing bracket, check empty */
- OP_SBRAPOS, /* 137 Ditto, with unlimited, possessive repeat */
- OP_SCBRA, /* 138 Start of capturing bracket, check empty */
- OP_SCBRAPOS, /* 139 Ditto, with unlimited, possessive repeat */
- OP_SCOND, /* 140 Conditional group, check empty */
+ OP_SBRA, /* 137 Start of non-capturing bracket, check empty */
+ OP_SBRAPOS, /* 138 Ditto, with unlimited, possessive repeat */
+ OP_SCBRA, /* 139 Start of capturing bracket, check empty */
+ OP_SCBRAPOS, /* 140 Ditto, with unlimited, possessive repeat */
+ OP_SCOND, /* 141 Conditional group, check empty */
/* The next two pairs must (respectively) be kept together. */
- OP_CREF, /* 141 Used to hold a capture number as condition */
- OP_DNCREF, /* 142 Used to point to duplicate names as a condition */
- OP_RREF, /* 143 Used to hold a recursion number as condition */
- OP_DNRREF, /* 144 Used to point to duplicate names as a condition */
- OP_DEF, /* 145 The DEFINE condition */
+ OP_CREF, /* 142 Used to hold a capture number as condition */
+ OP_DNCREF, /* 143 Used to point to duplicate names as a condition */
+ OP_RREF, /* 144 Used to hold a recursion number as condition */
+ OP_DNRREF, /* 145 Used to point to duplicate names as a condition */
+ OP_FALSE, /* 146 Always false (used by DEFINE and VERSION) */
+ OP_TRUE, /* 147 Always true (used by VERSION) */
- OP_BRAZERO, /* 146 These two must remain together and in this */
- OP_BRAMINZERO, /* 147 order. */
- OP_BRAPOSZERO, /* 148 */
+ OP_BRAZERO, /* 148 These two must remain together and in this */
+ OP_BRAMINZERO, /* 149 order. */
+ OP_BRAPOSZERO, /* 150 */
/* These are backtracking control verbs */
- OP_MARK, /* 149 always has an argument */
- OP_PRUNE, /* 150 */
- OP_PRUNE_ARG, /* 151 same, but with argument */
- OP_SKIP, /* 152 */
- OP_SKIP_ARG, /* 153 same, but with argument */
- OP_THEN, /* 154 */
- OP_THEN_ARG, /* 155 same, but with argument */
- OP_COMMIT, /* 156 */
+ OP_MARK, /* 151 always has an argument */
+ OP_PRUNE, /* 152 */
+ OP_PRUNE_ARG, /* 153 same, but with argument */
+ OP_SKIP, /* 154 */
+ OP_SKIP_ARG, /* 155 same, but with argument */
+ OP_THEN, /* 156 */
+ OP_THEN_ARG, /* 157 same, but with argument */
+ OP_COMMIT, /* 158 */
/* These are forced failure and success verbs */
- OP_FAIL, /* 157 */
- OP_ACCEPT, /* 158 */
- OP_ASSERT_ACCEPT, /* 159 Used inside assertions */
- OP_CLOSE, /* 160 Used before OP_ACCEPT to close open captures */
+ OP_FAIL, /* 159 */
+ OP_ACCEPT, /* 160 */
+ OP_ASSERT_ACCEPT, /* 161 Used inside assertions */
+ OP_CLOSE, /* 162 Used before OP_ACCEPT to close open captures */
/* This is used to skip a subpattern with a {0} quantifier */
- OP_SKIPZERO, /* 161 */
+ OP_SKIPZERO, /* 163 */
+
+ /* This is used to identify a DEFINE group during compilation so that it can
+ be checked for having only one branch. It is changed to OP_FALSE before
+ compilation finishes. */
+
+ OP_DEFINE, /* 164 */
/* This is not an opcode, but is used to check that tables indexed by opcode
are the correct length, in order to catch updating errors - there have been
some in the past. */
OP_TABLE_LENGTH
+
};
/* *** NOTE NOTE NOTE *** Whenever the list above is updated, the two macro
definitions that follow must also be updated to match. There are also tables
-called "opcode_possessify" in pcre_compile.c and "coptable" and "poptable" in
-pcre_dfa_exec.c that must be updated. */
+called "opcode_possessify" in pcre2_compile.c and "coptable" and "poptable" in
+pcre2_dfa_exec.c that must be updated. */
/* This macro defines textual names for all the opcodes. These are used only
for debugging, and some of them are only partial names. The macro is referenced
-only in pcre_printint.c, which fills out the full names in many cases (and in
+only in pcre2_printint.c, which fills out the full names in many cases (and in
some cases doesn't actually use these names at all). */
#define OP_NAME_LIST \
@@ -2167,7 +1635,7 @@ some cases doesn't actually use these names at all). */
"*", "*?", "+", "+?", "?", "??", "{", "{", \
"*+","++", "?+", "{", \
"class", "nclass", "xclass", "Ref", "Refi", "DnRef", "DnRefi", \
- "Recurse", "Callout", \
+ "Recurse", "Callout", "CalloutStr", \
"Alt", "Ket", "KetRmax", "KetRmin", "KetRpos", \
"Reverse", "Assert", "Assert not", "AssertB", "AssertB not", \
"Once", "Once_NC", \
@@ -2175,12 +1643,13 @@ some cases doesn't actually use these names at all). */
"Cond", \
"SBra", "SBraPos", "SCBra", "SCBraPos", \
"SCond", \
- "Cond ref", "Cond dnref", "Cond rec", "Cond dnrec", "Cond def", \
+ "Cond ref", "Cond dnref", "Cond rec", "Cond dnrec", \
+ "Cond false", "Cond true", \
"Brazero", "Braminzero", "Braposzero", \
"*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP", \
"*THEN", "*THEN", "*COMMIT", "*FAIL", \
"*ACCEPT", "*ASSERT_ACCEPT", \
- "Close", "Skip zero"
+ "Close", "Skip zero", "Define"
/* This macro defines the length of fixed length operations in the compiled
@@ -2232,15 +1701,16 @@ in UTF-8 mode. The code that uses this table must know about such things. */
1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \
1+2*IMM2_SIZE, 1+2*IMM2_SIZE, /* CRRANGE, CRMINRANGE */ \
1, 1, 1, 1+2*IMM2_SIZE, /* Possessive *+, ++, ?+, CRPOSRANGE */ \
- 1+(32/sizeof(pcre_uchar)), /* CLASS */ \
- 1+(32/sizeof(pcre_uchar)), /* NCLASS */ \
+ 1+(32/sizeof(PCRE2_UCHAR)), /* CLASS */ \
+ 1+(32/sizeof(PCRE2_UCHAR)), /* NCLASS */ \
0, /* XCLASS - variable length */ \
1+IMM2_SIZE, /* REF */ \
1+IMM2_SIZE, /* REFI */ \
1+2*IMM2_SIZE, /* DNREF */ \
1+2*IMM2_SIZE, /* DNREFI */ \
1+LINK_SIZE, /* RECURSE */ \
- 2+2*LINK_SIZE, /* CALLOUT */ \
+ 1+2*LINK_SIZE+1, /* CALLOUT */ \
+ 0, /* CALLOUT_STR - variable length */ \
1+LINK_SIZE, /* Alt */ \
1+LINK_SIZE, /* Ket */ \
1+LINK_SIZE, /* KetRmax */ \
@@ -2265,139 +1735,29 @@ in UTF-8 mode. The code that uses this table must know about such things. */
1+LINK_SIZE, /* SCOND */ \
1+IMM2_SIZE, 1+2*IMM2_SIZE, /* CREF, DNCREF */ \
1+IMM2_SIZE, 1+2*IMM2_SIZE, /* RREF, DNRREF */ \
- 1, /* DEF */ \
+ 1, 1, /* FALSE, TRUE */ \
1, 1, 1, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ \
3, 1, 3, /* MARK, PRUNE, PRUNE_ARG */ \
1, 3, /* SKIP, SKIP_ARG */ \
1, 3, /* THEN, THEN_ARG */ \
1, 1, 1, 1, /* COMMIT, FAIL, ACCEPT, ASSERT_ACCEPT */ \
- 1+IMM2_SIZE, 1 /* CLOSE, SKIPZERO */
+ 1+IMM2_SIZE, 1, /* CLOSE, SKIPZERO */ \
+ 1 /* DEFINE */
/* A magic value for OP_RREF to indicate the "any recursion" condition. */
#define RREF_ANY 0xffff
-/* Compile time error code numbers. They are given names so that they can more
-easily be tracked. When a new number is added, the table called eint in
-pcreposix.c must be updated. */
-
-enum { ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9,
- ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19,
- ERR20, ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29,
- ERR30, ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39,
- ERR40, ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49,
- ERR50, ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59,
- ERR60, ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69,
- ERR70, ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79,
- ERR80, ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERRCOUNT };
-
-/* JIT compiling modes. The function list is indexed by them. */
-
-enum { JIT_COMPILE, JIT_PARTIAL_SOFT_COMPILE, JIT_PARTIAL_HARD_COMPILE,
- JIT_NUMBER_OF_COMPILE_MODES };
-
-/* The real format of the start of the pcre block; the index of names and the
-code vector run on as long as necessary after the end. We store an explicit
-offset to the name table so that if a regex is compiled on one host, saved, and
-then run on another where the size of pointers is different, all might still
-be well.
-
-The size of the structure must be a multiple of 8 bytes. For the case of
-compiled-on-4 and run-on-8, we include an extra pointer that is always NULL so
-that there are an even number of pointers which therefore are a multiple of 8
-bytes.
-
-It is necessary to fork the struct for the 32 bit library, since it needs to
-use pcre_uint32 for first_char and req_char. We can't put an ifdef inside the
-typedef because pcretest needs access to the struct of the 8-, 16- and 32-bit
-variants.
-
-*** WARNING ***
-When new fields are added to these structures, remember to adjust the code in
-pcre_byte_order.c that is concerned with swapping the byte order of the fields
-when a compiled regex is reloaded on a host with different endianness.
-*** WARNING ***
-There is also similar byte-flipping code in pcretest.c, which is used for
-testing the byte-flipping features. It must also be kept in step.
-*** WARNING ***
-*/
-
-typedef struct real_pcre8_or_16 {
- pcre_uint32 magic_number;
- pcre_uint32 size; /* Total that was malloced */
- pcre_uint32 options; /* Public options */
- pcre_uint32 flags; /* Private flags */
- pcre_uint32 limit_match; /* Limit set from regex */
- pcre_uint32 limit_recursion; /* Limit set from regex */
- pcre_uint16 first_char; /* Starting character */
- pcre_uint16 req_char; /* This character must be seen */
- pcre_uint16 max_lookbehind; /* Longest lookbehind (characters) */
- pcre_uint16 top_bracket; /* Highest numbered group */
- pcre_uint16 top_backref; /* Highest numbered back reference */
- pcre_uint16 name_table_offset; /* Offset to name table that follows */
- pcre_uint16 name_entry_size; /* Size of any name items */
- pcre_uint16 name_count; /* Number of name items */
- pcre_uint16 ref_count; /* Reference count */
- pcre_uint16 dummy1; /* To ensure size is a multiple of 8 */
- pcre_uint16 dummy2; /* To ensure size is a multiple of 8 */
- pcre_uint16 dummy3; /* To ensure size is a multiple of 8 */
- const pcre_uint8 *tables; /* Pointer to tables or NULL for std */
- void *nullpad; /* NULL padding */
-} real_pcre8_or_16;
-
-typedef struct real_pcre8_or_16 real_pcre;
-typedef struct real_pcre8_or_16 real_pcre16;
-
-typedef struct real_pcre32 {
- pcre_uint32 magic_number;
- pcre_uint32 size; /* Total that was malloced */
- pcre_uint32 options; /* Public options */
- pcre_uint32 flags; /* Private flags */
- pcre_uint32 limit_match; /* Limit set from regex */
- pcre_uint32 limit_recursion; /* Limit set from regex */
- pcre_uint32 first_char; /* Starting character */
- pcre_uint32 req_char; /* This character must be seen */
- pcre_uint16 max_lookbehind; /* Longest lookbehind (characters) */
- pcre_uint16 top_bracket; /* Highest numbered group */
- pcre_uint16 top_backref; /* Highest numbered back reference */
- pcre_uint16 name_table_offset; /* Offset to name table that follows */
- pcre_uint16 name_entry_size; /* Size of any name items */
- pcre_uint16 name_count; /* Number of name items */
- pcre_uint16 ref_count; /* Reference count */
- pcre_uint16 dummy; /* To ensure size is a multiple of 8 */
- const pcre_uint8 *tables; /* Pointer to tables or NULL for std */
- void *nullpad; /* NULL padding */
-} real_pcre32;
-
-#if defined COMPILE_PCRE8
-#define REAL_PCRE real_pcre
-#elif defined COMPILE_PCRE16
-#define REAL_PCRE real_pcre16
-#elif defined COMPILE_PCRE32
-#define REAL_PCRE real_pcre32
-#endif
-/* Assert that the size of REAL_PCRE is divisible by 8 */
-typedef int __assert_real_pcre_size_divisible_8[(sizeof(REAL_PCRE) % 8) == 0 ? 1 : -1];
+/* ---------- Private structures that are mode-independent. ---------- */
-/* Needed in pcretest to access some fields in the real_pcre* structures
- * directly. They're unified for 8/16/32 bits since the structs only differ
- * after these fields; if that ever changes, need to fork those defines into
- * 8/16 and 32 bit versions. */
-#define REAL_PCRE_MAGIC(re) (((REAL_PCRE*)re)->magic_number)
-#define REAL_PCRE_SIZE(re) (((REAL_PCRE*)re)->size)
-#define REAL_PCRE_OPTIONS(re) (((REAL_PCRE*)re)->options)
-#define REAL_PCRE_FLAGS(re) (((REAL_PCRE*)re)->flags)
+/* Structure to hold data for custom memory management. */
-/* The format of the block used to store data from pcre_study(). The same
-remark (see NOTE above) about extending this structure applies. */
-
-typedef struct pcre_study_data {
- pcre_uint32 size; /* Total that was malloced */
- pcre_uint32 flags; /* Private flags */
- pcre_uint8 start_bits[32]; /* Starting char bits */
- pcre_uint32 minlength; /* Minimum subject length */
-} pcre_study_data;
+typedef struct pcre2_memctl {
+ void * (*malloc)(size_t, void *);
+ void (*free)(void *, void *);
+ void *memory_data;
+} pcre2_memctl;
/* Structure for building a chain of open capturing subpatterns during
compiling, so that instructions to close them can be compiled when (*ACCEPT) is
@@ -2406,377 +1766,31 @@ back references to themselves, so that they can be made atomic. */
typedef struct open_capitem {
struct open_capitem *next; /* Chain link */
- pcre_uint16 number; /* Capture number */
- pcre_uint16 flag; /* Set TRUE if recursive back ref */
+ uint16_t number; /* Capture number */
+ uint16_t flag; /* Set TRUE if recursive back ref */
} open_capitem;
-/* Structure for building a list of named groups during the first pass of
-compiling. */
-
-typedef struct named_group {
- const pcre_uchar *name; /* Points to the name in the pattern */
- int length; /* Length of the name */
- pcre_uint32 number; /* Group number */
-} named_group;
-
-/* Structure for passing "static" information around between the functions
-doing the compiling, so that they are thread-safe. */
-
-typedef struct compile_data {
- const pcre_uint8 *lcc; /* Points to lower casing table */
- const pcre_uint8 *fcc; /* Points to case-flipping table */
- const pcre_uint8 *cbits; /* Points to character type table */
- const pcre_uint8 *ctypes; /* Points to table of type maps */
- const pcre_uchar *start_workspace;/* The start of working space */
- const pcre_uchar *start_code; /* The start of the compiled code */
- const pcre_uchar *start_pattern; /* The start of the pattern */
- const pcre_uchar *end_pattern; /* The end of the pattern */
- pcre_uchar *hwm; /* High watermark of workspace */
- open_capitem *open_caps; /* Chain of open capture items */
- named_group *named_groups; /* Points to vector in pre-compile */
- pcre_uchar *name_table; /* The name/number table */
- int names_found; /* Number of entries so far */
- int name_entry_size; /* Size of each entry */
- int named_group_list_size; /* Number of entries in the list */
- int workspace_size; /* Size of workspace */
- unsigned int bracount; /* Count of capturing parens as we compile */
- int final_bracount; /* Saved value after first pass */
- int max_lookbehind; /* Maximum lookbehind (characters) */
- int top_backref; /* Maximum back reference */
- unsigned int backref_map; /* Bitmap of low back refs */
- unsigned int namedrefcount; /* Number of backreferences by name */
- int parens_depth; /* Depth of nested parentheses */
- int assert_depth; /* Depth of nested assertions */
- pcre_uint32 external_options; /* External (initial) options */
- pcre_uint32 external_flags; /* External flag bits to be set */
- int req_varyopt; /* "After variable item" flag for reqbyte */
- BOOL had_accept; /* (*ACCEPT) encountered */
- BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */
- BOOL check_lookbehind; /* Lookbehinds need later checking */
- BOOL dupnames; /* Duplicate names exist */
- BOOL dupgroups; /* Duplicate groups exist: (?| found */
- BOOL iscondassert; /* Next assert is a condition */
- int nltype; /* Newline type */
- int nllen; /* Newline string length */
- pcre_uchar nl[4]; /* Newline string when fixed length */
-} compile_data;
-
-/* Structure for maintaining a chain of pointers to the currently incomplete
-branches, for testing for left recursion while compiling. */
-
-typedef struct branch_chain {
- struct branch_chain *outer;
- pcre_uchar *current_branch;
-} branch_chain;
-
-/* Structure for mutual recursion detection. */
-
-typedef struct recurse_check {
- struct recurse_check *prev;
- const pcre_uchar *group;
-} recurse_check;
-
-/* Structure for items in a linked list that represents an explicit recursive
-call within the pattern; used by pcre_exec(). */
-
-typedef struct recursion_info {
- struct recursion_info *prevrec; /* Previous recursion record (or NULL) */
- unsigned int group_num; /* Number of group that was called */
- int *offset_save; /* Pointer to start of saved offsets */
- int saved_max; /* Number of saved offsets */
- int saved_capture_last; /* Last capture number */
- PCRE_PUCHAR subject_position; /* Position at start of recursion */
-} recursion_info;
-
-/* A similar structure for pcre_dfa_exec(). */
-
-typedef struct dfa_recursion_info {
- struct dfa_recursion_info *prevrec;
- int group_num;
- PCRE_PUCHAR subject_position;
-} dfa_recursion_info;
-
-/* Structure for building a chain of data for holding the values of the subject
-pointer at the start of each subpattern, so as to detect when an empty string
-has been matched by a subpattern - to break infinite loops; used by
-pcre_exec(). */
-
-typedef struct eptrblock {
- struct eptrblock *epb_prev;
- PCRE_PUCHAR epb_saved_eptr;
-} eptrblock;
-
-
-/* Structure for passing "static" information around between the functions
-doing traditional NFA matching, so that they are thread-safe. */
-
-typedef struct match_data {
- unsigned long int match_call_count; /* As it says */
- unsigned long int match_limit; /* As it says */
- unsigned long int match_limit_recursion; /* As it says */
- int *offset_vector; /* Offset vector */
- int offset_end; /* One past the end */
- int offset_max; /* The maximum usable for return data */
- int nltype; /* Newline type */
- int nllen; /* Newline string length */
- int name_count; /* Number of names in name table */
- int name_entry_size; /* Size of entry in names table */
- unsigned int skip_arg_count; /* For counting SKIP_ARGs */
- unsigned int ignore_skip_arg; /* For re-run when SKIP arg name not found */
- pcre_uchar *name_table; /* Table of names */
- pcre_uchar nl[4]; /* Newline string when fixed */
- const pcre_uint8 *lcc; /* Points to lower casing table */
- const pcre_uint8 *fcc; /* Points to case-flipping table */
- const pcre_uint8 *ctypes; /* Points to table of type maps */
- BOOL notbol; /* NOTBOL flag */
- BOOL noteol; /* NOTEOL flag */
- BOOL utf; /* UTF-8 / UTF-16 flag */
- BOOL jscript_compat; /* JAVASCRIPT_COMPAT flag */
- BOOL use_ucp; /* PCRE_UCP flag */
- BOOL endonly; /* Dollar not before final \n */
- BOOL notempty; /* Empty string match not wanted */
- BOOL notempty_atstart; /* Empty string match at start not wanted */
- BOOL hitend; /* Hit the end of the subject at some point */
- BOOL bsr_anycrlf; /* \R is just any CRLF, not full Unicode */
- BOOL hasthen; /* Pattern contains (*THEN) */
- const pcre_uchar *start_code; /* For use when recursing */
- PCRE_PUCHAR start_subject; /* Start of the subject string */
- PCRE_PUCHAR end_subject; /* End of the subject string */
- PCRE_PUCHAR start_match_ptr; /* Start of matched string */
- PCRE_PUCHAR end_match_ptr; /* Subject position at end match */
- PCRE_PUCHAR start_used_ptr; /* Earliest consulted character */
- int partial; /* PARTIAL options */
- int end_offset_top; /* Highwater mark at end of match */
- pcre_int32 capture_last; /* Most recent capture number + overflow flag */
- int start_offset; /* The start offset value */
- int match_function_type; /* Set for certain special calls of MATCH() */
- eptrblock *eptrchain; /* Chain of eptrblocks for tail recursions */
- int eptrn; /* Next free eptrblock */
- recursion_info *recursive; /* Linked list of recursion data */
- void *callout_data; /* To pass back to callouts */
- const pcre_uchar *mark; /* Mark pointer to pass back on success */
- const pcre_uchar *nomatch_mark;/* Mark pointer to pass back on failure */
- const pcre_uchar *once_target; /* Where to back up to for atomic groups */
-#ifdef NO_RECURSE
- void *match_frames_base; /* For remembering malloc'd frames */
-#endif
-} match_data;
-
-/* A similar structure is used for the same purpose by the DFA matching
-functions. */
-
-typedef struct dfa_match_data {
- const pcre_uchar *start_code; /* Start of the compiled pattern */
- const pcre_uchar *start_subject ; /* Start of the subject string */
- const pcre_uchar *end_subject; /* End of subject string */
- const pcre_uchar *start_used_ptr; /* Earliest consulted character */
- const pcre_uint8 *tables; /* Character tables */
- int start_offset; /* The start offset value */
- int moptions; /* Match options */
- int poptions; /* Pattern options */
- int nltype; /* Newline type */
- int nllen; /* Newline string length */
- pcre_uchar nl[4]; /* Newline string when fixed */
- void *callout_data; /* To pass back to callouts */
- dfa_recursion_info *recursive; /* Linked list of recursion data */
-} dfa_match_data;
-
-/* Bit definitions for entries in the pcre_ctypes table. */
-
-#define ctype_space 0x01
-#define ctype_letter 0x02
-#define ctype_digit 0x04
-#define ctype_xdigit 0x08
-#define ctype_word 0x10 /* alphanumeric or '_' */
-#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */
-
-/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
-of bits for a class map. Some classes are built by combining these tables. */
-
-#define cbit_space 0 /* [:space:] or \s */
-#define cbit_xdigit 32 /* [:xdigit:] */
-#define cbit_digit 64 /* [:digit:] or \d */
-#define cbit_upper 96 /* [:upper:] */
-#define cbit_lower 128 /* [:lower:] */
-#define cbit_word 160 /* [:word:] or \w */
-#define cbit_graph 192 /* [:graph:] */
-#define cbit_print 224 /* [:print:] */
-#define cbit_punct 256 /* [:punct:] */
-#define cbit_cntrl 288 /* [:cntrl:] */
-#define cbit_length 320 /* Length of the cbits table */
-
-/* Offsets of the various tables from the base tables pointer, and
-total length. */
-
-#define lcc_offset 0
-#define fcc_offset 256
-#define cbits_offset 512
-#define ctypes_offset (cbits_offset + cbit_length)
-#define tables_length (ctypes_offset + 256)
-
-/* Internal function and data prefixes. */
-
-#if defined COMPILE_PCRE8
-#ifndef PUBL
-#define PUBL(name) pcre_##name
-#endif
-#ifndef PRIV
-#define PRIV(name) _pcre_##name
-#endif
-#elif defined COMPILE_PCRE16
-#ifndef PUBL
-#define PUBL(name) pcre16_##name
-#endif
-#ifndef PRIV
-#define PRIV(name) _pcre16_##name
-#endif
-#elif defined COMPILE_PCRE32
-#ifndef PUBL
-#define PUBL(name) pcre32_##name
-#endif
-#ifndef PRIV
-#define PRIV(name) _pcre32_##name
-#endif
-#else
-#error Unsupported compiling mode
-#endif /* COMPILE_PCRE[8|16|32] */
-
/* Layout of the UCP type table that translates property names into types and
codes. Each entry used to point directly to a name, but to reduce the number of
relocations in shared libraries, it now has an offset into a single string
instead. */
typedef struct {
- pcre_uint16 name_offset;
- pcre_uint16 type;
- pcre_uint16 value;
+ uint16_t name_offset;
+ uint16_t type;
+ uint16_t value;
} ucp_type_table;
-
-/* Internal shared data tables. These are tables that are used by more than one
-of the exported public functions. They have to be "external" in the C sense,
-but are not part of the PCRE public API. The data for these tables is in the
-pcre_tables.c module. */
-
-#ifdef COMPILE_PCRE8
-extern const int PRIV(utf8_table1)[];
-extern const int PRIV(utf8_table1_size);
-extern const int PRIV(utf8_table2)[];
-extern const int PRIV(utf8_table3)[];
-extern const pcre_uint8 PRIV(utf8_table4)[];
-#endif /* COMPILE_PCRE8 */
-
-extern const char PRIV(utt_names)[];
-extern const ucp_type_table PRIV(utt)[];
-extern const int PRIV(utt_size);
-
-extern const pcre_uint8 PRIV(OP_lengths)[];
-extern const pcre_uint8 PRIV(default_tables)[];
-
-extern const pcre_uint32 PRIV(hspace_list)[];
-extern const pcre_uint32 PRIV(vspace_list)[];
-
-
-/* Internal shared functions. These are functions that are used by more than
-one of the exported public functions. They have to be "external" in the C
-sense, but are not part of the PCRE public API. */
-
-/* String comparison functions. */
-#if defined COMPILE_PCRE8
-
-#define STRCMP_UC_UC(str1, str2) \
- strcmp((char *)(str1), (char *)(str2))
-#define STRCMP_UC_C8(str1, str2) \
- strcmp((char *)(str1), (str2))
-#define STRNCMP_UC_UC(str1, str2, num) \
- strncmp((char *)(str1), (char *)(str2), (num))
-#define STRNCMP_UC_C8(str1, str2, num) \
- strncmp((char *)(str1), (str2), (num))
-#define STRLEN_UC(str) strlen((const char *)str)
-
-#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32
-
-extern int PRIV(strcmp_uc_uc)(const pcre_uchar *,
- const pcre_uchar *);
-extern int PRIV(strcmp_uc_c8)(const pcre_uchar *,
- const char *);
-extern int PRIV(strncmp_uc_uc)(const pcre_uchar *,
- const pcre_uchar *, unsigned int num);
-extern int PRIV(strncmp_uc_c8)(const pcre_uchar *,
- const char *, unsigned int num);
-extern unsigned int PRIV(strlen_uc)(const pcre_uchar *str);
-
-#define STRCMP_UC_UC(str1, str2) \
- PRIV(strcmp_uc_uc)((str1), (str2))
-#define STRCMP_UC_C8(str1, str2) \
- PRIV(strcmp_uc_c8)((str1), (str2))
-#define STRNCMP_UC_UC(str1, str2, num) \
- PRIV(strncmp_uc_uc)((str1), (str2), (num))
-#define STRNCMP_UC_C8(str1, str2, num) \
- PRIV(strncmp_uc_c8)((str1), (str2), (num))
-#define STRLEN_UC(str) PRIV(strlen_uc)(str)
-
-#endif /* COMPILE_PCRE[8|16|32] */
-
-#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16
-
-#define STRCMP_UC_UC_TEST(str1, str2) STRCMP_UC_UC(str1, str2)
-#define STRCMP_UC_C8_TEST(str1, str2) STRCMP_UC_C8(str1, str2)
-
-#elif defined COMPILE_PCRE32
-
-extern int PRIV(strcmp_uc_uc_utf)(const pcre_uchar *,
- const pcre_uchar *);
-extern int PRIV(strcmp_uc_c8_utf)(const pcre_uchar *,
- const char *);
-
-#define STRCMP_UC_UC_TEST(str1, str2) \
- (utf ? PRIV(strcmp_uc_uc_utf)((str1), (str2)) : PRIV(strcmp_uc_uc)((str1), (str2)))
-#define STRCMP_UC_C8_TEST(str1, str2) \
- (utf ? PRIV(strcmp_uc_c8_utf)((str1), (str2)) : PRIV(strcmp_uc_c8)((str1), (str2)))
-
-#endif /* COMPILE_PCRE[8|16|32] */
-
-extern const pcre_uchar *PRIV(find_bracket)(const pcre_uchar *, BOOL, int);
-extern BOOL PRIV(is_newline)(PCRE_PUCHAR, int, PCRE_PUCHAR,
- int *, BOOL);
-extern unsigned int PRIV(ord2utf)(pcre_uint32, pcre_uchar *);
-extern int PRIV(valid_utf)(PCRE_PUCHAR, int, int *);
-extern BOOL PRIV(was_newline)(PCRE_PUCHAR, int, PCRE_PUCHAR,
- int *, BOOL);
-extern BOOL PRIV(xclass)(pcre_uint32, const pcre_uchar *, BOOL);
-
-#ifdef SUPPORT_JIT
-extern void PRIV(jit_compile)(const REAL_PCRE *,
- PUBL(extra) *, int);
-extern int PRIV(jit_exec)(const PUBL(extra) *,
- const pcre_uchar *, int, int, int, int *, int);
-extern void PRIV(jit_free)(void *);
-extern int PRIV(jit_get_size)(void *);
-extern const char* PRIV(jit_get_target)(void);
-#endif
-
-/* Unicode character database (UCD) */
+/* Unicode character database (UCD) record format */
typedef struct {
- pcre_uint8 script; /* ucp_Arabic, etc. */
- pcre_uint8 chartype; /* ucp_Cc, etc. (general categories) */
- pcre_uint8 gbprop; /* ucp_gbControl, etc. (grapheme break property) */
- pcre_uint8 caseset; /* offset to multichar other cases or zero */
- pcre_int32 other_case; /* offset to other case, or zero if none */
+ uint8_t script; /* ucp_Arabic, etc. */
+ uint8_t chartype; /* ucp_Cc, etc. (general categories) */
+ uint8_t gbprop; /* ucp_gbControl, etc. (grapheme break property) */
+ uint8_t caseset; /* offset to multichar other cases or zero */
+ int32_t other_case; /* offset to other case, or zero if none */
} ucd_record;
-extern const pcre_uint32 PRIV(ucd_caseless_sets)[];
-extern const ucd_record PRIV(ucd_records)[];
-extern const pcre_uint8 PRIV(ucd_stage1)[];
-extern const pcre_uint16 PRIV(ucd_stage2)[];
-extern const pcre_uint32 PRIV(ucp_gentype)[];
-extern const pcre_uint32 PRIV(ucp_gbtable)[];
-#ifdef SUPPORT_JIT
-extern const int PRIV(ucp_typerange)[];
-#endif
-
-#ifdef SUPPORT_UCP
/* UCD access macros */
#define UCD_BLOCK_SIZE 128
@@ -2789,10 +1803,158 @@ extern const int PRIV(ucp_typerange)[];
#define UCD_CATEGORY(ch) PRIV(ucp_gentype)[UCD_CHARTYPE(ch)]
#define UCD_GRAPHBREAK(ch) GET_UCD(ch)->gbprop
#define UCD_CASESET(ch) GET_UCD(ch)->caseset
-#define UCD_OTHERCASE(ch) ((pcre_uint32)((int)ch + (int)(GET_UCD(ch)->other_case)))
+#define UCD_OTHERCASE(ch) ((uint32_t)((int)ch + (int)(GET_UCD(ch)->other_case)))
+
+/* Header for serialized pcre2 codes. */
-#endif /* SUPPORT_UCP */
+typedef struct pcre2_serialized_data {
+ uint32_t magic;
+ uint32_t version;
+ uint32_t config;
+ int32_t number_of_codes;
+} pcre2_serialized_data;
+
+
+/* ----------------- Items that need PCRE2_CODE_UNIT_WIDTH ----------------- */
+
+/* When this file is included by pcre2test, PCRE2_CODE_UNIT_WIDTH is defined as
+0, so the following items are omitted. */
+
+#if defined PCRE2_CODE_UNIT_WIDTH && PCRE2_CODE_UNIT_WIDTH != 0
+
+/* EBCDIC is supported only for the 8-bit library. */
+
+#if defined EBCDIC && PCRE2_CODE_UNIT_WIDTH != 8
+#error EBCDIC is not supported for the 16-bit or 32-bit libraries
#endif
-/* End of pcre_internal.h */
+/* This is the largest non-UTF code point. */
+
+#define MAX_NON_UTF_CHAR (0xffffffffU >> (32 - PCRE2_CODE_UNIT_WIDTH))
+
+/* Internal shared data tables and variables. These are used by more than one
+of the exported public functions. They have to be "external" in the C sense,
+but are not part of the PCRE2 public API. Although the data for some of them is
+identical in all libraries, they must have different names so that multiple
+libraries can be simultaneously linked to a single application. However, UTF-8
+tables are needed only when compiling the 8-bit library. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+extern const int PRIV(utf8_table1)[];
+extern const int PRIV(utf8_table1_size);
+extern const int PRIV(utf8_table2)[];
+extern const int PRIV(utf8_table3)[];
+extern const uint8_t PRIV(utf8_table4)[];
+#endif
+
+#define _pcre2_OP_lengths PCRE2_SUFFIX(_pcre2_OP_lengths_)
+#define _pcre2_callout_end_delims PCRE2_SUFFIX(_pcre2_callout_end_delims_)
+#define _pcre2_callout_start_delims PCRE2_SUFFIX(_pcre2_callout_start_delims_)
+#define _pcre2_default_compile_context PCRE2_SUFFIX(_pcre2_default_compile_context_)
+#define _pcre2_default_match_context PCRE2_SUFFIX(_pcre2_default_match_context_)
+#define _pcre2_default_tables PCRE2_SUFFIX(_pcre2_default_tables_)
+#define _pcre2_hspace_list PCRE2_SUFFIX(_pcre2_hspace_list_)
+#define _pcre2_vspace_list PCRE2_SUFFIX(_pcre2_vspace_list_)
+#define _pcre2_ucd_caseless_sets PCRE2_SUFFIX(_pcre2_ucd_caseless_sets_)
+#define _pcre2_ucd_records PCRE2_SUFFIX(_pcre2_ucd_records_)
+#define _pcre2_ucd_stage1 PCRE2_SUFFIX(_pcre2_ucd_stage1_)
+#define _pcre2_ucd_stage2 PCRE2_SUFFIX(_pcre2_ucd_stage2_)
+#define _pcre2_ucp_gbtable PCRE2_SUFFIX(_pcre2_ucp_gbtable_)
+#define _pcre2_ucp_gentype PCRE2_SUFFIX(_pcre2_ucp_gentype_)
+#define _pcre2_ucp_typerange PCRE2_SUFFIX(_pcre2_ucp_typerange_)
+#define _pcre2_unicode_version PCRE2_SUFFIX(_pcre2_unicode_version_)
+#define _pcre2_utt PCRE2_SUFFIX(_pcre2_utt_)
+#define _pcre2_utt_names PCRE2_SUFFIX(_pcre2_utt_names_)
+#define _pcre2_utt_size PCRE2_SUFFIX(_pcre2_utt_size_)
+
+extern const uint8_t PRIV(OP_lengths)[];
+extern const uint32_t PRIV(callout_end_delims)[];
+extern const uint32_t PRIV(callout_start_delims)[];
+extern const pcre2_compile_context PRIV(default_compile_context);
+extern const pcre2_match_context PRIV(default_match_context);
+extern const uint8_t PRIV(default_tables)[];
+extern const uint32_t PRIV(hspace_list)[];
+extern const uint32_t PRIV(vspace_list)[];
+extern const uint32_t PRIV(ucd_caseless_sets)[];
+extern const ucd_record PRIV(ucd_records)[];
+extern const uint8_t PRIV(ucd_stage1)[];
+extern const uint16_t PRIV(ucd_stage2)[];
+extern const uint32_t PRIV(ucp_gbtable)[];
+extern const uint32_t PRIV(ucp_gentype)[];
+#ifdef SUPPORT_JIT
+extern const int PRIV(ucp_typerange)[];
+#endif
+extern const char *PRIV(unicode_version);
+extern const ucp_type_table PRIV(utt)[];
+extern const char PRIV(utt_names)[];
+extern const size_t PRIV(utt_size);
+
+/* Mode-dependent macros and hidden and private structures are defined in a
+separate file so that pcre2test can include them at all supported widths. When
+compiling the library, PCRE2_CODE_UNIT_WIDTH will be defined, and we can
+include them at the appropriate width, after setting up suffix macros for the
+private structures. */
+
+#define branch_chain PCRE2_SUFFIX(branch_chain_)
+#define compile_block PCRE2_SUFFIX(compile_block_)
+#define dfa_match_block PCRE2_SUFFIX(dfa_match_block_)
+#define match_block PCRE2_SUFFIX(match_block_)
+#define named_group PCRE2_SUFFIX(named_group_)
+
+#include "pcre2_intmodedep.h"
+
+/* Private "external" functions. These are internal functions that are called
+from modules other than the one in which they are defined. They have to be
+"external" in the C sense, but are not part of the PCRE2 public API. They are
+not referenced from pcre2test, and must not be defined when no code unit width
+is available. */
+
+#define _pcre2_auto_possessify PCRE2_SUFFIX(_pcre2_auto_possessify_)
+#define _pcre2_check_escape PCRE2_SUFFIX(_pcre2_check_escape_)
+#define _pcre2_find_bracket PCRE2_SUFFIX(_pcre2_find_bracket_)
+#define _pcre2_is_newline PCRE2_SUFFIX(_pcre2_is_newline_)
+#define _pcre2_jit_free_rodata PCRE2_SUFFIX(_pcre2_jit_free_rodata_)
+#define _pcre2_jit_free PCRE2_SUFFIX(_pcre2_jit_free_)
+#define _pcre2_jit_get_size PCRE2_SUFFIX(_pcre2_jit_get_size_)
+#define _pcre2_jit_get_target PCRE2_SUFFIX(_pcre2_jit_get_target_)
+#define _pcre2_memctl_malloc PCRE2_SUFFIX(_pcre2_memctl_malloc_)
+#define _pcre2_ord2utf PCRE2_SUFFIX(_pcre2_ord2utf_)
+#define _pcre2_strcmp PCRE2_SUFFIX(_pcre2_strcmp_)
+#define _pcre2_strcmp_c8 PCRE2_SUFFIX(_pcre2_strcmp_c8_)
+#define _pcre2_strcpy_c8 PCRE2_SUFFIX(_pcre2_strcpy_c8_)
+#define _pcre2_strlen PCRE2_SUFFIX(_pcre2_strlen_)
+#define _pcre2_strncmp PCRE2_SUFFIX(_pcre2_strncmp_)
+#define _pcre2_strncmp_c8 PCRE2_SUFFIX(_pcre2_strncmp_c8_)
+#define _pcre2_study PCRE2_SUFFIX(_pcre2_study_)
+#define _pcre2_valid_utf PCRE2_SUFFIX(_pcre2_valid_utf_)
+#define _pcre2_was_newline PCRE2_SUFFIX(_pcre2_was_newline_)
+#define _pcre2_xclass PCRE2_SUFFIX(_pcre2_xclass_)
+
+extern int _pcre2_auto_possessify(PCRE2_UCHAR *, BOOL,
+ const compile_block *);
+extern int _pcre2_check_escape(PCRE2_SPTR *, PCRE2_SPTR, uint32_t *,
+ int *, uint32_t, BOOL, compile_block *);
+extern PCRE2_SPTR _pcre2_find_bracket(PCRE2_SPTR, BOOL, int);
+extern BOOL _pcre2_is_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR,
+ uint32_t *, BOOL);
+extern void _pcre2_jit_free_rodata(void *, void *);
+extern void _pcre2_jit_free(void *, pcre2_memctl *);
+extern size_t _pcre2_jit_get_size(void *);
+const char * _pcre2_jit_get_target(void);
+extern void * _pcre2_memctl_malloc(size_t, pcre2_memctl *);
+extern unsigned int _pcre2_ord2utf(uint32_t, PCRE2_UCHAR *);
+extern int _pcre2_strcmp(PCRE2_SPTR, PCRE2_SPTR);
+extern int _pcre2_strcmp_c8(PCRE2_SPTR, const char *);
+extern PCRE2_SIZE _pcre2_strcpy_c8(PCRE2_UCHAR *, const char *);
+extern PCRE2_SIZE _pcre2_strlen(PCRE2_SPTR);
+extern int _pcre2_strncmp(PCRE2_SPTR, PCRE2_SPTR, size_t);
+extern int _pcre2_strncmp_c8(PCRE2_SPTR, const char *, size_t);
+extern int _pcre2_study(pcre2_real_code *);
+extern int _pcre2_valid_utf(PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE *);
+extern BOOL _pcre2_was_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR,
+ uint32_t *, BOOL);
+extern BOOL _pcre2_xclass(uint32_t, PCRE2_SPTR, BOOL);
+#endif /* PCRE2_CODE_UNIT_WIDTH */
+
+/* End of pcre2_internal.h */
diff --git a/src/3rdparty/pcre2/src/pcre2_intmodedep.h b/src/3rdparty/pcre2/src/pcre2_intmodedep.h
new file mode 100644
index 0000000000..596d62cfdc
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_intmodedep.h
@@ -0,0 +1,852 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains mode-dependent macro and structure definitions. The
+file is #included by pcre2_internal.h if PCRE2_CODE_UNIT_WIDTH is defined.
+These mode-dependent items are kept in a separate file so that they can also be
+#included multiple times for different code unit widths by pcre2test in order
+to have access to the hidden structures at all supported widths.
+
+Some of the mode-dependent macros are required at different widths for
+different parts of the pcre2test code (in particular, the included
+pcre_printint.c file). We undefine them here so that they can be re-defined for
+multiple inclusions. Not all of these are used in pcre2test, but it's easier
+just to undefine them all. */
+
+#undef ACROSSCHAR
+#undef BACKCHAR
+#undef BYTES2CU
+#undef CU2BYTES
+#undef FORWARDCHAR
+#undef FORWARDCHARTEST
+#undef GET
+#undef GET2
+#undef GETCHAR
+#undef GETCHARINC
+#undef GETCHARINCTEST
+#undef GETCHARLEN
+#undef GETCHARLENTEST
+#undef GETCHARTEST
+#undef GET_EXTRALEN
+#undef HAS_EXTRALEN
+#undef IMM2_SIZE
+#undef MAX_255
+#undef MAX_MARK
+#undef MAX_PATTERN_SIZE
+#undef MAX_UTF_SINGLE_CU
+#undef NOT_FIRSTCU
+#undef PUT
+#undef PUT2
+#undef PUT2INC
+#undef PUTCHAR
+#undef PUTINC
+#undef TABLE_GET
+
+
+
+/* -------------------------- MACROS ----------------------------- */
+
+/* PCRE keeps offsets in its compiled code as at least 16-bit quantities
+(always stored in big-endian order in 8-bit mode) by default. These are used,
+for example, to link from the start of a subpattern to its alternatives and its
+end. The use of 16 bits per offset limits the size of an 8-bit compiled regex
+to around 64K, which is big enough for almost everybody. However, I received a
+request for an even bigger limit. For this reason, and also to make the code
+easier to maintain, the storing and loading of offsets from the compiled code
+unit string is now handled by the macros that are defined here.
+
+The macros are controlled by the value of LINK_SIZE. This defaults to 2, but
+values of 3 or 4 are also supported. */
+
+/* ------------------- 8-bit support ------------------ */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+
+#if LINK_SIZE == 2
+#define PUT(a,n,d) \
+ (a[n] = (PCRE2_UCHAR)((d) >> 8)), \
+ (a[(n)+1] = (PCRE2_UCHAR)((d) & 255))
+#define GET(a,n) \
+ (unsigned int)(((a)[n] << 8) | (a)[(n)+1])
+#define MAX_PATTERN_SIZE (1 << 16)
+
+#elif LINK_SIZE == 3
+#define PUT(a,n,d) \
+ (a[n] = (PCRE2_UCHAR)((d) >> 16)), \
+ (a[(n)+1] = (PCRE2_UCHAR)((d) >> 8)), \
+ (a[(n)+2] = (PCRE2_UCHAR)((d) & 255))
+#define GET(a,n) \
+ (unsigned int)(((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2])
+#define MAX_PATTERN_SIZE (1 << 24)
+
+#elif LINK_SIZE == 4
+#define PUT(a,n,d) \
+ (a[n] = (PCRE2_UCHAR)((d) >> 24)), \
+ (a[(n)+1] = (PCRE2_UCHAR)((d) >> 16)), \
+ (a[(n)+2] = (PCRE2_UCHAR)((d) >> 8)), \
+ (a[(n)+3] = (PCRE2_UCHAR)((d) & 255))
+#define GET(a,n) \
+ (unsigned int)(((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3])
+#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */
+
+#else
+#error LINK_SIZE must be 2, 3, or 4
+#endif
+
+
+/* ------------------- 16-bit support ------------------ */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+
+#if LINK_SIZE == 2
+#undef LINK_SIZE
+#define LINK_SIZE 1
+#define PUT(a,n,d) \
+ (a[n] = (d))
+#define GET(a,n) \
+ (a[n])
+#define MAX_PATTERN_SIZE (1 << 16)
+
+#elif LINK_SIZE == 3 || LINK_SIZE == 4
+#undef LINK_SIZE
+#define LINK_SIZE 2
+#define PUT(a,n,d) \
+ (a[n] = (PCRE2_UCHAR)((d) >> 16)), \
+ (a[(n)+1] = (PCRE2_UCHAR)((d) & 65535))
+#define GET(a,n) \
+ (unsigned int)(((a)[n] << 16) | (a)[(n)+1])
+#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */
+
+#else
+#error LINK_SIZE must be 2, 3, or 4
+#endif
+
+
+/* ------------------- 32-bit support ------------------ */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+#undef LINK_SIZE
+#define LINK_SIZE 1
+#define PUT(a,n,d) \
+ (a[n] = (d))
+#define GET(a,n) \
+ (a[n])
+#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */
+
+#else
+#error Unsupported compiling mode
+#endif
+
+
+/* --------------- Other mode-specific macros ----------------- */
+
+/* PCRE uses some other (at least) 16-bit quantities that do not change when
+the size of offsets changes. There are used for repeat counts and for other
+things such as capturing parenthesis numbers in back references.
+
+Define the number of code units required to hold a 16-bit count/offset, and
+macros to load and store such a value. For reasons that I do not understand,
+the expression in the 8-bit GET2 macro is treated by gcc as a signed
+expression, even when a is declared as unsigned. It seems that any kind of
+arithmetic results in a signed value. Hence the cast. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define IMM2_SIZE 2
+#define GET2(a,n) (unsigned int)(((a)[n] << 8) | (a)[(n)+1])
+#define PUT2(a,n,d) a[n] = (d) >> 8, a[(n)+1] = (d) & 255
+
+#else /* Code units are 16 or 32 bits */
+#define IMM2_SIZE 1
+#define GET2(a,n) a[n]
+#define PUT2(a,n,d) a[n] = d
+#endif
+
+/* Other macros that are different for 8-bit mode. The MAX_255 macro checks
+whether its argument is less than 256. The maximum length of a MARK name must
+fit in one code unit; currently it is set to 255 or 65535. The TABLE_GET macro
+is used to access elements of tables containing exactly 256 items. When code
+points can be greater than 255, a check is needed before accessing these
+tables. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define MAX_255(c) TRUE
+#define MAX_MARK ((1u << 8) - 1)
+#ifdef SUPPORT_UNICODE
+#define SUPPORT_WIDE_CHARS
+#endif /* SUPPORT_UNICODE */
+#define TABLE_GET(c, table, default) ((table)[c])
+
+#else /* Code units are 16 or 32 bits */
+#define MAX_255(c) ((c) <= 255u)
+#define MAX_MARK ((1u << 16) - 1)
+#define SUPPORT_WIDE_CHARS
+#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default))
+#endif
+
+
+
+/* ----------------- Character-handling macros ----------------- */
+
+/* There is a proposed future special "UTF-21" mode, in which only the lowest
+21 bits of a 32-bit character are interpreted as UTF, with the remaining 11
+high-order bits available to the application for other uses. In preparation for
+the future implementation of this mode, there are macros that load a data item
+and, if in this special mode, mask it to 21 bits. These macros all have names
+starting with UCHAR21. In all other modes, including the normal 32-bit
+library, the macros all have the same simple definitions. When the new mode is
+implemented, it is expected that these definitions will be varied appropriately
+using #ifdef when compiling the library that supports the special mode. */
+
+#define UCHAR21(eptr) (*(eptr))
+#define UCHAR21TEST(eptr) (*(eptr))
+#define UCHAR21INC(eptr) (*(eptr)++)
+#define UCHAR21INCTEST(eptr) (*(eptr)++)
+
+/* When UTF encoding is being used, a character is no longer just a single
+byte in 8-bit mode or a single short in 16-bit mode. The macros for character
+handling generate simple sequences when used in the basic mode, and more
+complicated ones for UTF characters. GETCHARLENTEST and other macros are not
+used when UTF is not supported. To make sure they can never even appear when
+UTF support is omitted, we don't even define them. */
+
+#ifndef SUPPORT_UNICODE
+
+/* #define MAX_UTF_SINGLE_CU */
+/* #define HAS_EXTRALEN(c) */
+/* #define GET_EXTRALEN(c) */
+/* #define NOT_FIRSTCU(c) */
+#define GETCHAR(c, eptr) c = *eptr;
+#define GETCHARTEST(c, eptr) c = *eptr;
+#define GETCHARINC(c, eptr) c = *eptr++;
+#define GETCHARINCTEST(c, eptr) c = *eptr++;
+#define GETCHARLEN(c, eptr, len) c = *eptr;
+#define PUTCHAR(c, p) (*p = c, 1)
+/* #define GETCHARLENTEST(c, eptr, len) */
+/* #define BACKCHAR(eptr) */
+/* #define FORWARDCHAR(eptr) */
+/* #define FORWARCCHARTEST(eptr,end) */
+/* #define ACROSSCHAR(condition, eptr, action) */
+
+#else /* SUPPORT_UNICODE */
+
+/* ------------------- 8-bit support ------------------ */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define MAYBE_UTF_MULTI /* UTF chars may use multiple code units */
+
+/* The largest UTF code point that can be encoded as a single code unit. */
+
+#define MAX_UTF_SINGLE_CU 127
+
+/* Tests whether the code point needs extra characters to decode. */
+
+#define HAS_EXTRALEN(c) HASUTF8EXTRALEN(c)
+
+/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
+Otherwise it has an undefined behaviour. */
+
+#define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3fu])
+
+/* Returns TRUE, if the given value is not the first code unit of a UTF
+sequence. */
+
+#define NOT_FIRSTCU(c) (((c) & 0xc0u) == 0x80u)
+
+/* Get the next UTF-8 character, not advancing the pointer. This is called when
+we know we are in UTF-8 mode. */
+
+#define GETCHAR(c, eptr) \
+ c = *eptr; \
+ if (c >= 0xc0u) GETUTF8(c, eptr);
+
+/* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the
+pointer. */
+
+#define GETCHARTEST(c, eptr) \
+ c = *eptr; \
+ if (utf && c >= 0xc0u) GETUTF8(c, eptr);
+
+/* Get the next UTF-8 character, advancing the pointer. This is called when we
+know we are in UTF-8 mode. */
+
+#define GETCHARINC(c, eptr) \
+ c = *eptr++; \
+ if (c >= 0xc0u) GETUTF8INC(c, eptr);
+
+/* Get the next character, testing for UTF-8 mode, and advancing the pointer.
+This is called when we don't know if we are in UTF-8 mode. */
+
+#define GETCHARINCTEST(c, eptr) \
+ c = *eptr++; \
+ if (utf && c >= 0xc0u) GETUTF8INC(c, eptr);
+
+/* Get the next UTF-8 character, not advancing the pointer, incrementing length
+if there are extra bytes. This is called when we know we are in UTF-8 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+ c = *eptr; \
+ if (c >= 0xc0u) GETUTF8LEN(c, eptr, len);
+
+/* Get the next UTF-8 character, testing for UTF-8 mode, not advancing the
+pointer, incrementing length if there are extra bytes. This is called when we
+do not know if we are in UTF-8 mode. */
+
+#define GETCHARLENTEST(c, eptr, len) \
+ c = *eptr; \
+ if (utf && c >= 0xc0u) GETUTF8LEN(c, eptr, len);
+
+/* If the pointer is not at the start of a character, move it back until
+it is. This is called only in UTF-8 mode - we don't put a test within the macro
+because almost all calls are already within a block of UTF-8 only code. */
+
+#define BACKCHAR(eptr) while((*eptr & 0xc0u) == 0x80u) eptr--
+
+/* Same as above, just in the other direction. */
+#define FORWARDCHAR(eptr) while((*eptr & 0xc0u) == 0x80u) eptr++
+#define FORWARDCHARTEST(eptr,end) while(eptr < end && (*eptr & 0xc0u) == 0x80u) eptr++
+
+/* Same as above, but it allows a fully customizable form. */
+#define ACROSSCHAR(condition, eptr, action) \
+ while((condition) && ((eptr) & 0xc0u) == 0x80u) action
+
+/* Deposit a character into memory, returning the number of code units. */
+
+#define PUTCHAR(c, p) ((utf && c > MAX_UTF_SINGLE_CU)? \
+ PRIV(ord2utf)(c,p) : (*p = c, 1))
+
+
+/* ------------------- 16-bit support ------------------ */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define MAYBE_UTF_MULTI /* UTF chars may use multiple code units */
+
+/* The largest UTF code point that can be encoded as a single code unit. */
+
+#define MAX_UTF_SINGLE_CU 65535
+
+/* Tests whether the code point needs extra characters to decode. */
+
+#define HAS_EXTRALEN(c) (((c) & 0xfc00u) == 0xd800u)
+
+/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
+Otherwise it has an undefined behaviour. */
+
+#define GET_EXTRALEN(c) 1
+
+/* Returns TRUE, if the given value is not the first code unit of a UTF
+sequence. */
+
+#define NOT_FIRSTCU(c) (((c) & 0xfc00u) == 0xdc00u)
+
+/* Base macro to pick up the low surrogate of a UTF-16 character, not
+advancing the pointer. */
+
+#define GETUTF16(c, eptr) \
+ { c = (((c & 0x3ffu) << 10) | (eptr[1] & 0x3ffu)) + 0x10000u; }
+
+/* Get the next UTF-16 character, not advancing the pointer. This is called when
+we know we are in UTF-16 mode. */
+
+#define GETCHAR(c, eptr) \
+ c = *eptr; \
+ if ((c & 0xfc00u) == 0xd800u) GETUTF16(c, eptr);
+
+/* Get the next UTF-16 character, testing for UTF-16 mode, and not advancing the
+pointer. */
+
+#define GETCHARTEST(c, eptr) \
+ c = *eptr; \
+ if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16(c, eptr);
+
+/* Base macro to pick up the low surrogate of a UTF-16 character, advancing
+the pointer. */
+
+#define GETUTF16INC(c, eptr) \
+ { c = (((c & 0x3ffu) << 10) | (*eptr++ & 0x3ffu)) + 0x10000u; }
+
+/* Get the next UTF-16 character, advancing the pointer. This is called when we
+know we are in UTF-16 mode. */
+
+#define GETCHARINC(c, eptr) \
+ c = *eptr++; \
+ if ((c & 0xfc00u) == 0xd800u) GETUTF16INC(c, eptr);
+
+/* Get the next character, testing for UTF-16 mode, and advancing the pointer.
+This is called when we don't know if we are in UTF-16 mode. */
+
+#define GETCHARINCTEST(c, eptr) \
+ c = *eptr++; \
+ if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16INC(c, eptr);
+
+/* Base macro to pick up the low surrogate of a UTF-16 character, not
+advancing the pointer, incrementing the length. */
+
+#define GETUTF16LEN(c, eptr, len) \
+ { c = (((c & 0x3ffu) << 10) | (eptr[1] & 0x3ffu)) + 0x10000u; len++; }
+
+/* Get the next UTF-16 character, not advancing the pointer, incrementing
+length if there is a low surrogate. This is called when we know we are in
+UTF-16 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+ c = *eptr; \
+ if ((c & 0xfc00u) == 0xd800u) GETUTF16LEN(c, eptr, len);
+
+/* Get the next UTF-816character, testing for UTF-16 mode, not advancing the
+pointer, incrementing length if there is a low surrogate. This is called when
+we do not know if we are in UTF-16 mode. */
+
+#define GETCHARLENTEST(c, eptr, len) \
+ c = *eptr; \
+ if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16LEN(c, eptr, len);
+
+/* If the pointer is not at the start of a character, move it back until
+it is. This is called only in UTF-16 mode - we don't put a test within the
+macro because almost all calls are already within a block of UTF-16 only
+code. */
+
+#define BACKCHAR(eptr) if ((*eptr & 0xfc00u) == 0xdc00u) eptr--
+
+/* Same as above, just in the other direction. */
+#define FORWARDCHAR(eptr) if ((*eptr & 0xfc00u) == 0xdc00u) eptr++
+#define FORWARDCHARTEST(eptr,end) if (eptr < end && (*eptr & 0xfc00u) == 0xdc00u) eptr++
+
+/* Same as above, but it allows a fully customizable form. */
+#define ACROSSCHAR(condition, eptr, action) \
+ if ((condition) && ((eptr) & 0xfc00u) == 0xdc00u) action
+
+/* Deposit a character into memory, returning the number of code units. */
+
+#define PUTCHAR(c, p) ((utf && c > MAX_UTF_SINGLE_CU)? \
+ PRIV(ord2utf)(c,p) : (*p = c, 1))
+
+
+/* ------------------- 32-bit support ------------------ */
+
+#else
+
+/* These are trivial for the 32-bit library, since all UTF-32 characters fit
+into one PCRE2_UCHAR unit. */
+
+#define MAX_UTF_SINGLE_CU (0x10ffffu)
+#define HAS_EXTRALEN(c) (0)
+#define GET_EXTRALEN(c) (0)
+#define NOT_FIRSTCU(c) (0)
+
+/* Get the next UTF-32 character, not advancing the pointer. This is called when
+we know we are in UTF-32 mode. */
+
+#define GETCHAR(c, eptr) \
+ c = *(eptr);
+
+/* Get the next UTF-32 character, testing for UTF-32 mode, and not advancing the
+pointer. */
+
+#define GETCHARTEST(c, eptr) \
+ c = *(eptr);
+
+/* Get the next UTF-32 character, advancing the pointer. This is called when we
+know we are in UTF-32 mode. */
+
+#define GETCHARINC(c, eptr) \
+ c = *((eptr)++);
+
+/* Get the next character, testing for UTF-32 mode, and advancing the pointer.
+This is called when we don't know if we are in UTF-32 mode. */
+
+#define GETCHARINCTEST(c, eptr) \
+ c = *((eptr)++);
+
+/* Get the next UTF-32 character, not advancing the pointer, not incrementing
+length (since all UTF-32 is of length 1). This is called when we know we are in
+UTF-32 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+ GETCHAR(c, eptr)
+
+/* Get the next UTF-32character, testing for UTF-32 mode, not advancing the
+pointer, not incrementing the length (since all UTF-32 is of length 1).
+This is called when we do not know if we are in UTF-32 mode. */
+
+#define GETCHARLENTEST(c, eptr, len) \
+ GETCHARTEST(c, eptr)
+
+/* If the pointer is not at the start of a character, move it back until
+it is. This is called only in UTF-32 mode - we don't put a test within the
+macro because almost all calls are already within a block of UTF-32 only
+code.
+
+These are all no-ops since all UTF-32 characters fit into one pcre_uchar. */
+
+#define BACKCHAR(eptr) do { } while (0)
+
+/* Same as above, just in the other direction. */
+
+#define FORWARDCHAR(eptr) do { } while (0)
+#define FORWARDCHARTEST(eptr,end) do { } while (0)
+
+/* Same as above, but it allows a fully customizable form. */
+
+#define ACROSSCHAR(condition, eptr, action) do { } while (0)
+
+/* Deposit a character into memory, returning the number of code units. */
+
+#define PUTCHAR(c, p) (*p = c, 1)
+
+#endif /* UTF-32 character handling */
+#endif /* SUPPORT_UNICODE */
+
+
+/* Mode-dependent macros that have the same definition in all modes. */
+
+#define CU2BYTES(x) ((x)*((PCRE2_CODE_UNIT_WIDTH/8)))
+#define BYTES2CU(x) ((x)/((PCRE2_CODE_UNIT_WIDTH/8)))
+#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE
+#define PUT2INC(a,n,d) PUT2(a,n,d), a += IMM2_SIZE
+
+
+/* ----------------------- HIDDEN STRUCTURES ----------------------------- */
+
+/* NOTE: All these structures *must* start with a pcre2_memctl structure. The
+code that uses them is simpler because it assumes this. */
+
+/* The real general context structure. At present it holds only data for custom
+memory control. */
+
+typedef struct pcre2_real_general_context {
+ pcre2_memctl memctl;
+} pcre2_real_general_context;
+
+/* The real compile context structure */
+
+typedef struct pcre2_real_compile_context {
+ pcre2_memctl memctl;
+ int (*stack_guard)(uint32_t, void *);
+ void *stack_guard_data;
+ const uint8_t *tables;
+ PCRE2_SIZE max_pattern_length;
+ uint16_t bsr_convention;
+ uint16_t newline_convention;
+ uint32_t parens_nest_limit;
+} pcre2_real_compile_context;
+
+/* The real match context structure. */
+
+typedef struct pcre2_real_match_context {
+ pcre2_memctl memctl;
+#ifdef HEAP_MATCH_RECURSE
+ pcre2_memctl stack_memctl;
+#endif
+#ifdef SUPPORT_JIT
+ pcre2_jit_callback jit_callback;
+ void *jit_callback_data;
+#endif
+ int (*callout)(pcre2_callout_block *, void *);
+ void *callout_data;
+ PCRE2_SIZE offset_limit;
+ uint32_t match_limit;
+ uint32_t recursion_limit;
+} pcre2_real_match_context;
+
+/* The real compiled code structure. The type for the blocksize field is
+defined specially because it is required in pcre2_serialize_decode() when
+copying the size from possibly unaligned memory into a variable of the same
+type. Use a macro rather than a typedef to avoid compiler warnings when this
+file is included multiple times by pcre2test. LOOKBEHIND_MAX specifies the
+largest lookbehind that is supported. (OP_REVERSE in a pattern has a 16-bit
+argument in 8-bit and 16-bit modes, so we need no more than a 16-bit field
+here.) */
+
+#undef CODE_BLOCKSIZE_TYPE
+#define CODE_BLOCKSIZE_TYPE size_t
+
+#undef LOOKBEHIND_MAX
+#define LOOKBEHIND_MAX UINT16_MAX
+
+typedef struct pcre2_real_code {
+ pcre2_memctl memctl; /* Memory control fields */
+ const uint8_t *tables; /* The character tables */
+ void *executable_jit; /* Pointer to JIT code */
+ uint8_t start_bitmap[32]; /* Bitmap for starting code unit < 256 */
+ CODE_BLOCKSIZE_TYPE blocksize; /* Total (bytes) that was malloc-ed */
+ uint32_t magic_number; /* Paranoid and endianness check */
+ uint32_t compile_options; /* Options passed to pcre2_compile() */
+ uint32_t overall_options; /* Options after processing the pattern */
+ uint32_t flags; /* Various state flags */
+ uint32_t limit_match; /* Limit set in the pattern */
+ uint32_t limit_recursion; /* Limit set in the pattern */
+ uint32_t first_codeunit; /* Starting code unit */
+ uint32_t last_codeunit; /* This codeunit must be seen */
+ uint16_t bsr_convention; /* What \R matches */
+ uint16_t newline_convention; /* What is a newline? */
+ uint16_t max_lookbehind; /* Longest lookbehind (characters) */
+ uint16_t minlength; /* Minimum length of match */
+ uint16_t top_bracket; /* Highest numbered group */
+ uint16_t top_backref; /* Highest numbered back reference */
+ uint16_t name_entry_size; /* Size (code units) of table entries */
+ uint16_t name_count; /* Number of name entries in the table */
+} pcre2_real_code;
+
+/* The real match data structure. */
+
+typedef struct pcre2_real_match_data {
+ pcre2_memctl memctl;
+ const pcre2_real_code *code; /* The pattern used for the match */
+ PCRE2_SPTR subject; /* The subject that was matched */
+ PCRE2_SPTR mark; /* Pointer to last mark */
+ PCRE2_SIZE leftchar; /* Offset to leftmost code unit */
+ PCRE2_SIZE rightchar; /* Offset to rightmost code unit */
+ PCRE2_SIZE startchar; /* Offset to starting code unit */
+ uint16_t matchedby; /* Type of match (normal, JIT, DFA) */
+ uint16_t oveccount; /* Number of pairs */
+ int rc; /* The return code from the match */
+ PCRE2_SIZE ovector[1]; /* The first field */
+} pcre2_real_match_data;
+
+
+/* ----------------------- PRIVATE STRUCTURES ----------------------------- */
+
+/* These structures are not needed for pcre2test. */
+
+#ifndef PCRE2_PCRE2TEST
+
+/* Structure for checking for mutual recursion when scanning compiled code. */
+
+typedef struct recurse_check {
+ struct recurse_check *prev;
+ PCRE2_SPTR group;
+} recurse_check;
+
+/* Structure for building a cache when filling in recursion offsets. */
+
+typedef struct recurse_cache {
+ PCRE2_SPTR group;
+ int recno;
+} recurse_cache;
+
+/* Structure for maintaining a chain of pointers to the currently incomplete
+branches, for testing for left recursion while compiling. */
+
+typedef struct branch_chain {
+ struct branch_chain *outer;
+ PCRE2_UCHAR *current_branch;
+} branch_chain;
+
+/* Structure for building a list of named groups during the first pass of
+compiling. */
+
+typedef struct named_group {
+ PCRE2_SPTR name; /* Points to the name in the pattern */
+ uint32_t number; /* Group number */
+ uint16_t length; /* Length of the name */
+ uint16_t isdup; /* TRUE if a duplicate */
+} named_group;
+
+/* Structure for passing "static" information around between the functions
+doing the compiling, so that they are thread-safe. */
+
+typedef struct compile_block {
+ pcre2_real_compile_context *cx; /* Points to the compile context */
+ const uint8_t *lcc; /* Points to lower casing table */
+ const uint8_t *fcc; /* Points to case-flipping table */
+ const uint8_t *cbits; /* Points to character type table */
+ const uint8_t *ctypes; /* Points to table of type maps */
+ PCRE2_SPTR start_workspace; /* The start of working space */
+ PCRE2_SPTR start_code; /* The start of the compiled code */
+ PCRE2_SPTR start_pattern; /* The start of the pattern */
+ PCRE2_SPTR end_pattern; /* The end of the pattern */
+ PCRE2_SPTR nestptr[2]; /* Pointer(s) saved for string substitution */
+ PCRE2_UCHAR *name_table; /* The name/number table */
+ size_t workspace_size; /* Size of workspace */
+ uint16_t names_found; /* Number of entries so far */
+ uint16_t name_entry_size; /* Size of each entry */
+ open_capitem *open_caps; /* Chain of open capture items */
+ named_group *named_groups; /* Points to vector in pre-compile */
+ uint32_t named_group_list_size; /* Number of entries in the list */
+ uint32_t external_options; /* External (initial) options */
+ uint32_t external_flags; /* External flag bits to be set */
+ uint32_t bracount; /* Count of capturing parens as we compile */
+ uint32_t final_bracount; /* Saved value after first pass */
+ uint32_t *groupinfo; /* Group info vector */
+ uint32_t top_backref; /* Maximum back reference */
+ uint32_t backref_map; /* Bitmap of low back refs */
+ uint32_t nltype; /* Newline type */
+ uint32_t nllen; /* Newline string length */
+ PCRE2_UCHAR nl[4]; /* Newline string when fixed length */
+ int max_lookbehind; /* Maximum lookbehind (characters) */
+ int parens_depth; /* Depth of nested parentheses */
+ int assert_depth; /* Depth of nested assertions */
+ int req_varyopt; /* "After variable item" flag for reqbyte */
+ BOOL had_accept; /* (*ACCEPT) encountered */
+ BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */
+ BOOL had_recurse; /* Had a recursion or subroutine call */
+ BOOL check_lookbehind; /* Lookbehinds need later checking */
+ BOOL dupnames; /* Duplicate names exist */
+ BOOL iscondassert; /* Next assert is a condition */
+} compile_block;
+
+/* Structure for keeping the properties of the in-memory stack used
+by the JIT matcher. */
+
+typedef struct pcre2_real_jit_stack {
+ pcre2_memctl memctl;
+ void* stack;
+} pcre2_real_jit_stack;
+
+/* Structure for keeping a chain of heap blocks used for saving ovectors
+during pattern recursion when the ovector is larger than can be saved on
+the system stack. */
+
+typedef struct ovecsave_frame {
+ struct ovecsave_frame *next; /* Next frame on free chain */
+ PCRE2_SIZE saved_ovec[1]; /* First vector element */
+} ovecsave_frame;
+
+/* Structure for items in a linked list that represents an explicit recursive
+call within the pattern; used by pcre_match(). */
+
+typedef struct recursion_info {
+ struct recursion_info *prevrec; /* Previous recursion record (or NULL) */
+ unsigned int group_num; /* Number of group that was called */
+ PCRE2_SIZE *ovec_save; /* Pointer to saved ovector frame */
+ uint32_t saved_capture_last; /* Last capture number */
+ PCRE2_SPTR subject_position; /* Position at start of recursion */
+} recursion_info;
+
+/* A similar structure for pcre_dfa_match(). */
+
+typedef struct dfa_recursion_info {
+ struct dfa_recursion_info *prevrec;
+ PCRE2_SPTR subject_position;
+ uint32_t group_num;
+} dfa_recursion_info;
+
+/* Structure for building a chain of data for holding the values of the subject
+pointer at the start of each subpattern, so as to detect when an empty string
+has been matched by a subpattern - to break infinite loops; used by
+pcre2_match(). */
+
+typedef struct eptrblock {
+ struct eptrblock *epb_prev;
+ PCRE2_SPTR epb_saved_eptr;
+} eptrblock;
+
+/* Structure for passing "static" information around between the functions
+doing traditional NFA matching (pcre2_match() and friends). */
+
+typedef struct match_block {
+ pcre2_memctl memctl; /* For general use */
+#ifdef HEAP_MATCH_RECURSE
+ pcre2_memctl stack_memctl; /* For "stack" frames */
+#endif
+ uint32_t match_call_count; /* As it says */
+ uint32_t match_limit; /* As it says */
+ uint32_t match_limit_recursion; /* As it says */
+ BOOL hitend; /* Hit the end of the subject at some point */
+ BOOL hasthen; /* Pattern contains (*THEN) */
+ const uint8_t *lcc; /* Points to lower casing table */
+ const uint8_t *fcc; /* Points to case-flipping table */
+ const uint8_t *ctypes; /* Points to table of type maps */
+ PCRE2_SIZE *ovector; /* Pointer to the offset vector */
+ PCRE2_SIZE offset_end; /* One past the end */
+ PCRE2_SIZE offset_max; /* The maximum usable for return data */
+ PCRE2_SIZE start_offset; /* The start offset value */
+ PCRE2_SIZE end_offset_top; /* Highwater mark at end of match */
+ uint16_t partial; /* PARTIAL options */
+ uint16_t bsr_convention; /* \R interpretation */
+ uint16_t name_count; /* Number of names in name table */
+ uint16_t name_entry_size; /* Size of entry in names table */
+ PCRE2_SPTR name_table; /* Table of group names */
+ PCRE2_SPTR start_code; /* For use when recursing */
+ PCRE2_SPTR start_subject; /* Start of the subject string */
+ PCRE2_SPTR end_subject; /* End of the subject string */
+ PCRE2_SPTR start_match_ptr; /* Start of matched string */
+ PCRE2_SPTR end_match_ptr; /* Subject position at end match */
+ PCRE2_SPTR start_used_ptr; /* Earliest consulted character */
+ PCRE2_SPTR last_used_ptr; /* Latest consulted character */
+ PCRE2_SPTR mark; /* Mark pointer to pass back on success */
+ PCRE2_SPTR nomatch_mark; /* Mark pointer to pass back on failure */
+ PCRE2_SPTR once_target; /* Where to back up to for atomic groups */
+ uint32_t moptions; /* Match options */
+ uint32_t poptions; /* Pattern options */
+ uint32_t capture_last; /* Most recent capture number + overflow flag */
+ uint32_t skip_arg_count; /* For counting SKIP_ARGs */
+ uint32_t ignore_skip_arg; /* For re-run when SKIP arg name not found */
+ uint32_t match_function_type; /* Set for certain special calls of match() */
+ uint32_t nltype; /* Newline type */
+ uint32_t nllen; /* Newline string length */
+ PCRE2_UCHAR nl[4]; /* Newline string when fixed */
+ eptrblock *eptrchain; /* Chain of eptrblocks for tail recursions */
+ recursion_info *recursive; /* Linked list of recursion data */
+ ovecsave_frame *ovecsave_chain; /* Linked list of free ovecsave blocks */
+ void *callout_data; /* To pass back to callouts */
+ int (*callout)(pcre2_callout_block *,void *); /* Callout function or NULL */
+#ifdef HEAP_MATCH_RECURSE
+ void *match_frames_base; /* For remembering malloc'd frames */
+#endif
+} match_block;
+
+/* A similar structure is used for the same purpose by the DFA matching
+functions. */
+
+typedef struct dfa_match_block {
+ pcre2_memctl memctl; /* For general use */
+ PCRE2_SPTR start_code; /* Start of the compiled pattern */
+ PCRE2_SPTR start_subject ; /* Start of the subject string */
+ PCRE2_SPTR end_subject; /* End of subject string */
+ PCRE2_SPTR start_used_ptr; /* Earliest consulted character */
+ PCRE2_SPTR last_used_ptr; /* Latest consulted character */
+ const uint8_t *tables; /* Character tables */
+ PCRE2_SIZE start_offset; /* The start offset value */
+ uint32_t moptions; /* Match options */
+ uint32_t poptions; /* Pattern options */
+ uint32_t nltype; /* Newline type */
+ uint32_t nllen; /* Newline string length */
+ PCRE2_UCHAR nl[4]; /* Newline string when fixed */
+ uint16_t bsr_convention; /* \R interpretation */
+ void *callout_data; /* To pass back to callouts */
+ int (*callout)(pcre2_callout_block *,void *); /* Callout function or NULL */
+ dfa_recursion_info *recursive; /* Linked list of recursion data */
+} dfa_match_block;
+
+#endif /* PCRE2_PCRE2TEST */
+
+/* End of pcre2_intmodedep.h */
diff --git a/src/3rdparty/pcre/pcre_jit_compile.c b/src/3rdparty/pcre2/src/pcre2_jit_compile.c
index 4f15a27ac2..8dea90a1c5 100644
--- a/src/3rdparty/pcre/pcre_jit_compile.c
+++ b/src/3rdparty/pcre2/src/pcre2_jit_compile.c
@@ -6,10 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2013 University of Cambridge
-
- The machine code generator part (this module) was written by Zoltan Herczeg
- Copyright (c) 2010-2013
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -44,20 +42,38 @@ POSSIBILITY OF SUCH DAMAGE.
#include "config.h"
#endif
-#include "pcre_internal.h"
+#include "pcre2_internal.h"
-#if defined SUPPORT_JIT
+#ifdef SUPPORT_JIT
/* All-in-one: Since we use the JIT compiler only from here,
we just include it. This way we don't need to touch the build
system files. */
-#define SLJIT_MALLOC(size, allocator_data) (PUBL(malloc))(size)
-#define SLJIT_FREE(ptr, allocator_data) (PUBL(free))(ptr)
#define SLJIT_CONFIG_AUTO 1
#define SLJIT_CONFIG_STATIC 1
#define SLJIT_VERBOSE 0
+
+#ifdef PCRE2_DEBUG
+#define SLJIT_DEBUG 1
+#else
#define SLJIT_DEBUG 0
+#endif
+
+#define SLJIT_MALLOC(size, allocator_data) pcre2_jit_malloc(size, allocator_data)
+#define SLJIT_FREE(ptr, allocator_data) pcre2_jit_free(ptr, allocator_data)
+
+static void * pcre2_jit_malloc(size_t size, void *allocator_data)
+{
+pcre2_memctl *allocator = ((pcre2_memctl*)allocator_data);
+return allocator->malloc(size, allocator->memory_data);
+}
+
+static void pcre2_jit_free(void *ptr, void *allocator_data)
+{
+pcre2_memctl *allocator = ((pcre2_memctl*)allocator_data);
+allocator->free(ptr, allocator->memory_data);
+}
#include "sljit/sljitLir.c"
@@ -160,29 +176,27 @@ Thus we can restore the private data to a particular point in the stack.
typedef struct jit_arguments {
/* Pointers first. */
struct sljit_stack *stack;
- const pcre_uchar *str;
- const pcre_uchar *begin;
- const pcre_uchar *end;
- int *offsets;
- pcre_uchar *uchar_ptr;
- pcre_uchar *mark_ptr;
+ PCRE2_SPTR str;
+ PCRE2_SPTR begin;
+ PCRE2_SPTR end;
+ pcre2_match_data *match_data;
+ PCRE2_SPTR startchar_ptr;
+ PCRE2_UCHAR *mark_ptr;
+ int (*callout)(pcre2_callout_block *, void *);
void *callout_data;
/* Everything else after. */
+ sljit_uw offset_limit;
sljit_u32 limit_match;
- int real_offset_count;
- int offset_count;
- sljit_u8 notbol;
- sljit_u8 noteol;
- sljit_u8 notempty;
- sljit_u8 notempty_atstart;
+ sljit_u32 oveccount;
+ sljit_u32 options;
} jit_arguments;
+#define JIT_NUMBER_OF_COMPILE_MODES 3
+
typedef struct executable_functions {
void *executable_funcs[JIT_NUMBER_OF_COMPILE_MODES];
void *read_only_data_heads[JIT_NUMBER_OF_COMPILE_MODES];
sljit_uw executable_sizes[JIT_NUMBER_OF_COMPILE_MODES];
- PUBL(jit_callback) callback;
- void *userdata;
sljit_u32 top_bracket;
sljit_u32 limit_match;
} executable_functions;
@@ -228,7 +242,7 @@ typedef struct backtrack_common {
struct backtrack_common *top;
jump_list *topbacktracks;
/* Opcode pointer. */
- pcre_uchar *cc;
+ PCRE2_SPTR cc;
} backtrack_common;
typedef struct assert_backtrack {
@@ -285,7 +299,7 @@ typedef struct char_iterator_backtrack {
jump_list *backtracks;
struct {
unsigned int othercasebit;
- pcre_uchar chr;
+ PCRE2_UCHAR chr;
BOOL enabled;
} charpos;
} u;
@@ -333,7 +347,7 @@ typedef struct compiler_common {
/* The sljit ceneric compiler. */
struct sljit_compiler *compiler;
/* First byte code. */
- pcre_uchar *start;
+ PCRE2_SPTR start;
/* Maps private data offset to each opcode. */
sljit_s32 *private_data_ptrs;
/* Chain list of read-only data ptrs. */
@@ -368,7 +382,7 @@ typedef struct compiler_common {
/* Points to the last matched capture block index. */
sljit_s32 capture_last_ptr;
/* Fast forward skipping byte code pointer. */
- pcre_uchar *fast_forward_bc_ptr;
+ PCRE2_SPTR fast_forward_bc_ptr;
/* Locals used by fast fail optimization. */
sljit_s32 fast_fail_start_ptr;
sljit_s32 fast_fail_end_ptr;
@@ -376,7 +390,7 @@ typedef struct compiler_common {
/* Flipped and lower case tables. */
const sljit_u8 *fcc;
sljit_sw lcc;
- /* Mode can be PCRE_STUDY_JIT_COMPILE and others. */
+ /* Mode can be PCRE2_JIT_COMPLETE and others. */
int mode;
/* TRUE, when minlength is greater than 0. */
BOOL might_be_empty;
@@ -405,7 +419,7 @@ typedef struct compiler_common {
/* Tables. */
sljit_sw ctypes;
/* Named capturing brackets. */
- pcre_uchar *name_table;
+ PCRE2_SPTR name_table;
sljit_sw name_count;
sljit_sw name_entry_size;
@@ -434,19 +448,18 @@ typedef struct compiler_common {
jump_list *casefulcmp;
jump_list *caselesscmp;
jump_list *reset_match;
- BOOL jscript_compat;
-#ifdef SUPPORT_UTF
+ BOOL unset_backref;
+ BOOL alt_circumflex;
+#ifdef SUPPORT_UNICODE
BOOL utf;
-#ifdef SUPPORT_UCP
BOOL use_ucp;
jump_list *getucd;
-#endif
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
jump_list *utfreadchar;
jump_list *utfreadchar16;
jump_list *utfreadtype8;
#endif
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
} compiler_common;
/* For byte_sequence_compare. */
@@ -459,24 +472,24 @@ typedef struct compare_context {
union {
sljit_s32 asint;
sljit_u16 asushort;
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
sljit_u8 asbyte;
sljit_u8 asuchars[4];
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
sljit_u16 asuchars[2];
-#elif defined COMPILE_PCRE32
+#elif PCRE2_CODE_UNIT_WIDTH == 32
sljit_u32 asuchars[1];
#endif
} c;
union {
sljit_s32 asint;
sljit_u16 asushort;
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
sljit_u8 asbyte;
sljit_u8 asuchars[4];
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
sljit_u16 asuchars[2];
-#elif defined COMPILE_PCRE32
+#elif PCRE2_CODE_UNIT_WIDTH == 32
sljit_u32 asuchars[1];
#endif
} oc;
@@ -518,15 +531,20 @@ the start pointers when the end of the capturing group has not yet reached. */
#define OVECTOR_PRIV(i) (common->cbra_ptr + (i) * (sljit_sw)sizeof(sljit_sw))
#define PRIVATE_DATA(cc) (common->private_data_ptrs[(cc) - common->start])
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
#define MOV_UCHAR SLJIT_MOV_U8
#define MOVU_UCHAR SLJIT_MOVU_U8
-#elif defined COMPILE_PCRE16
+#define IN_UCHARS(x) (x)
+#elif PCRE2_CODE_UNIT_WIDTH == 16
#define MOV_UCHAR SLJIT_MOV_U16
#define MOVU_UCHAR SLJIT_MOVU_U16
-#elif defined COMPILE_PCRE32
+#define UCHAR_SHIFT (1)
+#define IN_UCHARS(x) ((x) * 2)
+#elif PCRE2_CODE_UNIT_WIDTH == 32
#define MOV_UCHAR SLJIT_MOV_U32
#define MOVU_UCHAR SLJIT_MOVU_U32
+#define UCHAR_SHIFT (2)
+#define IN_UCHARS(x) ((x) * 4)
#else
#error Unsupported compiling mode
#endif
@@ -559,7 +577,7 @@ the start pointers when the end of the capturing group has not yet reached. */
#define READ_CHAR_MAX 0x7fffffff
-static pcre_uchar *bracketend(pcre_uchar *cc)
+static PCRE2_SPTR bracketend(PCRE2_SPTR cc)
{
SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND));
do cc += GET(cc, 1); while (*cc == OP_ALT);
@@ -568,7 +586,7 @@ cc += 1 + LINK_SIZE;
return cc;
}
-static int no_alternatives(pcre_uchar *cc)
+static int no_alternatives(PCRE2_SPTR cc)
{
int count = 0;
SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND));
@@ -594,7 +612,7 @@ return count;
compile_backtrackingpath
*/
-static pcre_uchar *next_opcode(compiler_common *common, pcre_uchar *cc)
+static PCRE2_SPTR next_opcode(compiler_common *common, PCRE2_SPTR cc)
{
SLJIT_UNUSED_ARG(common);
switch(*cc)
@@ -672,7 +690,8 @@ switch(*cc)
case OP_DNCREF:
case OP_RREF:
case OP_DNRREF:
- case OP_DEF:
+ case OP_FALSE:
+ case OP_TRUE:
case OP_BRAZERO:
case OP_BRAMINZERO:
case OP_BRAPOSZERO:
@@ -744,7 +763,7 @@ switch(*cc)
case OP_NOTPOSQUERYI:
case OP_NOTPOSUPTOI:
cc += PRIV(OP_lengths)[*cc];
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
return cc;
@@ -766,12 +785,15 @@ switch(*cc)
return cc + PRIV(OP_lengths)[*cc] - 1;
case OP_ANYBYTE:
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf) return NULL;
#endif
return cc + 1;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+ case OP_CALLOUT_STR:
+ return cc + GET(cc, 1 + 2*LINK_SIZE);
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
case OP_XCLASS:
return cc + GET(cc, 1);
#endif
@@ -789,11 +811,11 @@ switch(*cc)
}
}
-static BOOL check_opcode_types(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend)
+static BOOL check_opcode_types(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend)
{
int count;
-pcre_uchar *slot;
-pcre_uchar *assert_back_end = cc - 1;
+PCRE2_SPTR slot;
+PCRE2_SPTR assert_back_end = cc - 1;
/* Calculate important variables (like stack size) and checks whether all opcodes are supported. */
while (cc < ccend)
@@ -822,7 +844,7 @@ while (cc < ccend)
case OP_SCOND:
/* Only AUTO_CALLOUT can insert this opcode. We do
not intend to support this case. */
- if (cc[1 + LINK_SIZE] == OP_CALLOUT)
+ if (cc[1 + LINK_SIZE] == OP_CALLOUT || cc[1 + LINK_SIZE] == OP_CALLOUT_STR)
return FALSE;
cc += 1 + LINK_SIZE;
break;
@@ -856,12 +878,13 @@ while (cc < ccend)
break;
case OP_CALLOUT:
+ case OP_CALLOUT_STR:
if (common->capture_last_ptr == 0)
{
common->capture_last_ptr = common->ovector_start;
common->ovector_start += sizeof(sljit_sw);
}
- cc += 2 + 2 * LINK_SIZE;
+ cc += (*cc == OP_CALLOUT) ? PRIV(OP_lengths)[OP_CALLOUT] : GET(cc, 1 + 2*LINK_SIZE);
break;
case OP_ASSERTBACK:
@@ -916,7 +939,7 @@ while (cc < ccend)
return TRUE;
}
-static BOOL is_accelerated_repeat(pcre_uchar *cc)
+static BOOL is_accelerated_repeat(PCRE2_SPTR cc)
{
switch(*cc)
{
@@ -959,11 +982,11 @@ switch(*cc)
case OP_CLASS:
case OP_NCLASS:
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
case OP_XCLASS:
- cc += (*cc == OP_XCLASS) ? GET(cc, 1) : (int)(1 + (32 / sizeof(pcre_uchar)));
+ cc += (*cc == OP_XCLASS) ? GET(cc, 1) : (int)(1 + (32 / sizeof(PCRE2_UCHAR)));
#else
- cc += (1 + (32 / sizeof(pcre_uchar)));
+ cc += (1 + (32 / sizeof(PCRE2_UCHAR)));
#endif
switch(*cc)
@@ -983,8 +1006,8 @@ return FALSE;
static SLJIT_INLINE BOOL detect_fast_forward_skip(compiler_common *common, int *private_data_start)
{
-pcre_uchar *cc = common->start;
-pcre_uchar *end;
+PCRE2_SPTR cc = common->start;
+PCRE2_SPTR end;
/* Skip not repeated brackets. */
while (TRUE)
@@ -1032,9 +1055,9 @@ if (is_accelerated_repeat(cc))
return FALSE;
}
-static SLJIT_INLINE void detect_fast_fail(compiler_common *common, pcre_uchar *cc, int *private_data_start, sljit_s32 depth)
+static SLJIT_INLINE void detect_fast_fail(compiler_common *common, PCRE2_SPTR cc, int *private_data_start, sljit_s32 depth)
{
- pcre_uchar *next_alt;
+ PCRE2_SPTR next_alt;
SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA);
@@ -1095,7 +1118,7 @@ static SLJIT_INLINE void detect_fast_fail(compiler_common *common, pcre_uchar *c
while (*cc == OP_ALT);
}
-static int get_class_iterator_size(pcre_uchar *cc)
+static int get_class_iterator_size(PCRE2_SPTR cc)
{
sljit_u32 min;
sljit_u32 max;
@@ -1127,15 +1150,15 @@ switch(*cc)
}
}
-static BOOL detect_repeat(compiler_common *common, pcre_uchar *begin)
+static BOOL detect_repeat(compiler_common *common, PCRE2_SPTR begin)
{
-pcre_uchar *end = bracketend(begin);
-pcre_uchar *next;
-pcre_uchar *next_end;
-pcre_uchar *max_end;
-pcre_uchar type;
+PCRE2_SPTR end = bracketend(begin);
+PCRE2_SPTR next;
+PCRE2_SPTR next_end;
+PCRE2_SPTR max_end;
+PCRE2_UCHAR type;
sljit_sw length = end - begin;
-int min, max, i;
+sljit_s32 min, max, i;
/* Detect fixed iterations first. */
if (end[-(1 + LINK_SIZE)] != OP_KET)
@@ -1264,11 +1287,11 @@ return FALSE;
case OP_TYPEUPTO: \
case OP_TYPEMINUPTO:
-static void set_private_data_ptrs(compiler_common *common, int *private_data_start, pcre_uchar *ccend)
+static void set_private_data_ptrs(compiler_common *common, int *private_data_start, PCRE2_SPTR ccend)
{
-pcre_uchar *cc = common->start;
-pcre_uchar *alternative;
-pcre_uchar *end = NULL;
+PCRE2_SPTR cc = common->start;
+PCRE2_SPTR alternative;
+PCRE2_SPTR end = NULL;
int private_data_ptr = *private_data_start;
int space, size, bracketlen;
BOOL repeat_check = TRUE;
@@ -1394,10 +1417,10 @@ while (cc < ccend)
case OP_CLASS:
case OP_NCLASS:
space = get_class_iterator_size(cc + size);
- size = 1 + 32 / sizeof(pcre_uchar);
+ size = 1 + 32 / sizeof(PCRE2_UCHAR);
break;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
case OP_XCLASS:
space = get_class_iterator_size(cc + size);
size = GET(cc, 1);
@@ -1423,7 +1446,7 @@ while (cc < ccend)
if (size < 0)
{
cc += -size;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
}
@@ -1446,7 +1469,7 @@ while (cc < ccend)
}
/* Returns with a frame_types (always < 0) if no need for frame. */
-static int get_framesize(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, BOOL recursive, BOOL *needs_control_head)
+static int get_framesize(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, BOOL recursive, BOOL *needs_control_head)
{
int length = 0;
int possessive = 0;
@@ -1613,7 +1636,9 @@ while (cc < ccend)
case OP_CLASS:
case OP_NCLASS:
case OP_XCLASS:
+
case OP_CALLOUT:
+ case OP_CALLOUT_STR:
cc = next_opcode(common, cc);
SLJIT_ASSERT(cc != NULL);
@@ -1629,7 +1654,7 @@ if (length > 0)
return stack_restore ? no_frame : no_stack;
}
-static void init_frame(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, int stackpos, int stacktop, BOOL recursive)
+static void init_frame(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, int stackpos, int stacktop, BOOL recursive)
{
DEFINE_COMPILER;
BOOL setsom_found = recursive;
@@ -1751,11 +1776,11 @@ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, 0);
SLJIT_ASSERT(stackpos == STACK(stacktop));
}
-static SLJIT_INLINE int get_private_data_copy_length(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, BOOL needs_control_head)
+static SLJIT_INLINE int get_private_data_copy_length(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, BOOL needs_control_head)
{
int private_data_length = needs_control_head ? 3 : 2;
int size;
-pcre_uchar *alternative;
+PCRE2_SPTR alternative;
/* Calculate the sum of the private machine words. */
while (cc < ccend)
{
@@ -1812,7 +1837,7 @@ while (cc < ccend)
if (PRIVATE_DATA(cc))
private_data_length++;
cc += 2;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -1821,7 +1846,7 @@ while (cc < ccend)
if (PRIVATE_DATA(cc))
private_data_length += 2;
cc += 2;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -1830,7 +1855,7 @@ while (cc < ccend)
if (PRIVATE_DATA(cc))
private_data_length += 2;
cc += 2 + IMM2_SIZE;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -1855,11 +1880,11 @@ while (cc < ccend)
case OP_CLASS:
case OP_NCLASS:
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
case OP_XCLASS:
- size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(pcre_uchar);
+ size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR);
#else
- size = 1 + 32 / (int)sizeof(pcre_uchar);
+ size = 1 + 32 / (int)sizeof(PCRE2_UCHAR);
#endif
if (PRIVATE_DATA(cc))
private_data_length += get_class_iterator_size(cc + size);
@@ -1876,7 +1901,7 @@ SLJIT_ASSERT(cc == ccend);
return private_data_length;
}
-static void copy_private_data(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend,
+static void copy_private_data(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend,
BOOL save, int stackptr, int stacktop, BOOL needs_control_head)
{
DEFINE_COMPILER;
@@ -1885,7 +1910,7 @@ int count, size;
BOOL tmp1next = TRUE;
BOOL tmp1empty = TRUE;
BOOL tmp2empty = TRUE;
-pcre_uchar *alternative;
+PCRE2_SPTR alternative;
enum {
start,
loop,
@@ -2006,7 +2031,7 @@ do
srcw[0] = PRIVATE_DATA(cc);
}
cc += 2;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -2019,7 +2044,7 @@ do
srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
}
cc += 2;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -2032,7 +2057,7 @@ do
srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
}
cc += 2 + IMM2_SIZE;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -2068,11 +2093,11 @@ do
case OP_CLASS:
case OP_NCLASS:
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
case OP_XCLASS:
- size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(pcre_uchar);
+ size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR);
#else
- size = 1 + 32 / (int)sizeof(pcre_uchar);
+ size = 1 + 32 / (int)sizeof(PCRE2_UCHAR);
#endif
if (PRIVATE_DATA(cc))
switch(get_class_iterator_size(cc + size))
@@ -2198,9 +2223,9 @@ if (save)
SLJIT_ASSERT(cc == ccend && stackptr == stacktop && (save || (tmp1empty && tmp2empty)));
}
-static SLJIT_INLINE pcre_uchar *set_then_offsets(compiler_common *common, pcre_uchar *cc, sljit_u8 *current_offset)
+static SLJIT_INLINE PCRE2_SPTR set_then_offsets(compiler_common *common, PCRE2_SPTR cc, sljit_u8 *current_offset)
{
-pcre_uchar *end = bracketend(cc);
+PCRE2_SPTR end = bracketend(cc);
BOOL has_alternatives = cc[GET(cc, 1)] == OP_ALT;
/* Assert captures then. */
@@ -2361,25 +2386,11 @@ common->read_only_data_head = (void *)result;
return result + 1;
}
-static void free_read_only_data(void *current, void *allocator_data)
-{
-void *next;
-
-SLJIT_UNUSED_ARG(allocator_data);
-
-while (current != NULL)
- {
- next = *(void**)current;
- SLJIT_FREE(current, allocator_data);
- current = next;
- }
-}
-
static SLJIT_INLINE void reset_ovector(compiler_common *common, int length)
{
DEFINE_COMPILER;
struct sljit_label *loop;
-int i;
+sljit_s32 i;
/* At this point we can freely use all temporary registers. */
SLJIT_ASSERT(length > 1);
@@ -2448,7 +2459,7 @@ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, base));
}
-static sljit_sw SLJIT_CALL do_search_mark(sljit_sw *current, const pcre_uchar *skip_arg)
+static sljit_sw SLJIT_CALL do_search_mark(sljit_sw *current, PCRE2_SPTR skip_arg)
{
while (current != NULL)
{
@@ -2458,7 +2469,7 @@ while (current != NULL)
break;
case type_mark:
- if (STRCMP_UC_UC(skip_arg, (pcre_uchar *)current[-3]) == 0)
+ if (PRIV(strcmp)(skip_arg, (PCRE2_SPTR)current[-3]) == 0)
return current[-4];
break;
@@ -2476,34 +2487,39 @@ static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket)
{
DEFINE_COMPILER;
struct sljit_label *loop;
-struct sljit_jump *early_quit;
/* At this point we can freely use all registers. */
OP1(SLJIT_MOV, SLJIT_S2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(1), STR_PTR, 0);
OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
+OP1(SLJIT_MOV, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
if (common->mark_ptr != 0)
OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
-OP1(SLJIT_MOV_S32, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, offset_count));
+OP1(SLJIT_MOV_U32, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, oveccount));
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_S0, 0);
if (common->mark_ptr != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_R2, 0);
-OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, offsets), SLJIT_IMM, sizeof(int));
-OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, begin));
+OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, match_data),
+ SLJIT_IMM, SLJIT_OFFSETOF(pcre2_match_data, ovector) - sizeof(PCRE2_SIZE));
+
GET_LOCAL_BASE(SLJIT_S0, 0, OVECTOR_START);
-/* Unlikely, but possible */
-early_quit = CMP(SLJIT_EQUAL, SLJIT_R1, 0, SLJIT_IMM, 0);
+OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, begin));
+
loop = LABEL();
OP2(SLJIT_SUB, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_S0), 0, SLJIT_R0, 0);
OP2(SLJIT_ADD, SLJIT_S0, 0, SLJIT_S0, 0, SLJIT_IMM, sizeof(sljit_sw));
/* Copy the integer value to the output buffer */
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
-OP1(SLJIT_MOVU_S32, SLJIT_MEM1(SLJIT_R2), sizeof(int), SLJIT_S1, 0);
+SLJIT_ASSERT(sizeof(PCRE2_SIZE) == 4 || sizeof(PCRE2_SIZE) == 8);
+if (sizeof(PCRE2_SIZE) == 4)
+ OP1(SLJIT_MOVU_U32, SLJIT_MEM1(SLJIT_R2), sizeof(PCRE2_SIZE), SLJIT_S1, 0);
+else
+ OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_R2), sizeof(PCRE2_SIZE), SLJIT_S1, 0);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, loop);
-JUMPHERE(early_quit);
/* Calculate the return value, which is the maximum ovector value. */
if (topbracket > 1)
@@ -2525,41 +2541,35 @@ else
static SLJIT_INLINE void return_with_partial_match(compiler_common *common, struct sljit_label *quit)
{
DEFINE_COMPILER;
-struct sljit_jump *jump;
+sljit_s32 mov_opcode;
SLJIT_COMPILE_ASSERT(STR_END == SLJIT_S1, str_end_must_be_saved_reg2);
SLJIT_ASSERT(common->start_used_ptr != 0 && common->start_ptr != 0
- && (common->mode == JIT_PARTIAL_SOFT_COMPILE ? common->hit_start != 0 : common->hit_start == 0));
+ && (common->mode == PCRE2_JIT_PARTIAL_SOFT ? common->hit_start != 0 : common->hit_start == 0));
OP1(SLJIT_MOV, SLJIT_R1, 0, ARGUMENTS, 0);
-OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_PARTIAL);
-OP1(SLJIT_MOV_S32, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, real_offset_count));
-CMPTO(SLJIT_SIG_LESS, SLJIT_R2, 0, SLJIT_IMM, 2, quit);
+OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP),
+ common->mode == PCRE2_JIT_PARTIAL_SOFT ? common->hit_start : common->start_ptr);
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_PARTIAL);
/* Store match begin and end. */
OP1(SLJIT_MOV, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, begin));
-OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, offsets));
-
-jump = CMP(SLJIT_SIG_LESS, SLJIT_R2, 0, SLJIT_IMM, 3);
-OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mode == JIT_PARTIAL_HARD_COMPILE ? common->start_ptr : (common->hit_start + (int)sizeof(sljit_sw)), SLJIT_S0, 0);
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
-OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT);
-#endif
-OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R1), 2 * sizeof(int), SLJIT_R2, 0);
-JUMPHERE(jump);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_R2, 0);
+OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, match_data));
-OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mode == JIT_PARTIAL_HARD_COMPILE ? common->start_used_ptr : common->hit_start);
-OP2(SLJIT_SUB, SLJIT_S1, 0, STR_END, 0, SLJIT_S0, 0);
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
-OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT);
-#endif
-OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R1), sizeof(int), SLJIT_S1, 0);
+mov_opcode = (sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV;
OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_S0, 0);
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
-OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R2, 0);
+OP1(mov_opcode, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(pcre2_match_data, ovector), SLJIT_R2, 0);
+
+OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_S0, 0);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+OP2(SLJIT_ASHR, STR_END, 0, STR_END, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+OP1(mov_opcode, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(pcre2_match_data, ovector) + sizeof(PCRE2_SIZE), STR_END, 0);
JUMPTO(SLJIT_JUMP, quit);
}
@@ -2570,7 +2580,7 @@ static SLJIT_INLINE void check_start_used_ptr(compiler_common *common)
DEFINE_COMPILER;
struct sljit_jump *jump;
-if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
{
/* The value of -1 must be kept for start_used_ptr! */
OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, 1);
@@ -2580,7 +2590,7 @@ if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
JUMPHERE(jump);
}
-else if (common->mode == JIT_PARTIAL_HARD_COMPILE)
+else if (common->mode == PCRE2_JIT_PARTIAL_HARD)
{
jump = CMP(SLJIT_LESS_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
@@ -2588,24 +2598,20 @@ else if (common->mode == JIT_PARTIAL_HARD_COMPILE)
}
}
-static SLJIT_INLINE BOOL char_has_othercase(compiler_common *common, pcre_uchar *cc)
+static SLJIT_INLINE BOOL char_has_othercase(compiler_common *common, PCRE2_SPTR cc)
{
/* Detects if the character has an othercase. */
unsigned int c;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf)
{
GETCHAR(c, cc);
if (c > 127)
{
-#ifdef SUPPORT_UCP
return c != UCD_OTHERCASE(c);
-#else
- return FALSE;
-#endif
}
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
return common->fcc[c] != c;
#endif
}
@@ -2618,28 +2624,24 @@ return MAX_255(c) ? common->fcc[c] != c : FALSE;
static SLJIT_INLINE unsigned int char_othercase(compiler_common *common, unsigned int c)
{
/* Returns with the othercase. */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && c > 127)
{
-#ifdef SUPPORT_UCP
return UCD_OTHERCASE(c);
-#else
- return c;
-#endif
}
#endif
return TABLE_GET(c, common->fcc, c);
}
-static unsigned int char_get_othercase_bit(compiler_common *common, pcre_uchar *cc)
+static unsigned int char_get_othercase_bit(compiler_common *common, PCRE2_SPTR cc)
{
/* Detects if the character and its othercase has only 1 bit difference. */
unsigned int c, oc, bit;
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
int n;
#endif
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf)
{
GETCHAR(c, cc);
@@ -2647,11 +2649,7 @@ if (common->utf)
oc = common->fcc[c];
else
{
-#ifdef SUPPORT_UCP
oc = UCD_OTHERCASE(c);
-#else
- oc = c;
-#endif
}
}
else
@@ -2675,9 +2673,9 @@ if (c <= 127 && bit == 0x20)
if (!is_powerof2(bit))
return 0;
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && c > 127)
{
n = GET_EXTRALEN(*cc);
@@ -2688,12 +2686,12 @@ if (common->utf && c > 127)
}
return (n << 8) | bit;
}
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
return (0 << 8) | bit;
-#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && c > 65535)
{
if (bit >= (1 << 10))
@@ -2701,10 +2699,10 @@ if (common->utf && c > 65535)
else
return (bit < 256) ? ((2 << 8) | bit) : ((3 << 8) | (bit >> 8));
}
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
return (bit < 256) ? ((0 << 8) | bit) : ((1 << 8) | (bit >> 8));
-#endif /* COMPILE_PCRE[8|16|32] */
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
}
static void check_partial(compiler_common *common, BOOL force)
@@ -2713,17 +2711,17 @@ static void check_partial(compiler_common *common, BOOL force)
DEFINE_COMPILER;
struct sljit_jump *jump = NULL;
-SLJIT_ASSERT(!force || common->mode != JIT_COMPILE);
+SLJIT_ASSERT(!force || common->mode != PCRE2_JIT_COMPLETE);
-if (common->mode == JIT_COMPILE)
+if (common->mode == PCRE2_JIT_COMPLETE)
return;
if (!force)
jump = CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
-else if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
+else if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
jump = CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1);
-if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
else
{
@@ -2743,14 +2741,14 @@ static void check_str_end(compiler_common *common, jump_list **end_reached)
DEFINE_COMPILER;
struct sljit_jump *jump;
-if (common->mode == JIT_COMPILE)
+if (common->mode == PCRE2_JIT_COMPLETE)
{
add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
return;
}
jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
-if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
{
add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
@@ -2772,7 +2770,7 @@ static void detect_partial_match(compiler_common *common, jump_list **backtracks
DEFINE_COMPILER;
struct sljit_jump *jump;
-if (common->mode == JIT_COMPILE)
+if (common->mode == PCRE2_JIT_COMPLETE)
{
add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
return;
@@ -2781,7 +2779,7 @@ if (common->mode == JIT_COMPILE)
/* Partial matching mode. */
jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0));
-if (common->mode == JIT_PARTIAL_SOFT_COMPILE)
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
{
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
@@ -2801,14 +2799,14 @@ static void peek_char(compiler_common *common, sljit_u32 max)
/* Reads the character into TMP1, keeps STR_PTR.
Does not check STR_END. TMP2 Destroyed. */
DEFINE_COMPILER;
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_jump *jump;
#endif
SLJIT_UNUSED_ARG(max);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf)
{
if (max < 128) return;
@@ -2819,9 +2817,9 @@ if (common->utf)
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
JUMPHERE(jump);
}
-#endif /* SUPPORT_UTF && !COMPILE_PCRE32 */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
-#if defined SUPPORT_UTF && defined COMPILE_PCRE16
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
if (common->utf)
{
if (max < 0xd800) return;
@@ -2839,7 +2837,7 @@ if (common->utf)
#endif
}
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
static BOOL is_char7_bitset(const sljit_u8 *bitset, BOOL nclass)
{
@@ -2882,7 +2880,7 @@ if (full_read)
}
}
-#endif /* SUPPORT_UTF && COMPILE_PCRE8 */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
static void read_char_range(compiler_common *common, sljit_u32 min, sljit_u32 max, BOOL update_str_ptr)
{
@@ -2890,10 +2888,10 @@ static void read_char_range(compiler_common *common, sljit_u32 min, sljit_u32 ma
between min and max (c >= min && c <= max). Otherwise it returns with a value
outside the range. Does not check STR_END. */
DEFINE_COMPILER;
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_jump *jump;
#endif
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
struct sljit_jump *jump2;
#endif
@@ -2905,7 +2903,7 @@ SLJIT_ASSERT(min <= max);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf)
{
if (max < 128 && !update_str_ptr) return;
@@ -2980,7 +2978,7 @@ if (common->utf)
}
#endif
-#if defined SUPPORT_UTF && defined COMPILE_PCRE16
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
if (common->utf)
{
if (max >= 0x10000)
@@ -3021,10 +3019,10 @@ static void read_char8_type(compiler_common *common, BOOL update_str_ptr)
{
/* Reads the character type into TMP1, updates STR_PTR. Does not check STR_END. */
DEFINE_COMPILER;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
struct sljit_jump *jump;
#endif
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
struct sljit_jump *jump2;
#endif
@@ -3033,7 +3031,7 @@ SLJIT_UNUSED_ARG(update_str_ptr);
OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf)
{
/* This can be an extra read in some situations, but hopefully
@@ -3058,19 +3056,19 @@ if (common->utf)
JUMPHERE(jump);
return;
}
-#endif /* SUPPORT_UTF && COMPILE_PCRE8 */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
-#if !defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
/* The ctypes array contains only 256 values. */
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255);
#endif
OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
-#if !defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
JUMPHERE(jump);
#endif
-#if defined SUPPORT_UTF && defined COMPILE_PCRE16
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
if (common->utf && update_str_ptr)
{
/* Skip low surrogate if necessary. */
@@ -3079,15 +3077,15 @@ if (common->utf && update_str_ptr)
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
JUMPHERE(jump);
}
-#endif /* SUPPORT_UTF && COMPILE_PCRE16 */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16 */
}
static void skip_char_back(compiler_common *common)
{
/* Goes one character back. Affects STR_PTR and TMP1. Does not check begin. */
DEFINE_COMPILER;
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
-#if defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
struct sljit_label *label;
if (common->utf)
@@ -3099,7 +3097,7 @@ if (common->utf)
CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, label);
return;
}
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
if (common->utf)
{
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1));
@@ -3112,8 +3110,8 @@ if (common->utf)
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
return;
}
-#endif /* COMPILE_PCRE[8|16] */
-#endif /* SUPPORT_UTF && !COMPILE_PCRE32 */
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
}
@@ -3149,9 +3147,9 @@ else
}
}
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
static void do_utfreadchar(compiler_common *common)
{
/* Fast decoding a UTF-8 character. TMP1 contains the first byte
@@ -3272,11 +3270,7 @@ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
}
-#endif /* COMPILE_PCRE8 */
-
-#endif /* SUPPORT_UTF */
-
-#ifdef SUPPORT_UCP
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
/* UCD_BLOCK_SIZE must be 128 (see the assert below). */
#define UCD_BLOCK_MASK 127
@@ -3302,9 +3296,10 @@ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(
OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
}
-#endif
-static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common, BOOL hascrorlf)
+#endif /* SUPPORT_UNICODE */
+
+static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common, BOOL hascrorlf, sljit_u32 overall_options)
{
DEFINE_COMPILER;
struct sljit_label *mainloop;
@@ -3312,20 +3307,23 @@ struct sljit_label *newlinelabel = NULL;
struct sljit_jump *start;
struct sljit_jump *end = NULL;
struct sljit_jump *end2 = NULL;
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_jump *singlechar;
#endif
jump_list *newline = NULL;
BOOL newlinecheck = FALSE;
BOOL readuchar = FALSE;
-if (!(hascrorlf || (common->match_end_ptr != 0)) &&
- (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF || common->newline > 255))
+if (!(hascrorlf || (overall_options & PCRE2_FIRSTLINE) != 0)
+ && (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF || common->newline > 255))
newlinecheck = TRUE;
-if (common->match_end_ptr != 0)
+SLJIT_ASSERT(common->forced_quit_label == NULL);
+
+if ((overall_options & PCRE2_FIRSTLINE) != 0)
{
/* Search for the end of the first line. */
+ SLJIT_ASSERT(common->match_end_ptr != 0);
OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
if (common->nltype == NLTYPE_FIXED && common->newline > 255)
@@ -3356,6 +3354,31 @@ if (common->match_end_ptr != 0)
OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
}
+else if ((overall_options & PCRE2_USE_OFFSET_LIMIT) != 0)
+ {
+ /* Check whether offset limit is set and valid. */
+ SLJIT_ASSERT(common->match_end_ptr != 0);
+
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, offset_limit));
+ OP1(SLJIT_MOV, TMP2, 0, STR_END, 0);
+ end = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, (sljit_sw) PCRE2_UNSET);
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+#if PCRE2_CODE_UNIT_WIDTH == 16
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 2);
+#endif
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
+ OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+ end2 = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0);
+ OP1(SLJIT_MOV, TMP2, 0, STR_END, 0);
+ JUMPHERE(end2);
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+ add_jump(compiler, &common->forced_quit, CMP(SLJIT_LESS, TMP2, 0, STR_PTR, 0));
+ JUMPHERE(end);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, TMP2, 0);
+ }
start = JUMP(SLJIT_JUMP);
@@ -3367,7 +3390,7 @@ if (newlinecheck)
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff);
OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
@@ -3377,7 +3400,7 @@ if (newlinecheck)
mainloop = LABEL();
/* Increasing the STR_PTR here requires one less jump in the most common case. */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf) readuchar = TRUE;
#endif
if (newlinecheck) readuchar = TRUE;
@@ -3389,8 +3412,8 @@ if (newlinecheck)
CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, newlinelabel);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
-#if defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf)
{
singlechar = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
@@ -3398,7 +3421,7 @@ if (common->utf)
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
JUMPHERE(singlechar);
}
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
if (common->utf)
{
singlechar = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800);
@@ -3409,8 +3432,8 @@ if (common->utf)
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
JUMPHERE(singlechar);
}
-#endif /* COMPILE_PCRE[8|16] */
-#endif /* SUPPORT_UTF && !COMPILE_PCRE32 */
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
JUMPHERE(start);
if (newlinecheck)
@@ -3425,9 +3448,9 @@ return mainloop;
#define MAX_N_CHARS 16
#define MAX_DIFF_CHARS 6
-static SLJIT_INLINE void add_prefix_char(pcre_uchar chr, pcre_uchar *chars)
+static SLJIT_INLINE void add_prefix_char(PCRE2_UCHAR chr, PCRE2_UCHAR *chars)
{
-pcre_uchar i, len;
+PCRE2_UCHAR i, len;
len = chars[0];
if (len == 255)
@@ -3455,20 +3478,20 @@ chars[len] = chr;
chars[0] = len;
}
-static int scan_prefix(compiler_common *common, pcre_uchar *cc, pcre_uchar *chars, int max_chars, sljit_u32 *rec_count)
+static int scan_prefix(compiler_common *common, PCRE2_SPTR cc, PCRE2_UCHAR *chars, int max_chars, sljit_u32 *rec_count)
{
/* Recursive function, which scans prefix literals. */
BOOL last, any, class, caseless;
int len, repeat, len_save, consumed = 0;
sljit_u32 chr; /* Any unicode character. */
sljit_u8 *bytes, *bytes_end, byte;
-pcre_uchar *alternative, *cc_save, *oc;
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
-pcre_uchar othercase[8];
-#elif defined SUPPORT_UTF && defined COMPILE_PCRE16
-pcre_uchar othercase[2];
+PCRE2_SPTR alternative, cc_save, oc;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+PCRE2_UCHAR othercase[8];
+#elif defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
+PCRE2_UCHAR othercase[2];
#else
-pcre_uchar othercase[1];
+PCRE2_UCHAR othercase[1];
#endif
repeat = 1;
@@ -3541,7 +3564,7 @@ while (TRUE)
case OP_POSQUERY:
len = 1;
cc++;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc);
#endif
max_chars = scan_prefix(common, cc + len, chars, max_chars, rec_count);
@@ -3579,7 +3602,7 @@ while (TRUE)
continue;
case OP_CLASS:
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf && !is_char7_bitset((const sljit_u8 *)(cc + 1), FALSE))
return consumed;
#endif
@@ -3587,15 +3610,15 @@ while (TRUE)
break;
case OP_NCLASS:
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf) return consumed;
#endif
class = TRUE;
break;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
case OP_XCLASS:
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf) return consumed;
#endif
any = TRUE;
@@ -3604,7 +3627,7 @@ while (TRUE)
#endif
case OP_DIGIT:
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_digit, FALSE))
return consumed;
#endif
@@ -3613,7 +3636,7 @@ while (TRUE)
break;
case OP_WHITESPACE:
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_space, FALSE))
return consumed;
#endif
@@ -3622,7 +3645,7 @@ while (TRUE)
break;
case OP_WORDCHAR:
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_word, FALSE))
return consumed;
#endif
@@ -3639,17 +3662,17 @@ while (TRUE)
case OP_NOT_WORDCHAR:
case OP_ANY:
case OP_ALLANY:
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf) return consumed;
#endif
any = TRUE;
cc++;
break;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
case OP_NOTPROP:
case OP_PROP:
-#ifndef COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf) return consumed;
#endif
any = TRUE;
@@ -3664,7 +3687,7 @@ while (TRUE)
case OP_NOTEXACT:
case OP_NOTEXACTI:
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf) return consumed;
#endif
any = TRUE;
@@ -3696,7 +3719,7 @@ while (TRUE)
if (class)
{
bytes = (sljit_u8*) (cc + 1);
- cc += 1 + 32 / sizeof(pcre_uchar);
+ cc += 1 + 32 / sizeof(PCRE2_UCHAR);
switch (*cc)
{
@@ -3791,13 +3814,13 @@ while (TRUE)
}
len = 1;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc);
#endif
if (caseless && char_has_othercase(common, cc))
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf)
{
GETCHAR(chr, cc);
@@ -3855,16 +3878,16 @@ while (TRUE)
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
-static sljit_s32 character_to_int32(pcre_uchar chr)
+static sljit_s32 character_to_int32(PCRE2_UCHAR chr)
{
sljit_s32 value = (sljit_s32)chr;
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
#define SSE2_COMPARE_TYPE_INDEX 0
return (value << 24) | (value << 16) | (value << 8) | value;
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
#define SSE2_COMPARE_TYPE_INDEX 1
return (value << 16) | value;
-#elif defined COMPILE_PCRE32
+#elif PCRE2_CODE_UNIT_WIDTH == 32
#define SSE2_COMPARE_TYPE_INDEX 2
return value;
#else
@@ -3872,7 +3895,7 @@ return value;
#endif
}
-static SLJIT_INLINE void fast_forward_first_char2_sse2(compiler_common *common, pcre_uchar char1, pcre_uchar char2)
+static SLJIT_INLINE void fast_forward_first_char2_sse2(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
{
DEFINE_COMPILER;
struct sljit_label *start;
@@ -3883,7 +3906,7 @@ sljit_s32 tmp1_ind = sljit_get_register_index(TMP1);
sljit_s32 tmp2_ind = sljit_get_register_index(TMP2);
sljit_s32 str_ptr_ind = sljit_get_register_index(STR_PTR);
BOOL load_twice = FALSE;
-pcre_uchar bit;
+PCRE2_UCHAR bit;
bit = char1 ^ char2;
if (!is_powerof2(bit))
@@ -4004,12 +4027,12 @@ sljit_emit_op_custom(compiler, instruction, 4);
if (load_twice)
{
- OP1(SLJIT_MOV, TMP3, 0, TMP2, 0);
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP2, 0);
instruction[3] = 0xc0 | (tmp2_ind << 3) | 1;
sljit_emit_op_custom(compiler, instruction, 4);
OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
- OP1(SLJIT_MOV, TMP2, 0, TMP3, 0);
+ OP1(SLJIT_MOV, TMP2, 0, RETURN_ADDR, 0);
}
OP2(SLJIT_ASHR, TMP1, 0, TMP1, 0, TMP2, 0);
@@ -4134,14 +4157,14 @@ SET_LABEL(quit[2], start);
#endif
-static void fast_forward_first_char2(compiler_common *common, pcre_uchar char1, pcre_uchar char2, sljit_s32 offset)
+static void fast_forward_first_char2(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
{
DEFINE_COMPILER;
struct sljit_label *start;
struct sljit_jump *quit;
struct sljit_jump *found;
-pcre_uchar mask;
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+PCRE2_UCHAR mask;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_label *utf_start = NULL;
struct sljit_jump *utf_quit = NULL;
#endif
@@ -4169,7 +4192,7 @@ if (has_match_end)
}
}
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf && offset > 0)
utf_start = LABEL();
#endif
@@ -4182,25 +4205,25 @@ if (sljit_x86_is_sse2_available())
{
fast_forward_first_char2_sse2(common, char1, char2);
- SLJIT_ASSERT(common->mode == JIT_COMPILE || offset == 0);
- if (common->mode == JIT_COMPILE)
+ SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE || offset == 0);
+ if (common->mode == PCRE2_JIT_COMPLETE)
{
/* In complete mode, we don't need to run a match when STR_PTR == STR_END. */
SLJIT_ASSERT(common->forced_quit_label == NULL);
- OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH);
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
add_jump(compiler, &common->forced_quit, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf && offset > 0)
{
- SLJIT_ASSERT(common->mode == JIT_COMPILE);
+ SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset));
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, utf_start);
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, utf_start);
#else
@@ -4260,22 +4283,22 @@ else
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, start);
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf && offset > 0)
utf_quit = JUMP(SLJIT_JUMP);
#endif
JUMPHERE(found);
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf && offset > 0)
{
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset));
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, utf_start);
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, utf_start);
#else
@@ -4310,10 +4333,10 @@ struct sljit_jump *quit;
struct sljit_jump *match;
/* bytes[0] represent the number of characters between 0
and MAX_N_BYTES - 1, 255 represents any character. */
-pcre_uchar chars[MAX_N_CHARS * MAX_DIFF_CHARS];
+PCRE2_UCHAR chars[MAX_N_CHARS * MAX_DIFF_CHARS];
sljit_s32 offset;
-pcre_uchar mask;
-pcre_uchar *char_set, *char_set_end;
+PCRE2_UCHAR mask;
+PCRE2_UCHAR *char_set, *char_set_end;
int i, max, from;
int range_right = -1, range_len;
sljit_u8 *update_table = NULL;
@@ -4441,7 +4464,7 @@ OP1(SLJIT_MOV, RETURN_ADDR, 0, SLJIT_IMM, (sljit_sw)update_table);
start = LABEL();
quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
-#if defined COMPILE_PCRE8 || (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+#if PCRE2_CODE_UNIT_WIDTH == 8 || (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right));
#else
OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right + 1) - 1);
@@ -4479,7 +4502,7 @@ if (offset >= 0)
}
}
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf && offset != 0)
{
if (offset < 0)
@@ -4489,10 +4512,10 @@ if (common->utf && offset != 0)
}
else
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, start);
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00, start);
#else
@@ -4526,17 +4549,16 @@ return TRUE;
}
#undef MAX_N_CHARS
-#undef MAX_DIFF_CHARS
-static SLJIT_INLINE void fast_forward_first_char(compiler_common *common, pcre_uchar first_char, BOOL caseless)
+static SLJIT_INLINE void fast_forward_first_char(compiler_common *common, PCRE2_UCHAR first_char, BOOL caseless)
{
-pcre_uchar oc;
+PCRE2_UCHAR oc;
oc = first_char;
if (caseless)
{
oc = TABLE_GET(first_char, common->fcc, first_char);
-#if defined SUPPORT_UCP && !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
if (first_char > 127 && common->utf)
oc = UCD_OTHERCASE(first_char);
#endif
@@ -4573,7 +4595,7 @@ if (common->nltype == NLTYPE_FIXED && common->newline > 255)
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(2));
OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0);
OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_GREATER_EQUAL);
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
@@ -4618,7 +4640,7 @@ if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF)
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL);
OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
@@ -4641,7 +4663,7 @@ struct sljit_label *start;
struct sljit_jump *quit;
struct sljit_jump *found = NULL;
jump_list *matches = NULL;
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
struct sljit_jump *jump;
#endif
@@ -4654,14 +4676,14 @@ if (common->match_end_ptr != 0)
start = LABEL();
quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf)
OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
#endif
if (!check_class_ranges(common, start_bits, (start_bits[31] & 0x80) != 0, TRUE, &matches))
{
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 255);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 255);
JUMPHERE(jump);
@@ -4674,20 +4696,20 @@ if (!check_class_ranges(common, start_bits, (start_bits[31] & 0x80) != 0, TRUE,
found = JUMP(SLJIT_NOT_ZERO);
}
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf)
OP1(SLJIT_MOV, TMP1, 0, TMP3, 0);
#endif
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-#ifdef SUPPORT_UTF
-#if defined COMPILE_PCRE8
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf)
{
CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0, start);
OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
}
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
if (common->utf)
{
CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800, start);
@@ -4697,8 +4719,8 @@ if (common->utf)
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
}
-#endif /* COMPILE_PCRE[8|16] */
-#endif /* SUPPORT_UTF */
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
+#endif /* SUPPORT_UNICODE */
JUMPTO(SLJIT_JUMP, start);
if (found != NULL)
JUMPHERE(found);
@@ -4710,7 +4732,7 @@ if (common->match_end_ptr != 0)
OP1(SLJIT_MOV, STR_END, 0, RETURN_ADDR, 0);
}
-static SLJIT_INLINE struct sljit_jump *search_requested_char(compiler_common *common, pcre_uchar req_char, BOOL caseless, BOOL has_firstchar)
+static SLJIT_INLINE struct sljit_jump *search_requested_char(compiler_common *common, PCRE2_UCHAR req_char, BOOL caseless, BOOL has_firstchar)
{
DEFINE_COMPILER;
struct sljit_label *loop;
@@ -4723,7 +4745,7 @@ sljit_u32 oc, bit;
SLJIT_ASSERT(common->req_char_ptr != 0);
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr);
-OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, REQ_BYTE_MAX);
+OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, REQ_CU_MAX);
toolong = CMP(SLJIT_LESS, TMP1, 0, STR_END, 0);
alreadyfound = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0);
@@ -4740,7 +4762,7 @@ oc = req_char;
if (caseless)
{
oc = TABLE_GET(req_char, common->fcc, req_char);
-#if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
if (req_char > 127 && common->utf)
oc = UCD_OTHERCASE(req_char);
#endif
@@ -4813,7 +4835,7 @@ static void check_wordboundary(compiler_common *common)
DEFINE_COMPILER;
struct sljit_jump *skipread;
jump_list *skipread_list = NULL;
-#if !(defined COMPILE_PCRE8) || defined SUPPORT_UTF
+#if PCRE2_CODE_UNIT_WIDTH != 8 || defined SUPPORT_UNICODE
struct sljit_jump *jump;
#endif
@@ -4830,7 +4852,7 @@ check_start_used_ptr(common);
read_char(common);
/* Testing char type. */
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (common->use_ucp)
{
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
@@ -4848,24 +4870,24 @@ if (common->use_ucp)
else
#endif
{
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
-#elif defined SUPPORT_UTF
+#elif defined SUPPORT_UNICODE
/* Here LOCALS1 has already been zeroed. */
jump = NULL;
if (common->utf)
jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
-#endif /* COMPILE_PCRE8 */
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), common->ctypes);
OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 4 /* ctype_word */);
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0);
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
JUMPHERE(jump);
-#elif defined SUPPORT_UTF
+#elif defined SUPPORT_UNICODE
if (jump != NULL)
JUMPHERE(jump);
-#endif /* COMPILE_PCRE8 */
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
}
JUMPHERE(skipread);
@@ -4874,7 +4896,7 @@ check_str_end(common, &skipread_list);
peek_char(common, READ_CHAR_MAX);
/* Testing char type. This is a code duplication. */
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (common->use_ucp)
{
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
@@ -4891,11 +4913,11 @@ if (common->use_ucp)
else
#endif
{
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
/* TMP2 may be destroyed by peek_char. */
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
-#elif defined SUPPORT_UTF
+#elif defined SUPPORT_UNICODE
OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
jump = NULL;
if (common->utf)
@@ -4904,12 +4926,12 @@ else
OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), common->ctypes);
OP2(SLJIT_LSHR, TMP2, 0, TMP2, 0, SLJIT_IMM, 4 /* ctype_word */);
OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
JUMPHERE(jump);
-#elif defined SUPPORT_UTF
+#elif defined SUPPORT_UNICODE
if (jump != NULL)
JUMPHERE(jump);
-#endif /* COMPILE_PCRE8 */
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
}
set_jumps(skipread_list, LABEL());
@@ -5080,18 +5102,18 @@ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
-#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
-#ifdef COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf)
{
#endif
OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
}
#endif
-#endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */
+#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */
OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
}
@@ -5108,8 +5130,8 @@ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_EQUAL);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20);
OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0);
-#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
-#ifdef COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf)
{
#endif
@@ -5126,10 +5148,10 @@ if (common->utf)
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000);
OP_FLAGS(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000);
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
}
#endif
-#endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */
+#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */
OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
@@ -5146,18 +5168,18 @@ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
OP2(SLJIT_SUB | SLJIT_SET_U, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_UNUSED, 0, SLJIT_LESS_EQUAL);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
-#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
-#ifdef COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf)
{
#endif
OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
}
#endif
-#endif /* SUPPORT_UTF || COMPILE_PCRE16 || COMPILE_PCRE32 */
+#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */
OP_FLAGS(SLJIT_OR | SLJIT_SET_E, TMP2, 0, TMP2, 0, SLJIT_EQUAL);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
@@ -5214,16 +5236,16 @@ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
label = LABEL();
OP1(MOVU_UCHAR, CHAR1, 0, SLJIT_MEM1(TMP1), IN_UCHARS(1));
OP1(MOVU_UCHAR, CHAR2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
jump = CMP(SLJIT_GREATER, CHAR1, 0, SLJIT_IMM, 255);
#endif
OP1(SLJIT_MOV_U8, CHAR1, 0, SLJIT_MEM2(LCC_TABLE, CHAR1), 0);
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
JUMPHERE(jump);
jump = CMP(SLJIT_GREATER, CHAR2, 0, SLJIT_IMM, 255);
#endif
OP1(SLJIT_MOV_U8, CHAR2, 0, SLJIT_MEM2(LCC_TABLE, CHAR2), 0);
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
JUMPHERE(jump);
#endif
jump = CMP(SLJIT_NOT_EQUAL, CHAR1, 0, CHAR2, 0);
@@ -5242,21 +5264,21 @@ sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
#undef CHAR1
#undef CHAR2
-#if defined SUPPORT_UTF && defined SUPPORT_UCP
+#if defined SUPPORT_UNICODE
-static const pcre_uchar * SLJIT_CALL do_utf_caselesscmp(pcre_uchar *src1, jit_arguments *args, pcre_uchar *end1)
+static PCRE2_SPTR SLJIT_CALL do_utf_caselesscmp(PCRE2_SPTR src1, jit_arguments *args, PCRE2_SPTR end1)
{
/* This function would be ineffective to do in JIT level. */
sljit_u32 c1, c2;
-const pcre_uchar *src2 = args->uchar_ptr;
-const pcre_uchar *end2 = args->end;
+PCRE2_SPTR src2 = args->startchar_ptr;
+PCRE2_SPTR end2 = args->end;
const ucd_record *ur;
const sljit_u32 *pp;
while (src1 < end1)
{
if (src2 >= end2)
- return (pcre_uchar*)1;
+ return (PCRE2_SPTR)1;
GETCHARINC(c1, src1);
GETCHARINC(c2, src2);
ur = GET_UCD(c2);
@@ -5273,15 +5295,15 @@ while (src1 < end1)
return src2;
}
-#endif /* SUPPORT_UTF && SUPPORT_UCP */
+#endif /* SUPPORT_UNICODE */
-static pcre_uchar *byte_sequence_compare(compiler_common *common, BOOL caseless, pcre_uchar *cc,
+static PCRE2_SPTR byte_sequence_compare(compiler_common *common, BOOL caseless, PCRE2_SPTR cc,
compare_context *context, jump_list **backtracks)
{
DEFINE_COMPILER;
unsigned int othercasebit = 0;
-pcre_uchar *othercasechar = NULL;
-#ifdef SUPPORT_UTF
+PCRE2_SPTR othercasechar = NULL;
+#ifdef SUPPORT_UNICODE
int utflength;
#endif
@@ -5290,25 +5312,25 @@ if (caseless && char_has_othercase(common, cc))
othercasebit = char_get_othercase_bit(common, cc);
SLJIT_ASSERT(othercasebit);
/* Extracting bit difference info. */
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
othercasechar = cc + (othercasebit >> 8);
othercasebit &= 0xff;
-#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
/* Note that this code only handles characters in the BMP. If there
ever are characters outside the BMP whose othercase differs in only one
bit from itself (there currently are none), this code will need to be
- revised for COMPILE_PCRE32. */
+ revised for PCRE2_CODE_UNIT_WIDTH == 32. */
othercasechar = cc + (othercasebit >> 9);
if ((othercasebit & 0x100) != 0)
othercasebit = (othercasebit & 0xff) << 8;
else
othercasebit &= 0xff;
-#endif /* COMPILE_PCRE[8|16|32] */
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
}
if (context->sourcereg == -1)
{
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
if (context->length >= 4)
OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
@@ -5317,20 +5339,20 @@ if (context->sourcereg == -1)
else
#endif
OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
if (context->length >= 4)
OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
else
#endif
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
-#elif defined COMPILE_PCRE32
+#elif PCRE2_CODE_UNIT_WIDTH == 32
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
-#endif /* COMPILE_PCRE[8|16|32] */
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
context->sourcereg = TMP2;
}
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
utflength = 1;
if (common->utf && HAS_EXTRALEN(*cc))
utflength += GET_EXTRALEN(*cc);
@@ -5340,7 +5362,7 @@ do
#endif
context->length -= IN_UCHARS(1);
-#if (defined SLJIT_UNALIGNED && SLJIT_UNALIGNED) && (defined COMPILE_PCRE8 || defined COMPILE_PCRE16)
+#if (defined SLJIT_UNALIGNED && SLJIT_UNALIGNED) && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16)
/* Unaligned read is supported. */
if (othercasebit != 0 && othercasechar == cc)
@@ -5355,7 +5377,7 @@ do
}
context->ucharptr++;
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
if (context->ucharptr >= 4 || context->length == 0 || (context->ucharptr == 2 && context->length == 1))
#else
if (context->ucharptr >= 2 || context->length == 0)
@@ -5365,27 +5387,27 @@ do
OP1(SLJIT_MOV_S32, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
else if (context->length >= 2)
OP1(SLJIT_MOV_U16, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
else if (context->length >= 1)
OP1(SLJIT_MOV_U8, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
-#endif /* COMPILE_PCRE8 */
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1;
switch(context->ucharptr)
{
- case 4 / sizeof(pcre_uchar):
+ case 4 / sizeof(PCRE2_UCHAR):
if (context->oc.asint != 0)
OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asint);
add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asint | context->oc.asint));
break;
- case 2 / sizeof(pcre_uchar):
+ case 2 / sizeof(PCRE2_UCHAR):
if (context->oc.asushort != 0)
OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asushort);
add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asushort | context->oc.asushort));
break;
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
case 1:
if (context->oc.asbyte != 0)
OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asbyte);
@@ -5419,7 +5441,7 @@ do
#endif
cc++;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
utflength--;
}
while (utflength > 0);
@@ -5428,7 +5450,7 @@ while (utflength > 0);
return cc;
}
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
#define SET_TYPE_OFFSET(value) \
if ((value) != typeoffset) \
@@ -5450,22 +5472,22 @@ return cc;
} \
charoffset = (value);
-static pcre_uchar *compile_char1_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks, BOOL check_str_ptr);
+static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks, BOOL check_str_ptr);
-static void compile_xclass_matchingpath(compiler_common *common, pcre_uchar *cc, jump_list **backtracks)
+static void compile_xclass_matchingpath(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks)
{
DEFINE_COMPILER;
jump_list *found = NULL;
jump_list **list = (cc[0] & XCL_NOT) == 0 ? &found : backtracks;
sljit_uw c, charoffset, max = 256, min = READ_CHAR_MAX;
struct sljit_jump *jump = NULL;
-pcre_uchar *ccbegin;
+PCRE2_SPTR ccbegin;
int compares, invertcmp, numberofcmps;
-#if defined SUPPORT_UTF && (defined COMPILE_PCRE8 || defined COMPILE_PCRE16)
+#if defined SUPPORT_UNICODE && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16)
BOOL utf = common->utf;
#endif
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
BOOL needstype = FALSE, needsscript = FALSE, needschar = FALSE;
BOOL charsaved = FALSE;
int typereg = TMP1;
@@ -5477,10 +5499,11 @@ sljit_uw typeoffset;
cc++;
ccbegin = cc;
compares = 0;
+
if (cc[-1] & XCL_MAP)
{
min = 0;
- cc += 32 / sizeof(pcre_uchar);
+ cc += 32 / sizeof(PCRE2_UCHAR);
}
while (*cc != XCL_END)
@@ -5492,7 +5515,7 @@ while (*cc != XCL_END)
GETCHARINCTEST(c, cc);
if (c > max) max = c;
if (c < min) min = c;
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
needschar = TRUE;
#endif
}
@@ -5503,11 +5526,11 @@ while (*cc != XCL_END)
if (c < min) min = c;
GETCHARINCTEST(c, cc);
if (c > max) max = c;
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
needschar = TRUE;
#endif
}
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
else
{
SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
@@ -5599,7 +5622,7 @@ if ((cc[-1] & XCL_HASPROP) == 0)
add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
JUMPHERE(jump);
- cc += 32 / sizeof(pcre_uchar);
+ cc += 32 / sizeof(PCRE2_UCHAR);
}
else
{
@@ -5610,12 +5633,12 @@ if ((cc[-1] & XCL_HASPROP) == 0)
else if ((cc[-1] & XCL_MAP) != 0)
{
OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
charsaved = TRUE;
#endif
if (!check_class_ranges(common, (const sljit_u8 *)cc, FALSE, TRUE, list))
{
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
jump = NULL;
if (common->utf)
#endif
@@ -5628,17 +5651,17 @@ else if ((cc[-1] & XCL_MAP) != 0)
OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
add_jump(compiler, list, JUMP(SLJIT_NOT_ZERO));
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
if (common->utf)
#endif
JUMPHERE(jump);
}
OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
- cc += 32 / sizeof(pcre_uchar);
+ cc += 32 / sizeof(PCRE2_UCHAR);
}
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (needstype || needsscript)
{
if (needschar && !charsaved)
@@ -5718,7 +5741,7 @@ if (needstype || needsscript)
/* Generating code. */
charoffset = 0;
numberofcmps = 0;
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
typeoffset = 0;
#endif
@@ -5778,7 +5801,7 @@ while (*cc != XCL_END)
numberofcmps = 0;
}
}
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
else
{
SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
@@ -6002,14 +6025,14 @@ if (found != NULL)
#endif
-static pcre_uchar *compile_simple_assertion_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks)
+static PCRE2_SPTR compile_simple_assertion_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks)
{
DEFINE_COMPILER;
int length;
struct sljit_jump *jump[4];
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
struct sljit_label *label;
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
switch(type)
{
@@ -6038,7 +6061,7 @@ switch(type)
{
OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
- if (common->mode == JIT_COMPILE)
+ if (common->mode == PCRE2_JIT_COMPLETE)
add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0));
else
{
@@ -6106,8 +6129,8 @@ switch(type)
case OP_DOLL:
OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ OP2(SLJIT_AND32 | SLJIT_SET_E, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
if (!common->endonly)
compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks);
@@ -6121,8 +6144,8 @@ switch(type)
case OP_DOLLM:
jump[1] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, noteol));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ OP2(SLJIT_AND32 | SLJIT_SET_E, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
check_partial(common, FALSE);
jump[0] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[1]);
@@ -6131,7 +6154,7 @@ switch(type)
{
OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
- if (common->mode == JIT_COMPILE)
+ if (common->mode == PCRE2_JIT_COMPLETE)
add_jump(compiler, backtracks, CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0));
else
{
@@ -6159,20 +6182,22 @@ switch(type)
OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
- OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ OP2(SLJIT_AND32 | SLJIT_SET_E, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
return cc;
case OP_CIRCM:
OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0);
- OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, notbol));
- add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ OP2(SLJIT_AND32 | SLJIT_SET_E, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO));
jump[0] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[1]);
- add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+ if (!common->alt_circumflex)
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
if (common->nltype == NLTYPE_FIXED && common->newline > 255)
{
OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
@@ -6196,7 +6221,7 @@ switch(type)
if (length == 0)
return cc + LINK_SIZE;
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf)
{
OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
@@ -6221,7 +6246,7 @@ SLJIT_ASSERT_STOP();
return cc;
}
-static pcre_uchar *compile_char1_matchingpath(compiler_common *common, pcre_uchar type, pcre_uchar *cc, jump_list **backtracks, BOOL check_str_ptr)
+static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks, BOOL check_str_ptr)
{
DEFINE_COMPILER;
int length;
@@ -6229,12 +6254,10 @@ unsigned int c, oc, bit;
compare_context context;
struct sljit_jump *jump[3];
jump_list *end_list;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
struct sljit_label *label;
-#ifdef SUPPORT_UCP
-pcre_uchar propdata[5];
-#endif
-#endif /* SUPPORT_UTF */
+PCRE2_UCHAR propdata[5];
+#endif /* SUPPORT_UNICODE */
switch(type)
{
@@ -6243,8 +6266,8 @@ switch(type)
/* Digits are usually 0-9, so it is worth to optimize them. */
if (check_str_ptr)
detect_partial_match(common, backtracks);
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_digit, FALSE))
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_digit, FALSE))
read_char7_type(common, type == OP_NOT_DIGIT);
else
#endif
@@ -6258,8 +6281,8 @@ switch(type)
case OP_WHITESPACE:
if (check_str_ptr)
detect_partial_match(common, backtracks);
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_space, FALSE))
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_space, FALSE))
read_char7_type(common, type == OP_NOT_WHITESPACE);
else
#endif
@@ -6272,8 +6295,8 @@ switch(type)
case OP_WORDCHAR:
if (check_str_ptr)
detect_partial_match(common, backtracks);
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (common->utf && is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_word, FALSE))
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_word, FALSE))
read_char7_type(common, type == OP_NOT_WORDCHAR);
else
#endif
@@ -6290,7 +6313,7 @@ switch(type)
{
jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff);
end_list = NULL;
- if (common->mode != JIT_PARTIAL_HARD_COMPILE)
+ if (common->mode != PCRE2_JIT_PARTIAL_HARD)
add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
else
check_str_end(common, &end_list);
@@ -6307,17 +6330,17 @@ switch(type)
case OP_ALLANY:
if (check_str_ptr)
detect_partial_match(common, backtracks);
-#ifdef SUPPORT_UTF
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf)
{
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16
+#if PCRE2_CODE_UNIT_WIDTH == 8
jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
-#elif defined COMPILE_PCRE16
+#elif PCRE2_CODE_UNIT_WIDTH == 16
jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800);
OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
OP2(SLJIT_SUB | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
@@ -6326,7 +6349,7 @@ switch(type)
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
#endif
JUMPHERE(jump[0]);
-#endif /* COMPILE_PCRE[8|16] */
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
return cc;
}
#endif
@@ -6339,8 +6362,7 @@ switch(type)
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
return cc;
-#ifdef SUPPORT_UTF
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
case OP_NOTPROP:
case OP_PROP:
propdata[0] = XCL_HASPROP;
@@ -6353,7 +6375,6 @@ switch(type)
compile_xclass_matchingpath(common, propdata, backtracks);
return cc + 2;
#endif
-#endif
case OP_ANYNL:
if (check_str_ptr)
@@ -6362,7 +6383,7 @@ switch(type)
jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
/* We don't need to handle soft partial matching case. */
end_list = NULL;
- if (common->mode != JIT_PARTIAL_HARD_COMPILE)
+ if (common->mode != PCRE2_JIT_PARTIAL_HARD)
add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
else
check_str_end(common, &end_list);
@@ -6395,7 +6416,7 @@ switch(type)
add_jump(compiler, backtracks, JUMP(type == OP_NOT_VSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO));
return cc;
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
case OP_EXTUNI:
if (check_str_ptr)
detect_partial_match(common, backtracks);
@@ -6425,7 +6446,7 @@ switch(type)
JUMPHERE(jump[0]);
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
- if (common->mode == JIT_PARTIAL_HARD_COMPILE)
+ if (common->mode == PCRE2_JIT_PARTIAL_HARD)
{
jump[0] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
/* Since we successfully read a char above, partial matching must occure. */
@@ -6438,10 +6459,10 @@ switch(type)
case OP_CHAR:
case OP_CHARI:
length = 1;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(*cc)) length += GET_EXTRALEN(*cc);
#endif
- if (common->mode == JIT_COMPILE && check_str_ptr
+ if (common->mode == PCRE2_JIT_COMPLETE && check_str_ptr
&& (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0))
{
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
@@ -6457,7 +6478,7 @@ switch(type)
if (check_str_ptr)
detect_partial_match(common, backtracks);
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf)
{
GETCHAR(c, cc);
@@ -6490,11 +6511,12 @@ switch(type)
case OP_NOTI:
if (check_str_ptr)
detect_partial_match(common, backtracks);
+
length = 1;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf)
{
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
c = *cc;
if (c < 128)
{
@@ -6516,13 +6538,13 @@ switch(type)
return cc + 1;
}
else
-#endif /* COMPILE_PCRE8 */
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
{
GETCHARLEN(c, cc, length);
}
}
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
c = *cc;
if (type == OP_NOT || !char_has_othercase(common, cc))
@@ -6553,7 +6575,7 @@ switch(type)
if (check_str_ptr)
detect_partial_match(common, backtracks);
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
bit = (common->utf && is_char7_bitset((const sljit_u8 *)cc, type == OP_NCLASS)) ? 127 : 255;
read_char_range(common, 0, bit, type == OP_NCLASS);
#else
@@ -6561,9 +6583,9 @@ switch(type)
#endif
if (check_class_ranges(common, (const sljit_u8 *)cc, type == OP_NCLASS, FALSE, backtracks))
- return cc + 32 / sizeof(pcre_uchar);
+ return cc + 32 / sizeof(PCRE2_UCHAR);
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
jump[0] = NULL;
if (common->utf)
{
@@ -6574,14 +6596,14 @@ switch(type)
jump[0] = NULL;
}
}
-#elif !defined COMPILE_PCRE8
+#elif PCRE2_CODE_UNIT_WIDTH != 8
jump[0] = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
if (type == OP_CLASS)
{
add_jump(compiler, backtracks, jump[0]);
jump[0] = NULL;
}
-#endif /* SUPPORT_UTF && COMPILE_PCRE8 */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
@@ -6590,13 +6612,13 @@ switch(type)
OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
add_jump(compiler, backtracks, JUMP(SLJIT_ZERO));
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
if (jump[0] != NULL)
JUMPHERE(jump[0]);
#endif
- return cc + 32 / sizeof(pcre_uchar);
+ return cc + 32 / sizeof(PCRE2_UCHAR);
-#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
case OP_XCLASS:
if (check_str_ptr)
detect_partial_match(common, backtracks);
@@ -6608,12 +6630,12 @@ SLJIT_ASSERT_STOP();
return cc;
}
-static SLJIT_INLINE pcre_uchar *compile_charn_matchingpath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, jump_list **backtracks)
+static SLJIT_INLINE PCRE2_SPTR compile_charn_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, jump_list **backtracks)
{
/* This function consumes at least one input character. */
/* To decrease the number of length checks, we try to concatenate the fixed length character sequences. */
DEFINE_COMPILER;
-pcre_uchar *ccbegin = cc;
+PCRE2_SPTR ccbegin = cc;
compare_context context;
int size;
@@ -6626,7 +6648,7 @@ do
if (*cc == OP_CHAR)
{
size = 1;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[1]))
size += GET_EXTRALEN(cc[1]);
#endif
@@ -6634,7 +6656,7 @@ do
else if (*cc == OP_CHARI)
{
size = 1;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf)
{
if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0)
@@ -6675,7 +6697,7 @@ return compile_char1_matchingpath(common, *cc, cc + 1, backtracks, TRUE);
}
/* Forward definitions. */
-static void compile_matchingpath(compiler_common *, pcre_uchar *, pcre_uchar *, backtrack_common *);
+static void compile_matchingpath(compiler_common *, PCRE2_SPTR, PCRE2_SPTR, backtrack_common *);
static void compile_backtrackingpath(compiler_common *, struct backtrack_common *);
#define PUSH_BACKTRACK(size, ccstart, error) \
@@ -6706,12 +6728,12 @@ static void compile_backtrackingpath(compiler_common *, struct backtrack_common
#define BACKTRACK_AS(type) ((type *)backtrack)
-static void compile_dnref_search(compiler_common *common, pcre_uchar *cc, jump_list **backtracks)
+static void compile_dnref_search(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks)
{
/* The OVECTOR offset goes to TMP2. */
DEFINE_COMPILER;
int count = GET2(cc, 1 + IMM2_SIZE);
-pcre_uchar *slot = common->name_table + GET2(cc, 1) * common->name_entry_size;
+PCRE2_SPTR slot = common->name_table + GET2(cc, 1) * common->name_entry_size;
unsigned int offset;
jump_list *found = NULL;
@@ -6730,13 +6752,13 @@ while (count-- > 0)
offset = GET2(slot, 0) << 1;
GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset));
-if (backtracks != NULL && !common->jscript_compat)
+if (backtracks != NULL && !common->unset_backref)
add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0));
set_jumps(found, LABEL());
}
-static void compile_ref_matchingpath(compiler_common *common, pcre_uchar *cc, jump_list **backtracks, BOOL withchecks, BOOL emptyfail)
+static void compile_ref_matchingpath(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks, BOOL withchecks, BOOL emptyfail)
{
DEFINE_COMPILER;
BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
@@ -6750,13 +6772,13 @@ if (ref)
offset = GET2(cc, 1) << 1;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
/* OVECTOR(1) contains the "string begin - 1" constant. */
- if (withchecks && !common->jscript_compat)
+ if (withchecks && !common->unset_backref)
add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
}
else
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
-#if defined SUPPORT_UTF && defined SUPPORT_UCP
+#if defined SUPPORT_UNICODE
if (common->utf && *cc == OP_REFI)
{
SLJIT_ASSERT(TMP1 == SLJIT_R0 && STACK_TOP == SLJIT_R1 && TMP2 == SLJIT_R2);
@@ -6771,10 +6793,10 @@ if (common->utf && *cc == OP_REFI)
/* Needed to save important temporary registers. */
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0);
OP1(SLJIT_MOV, SLJIT_R1, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, uchar_ptr), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), STR_PTR, 0);
sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_utf_caselesscmp));
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
- if (common->mode == JIT_COMPILE)
+ if (common->mode == PCRE2_JIT_COMPLETE)
add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1));
else
{
@@ -6787,7 +6809,7 @@ if (common->utf && *cc == OP_REFI)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
}
else
-#endif /* SUPPORT_UTF && SUPPORT_UCP */
+#endif /* SUPPORT_UNICODE */
{
if (ref)
OP2(SLJIT_SUB | SLJIT_SET_E, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0);
@@ -6799,13 +6821,13 @@ else
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
partial = CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0);
- if (common->mode == JIT_COMPILE)
+ if (common->mode == PCRE2_JIT_COMPLETE)
add_jump(compiler, backtracks, partial);
add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
- if (common->mode != JIT_COMPILE)
+ if (common->mode != PCRE2_JIT_COMPLETE)
{
nopartial = JUMP(SLJIT_JUMP);
JUMPHERE(partial);
@@ -6832,17 +6854,17 @@ if (jump != NULL)
}
}
-static SLJIT_INLINE pcre_uchar *compile_ref_iterator_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
+static SLJIT_INLINE PCRE2_SPTR compile_ref_iterator_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
{
DEFINE_COMPILER;
BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
backtrack_common *backtrack;
-pcre_uchar type;
+PCRE2_UCHAR type;
int offset = 0;
struct sljit_label *label;
struct sljit_jump *zerolength;
struct sljit_jump *jump = NULL;
-pcre_uchar *ccbegin = cc;
+PCRE2_SPTR ccbegin = cc;
int min = 0, max = 0;
BOOL minimize;
@@ -7039,14 +7061,14 @@ count_match(common);
return cc;
}
-static SLJIT_INLINE pcre_uchar *compile_recurse_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
+static SLJIT_INLINE PCRE2_SPTR compile_recurse_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
{
DEFINE_COMPILER;
backtrack_common *backtrack;
recurse_entry *entry = common->entries;
recurse_entry *prev = NULL;
sljit_sw start = GET(cc, 1);
-pcre_uchar *start_cc;
+PCRE2_SPTR start_cc;
BOOL needs_control_head;
PUSH_BACKTRACK(sizeof(recurse_backtrack), cc, NULL);
@@ -7108,61 +7130,58 @@ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IM
return cc + 1 + LINK_SIZE;
}
-static int SLJIT_CALL do_callout(struct jit_arguments *arguments, PUBL(callout_block) *callout_block, pcre_uchar **jit_ovector)
+static int SLJIT_CALL do_callout(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector)
{
-const pcre_uchar *begin = arguments->begin;
-int *offset_vector = arguments->offsets;
-int offset_count = arguments->offset_count;
-int i;
+PCRE2_SPTR begin = arguments->begin;
+PCRE2_SIZE *ovector = arguments->match_data->ovector;
+sljit_u32 oveccount = arguments->oveccount;
+sljit_u32 i;
-if (PUBL(callout) == NULL)
+if (arguments->callout == NULL)
return 0;
-callout_block->version = 2;
-callout_block->callout_data = arguments->callout_data;
+callout_block->version = 1;
/* Offsets in subject. */
callout_block->subject_length = arguments->end - arguments->begin;
-callout_block->start_match = (pcre_uchar*)callout_block->subject - arguments->begin;
-callout_block->current_position = (pcre_uchar*)callout_block->offset_vector - arguments->begin;
-#if defined COMPILE_PCRE8
-callout_block->subject = (PCRE_SPTR)begin;
-#elif defined COMPILE_PCRE16
-callout_block->subject = (PCRE_SPTR16)begin;
-#elif defined COMPILE_PCRE32
-callout_block->subject = (PCRE_SPTR32)begin;
-#endif
+callout_block->start_match = (PCRE2_SPTR)callout_block->subject - arguments->begin;
+callout_block->current_position = (PCRE2_SPTR)callout_block->offset_vector - arguments->begin;
+callout_block->subject = begin;
-/* Convert and copy the JIT offset vector to the offset_vector array. */
+/* Convert and copy the JIT offset vector to the ovector array. */
callout_block->capture_top = 0;
-callout_block->offset_vector = offset_vector;
-for (i = 2; i < offset_count; i += 2)
+callout_block->offset_vector = ovector;
+for (i = 2; i < oveccount; i += 2)
{
- offset_vector[i] = jit_ovector[i] - begin;
- offset_vector[i + 1] = jit_ovector[i + 1] - begin;
+ ovector[i] = jit_ovector[i] - begin;
+ ovector[i + 1] = jit_ovector[i + 1] - begin;
if (jit_ovector[i] >= begin)
callout_block->capture_top = i;
}
callout_block->capture_top = (callout_block->capture_top >> 1) + 1;
-if (offset_count > 0)
- offset_vector[0] = -1;
-if (offset_count > 1)
- offset_vector[1] = -1;
-return (*PUBL(callout))(callout_block);
+ovector[0] = PCRE2_UNSET;
+ovector[1] = PCRE2_UNSET;
+return (arguments->callout)(callout_block, arguments->callout_data);
}
/* Aligning to 8 byte. */
#define CALLOUT_ARG_SIZE \
- (((int)sizeof(PUBL(callout_block)) + 7) & ~7)
+ (((int)sizeof(pcre2_callout_block) + 7) & ~7)
#define CALLOUT_ARG_OFFSET(arg) \
- (-CALLOUT_ARG_SIZE + SLJIT_OFFSETOF(PUBL(callout_block), arg))
+ (-CALLOUT_ARG_SIZE + SLJIT_OFFSETOF(pcre2_callout_block, arg))
-static SLJIT_INLINE pcre_uchar *compile_callout_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
+static SLJIT_INLINE PCRE2_SPTR compile_callout_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
{
DEFINE_COMPILER;
backtrack_common *backtrack;
+sljit_s32 mov_opcode;
+unsigned int callout_length = (*cc == OP_CALLOUT)
+ ? PRIV(OP_lengths)[OP_CALLOUT] : GET(cc, 1 + 2 * LINK_SIZE);
+sljit_sw value1;
+sljit_sw value2;
+sljit_sw value3;
PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL);
@@ -7171,8 +7190,9 @@ allocate_stack(common, CALLOUT_ARG_SIZE / sizeof(sljit_sw));
SLJIT_ASSERT(common->capture_last_ptr != 0);
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
-OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, cc[1]);
-OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0);
+value1 = (*cc == OP_CALLOUT) ? cc[1 + 2 * LINK_SIZE] : 0;
+OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, value1);
+OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0);
/* These pointer sized fields temporarly stores internal variables. */
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
@@ -7181,8 +7201,26 @@ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(subject), TMP2, 0);
if (common->mark_ptr != 0)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr));
-OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(pattern_position), SLJIT_IMM, GET(cc, 2));
-OP1(SLJIT_MOV_S32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(next_item_length), SLJIT_IMM, GET(cc, 2 + LINK_SIZE));
+mov_opcode = (sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV;
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(pattern_position), SLJIT_IMM, GET(cc, 1));
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(next_item_length), SLJIT_IMM, GET(cc, 1 + LINK_SIZE));
+
+if (*cc == OP_CALLOUT)
+ {
+ value1 = 0;
+ value2 = 0;
+ value3 = 0;
+ }
+else
+ {
+ value1 = (sljit_sw) (cc + (1 + 4*LINK_SIZE) + 1);
+ value2 = (callout_length - (1 + 4*LINK_SIZE + 2));
+ value3 = (sljit_sw) (GET(cc, 1 + 3*LINK_SIZE));
+ }
+
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string), SLJIT_IMM, value1);
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_length), SLJIT_IMM, value2);
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_offset), SLJIT_IMM, value3);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_ptr != 0) ? TMP2 : SLJIT_IMM, 0);
/* Needed to save important temporary registers. */
@@ -7201,18 +7239,22 @@ if (common->forced_quit_label == NULL)
add_jump(compiler, &common->forced_quit, JUMP(SLJIT_SIG_LESS));
else
JUMPTO(SLJIT_SIG_LESS, common->forced_quit_label);
-return cc + 2 + 2 * LINK_SIZE;
+return cc + callout_length;
}
#undef CALLOUT_ARG_SIZE
#undef CALLOUT_ARG_OFFSET
-static SLJIT_INLINE BOOL assert_needs_str_ptr_saving(pcre_uchar *cc)
+static SLJIT_INLINE BOOL assert_needs_str_ptr_saving(PCRE2_SPTR cc)
{
while (TRUE)
{
switch (*cc)
{
+ case OP_CALLOUT_STR:
+ cc += GET(cc, 1 + 2*LINK_SIZE);
+ break;
+
case OP_NOT_WORD_BOUNDARY:
case OP_WORD_BOUNDARY:
case OP_CIRC:
@@ -7233,7 +7275,7 @@ while (TRUE)
}
}
-static pcre_uchar *compile_assert_matchingpath(compiler_common *common, pcre_uchar *cc, assert_backtrack *backtrack, BOOL conditional)
+static PCRE2_SPTR compile_assert_matchingpath(compiler_common *common, PCRE2_SPTR cc, assert_backtrack *backtrack, BOOL conditional)
{
DEFINE_COMPILER;
int framesize;
@@ -7241,9 +7283,9 @@ int extrasize;
BOOL needs_control_head;
int private_data_ptr;
backtrack_common altbacktrack;
-pcre_uchar *ccbegin;
-pcre_uchar opcode;
-pcre_uchar bra = OP_BRA;
+PCRE2_SPTR ccbegin;
+PCRE2_UCHAR opcode;
+PCRE2_UCHAR bra = OP_BRA;
jump_list *tmp = NULL;
jump_list **target = (conditional) ? &backtrack->condfailed : &backtrack->common.topbacktracks;
jump_list **found;
@@ -7655,7 +7697,7 @@ common->accept = save_accept;
return cc + 1 + LINK_SIZE;
}
-static SLJIT_INLINE void match_once_common(compiler_common *common, pcre_uchar ket, int framesize, int private_data_ptr, BOOL has_alternatives, BOOL needs_control_head)
+static SLJIT_INLINE void match_once_common(compiler_common *common, PCRE2_UCHAR ket, int framesize, int private_data_ptr, BOOL has_alternatives, BOOL needs_control_head)
{
DEFINE_COMPILER;
int stacksize;
@@ -7782,21 +7824,21 @@ return stacksize;
Or nothing, if trace is unnecessary
*/
-static pcre_uchar *compile_bracket_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
+static PCRE2_SPTR compile_bracket_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
{
DEFINE_COMPILER;
backtrack_common *backtrack;
-pcre_uchar opcode;
+PCRE2_UCHAR opcode;
int private_data_ptr = 0;
int offset = 0;
int i, stacksize;
int repeat_ptr = 0, repeat_length = 0;
int repeat_type = 0, repeat_count = 0;
-pcre_uchar *ccbegin;
-pcre_uchar *matchingpath;
-pcre_uchar *slot;
-pcre_uchar bra = OP_BRA;
-pcre_uchar ket;
+PCRE2_SPTR ccbegin;
+PCRE2_SPTR matchingpath;
+PCRE2_SPTR slot;
+PCRE2_UCHAR bra = OP_BRA;
+PCRE2_UCHAR ket;
assert_backtrack *assert;
BOOL has_alternatives;
BOOL needs_control_head = FALSE;
@@ -7831,13 +7873,6 @@ if (ket == OP_KET && PRIVATE_DATA(matchingpath) != 0)
ket = OP_KETRMIN;
}
-if ((opcode == OP_COND || opcode == OP_SCOND) && cc[1 + LINK_SIZE] == OP_DEF)
- {
- /* Drop this bracket_backtrack. */
- parent->top = backtrack->prev;
- return matchingpath + 1 + LINK_SIZE + repeat_length;
- }
-
matchingpath = ccbegin + 1 + LINK_SIZE;
SLJIT_ASSERT(ket == OP_KET || ket == OP_KETRMAX || ket == OP_KETRMIN);
SLJIT_ASSERT(!((bra == OP_BRAZERO && ket == OP_KETRMIN) || (bra == OP_BRAMINZERO && ket == OP_KETRMAX)));
@@ -7845,7 +7880,11 @@ cc += GET(cc, 1);
has_alternatives = *cc == OP_ALT;
if (SLJIT_UNLIKELY(opcode == OP_COND || opcode == OP_SCOND))
- has_alternatives = (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF || *matchingpath == OP_FAIL) ? FALSE : TRUE;
+ {
+ SLJIT_COMPILE_ASSERT(OP_DNRREF == OP_RREF + 1 && OP_FALSE == OP_RREF + 2 && OP_TRUE == OP_RREF + 3,
+ compile_time_checks_must_be_grouped_together);
+ has_alternatives = ((*matchingpath >= OP_RREF && *matchingpath <= OP_TRUE) || *matchingpath == OP_FAIL) ? FALSE : TRUE;
+ }
if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN))
opcode = OP_SCOND;
@@ -8103,15 +8142,20 @@ if (opcode == OP_COND || opcode == OP_SCOND)
add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), JUMP(SLJIT_ZERO));
matchingpath += 1 + 2 * IMM2_SIZE;
}
- else if (*matchingpath == OP_RREF || *matchingpath == OP_DNRREF || *matchingpath == OP_FAIL)
+ else if ((*matchingpath >= OP_RREF && *matchingpath <= OP_TRUE) || *matchingpath == OP_FAIL)
{
/* Never has other case. */
BACKTRACK_AS(bracket_backtrack)->u.condfailed = NULL;
SLJIT_ASSERT(!has_alternatives);
- if (*matchingpath == OP_FAIL)
+ if (*matchingpath == OP_TRUE)
+ {
+ stacksize = 1;
+ matchingpath++;
+ }
+ else if (*matchingpath == OP_FALSE || *matchingpath == OP_FAIL)
stacksize = 0;
- if (*matchingpath == OP_RREF)
+ else if (*matchingpath == OP_RREF)
{
stacksize = GET2(matchingpath, 1);
if (common->currententry == NULL)
@@ -8327,11 +8371,11 @@ if (opcode == OP_ONCE)
return cc + repeat_length;
}
-static pcre_uchar *compile_bracketpos_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
+static PCRE2_SPTR compile_bracketpos_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
{
DEFINE_COMPILER;
backtrack_common *backtrack;
-pcre_uchar opcode;
+PCRE2_UCHAR opcode;
int private_data_ptr;
int cbraprivptr = 0;
BOOL needs_control_head;
@@ -8339,7 +8383,7 @@ int framesize;
int stacksize;
int offset = 0;
BOOL zero = FALSE;
-pcre_uchar *ccbegin = NULL;
+PCRE2_SPTR ccbegin = NULL;
int stack; /* Also contains the offset of control head. */
struct sljit_label *loop = NULL;
struct jump_list *emptymatch = NULL;
@@ -8610,7 +8654,7 @@ count_match(common);
return cc + 1 + LINK_SIZE;
}
-static SLJIT_INLINE pcre_uchar *get_iterator_parameters(compiler_common *common, pcre_uchar *cc, pcre_uchar *opcode, pcre_uchar *type, sljit_u32 *max, sljit_u32 *exact, pcre_uchar **end)
+static SLJIT_INLINE PCRE2_SPTR get_iterator_parameters(compiler_common *common, PCRE2_SPTR cc, PCRE2_UCHAR *opcode, PCRE2_UCHAR *type, sljit_u32 *max, sljit_u32 *exact, PCRE2_SPTR *end)
{
int class_len;
@@ -8651,7 +8695,7 @@ else
SLJIT_ASSERT(*opcode == OP_CLASS || *opcode == OP_NCLASS || *opcode == OP_XCLASS);
*type = *opcode;
cc++;
- class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(pcre_uchar))) : GET(cc, 0);
+ class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(PCRE2_UCHAR))) : GET(cc, 0);
*opcode = cc[class_len - 1];
if (*opcode >= OP_CRSTAR && *opcode <= OP_CRMINQUERY)
@@ -8749,25 +8793,25 @@ if (*type == OP_END)
}
*end = cc + 1;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(*cc)) *end += GET_EXTRALEN(*cc);
#endif
return cc;
}
-static pcre_uchar *compile_iterator_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
+static PCRE2_SPTR compile_iterator_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
{
DEFINE_COMPILER;
backtrack_common *backtrack;
-pcre_uchar opcode;
-pcre_uchar type;
+PCRE2_UCHAR opcode;
+PCRE2_UCHAR type;
sljit_u32 max = 0, exact;
BOOL fast_fail;
sljit_s32 fast_str_ptr;
BOOL charpos_enabled;
-pcre_uchar charpos_char;
+PCRE2_UCHAR charpos_char;
unsigned int charpos_othercasebit;
-pcre_uchar *end;
+PCRE2_SPTR end;
jump_list *no_match = NULL;
jump_list *no_char1_match = NULL;
struct sljit_jump *jump = NULL;
@@ -8813,8 +8857,8 @@ if (fast_fail && fast_str_ptr != 0)
if (exact > 1)
{
SLJIT_ASSERT(fast_str_ptr == 0);
- if (common->mode == JIT_COMPILE
-#ifdef SUPPORT_UTF
+ if (common->mode == PCRE2_JIT_COMPLETE
+#ifdef SUPPORT_UNICODE
&& !common->utf
#endif
)
@@ -8883,7 +8927,7 @@ switch(opcode)
if ((type != OP_CHAR && type != OP_CHARI) && (*end == OP_CHAR || *end == OP_CHARI))
{
charpos_enabled = TRUE;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
charpos_enabled = !common->utf || !HAS_EXTRALEN(end[1]);
#endif
if (charpos_enabled && *end == OP_CHARI && char_has_othercase(common, end + 1))
@@ -8898,9 +8942,9 @@ switch(opcode)
charpos_char = end[1];
/* Consumpe the OP_CHAR opcode. */
end += 2;
-#if defined COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
SLJIT_ASSERT((charpos_othercasebit >> 8) == 0);
-#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
SLJIT_ASSERT((charpos_othercasebit >> 9) == 0);
if ((charpos_othercasebit & 0x100) != 0)
charpos_othercasebit = (charpos_othercasebit & 0xff) << 8;
@@ -8982,7 +9026,7 @@ switch(opcode)
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
}
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
else if (common->utf)
{
if (private_data_ptr == 0)
@@ -9077,7 +9121,7 @@ switch(opcode)
break;
case OP_POSSTAR:
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf)
{
OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
@@ -9105,7 +9149,7 @@ switch(opcode)
case OP_POSUPTO:
SLJIT_ASSERT(fast_str_ptr == 0);
-#if defined SUPPORT_UTF && !defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
if (common->utf)
{
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0);
@@ -9150,7 +9194,7 @@ count_match(common);
return end;
}
-static SLJIT_INLINE pcre_uchar *compile_fail_accept_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
+static SLJIT_INLINE PCRE2_SPTR compile_fail_accept_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
{
DEFINE_COMPILER;
backtrack_common *backtrack;
@@ -9178,13 +9222,14 @@ if (common->accept_label == NULL)
else
CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), common->accept_label);
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
-OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty));
-add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
-OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart));
+OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options));
+OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY);
+add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_NOT_ZERO));
+OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART);
if (common->accept_label == NULL)
- add_jump(compiler, &common->accept, CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ add_jump(compiler, &common->accept, JUMP(SLJIT_ZERO));
else
- CMPTO(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0, common->accept_label);
+ JUMPTO(SLJIT_ZERO, common->accept_label);
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
if (common->accept_label == NULL)
add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0));
@@ -9194,7 +9239,7 @@ add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP));
return cc + 1;
}
-static SLJIT_INLINE pcre_uchar *compile_close_matchingpath(compiler_common *common, pcre_uchar *cc)
+static SLJIT_INLINE PCRE2_SPTR compile_close_matchingpath(compiler_common *common, PCRE2_SPTR cc)
{
DEFINE_COMPILER;
int offset = GET2(cc, 1);
@@ -9213,12 +9258,12 @@ if (!optimized_cbracket)
return cc + 1 + IMM2_SIZE;
}
-static SLJIT_INLINE pcre_uchar *compile_control_verb_matchingpath(compiler_common *common, pcre_uchar *cc, backtrack_common *parent)
+static SLJIT_INLINE PCRE2_SPTR compile_control_verb_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
{
DEFINE_COMPILER;
backtrack_common *backtrack;
-pcre_uchar opcode = *cc;
-pcre_uchar *ccend = cc + 1;
+PCRE2_UCHAR opcode = *cc;
+PCRE2_SPTR ccend = cc + 1;
if (opcode == OP_PRUNE_ARG || opcode == OP_SKIP_ARG || opcode == OP_THEN_ARG)
ccend += 2 + cc[1];
@@ -9243,9 +9288,9 @@ if (opcode == OP_PRUNE_ARG || opcode == OP_THEN_ARG)
return ccend;
}
-static pcre_uchar then_trap_opcode[1] = { OP_THEN_TRAP };
+static PCRE2_UCHAR then_trap_opcode[1] = { OP_THEN_TRAP };
-static SLJIT_INLINE void compile_then_trap_matchingpath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, backtrack_common *parent)
+static SLJIT_INLINE void compile_then_trap_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent)
{
DEFINE_COMPILER;
backtrack_common *backtrack;
@@ -9276,7 +9321,7 @@ if (size >= 0)
init_frame(common, cc, ccend, size - 1, 0, FALSE);
}
-static void compile_matchingpath(compiler_common *common, pcre_uchar *cc, pcre_uchar *ccend, backtrack_common *parent)
+static void compile_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent)
{
DEFINE_COMPILER;
backtrack_common *backtrack;
@@ -9345,7 +9390,7 @@ while (cc < ccend)
case OP_CHAR:
case OP_CHARI:
- if (common->mode == JIT_COMPILE)
+ if (common->mode == PCRE2_JIT_COMPLETE)
cc = compile_charn_matchingpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
else
cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
@@ -9421,13 +9466,13 @@ while (cc < ccend)
case OP_CLASS:
case OP_NCLASS:
- if (cc[1 + (32 / sizeof(pcre_uchar))] >= OP_CRSTAR && cc[1 + (32 / sizeof(pcre_uchar))] <= OP_CRPOSRANGE)
+ if (cc[1 + (32 / sizeof(PCRE2_UCHAR))] >= OP_CRSTAR && cc[1 + (32 / sizeof(PCRE2_UCHAR))] <= OP_CRPOSRANGE)
cc = compile_iterator_matchingpath(common, cc, parent);
else
cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
break;
-#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
case OP_XCLASS:
if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= OP_CRPOSRANGE)
cc = compile_iterator_matchingpath(common, cc, parent);
@@ -9464,6 +9509,7 @@ while (cc < ccend)
break;
case OP_CALLOUT:
+ case OP_CALLOUT_STR:
cc = compile_callout_matchingpath(common, cc, parent);
break;
@@ -9605,14 +9651,14 @@ SLJIT_ASSERT(cc == ccend);
static void compile_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current)
{
DEFINE_COMPILER;
-pcre_uchar *cc = current->cc;
-pcre_uchar opcode;
-pcre_uchar type;
+PCRE2_SPTR cc = current->cc;
+PCRE2_UCHAR opcode;
+PCRE2_UCHAR type;
sljit_u32 max = 0, exact;
struct sljit_label *label = NULL;
struct sljit_jump *jump = NULL;
jump_list *jumplist = NULL;
-pcre_uchar *end;
+PCRE2_SPTR end;
int private_data_ptr = PRIVATE_DATA(cc);
int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP);
int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr;
@@ -9733,9 +9779,9 @@ set_jumps(current->topbacktracks, LABEL());
static SLJIT_INLINE void compile_ref_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current)
{
DEFINE_COMPILER;
-pcre_uchar *cc = current->cc;
+PCRE2_SPTR cc = current->cc;
BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
-pcre_uchar type;
+PCRE2_UCHAR type;
type = cc[ref ? 1 + IMM2_SIZE : 1 + 2 * IMM2_SIZE];
@@ -9784,8 +9830,8 @@ else if (common->has_set_som || common->mark_ptr != 0)
static void compile_assert_backtrackingpath(compiler_common *common, struct backtrack_common *current)
{
DEFINE_COMPILER;
-pcre_uchar *cc = current->cc;
-pcre_uchar bra = OP_BRA;
+PCRE2_SPTR cc = current->cc;
+PCRE2_UCHAR bra = OP_BRA;
struct sljit_jump *brajump = NULL;
SLJIT_ASSERT(*cc != OP_BRAMINZERO);
@@ -9855,11 +9901,11 @@ int opcode, stacksize, alt_count, alt_max;
int offset = 0;
int private_data_ptr = CURRENT_AS(bracket_backtrack)->private_data_ptr;
int repeat_ptr = 0, repeat_type = 0, repeat_count = 0;
-pcre_uchar *cc = current->cc;
-pcre_uchar *ccbegin;
-pcre_uchar *ccprev;
-pcre_uchar bra = OP_BRA;
-pcre_uchar ket;
+PCRE2_SPTR cc = current->cc;
+PCRE2_SPTR ccbegin;
+PCRE2_SPTR ccprev;
+PCRE2_UCHAR bra = OP_BRA;
+PCRE2_UCHAR ket;
assert_backtrack *assert;
sljit_uw *next_update_addr = NULL;
BOOL has_alternatives;
@@ -10376,7 +10422,7 @@ SLJIT_ASSERT(!current->nextbacktracks && !current->topbacktracks);
static SLJIT_INLINE void compile_control_verb_backtrackingpath(compiler_common *common, struct backtrack_common *current)
{
DEFINE_COMPILER;
-pcre_uchar opcode = *current->cc;
+PCRE2_UCHAR opcode = *current->cc;
struct sljit_label *loop;
struct sljit_jump *jump;
@@ -10550,7 +10596,7 @@ while (current)
case OP_TYPEPOSUPTO:
case OP_CLASS:
case OP_NCLASS:
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
case OP_XCLASS:
#endif
compile_iterator_backtrackingpath(common, current);
@@ -10625,7 +10671,7 @@ while (current)
case OP_COMMIT:
if (!common->local_exit)
- OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH);
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
if (common->quit_label == NULL)
add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP));
else
@@ -10633,6 +10679,7 @@ while (current)
break;
case OP_CALLOUT:
+ case OP_CALLOUT_STR:
case OP_FAIL:
case OP_ACCEPT:
case OP_ASSERT_ACCEPT:
@@ -10656,9 +10703,9 @@ common->then_trap = save_then_trap;
static SLJIT_INLINE void compile_recurse(compiler_common *common)
{
DEFINE_COMPILER;
-pcre_uchar *cc = common->start + common->currententry->start;
-pcre_uchar *ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : IMM2_SIZE);
-pcre_uchar *ccend = bracketend(cc) - (1 + LINK_SIZE);
+PCRE2_SPTR cc = common->start + common->currententry->start;
+PCRE2_SPTR ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : IMM2_SIZE);
+PCRE2_SPTR ccend = bracketend(cc) - (1 + LINK_SIZE);
BOOL needs_control_head;
int framesize = get_framesize(common, cc, NULL, TRUE, &needs_control_head);
int private_data_size = get_private_data_copy_length(common, ccbegin, ccend, needs_control_head);
@@ -10781,17 +10828,17 @@ sljit_emit_fast_return(compiler, SLJIT_MEM1(STACK_TOP), 0);
#undef COMPILE_BACKTRACKINGPATH
#undef CURRENT_AS
-void
-PRIV(jit_compile)(const REAL_PCRE *re, PUBL(extra) *extra, int mode)
+static int jit_compile(pcre2_code *code, sljit_u32 mode)
{
+pcre2_real_code *re = (pcre2_real_code *)code;
struct sljit_compiler *compiler;
backtrack_common rootbacktrack;
compiler_common common_data;
compiler_common *common = &common_data;
const sljit_u8 *tables = re->tables;
-pcre_study_data *study;
+void *allocator_data = &re->memctl;
int private_data_size;
-pcre_uchar *ccend;
+PCRE2_SPTR ccend;
executable_functions *functions;
void *executable_func;
sljit_uw executable_size;
@@ -10808,48 +10855,35 @@ struct sljit_jump *minlength_check_failed = NULL;
struct sljit_jump *reqbyte_notfound = NULL;
struct sljit_jump *empty_match = NULL;
-SLJIT_ASSERT((extra->flags & PCRE_EXTRA_STUDY_DATA) != 0);
-study = extra->study_data;
-
-if (!tables)
- tables = PRIV(default_tables);
+SLJIT_ASSERT(tables);
memset(&rootbacktrack, 0, sizeof(backtrack_common));
memset(common, 0, sizeof(compiler_common));
-rootbacktrack.cc = (pcre_uchar *)re + re->name_table_offset + re->name_count * re->name_entry_size;
+common->name_table = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code));
+rootbacktrack.cc = common->name_table + re->name_count * re->name_entry_size;
common->start = rootbacktrack.cc;
common->read_only_data_head = NULL;
common->fcc = tables + fcc_offset;
common->lcc = (sljit_sw)(tables + lcc_offset);
common->mode = mode;
-common->might_be_empty = study->minlength == 0;
+common->might_be_empty = re->minlength == 0;
common->nltype = NLTYPE_FIXED;
-switch(re->options & PCRE_NEWLINE_BITS)
+switch(re->newline_convention)
{
- case 0:
- /* Compile-time default */
- switch(NEWLINE)
- {
- case -1: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break;
- case -2: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break;
- default: common->newline = NEWLINE; break;
- }
- break;
- case PCRE_NEWLINE_CR: common->newline = CHAR_CR; break;
- case PCRE_NEWLINE_LF: common->newline = CHAR_NL; break;
- case PCRE_NEWLINE_CR+
- PCRE_NEWLINE_LF: common->newline = (CHAR_CR << 8) | CHAR_NL; break;
- case PCRE_NEWLINE_ANY: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break;
- case PCRE_NEWLINE_ANYCRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break;
- default: return;
+ case PCRE2_NEWLINE_CR: common->newline = CHAR_CR; break;
+ case PCRE2_NEWLINE_LF: common->newline = CHAR_NL; break;
+ case PCRE2_NEWLINE_CRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; break;
+ case PCRE2_NEWLINE_ANY: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break;
+ case PCRE2_NEWLINE_ANYCRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break;
+ default: return PCRE2_ERROR_INTERNAL;
}
common->nlmax = READ_CHAR_MAX;
common->nlmin = 0;
-if ((re->options & PCRE_BSR_ANYCRLF) != 0)
- common->bsr_nltype = NLTYPE_ANYCRLF;
-else if ((re->options & PCRE_BSR_UNICODE) != 0)
+if (re->bsr_convention == PCRE2_BSR_UNICODE)
common->bsr_nltype = NLTYPE_ANY;
+else if (re->bsr_convention == PCRE2_BSR_ANYCRLF)
+ common->bsr_nltype = NLTYPE_ANYCRLF;
else
{
#ifdef BSR_ANYCRLF
@@ -10860,18 +10894,16 @@ else
}
common->bsr_nlmax = READ_CHAR_MAX;
common->bsr_nlmin = 0;
-common->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
+common->endonly = (re->overall_options & PCRE2_DOLLAR_ENDONLY) != 0;
common->ctypes = (sljit_sw)(tables + ctypes_offset);
-common->name_table = ((pcre_uchar *)re) + re->name_table_offset;
common->name_count = re->name_count;
common->name_entry_size = re->name_entry_size;
-common->jscript_compat = (re->options & PCRE_JAVASCRIPT_COMPAT) != 0;
-#ifdef SUPPORT_UTF
+common->unset_backref = (re->overall_options & PCRE2_MATCH_UNSET_BACKREF) != 0;
+common->alt_circumflex = (re->overall_options & PCRE2_ALT_CIRCUMFLEX) != 0;
+#ifdef SUPPORT_UNICODE
/* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */
-common->utf = (re->options & PCRE_UTF8) != 0;
-#ifdef SUPPORT_UCP
-common->use_ucp = (re->options & PCRE_UCP) != 0;
-#endif
+common->utf = (re->overall_options & PCRE2_UTF) != 0;
+common->use_ucp = (re->overall_options & PCRE2_UCP) != 0;
if (common->utf)
{
if (common->nltype == NLTYPE_ANY)
@@ -10895,14 +10927,14 @@ if (common->utf)
common->bsr_nlmax = (CHAR_CR > CHAR_NL) ? CHAR_CR : CHAR_NL;
common->bsr_nlmin = (CHAR_CR < CHAR_NL) ? CHAR_CR : CHAR_NL;
}
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
ccend = bracketend(common->start);
/* Calculate the local space size on the stack. */
common->ovector_start = LIMIT_MATCH + sizeof(sljit_sw);
-common->optimized_cbracket = (sljit_u8 *)SLJIT_MALLOC(re->top_bracket + 1, compiler->allocator_data);
+common->optimized_cbracket = (sljit_u8 *)SLJIT_MALLOC(re->top_bracket + 1, allocator_data);
if (!common->optimized_cbracket)
- return;
+ return PCRE2_ERROR_NOMEMORY;
#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 1
memset(common->optimized_cbracket, 0, re->top_bracket + 1);
#else
@@ -10916,27 +10948,27 @@ common->ovector_start += sizeof(sljit_sw);
#endif
if (!check_opcode_types(common, common->start, ccend))
{
- SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data);
- return;
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
}
/* Checking flags and updating ovector_start. */
-if (mode == JIT_COMPILE && (re->flags & PCRE_REQCHSET) != 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0)
+if (mode == PCRE2_JIT_COMPLETE && (re->flags & PCRE2_LASTSET) != 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
{
common->req_char_ptr = common->ovector_start;
common->ovector_start += sizeof(sljit_sw);
}
-if (mode != JIT_COMPILE)
+if (mode != PCRE2_JIT_COMPLETE)
{
common->start_used_ptr = common->ovector_start;
common->ovector_start += sizeof(sljit_sw);
- if (mode == JIT_PARTIAL_SOFT_COMPILE)
+ if (mode == PCRE2_JIT_PARTIAL_SOFT)
{
common->hit_start = common->ovector_start;
- common->ovector_start += 2 * sizeof(sljit_sw);
+ common->ovector_start += sizeof(sljit_sw);
}
}
-if ((re->options & PCRE_FIRSTLINE) != 0)
+if ((re->overall_options & (PCRE2_FIRSTLINE | PCRE2_USE_OFFSET_LIMIT)) != 0)
{
common->match_end_ptr = common->ovector_start;
common->ovector_start += sizeof(sljit_sw);
@@ -10971,17 +11003,17 @@ SLJIT_ASSERT(!(common->req_char_ptr != 0 && common->start_used_ptr != 0));
common->cbra_ptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_sw);
total_length = ccend - common->start;
-common->private_data_ptrs = (sljit_s32 *)SLJIT_MALLOC(total_length * (sizeof(sljit_s32) + (common->has_then ? 1 : 0)), compiler->allocator_data);
+common->private_data_ptrs = (sljit_s32 *)SLJIT_MALLOC(total_length * (sizeof(sljit_s32) + (common->has_then ? 1 : 0)), allocator_data);
if (!common->private_data_ptrs)
{
- SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data);
- return;
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
}
memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32));
private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw);
set_private_data_ptrs(common, &private_data_size, ccend);
-if ((re->options & PCRE_ANCHORED) == 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0)
+if ((re->overall_options & PCRE2_ANCHORED) == 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
{
if (!detect_fast_forward_skip(common, &private_data_size) && !common->has_skip_in_assert_back)
detect_fast_fail(common, common->start, &private_data_size, 4);
@@ -10991,9 +11023,9 @@ SLJIT_ASSERT(common->fast_fail_start_ptr <= common->fast_fail_end_ptr);
if (private_data_size > SLJIT_MAX_LOCAL_SIZE)
{
- SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data);
- SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data);
- return;
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
}
if (common->has_then)
@@ -11003,12 +11035,12 @@ if (common->has_then)
set_then_offsets(common, common->start, NULL);
}
-compiler = sljit_create_compiler(NULL);
+compiler = sljit_create_compiler(allocator_data);
if (!compiler)
{
- SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data);
- SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data);
- return;
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
}
common->compiler = compiler;
@@ -11034,7 +11066,7 @@ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0);
if (common->fast_fail_start_ptr < common->fast_fail_end_ptr)
reset_fast_fail(common);
-if (mode == JIT_PARTIAL_SOFT_COMPILE)
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1);
if (common->mark_ptr != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, SLJIT_IMM, 0);
@@ -11042,41 +11074,41 @@ if (common->control_head_ptr != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
/* Main part of the matching */
-if ((re->options & PCRE_ANCHORED) == 0)
+if ((re->overall_options & PCRE2_ANCHORED) == 0)
{
- mainloop_label = mainloop_entry(common, (re->flags & PCRE_HASCRORLF) != 0);
+ mainloop_label = mainloop_entry(common, (re->flags & PCRE2_HASCRORLF) != 0, re->overall_options);
continue_match_label = LABEL();
/* Forward search if possible. */
- if ((re->options & PCRE_NO_START_OPTIMIZE) == 0)
+ if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
{
- if (mode == JIT_COMPILE && fast_forward_first_n_chars(common))
+ if (mode == PCRE2_JIT_COMPLETE && fast_forward_first_n_chars(common))
;
- else if ((re->flags & PCRE_FIRSTSET) != 0)
- fast_forward_first_char(common, (pcre_uchar)re->first_char, (re->flags & PCRE_FCH_CASELESS) != 0);
- else if ((re->flags & PCRE_STARTLINE) != 0)
+ else if ((re->flags & PCRE2_FIRSTSET) != 0)
+ fast_forward_first_char(common, (PCRE2_UCHAR)(re->first_codeunit), (re->flags & PCRE2_FIRSTCASELESS) != 0);
+ else if ((re->flags & PCRE2_STARTLINE) != 0)
fast_forward_newline(common);
- else if (study != NULL && (study->flags & PCRE_STUDY_MAPPED) != 0)
- fast_forward_start_bits(common, study->start_bits);
+ else if ((re->flags & PCRE2_FIRSTMAPSET) != 0)
+ fast_forward_start_bits(common, re->start_bitmap);
}
}
else
continue_match_label = LABEL();
-if (mode == JIT_COMPILE && study->minlength > 0 && (re->options & PCRE_NO_START_OPTIMIZE) == 0)
+if (mode == PCRE2_JIT_COMPLETE && re->minlength > 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
{
- OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH);
- OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(study->minlength));
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(re->minlength));
minlength_check_failed = CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0);
}
if (common->req_char_ptr != 0)
- reqbyte_notfound = search_requested_char(common, (pcre_uchar)re->req_char, (re->flags & PCRE_RCH_CASELESS) != 0, (re->flags & PCRE_FIRSTSET) != 0);
+ reqbyte_notfound = search_requested_char(common, (PCRE2_UCHAR)(re->last_codeunit), (re->flags & PCRE2_LASTCASELESS) != 0, (re->flags & PCRE2_FIRSTSET) != 0);
/* Store the current STR_PTR in OVECTOR(0). */
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), STR_PTR, 0);
/* Copy the limit of allowed recursions. */
OP1(SLJIT_MOV, COUNT_MATCH, 0, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH);
if (common->capture_last_ptr != 0)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, -1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, 0);
if (common->fast_forward_bc_ptr != NULL)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), PRIVATE_DATA(common->fast_forward_bc_ptr + 1), STR_PTR, 0);
@@ -11084,24 +11116,23 @@ if (common->start_ptr != OVECTOR(0))
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_ptr, STR_PTR, 0);
/* Copy the beginning of the string. */
-if (mode == JIT_PARTIAL_SOFT_COMPILE)
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
{
jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start + sizeof(sljit_sw), STR_PTR, 0);
JUMPHERE(jump);
}
-else if (mode == JIT_PARTIAL_HARD_COMPILE)
+else if (mode == PCRE2_JIT_PARTIAL_HARD)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
compile_matchingpath(common, common->start, ccend, &rootbacktrack);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
{
sljit_free_compiler(compiler);
- SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data);
- SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data);
- free_read_only_data(common->read_only_data_head, compiler->allocator_data);
- return;
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
}
if (common->might_be_empty)
@@ -11125,7 +11156,7 @@ if (minlength_check_failed != NULL)
SET_LABEL(minlength_check_failed, common->forced_quit_label);
sljit_emit_return(compiler, SLJIT_MOV, SLJIT_RETURN_REG, 0);
-if (mode != JIT_COMPILE)
+if (mode != PCRE2_JIT_COMPLETE)
{
common->partialmatchlabel = LABEL();
set_jumps(common->partialmatch, common->partialmatchlabel);
@@ -11138,55 +11169,64 @@ compile_backtrackingpath(common, rootbacktrack.top);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
{
sljit_free_compiler(compiler);
- SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data);
- SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data);
- free_read_only_data(common->read_only_data_head, compiler->allocator_data);
- return;
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
}
SLJIT_ASSERT(rootbacktrack.prev == NULL);
reset_match_label = LABEL();
-if (mode == JIT_PARTIAL_SOFT_COMPILE)
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
{
/* Update hit_start only in the first time. */
jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, TMP1, 0);
JUMPHERE(jump);
}
/* Check we have remaining characters. */
-if ((re->options & PCRE_ANCHORED) == 0 && (re->options & PCRE_FIRSTLINE) != 0)
+if ((re->overall_options & PCRE2_ANCHORED) == 0 && common->match_end_ptr != 0)
{
- SLJIT_ASSERT(common->match_end_ptr != 0);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
}
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP),
(common->fast_forward_bc_ptr != NULL) ? (PRIVATE_DATA(common->fast_forward_bc_ptr + 1)) : common->start_ptr);
-if ((re->options & PCRE_ANCHORED) == 0)
+if ((re->overall_options & PCRE2_ANCHORED) == 0)
{
if (common->ff_newline_shortcut != NULL)
{
- if ((re->options & PCRE_FIRSTLINE) == 0)
- CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, common->ff_newline_shortcut);
- /* There cannot be more newlines here. */
+ /* There cannot be more newlines if PCRE2_FIRSTLINE is set. */
+ if ((re->overall_options & PCRE2_FIRSTLINE) == 0)
+ {
+ if (common->match_end_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+ OP1(SLJIT_MOV, STR_END, 0, TMP1, 0);
+ CMPTO(SLJIT_LESS, STR_PTR, 0, TMP1, 0, common->ff_newline_shortcut);
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+ }
+ else
+ CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, common->ff_newline_shortcut);
+ }
}
else
- CMPTO(SLJIT_LESS, STR_PTR, 0, ((re->options & PCRE_FIRSTLINE) == 0) ? STR_END : TMP1, 0, mainloop_label);
+ CMPTO(SLJIT_LESS, STR_PTR, 0, (common->match_end_ptr == 0) ? STR_END : TMP1, 0, mainloop_label);
}
/* No more remaining characters. */
if (reqbyte_notfound != NULL)
JUMPHERE(reqbyte_notfound);
-if (mode == JIT_PARTIAL_SOFT_COMPILE)
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1, common->partialmatchlabel);
-OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_NOMATCH);
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
JUMPTO(SLJIT_JUMP, common->quit_label);
flush_stubs(common);
@@ -11195,10 +11235,11 @@ if (common->might_be_empty)
{
JUMPHERE(empty_match);
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty));
- CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_backtrack_label);
- OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, notempty_atstart));
- CMPTO(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0, empty_match_found_label);
+ OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options));
+ OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY);
+ JUMPTO(SLJIT_NOT_ZERO, empty_match_backtrack_label);
+ OP2(SLJIT_AND | SLJIT_SET_E, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART);
+ JUMPTO(SLJIT_ZERO, empty_match_found_label);
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found_label);
JUMPTO(SLJIT_JUMP, empty_match_backtrack_label);
@@ -11217,10 +11258,10 @@ while (common->currententry != NULL)
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
{
sljit_free_compiler(compiler);
- SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data);
- SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data);
- free_read_only_data(common->read_only_data_head, compiler->allocator_data);
- return;
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
}
flush_stubs(common);
common->currententry = common->currententry->next;
@@ -11251,12 +11292,12 @@ sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
/* Allocation failed. */
JUMPHERE(jump);
/* We break the return address cache here, but this is a really rare case. */
-OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_JIT_STACKLIMIT);
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_JIT_STACKLIMIT);
JUMPTO(SLJIT_JUMP, common->quit_label);
/* Call limit reached. */
set_jumps(common->calllimit, LABEL());
-OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE_ERROR_MATCHLIMIT);
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_MATCHLIMIT);
JUMPTO(SLJIT_JUMP, common->quit_label);
if (common->revertframes != NULL)
@@ -11302,8 +11343,8 @@ if (common->reset_match != NULL)
OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0);
JUMPTO(SLJIT_JUMP, reset_match_label);
}
-#ifdef SUPPORT_UTF
-#ifdef COMPILE_PCRE8
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
if (common->utfreadchar != NULL)
{
set_jumps(common->utfreadchar, LABEL());
@@ -11319,18 +11360,16 @@ if (common->utfreadtype8 != NULL)
set_jumps(common->utfreadtype8, LABEL());
do_utfreadtype8(common);
}
-#endif /* COMPILE_PCRE8 */
-#endif /* SUPPORT_UTF */
-#ifdef SUPPORT_UCP
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
if (common->getucd != NULL)
{
set_jumps(common->getucd, LABEL());
do_getucd(common);
}
-#endif
+#endif /* SUPPORT_UNICODE */
-SLJIT_FREE(common->optimized_cbracket, compiler->allocator_data);
-SLJIT_FREE(common->private_data_ptrs, compiler->allocator_data);
+SLJIT_FREE(common->optimized_cbracket, allocator_data);
+SLJIT_FREE(common->private_data_ptrs, allocator_data);
executable_func = sljit_generate_code(compiler);
executable_size = sljit_get_generated_code_size(compiler);
@@ -11343,384 +11382,120 @@ while (label_addr != NULL)
sljit_free_compiler(compiler);
if (executable_func == NULL)
{
- free_read_only_data(common->read_only_data_head, compiler->allocator_data);
- return;
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
}
/* Reuse the function descriptor if possible. */
-if ((extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 && extra->executable_jit != NULL)
- functions = (executable_functions *)extra->executable_jit;
+if (re->executable_jit != NULL)
+ functions = (executable_functions *)re->executable_jit;
else
{
- /* Note: If your memory-checker has flagged the allocation below as a
- * memory leak, it is probably because you either forgot to call
- * pcre_free_study() (or pcre16_free_study()) on the pcre_extra (or
- * pcre16_extra) object, or you called said function after having
- * cleared the PCRE_EXTRA_EXECUTABLE_JIT bit from the "flags" field
- * of the object. (The function will only free the JIT data if the
- * bit remains set, as the bit indicates that the pointer to the data
- * is valid.)
- */
- functions = SLJIT_MALLOC(sizeof(executable_functions), compiler->allocator_data);
+ functions = SLJIT_MALLOC(sizeof(executable_functions), allocator_data);
if (functions == NULL)
{
/* This case is highly unlikely since we just recently
freed a lot of memory. Not impossible though. */
sljit_free_code(executable_func);
- free_read_only_data(common->read_only_data_head, compiler->allocator_data);
- return;
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
}
memset(functions, 0, sizeof(executable_functions));
- functions->top_bracket = (re->top_bracket + 1) * 2;
- functions->limit_match = (re->flags & PCRE_MLSET) != 0 ? re->limit_match : 0;
- extra->executable_jit = functions;
- extra->flags |= PCRE_EXTRA_EXECUTABLE_JIT;
+ functions->top_bracket = re->top_bracket + 1;
+ functions->limit_match = re->limit_match;
+ re->executable_jit = functions;
}
+/* Turn mode into an index. */
+if (mode == PCRE2_JIT_COMPLETE)
+ mode = 0;
+else
+ mode = (mode == PCRE2_JIT_PARTIAL_SOFT) ? 1 : 2;
+
+SLJIT_ASSERT(mode < JIT_NUMBER_OF_COMPILE_MODES);
functions->executable_funcs[mode] = executable_func;
functions->read_only_data_heads[mode] = common->read_only_data_head;
functions->executable_sizes[mode] = executable_size;
+return 0;
}
-static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, void *executable_func)
-{
-union {
- void *executable_func;
- jit_function call_executable_func;
-} convert_executable_func;
-sljit_u8 local_space[MACHINE_STACK_SIZE];
-struct sljit_stack local_stack;
-
-local_stack.top = (sljit_sw)&local_space;
-local_stack.base = local_stack.top;
-local_stack.limit = local_stack.base + MACHINE_STACK_SIZE;
-local_stack.max_limit = local_stack.limit;
-arguments->stack = &local_stack;
-convert_executable_func.executable_func = executable_func;
-return convert_executable_func.call_executable_func(arguments);
-}
+#endif
-int
-PRIV(jit_exec)(const PUBL(extra) *extra_data, const pcre_uchar *subject,
- int length, int start_offset, int options, int *offsets, int offset_count)
-{
-executable_functions *functions = (executable_functions *)extra_data->executable_jit;
-union {
- void *executable_func;
- jit_function call_executable_func;
-} convert_executable_func;
-jit_arguments arguments;
-int max_offset_count;
-int retval;
-int mode = JIT_COMPILE;
-
-if ((options & PCRE_PARTIAL_HARD) != 0)
- mode = JIT_PARTIAL_HARD_COMPILE;
-else if ((options & PCRE_PARTIAL_SOFT) != 0)
- mode = JIT_PARTIAL_SOFT_COMPILE;
-
-if (functions->executable_funcs[mode] == NULL)
- return PCRE_ERROR_JIT_BADOPTION;
-
-/* Sanity checks should be handled by pcre_exec. */
-arguments.str = subject + start_offset;
-arguments.begin = subject;
-arguments.end = subject + length;
-arguments.mark_ptr = NULL;
-/* JIT decreases this value less frequently than the interpreter. */
-arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (sljit_u32)(extra_data->match_limit);
-if (functions->limit_match != 0 && functions->limit_match < arguments.limit_match)
- arguments.limit_match = functions->limit_match;
-arguments.notbol = (options & PCRE_NOTBOL) != 0;
-arguments.noteol = (options & PCRE_NOTEOL) != 0;
-arguments.notempty = (options & PCRE_NOTEMPTY) != 0;
-arguments.notempty_atstart = (options & PCRE_NOTEMPTY_ATSTART) != 0;
-arguments.offsets = offsets;
-arguments.callout_data = (extra_data->flags & PCRE_EXTRA_CALLOUT_DATA) != 0 ? extra_data->callout_data : NULL;
-arguments.real_offset_count = offset_count;
-
-/* pcre_exec() rounds offset_count to a multiple of 3, and then uses only 2/3 of
-the output vector for storing captured strings, with the remainder used as
-workspace. We don't need the workspace here. For compatibility, we limit the
-number of captured strings in the same way as pcre_exec(), so that the user
-gets the same result with and without JIT. */
-
-if (offset_count != 2)
- offset_count = ((offset_count - (offset_count % 3)) * 2) / 3;
-max_offset_count = functions->top_bracket;
-if (offset_count > max_offset_count)
- offset_count = max_offset_count;
-arguments.offset_count = offset_count;
-
-if (functions->callback)
- arguments.stack = (struct sljit_stack *)functions->callback(functions->userdata);
-else
- arguments.stack = (struct sljit_stack *)functions->userdata;
+/*************************************************
+* JIT compile a Regular Expression *
+*************************************************/
-if (arguments.stack == NULL)
- retval = jit_machine_stack_exec(&arguments, functions->executable_funcs[mode]);
-else
- {
- convert_executable_func.executable_func = functions->executable_funcs[mode];
- retval = convert_executable_func.call_executable_func(&arguments);
- }
+/* This function used JIT to convert a previously-compiled pattern into machine
+code.
-if (retval * 2 > offset_count)
- retval = 0;
-if ((extra_data->flags & PCRE_EXTRA_MARK) != 0)
- *(extra_data->mark) = arguments.mark_ptr;
+Arguments:
+ code a compiled pattern
+ options JIT option bits
-return retval;
-}
+Returns: 0: success or (*NOJIT) was used
+ <0: an error code
+*/
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_jit_exec(const pcre *argument_re, const pcre_extra *extra_data,
- PCRE_SPTR subject, int length, int start_offset, int options,
- int *offsets, int offset_count, pcre_jit_stack *stack)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_jit_exec(const pcre16 *argument_re, const pcre16_extra *extra_data,
- PCRE_SPTR16 subject, int length, int start_offset, int options,
- int *offsets, int offset_count, pcre16_jit_stack *stack)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_jit_exec(const pcre32 *argument_re, const pcre32_extra *extra_data,
- PCRE_SPTR32 subject, int length, int start_offset, int options,
- int *offsets, int offset_count, pcre32_jit_stack *stack)
-#endif
-{
-pcre_uchar *subject_ptr = (pcre_uchar *)subject;
-executable_functions *functions = (executable_functions *)extra_data->executable_jit;
-union {
- void *executable_func;
- jit_function call_executable_func;
-} convert_executable_func;
-jit_arguments arguments;
-int max_offset_count;
-int retval;
-int mode = JIT_COMPILE;
-
-SLJIT_UNUSED_ARG(argument_re);
-
-/* Plausibility checks */
-if ((options & ~PUBLIC_JIT_EXEC_OPTIONS) != 0) return PCRE_ERROR_JIT_BADOPTION;
-
-if ((options & PCRE_PARTIAL_HARD) != 0)
- mode = JIT_PARTIAL_HARD_COMPILE;
-else if ((options & PCRE_PARTIAL_SOFT) != 0)
- mode = JIT_PARTIAL_SOFT_COMPILE;
-
-if (functions->executable_funcs[mode] == NULL)
- return PCRE_ERROR_JIT_BADOPTION;
-
-/* Sanity checks should be handled by pcre_exec. */
-arguments.stack = (struct sljit_stack *)stack;
-arguments.str = subject_ptr + start_offset;
-arguments.begin = subject_ptr;
-arguments.end = subject_ptr + length;
-arguments.mark_ptr = NULL;
-/* JIT decreases this value less frequently than the interpreter. */
-arguments.limit_match = ((extra_data->flags & PCRE_EXTRA_MATCH_LIMIT) == 0) ? MATCH_LIMIT : (sljit_u32)(extra_data->match_limit);
-if (functions->limit_match != 0 && functions->limit_match < arguments.limit_match)
- arguments.limit_match = functions->limit_match;
-arguments.notbol = (options & PCRE_NOTBOL) != 0;
-arguments.noteol = (options & PCRE_NOTEOL) != 0;
-arguments.notempty = (options & PCRE_NOTEMPTY) != 0;
-arguments.notempty_atstart = (options & PCRE_NOTEMPTY_ATSTART) != 0;
-arguments.offsets = offsets;
-arguments.callout_data = (extra_data->flags & PCRE_EXTRA_CALLOUT_DATA) != 0 ? extra_data->callout_data : NULL;
-arguments.real_offset_count = offset_count;
-
-/* pcre_exec() rounds offset_count to a multiple of 3, and then uses only 2/3 of
-the output vector for storing captured strings, with the remainder used as
-workspace. We don't need the workspace here. For compatibility, we limit the
-number of captured strings in the same way as pcre_exec(), so that the user
-gets the same result with and without JIT. */
-
-if (offset_count != 2)
- offset_count = ((offset_count - (offset_count % 3)) * 2) / 3;
-max_offset_count = functions->top_bracket;
-if (offset_count > max_offset_count)
- offset_count = max_offset_count;
-arguments.offset_count = offset_count;
-
-convert_executable_func.executable_func = functions->executable_funcs[mode];
-retval = convert_executable_func.call_executable_func(&arguments);
-
-if (retval * 2 > offset_count)
- retval = 0;
-if ((extra_data->flags & PCRE_EXTRA_MARK) != 0)
- *(extra_data->mark) = arguments.mark_ptr;
-
-return retval;
-}
+#define PUBLIC_JIT_COMPILE_OPTIONS \
+ (PCRE2_JIT_COMPLETE|PCRE2_JIT_PARTIAL_SOFT|PCRE2_JIT_PARTIAL_HARD)
-void
-PRIV(jit_free)(void *executable_funcs)
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_jit_compile(pcre2_code *code, uint32_t options)
{
-int i;
-executable_functions *functions = (executable_functions *)executable_funcs;
-for (i = 0; i < JIT_NUMBER_OF_COMPILE_MODES; i++)
- {
- if (functions->executable_funcs[i] != NULL)
- sljit_free_code(functions->executable_funcs[i]);
- free_read_only_data(functions->read_only_data_heads[i], NULL);
- }
-SLJIT_FREE(functions, compiler->allocator_data);
-}
+#ifndef SUPPORT_JIT
-int
-PRIV(jit_get_size)(void *executable_funcs)
-{
-int i;
-sljit_uw size = 0;
-sljit_uw *executable_sizes = ((executable_functions *)executable_funcs)->executable_sizes;
-for (i = 0; i < JIT_NUMBER_OF_COMPILE_MODES; i++)
- size += executable_sizes[i];
-return (int)size;
-}
+(void)code;
+(void)options;
+return PCRE2_ERROR_JIT_BADOPTION;
-const char*
-PRIV(jit_get_target)(void)
-{
-return sljit_get_platform_name();
-}
+#else /* SUPPORT_JIT */
-#if defined COMPILE_PCRE8
-PCRE_EXP_DECL pcre_jit_stack *
-pcre_jit_stack_alloc(int startsize, int maxsize)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DECL pcre16_jit_stack *
-pcre16_jit_stack_alloc(int startsize, int maxsize)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DECL pcre32_jit_stack *
-pcre32_jit_stack_alloc(int startsize, int maxsize)
-#endif
-{
-if (startsize < 1 || maxsize < 1)
- return NULL;
-if (startsize > maxsize)
- startsize = maxsize;
-startsize = (startsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
-maxsize = (maxsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
-return (PUBL(jit_stack)*)sljit_allocate_stack(startsize, maxsize, NULL);
-}
+pcre2_real_code *re = (pcre2_real_code *)code;
+executable_functions *functions;
+int result;
-#if defined COMPILE_PCRE8
-PCRE_EXP_DECL void
-pcre_jit_stack_free(pcre_jit_stack *stack)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DECL void
-pcre16_jit_stack_free(pcre16_jit_stack *stack)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DECL void
-pcre32_jit_stack_free(pcre32_jit_stack *stack)
-#endif
-{
-sljit_free_stack((struct sljit_stack *)stack, NULL);
-}
+if (code == NULL)
+ return PCRE2_ERROR_NULL;
-#if defined COMPILE_PCRE8
-PCRE_EXP_DECL void
-pcre_assign_jit_stack(pcre_extra *extra, pcre_jit_callback callback, void *userdata)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DECL void
-pcre16_assign_jit_stack(pcre16_extra *extra, pcre16_jit_callback callback, void *userdata)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DECL void
-pcre32_assign_jit_stack(pcre32_extra *extra, pcre32_jit_callback callback, void *userdata)
-#endif
-{
-executable_functions *functions;
-if (extra != NULL &&
- (extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 &&
- extra->executable_jit != NULL)
- {
- functions = (executable_functions *)extra->executable_jit;
- functions->callback = callback;
- functions->userdata = userdata;
- }
-}
+if ((options & ~PUBLIC_JIT_COMPILE_OPTIONS) != 0)
+ return PCRE2_ERROR_JIT_BADOPTION;
-#if defined COMPILE_PCRE8
-PCRE_EXP_DECL void
-pcre_jit_free_unused_memory(void)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DECL void
-pcre16_jit_free_unused_memory(void)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DECL void
-pcre32_jit_free_unused_memory(void)
-#endif
-{
-sljit_free_unused_memory_exec();
-}
+if ((re->flags & PCRE2_NOJIT) != 0) return 0;
-#else /* SUPPORT_JIT */
+functions = (executable_functions *)re->executable_jit;
-/* These are dummy functions to avoid linking errors when JIT support is not
-being compiled. */
+if ((options & PCRE2_JIT_COMPLETE) != 0 && (functions == NULL
+ || functions->executable_funcs[0] == NULL)) {
+ result = jit_compile(code, PCRE2_JIT_COMPLETE);
+ if (result != 0)
+ return result;
+ }
-#if defined COMPILE_PCRE8
-PCRE_EXP_DECL pcre_jit_stack *
-pcre_jit_stack_alloc(int startsize, int maxsize)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DECL pcre16_jit_stack *
-pcre16_jit_stack_alloc(int startsize, int maxsize)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DECL pcre32_jit_stack *
-pcre32_jit_stack_alloc(int startsize, int maxsize)
-#endif
-{
-(void)startsize;
-(void)maxsize;
-return NULL;
-}
+if ((options & PCRE2_JIT_PARTIAL_SOFT) != 0 && (functions == NULL
+ || functions->executable_funcs[1] == NULL)) {
+ result = jit_compile(code, PCRE2_JIT_PARTIAL_SOFT);
+ if (result != 0)
+ return result;
+ }
-#if defined COMPILE_PCRE8
-PCRE_EXP_DECL void
-pcre_jit_stack_free(pcre_jit_stack *stack)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DECL void
-pcre16_jit_stack_free(pcre16_jit_stack *stack)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DECL void
-pcre32_jit_stack_free(pcre32_jit_stack *stack)
-#endif
-{
-(void)stack;
-}
+if ((options & PCRE2_JIT_PARTIAL_HARD) != 0 && (functions == NULL
+ || functions->executable_funcs[2] == NULL)) {
+ result = jit_compile(code, PCRE2_JIT_PARTIAL_HARD);
+ if (result != 0)
+ return result;
+ }
-#if defined COMPILE_PCRE8
-PCRE_EXP_DECL void
-pcre_assign_jit_stack(pcre_extra *extra, pcre_jit_callback callback, void *userdata)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DECL void
-pcre16_assign_jit_stack(pcre16_extra *extra, pcre16_jit_callback callback, void *userdata)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DECL void
-pcre32_assign_jit_stack(pcre32_extra *extra, pcre32_jit_callback callback, void *userdata)
-#endif
-{
-(void)extra;
-(void)callback;
-(void)userdata;
-}
+return 0;
-#if defined COMPILE_PCRE8
-PCRE_EXP_DECL void
-pcre_jit_free_unused_memory(void)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DECL void
-pcre16_jit_free_unused_memory(void)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DECL void
-pcre32_jit_free_unused_memory(void)
-#endif
-{
+#endif /* SUPPORT_JIT */
}
-#endif
+/* JIT compiler uses an all-in-one approach. This improves security,
+ since the code generator functions are not exported. */
+
+#define INCLUDED_FROM_PCRE2_JIT_COMPILE
+
+#include "pcre2_jit_match.c"
+#include "pcre2_jit_misc.c"
-/* End of pcre_jit_compile.c */
+/* End of pcre2_jit_compile.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_jit_match.c b/src/3rdparty/pcre2/src/pcre2_jit_match.c
new file mode 100644
index 0000000000..a323971ff3
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_jit_match.c
@@ -0,0 +1,189 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef INCLUDED_FROM_PCRE2_JIT_COMPILE
+#error This file must be included from pcre2_jit_compile.c.
+#endif
+
+#ifdef SUPPORT_JIT
+
+static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, jit_function executable_func)
+{
+sljit_u8 local_space[MACHINE_STACK_SIZE];
+struct sljit_stack local_stack;
+
+local_stack.top = (sljit_sw)&local_space;
+local_stack.base = local_stack.top;
+local_stack.limit = local_stack.base + MACHINE_STACK_SIZE;
+local_stack.max_limit = local_stack.limit;
+arguments->stack = &local_stack;
+return executable_func(arguments);
+}
+
+#endif
+
+
+/*************************************************
+* Do a JIT pattern match *
+*************************************************/
+
+/* This function runs a JIT pattern match.
+
+Arguments:
+ code points to the compiled expression
+ subject points to the subject string
+ length length of subject string (may contain binary zeros)
+ start_offset where to start in the subject string
+ options option bits
+ match_data points to a match_data block
+ mcontext points to a match context
+ jit_stack points to a JIT stack
+
+Returns: > 0 => success; value is the number of ovector pairs filled
+ = 0 => success, but ovector is not big enough
+ -1 => failed to match (PCRE_ERROR_NOMATCH)
+ < -1 => some kind of unexpected problem
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_jit_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+ PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+ pcre2_match_context *mcontext)
+{
+#ifndef SUPPORT_JIT
+
+(void)code;
+(void)subject;
+(void)length;
+(void)start_offset;
+(void)options;
+(void)match_data;
+(void)mcontext;
+return PCRE2_ERROR_JIT_BADOPTION;
+
+#else /* SUPPORT_JIT */
+
+pcre2_real_code *re = (pcre2_real_code *)code;
+executable_functions *functions = (executable_functions *)re->executable_jit;
+pcre2_jit_stack *jit_stack;
+uint32_t oveccount = match_data->oveccount;
+uint32_t max_oveccount;
+union {
+ void *executable_func;
+ jit_function call_executable_func;
+} convert_executable_func;
+jit_arguments arguments;
+int rc;
+int index = 0;
+
+if ((options & PCRE2_PARTIAL_HARD) != 0)
+ index = 2;
+else if ((options & PCRE2_PARTIAL_SOFT) != 0)
+ index = 1;
+
+if (functions->executable_funcs[index] == NULL)
+ return PCRE2_ERROR_JIT_BADOPTION;
+
+/* Sanity checks should be handled by pcre_exec. */
+arguments.str = subject + start_offset;
+arguments.begin = subject;
+arguments.end = subject + length;
+arguments.match_data = match_data;
+arguments.startchar_ptr = subject;
+arguments.mark_ptr = NULL;
+arguments.options = options;
+
+if (mcontext != NULL)
+ {
+ arguments.callout = mcontext->callout;
+ arguments.callout_data = mcontext->callout_data;
+ arguments.offset_limit = mcontext->offset_limit;
+ arguments.limit_match = (mcontext->match_limit < re->limit_match)?
+ mcontext->match_limit : re->limit_match;
+ if (mcontext->jit_callback != NULL)
+ jit_stack = mcontext->jit_callback(mcontext->jit_callback_data);
+ else
+ jit_stack = (pcre2_jit_stack *)mcontext->jit_callback_data;
+ }
+else
+ {
+ arguments.callout = NULL;
+ arguments.callout_data = NULL;
+ arguments.offset_limit = PCRE2_UNSET;
+ arguments.limit_match = (MATCH_LIMIT < re->limit_match)?
+ MATCH_LIMIT : re->limit_match;
+ jit_stack = NULL;
+ }
+
+/* JIT only need two offsets for each ovector entry. Hence
+ the last 1/3 of the ovector will never be touched. */
+
+max_oveccount = functions->top_bracket;
+if (oveccount > max_oveccount)
+ oveccount = max_oveccount;
+arguments.oveccount = oveccount << 1;
+
+
+convert_executable_func.executable_func = functions->executable_funcs[index];
+if (jit_stack != NULL)
+ {
+ arguments.stack = (struct sljit_stack *)(jit_stack->stack);
+ rc = convert_executable_func.call_executable_func(&arguments);
+ }
+else
+ rc = jit_machine_stack_exec(&arguments, convert_executable_func.call_executable_func);
+
+if (rc > (int)oveccount)
+ rc = 0;
+match_data->code = re;
+match_data->subject = subject;
+match_data->rc = rc;
+match_data->startchar = arguments.startchar_ptr - subject;
+match_data->leftchar = 0;
+match_data->rightchar = 0;
+match_data->mark = arguments.mark_ptr;
+match_data->matchedby = PCRE2_MATCHEDBY_JIT;
+
+return match_data->rc;
+
+#endif /* SUPPORT_JIT */
+}
+
+/* End of pcre2_jit_match.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_jit_misc.c b/src/3rdparty/pcre2/src/pcre2_jit_misc.c
new file mode 100644
index 0000000000..efdb05580f
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_jit_misc.c
@@ -0,0 +1,227 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifndef INCLUDED_FROM_PCRE2_JIT_COMPILE
+#error This file must be included from pcre2_jit_compile.c.
+#endif
+
+
+
+/*************************************************
+* Free JIT read-only data *
+*************************************************/
+
+void
+PRIV(jit_free_rodata)(void *current, void *allocator_data)
+{
+#ifndef SUPPORT_JIT
+(void)current;
+(void)allocator_data;
+#else /* SUPPORT_JIT */
+void *next;
+
+SLJIT_UNUSED_ARG(allocator_data);
+
+while (current != NULL)
+ {
+ next = *(void**)current;
+ SLJIT_FREE(current, allocator_data);
+ current = next;
+ }
+
+#endif /* SUPPORT_JIT */
+}
+
+/*************************************************
+* Free JIT compiled code *
+*************************************************/
+
+void
+PRIV(jit_free)(void *executable_jit, pcre2_memctl *memctl)
+{
+#ifndef SUPPORT_JIT
+(void)executable_jit;
+(void)memctl;
+#else /* SUPPORT_JIT */
+
+executable_functions *functions = (executable_functions *)executable_jit;
+void *allocator_data = memctl;
+int i;
+
+for (i = 0; i < JIT_NUMBER_OF_COMPILE_MODES; i++)
+ {
+ if (functions->executable_funcs[i] != NULL)
+ sljit_free_code(functions->executable_funcs[i]);
+ PRIV(jit_free_rodata)(functions->read_only_data_heads[i], allocator_data);
+ }
+
+SLJIT_FREE(functions, allocator_data);
+
+#endif /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+* Free unused JIT memory *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_jit_free_unused_memory(pcre2_general_context *gcontext)
+{
+#ifndef SUPPORT_JIT
+(void)gcontext; /* Suppress warning */
+#else /* SUPPORT_JIT */
+SLJIT_UNUSED_ARG(gcontext);
+sljit_free_unused_memory_exec();
+#endif /* SUPPORT_JIT */
+}
+
+
+
+/*************************************************
+* Allocate a JIT stack *
+*************************************************/
+
+PCRE2_EXP_DEFN pcre2_jit_stack * PCRE2_CALL_CONVENTION
+pcre2_jit_stack_create(size_t startsize, size_t maxsize,
+ pcre2_general_context *gcontext)
+{
+#ifndef SUPPORT_JIT
+
+(void)gcontext;
+(void)startsize;
+(void)maxsize;
+return NULL;
+
+#else /* SUPPORT_JIT */
+
+pcre2_jit_stack *jit_stack;
+
+if (startsize < 1 || maxsize < 1)
+ return NULL;
+if (startsize > maxsize)
+ startsize = maxsize;
+startsize = (startsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
+maxsize = (maxsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
+
+jit_stack = PRIV(memctl_malloc)(sizeof(pcre2_real_jit_stack), (pcre2_memctl *)gcontext);
+if (jit_stack == NULL) return NULL;
+jit_stack->stack = sljit_allocate_stack(startsize, maxsize, &jit_stack->memctl);
+return jit_stack;
+
+#endif
+}
+
+
+/*************************************************
+* Assign a JIT stack to a pattern *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_jit_stack_assign(pcre2_match_context *mcontext, pcre2_jit_callback callback,
+ void *callback_data)
+{
+#ifndef SUPPORT_JIT
+(void)mcontext;
+(void)callback;
+(void)callback_data;
+#else /* SUPPORT_JIT */
+
+if (mcontext == NULL) return;
+mcontext->jit_callback = callback;
+mcontext->jit_callback_data = callback_data;
+
+#endif /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+* Free a JIT stack *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_jit_stack_free(pcre2_jit_stack *jit_stack)
+{
+#ifndef SUPPORT_JIT
+(void)jit_stack;
+#else /* SUPPORT_JIT */
+if (jit_stack != NULL)
+ {
+ sljit_free_stack((struct sljit_stack *)(jit_stack->stack), &jit_stack->memctl);
+ jit_stack->memctl.free(jit_stack, jit_stack->memctl.memory_data);
+ }
+#endif /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+* Get target CPU type *
+*************************************************/
+
+const char*
+PRIV(jit_get_target)(void)
+{
+#ifndef SUPPORT_JIT
+return "JIT is not supported";
+#else /* SUPPORT_JIT */
+return sljit_get_platform_name();
+#endif /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+* Get size of JIT code *
+*************************************************/
+
+size_t
+PRIV(jit_get_size)(void *executable_jit)
+{
+#ifndef SUPPORT_JIT
+(void)executable_jit;
+return 0;
+#else /* SUPPORT_JIT */
+sljit_uw *executable_sizes = ((executable_functions *)executable_jit)->executable_sizes;
+SLJIT_COMPILE_ASSERT(JIT_NUMBER_OF_COMPILE_MODES == 3, number_of_compile_modes_changed);
+return executable_sizes[0] + executable_sizes[1] + executable_sizes[2];
+#endif
+}
+
+/* End of pcre2_jit_misc.c */
diff --git a/src/3rdparty/pcre/pcre_maketables.c b/src/3rdparty/pcre2/src/pcre2_maketables.c
index a44a6eaa90..2c7ae84d86 100644
--- a/src/3rdparty/pcre/pcre_maketables.c
+++ b/src/3rdparty/pcre2/src/pcre2_maketables.c
@@ -6,7 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -38,53 +39,53 @@ POSSIBILITY OF SUCH DAMAGE.
*/
-/* This module contains the external function pcre_maketables(), which builds
-character tables for PCRE in the current locale. The file is compiled on its
-own as part of the PCRE library. However, it is also included in the
+/* This module contains the external function pcre2_maketables(), which builds
+character tables for PCRE2 in the current locale. The file is compiled on its
+own as part of the PCRE2 library. However, it is also included in the
compilation of dftables.c, in which case the macro DFTABLES is defined. */
-
#ifndef DFTABLES
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
-# include "pcre_internal.h"
+# include "pcre2_internal.h"
#endif
+
/*************************************************
-* Create PCRE character tables *
+* Create PCRE2 character tables *
*************************************************/
-/* This function builds a set of character tables for use by PCRE and returns
+/* This function builds a set of character tables for use by PCRE2 and returns
a pointer to them. They are build using the ctype functions, and consequently
their contents will depend upon the current locale setting. When compiled as
-part of the library, the store is obtained via PUBL(malloc)(), but when
-compiled inside dftables, use malloc().
+part of the library, the store is obtained via a general context malloc, if
+supplied, but when DFTABLES is defined (when compiling the dftables auxiliary
+program) malloc() is used, and the function has a different name so as not to
+clash with the prototype in pcre2.h.
-Arguments: none
+Arguments: none when DFTABLES is defined
+ else a PCRE2 general context or NULL
Returns: pointer to the contiguous block of data
*/
-#if defined COMPILE_PCRE8
-const unsigned char *
-pcre_maketables(void)
-#elif defined COMPILE_PCRE16
-const unsigned char *
-pcre16_maketables(void)
-#elif defined COMPILE_PCRE32
-const unsigned char *
-pcre32_maketables(void)
-#endif
+#ifdef DFTABLES /* Included in freestanding dftables.c program */
+static const uint8_t *maketables(void)
{
-unsigned char *yield, *p;
-int i;
+uint8_t *yield = (uint8_t *)malloc(tables_length);
-#ifndef DFTABLES
-yield = (unsigned char*)(PUBL(malloc))(tables_length);
-#else
-yield = (unsigned char*)malloc(tables_length);
-#endif
+#else /* Not DFTABLES, compiling the library */
+PCRE2_EXP_DEFN const uint8_t * PCRE2_CALL_CONVENTION
+pcre2_maketables(pcre2_general_context *gcontext)
+{
+uint8_t *yield = (uint8_t *)((gcontext != NULL)?
+ gcontext->memctl.malloc(tables_length, gcontext->memctl.memory_data) :
+ malloc(tables_length));
+#endif /* DFTABLES */
+
+int i;
+uint8_t *p;
if (yield == NULL) return NULL;
p = yield;
@@ -153,4 +154,4 @@ for (i = 0; i < 256; i++)
return yield;
}
-/* End of pcre_maketables.c */
+/* End of pcre2_maketables.c */
diff --git a/src/3rdparty/pcre/pcre_exec.c b/src/3rdparty/pcre2/src/pcre2_match.c
index 24b23ca286..0763a239e1 100644
--- a/src/3rdparty/pcre/pcre_exec.c
+++ b/src/3rdparty/pcre2/src/pcre2_match.c
@@ -6,7 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2014 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -37,26 +38,30 @@ POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
-/* This module contains pcre_exec(), the externally visible function that does
-pattern matching using an NFA algorithm, trying to mimic Perl as closely as
-possible. There are also some static supporting functions. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#define NLBLOCK md /* Block containing newline information */
+#define NLBLOCK mb /* Block containing newline information */
#define PSSTART start_subject /* Field containing processed string start */
#define PSEND end_subject /* Field containing processed string end */
-#include "pcre_internal.h"
+#include "pcre2_internal.h"
-/* Undefine some potentially clashing cpp symbols */
+/* Masks for identifying the public options that are permitted at match time.
+*/
-#undef min
-#undef max
+#define PUBLIC_MATCH_OPTIONS \
+ (PCRE2_ANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
+ PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \
+ PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT)
+
+#define PUBLIC_JIT_MATCH_OPTIONS \
+ (PCRE2_NO_UTF_CHECK|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY|\
+ PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_SOFT|PCRE2_PARTIAL_HARD)
-/* The md->capture_last field uses the lower 16 bits for the last captured
+/* The mb->capture_last field uses the lower 16 bits for the last captured
substring (which can never be greater than 65535) and a bit in the top half
to mean "capture vector overflowed". This odd way of doing things was
implemented when it was realized that preserving and restoring the overflow bit
@@ -70,7 +75,7 @@ implementing this. */
#define OVFLMASK 0xffff0000 /* The bits used for the overflow flag */
#define OVFLBIT 0x00010000 /* The bit that is set for overflow */
-/* Values for setting in md->match_function_type to indicate two special types
+/* Bits for setting in mb->match_function_type to indicate two special types
of call to match(). We do it this way to save on using another stack variable,
as stack usage is to be discouraged. */
@@ -78,7 +83,7 @@ as stack usage is to be discouraged. */
#define MATCH_CBEGROUP 2 /* Could-be-empty unlimited repeat group */
/* Non-error returns from the match() function. Error returns are externally
-defined PCRE_ERROR_xxx codes, which are all negative. */
+defined PCRE2_ERROR_xxx codes, which are all negative. */
#define MATCH_MATCH 1
#define MATCH_NOMATCH 0
@@ -99,44 +104,17 @@ for any one of them can use a range. */
#define MATCH_BACKTRACK_MAX MATCH_THEN
#define MATCH_BACKTRACK_MIN MATCH_COMMIT
-/* Maximum number of ints of offset to save on the stack for recursive calls.
-If the offset vector is bigger, malloc is used. This should be a multiple of 3,
-because the offset vector is always a multiple of 3 long. */
-
-#define REC_STACK_SAVE_MAX 30
-
/* Min and max values for the common repeats; for the maxima, 0 => infinity */
static const char rep_min[] = { 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, };
static const char rep_max[] = { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, };
-#ifdef PCRE_DEBUG
-/*************************************************
-* Debugging function to print chars *
-*************************************************/
-
-/* Print a sequence of chars in printable format, stopping at the end of the
-subject if the requested.
-
-Arguments:
- p points to characters
- length number to print
- is_subject TRUE if printing from within md->start_subject
- md pointer to matching data block, if is_subject is TRUE
-
-Returns: nothing
-*/
+/* Maximum number of ovector elements that can be saved on the system stack
+when processing OP_RECURSE in non-HEAP_MATCH_RECURSE mode. If the ovector is
+bigger, malloc() is used. This value should be a multiple of 3, because the
+ovector length is always a multiple of 3. */
-static void
-pchars(const pcre_uchar *p, int length, BOOL is_subject, match_data *md)
-{
-pcre_uint32 c;
-BOOL utf = md->utf;
-if (is_subject && length > md->end_subject - p) length = md->end_subject - p;
-while (length-- > 0)
- if (isprint(c = UCHAR21INCTEST(p))) printf("%c", (char)c); else printf("\\x{%02x}", c);
-}
-#endif
+#define OP_RECURSE_STACK_SAVE_MAX 45
@@ -144,62 +122,62 @@ while (length-- > 0)
* Match a back-reference *
*************************************************/
-/* Normally, if a back reference hasn't been set, the length that is passed is
-negative, so the match always fails. However, in JavaScript compatibility mode,
-the length passed is zero. Note that in caseless UTF-8 mode, the number of
-subject bytes matched may be different to the number of reference bytes.
+/* This function is called only when it is known that the offset lies within
+the offsets that have so far been used in the match. Note that in caseless
+UTF-8 mode, the number of subject bytes matched may be different to the number
+of reference bytes. (In theory this could also happen in UTF-16 mode, but it
+seems unlikely.)
Arguments:
offset index into the offset vector
+ offset_top top of the used offset vector
eptr pointer into the subject
- length length of reference to be matched (number of bytes)
- md points to match data block
+ mb points to match block
caseless TRUE if caseless
+ lengthptr pointer for returning the length matched
-Returns: >= 0 the number of subject bytes matched
- -1 no match
- -2 partial match; always given if at end subject
+Returns: = 0 sucessful match; number of code units matched is set
+ < 0 no match
+ > 0 partial match
*/
static int
-match_ref(int offset, register PCRE_PUCHAR eptr, int length, match_data *md,
- BOOL caseless)
+match_ref(PCRE2_SIZE offset, PCRE2_SIZE offset_top, register PCRE2_SPTR eptr,
+ match_block *mb, BOOL caseless, PCRE2_SIZE *lengthptr)
{
-PCRE_PUCHAR eptr_start = eptr;
-register PCRE_PUCHAR p = md->start_subject + md->offset_vector[offset];
-#if defined SUPPORT_UTF && defined SUPPORT_UCP
-BOOL utf = md->utf;
+#if defined SUPPORT_UNICODE
+BOOL utf = (mb->poptions & PCRE2_UTF) != 0;
#endif
-#ifdef PCRE_DEBUG
-if (eptr >= md->end_subject)
- printf("matching subject <null>");
-else
+register PCRE2_SPTR p;
+PCRE2_SIZE length;
+PCRE2_SPTR eptr_start = eptr;
+
+/* Deal with an unset group. The default is no match, but there is an option to
+match an empty string. */
+
+if (offset >= offset_top || mb->ovector[offset] == PCRE2_UNSET)
{
- printf("matching subject ");
- pchars(eptr, length, TRUE, md);
+ if ((mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0)
+ {
+ *lengthptr = 0;
+ return 0; /* Match */
+ }
+ else return -1; /* No match */
}
-printf(" against backref ");
-pchars(p, length, FALSE, md);
-printf("\n");
-#endif
-/* Always fail if reference not set (and not JavaScript compatible - in that
-case the length is passed as zero). */
+/* Separate the caseless and UTF cases for speed. */
-if (length < 0) return -1;
-
-/* Separate the caseless case for speed. In UTF-8 mode we can only do this
-properly if Unicode properties are supported. Otherwise, we can check only
-ASCII characters. */
+p = mb->start_subject + mb->ovector[offset];
+length = mb->ovector[offset+1] - mb->ovector[offset];
if (caseless)
{
-#if defined SUPPORT_UTF && defined SUPPORT_UCP
+#if defined SUPPORT_UNICODE
if (utf)
{
/* Match characters up to the end of the reference. NOTE: the number of
- data units matched may differ, because in UTF-8 there are some characters
+ code units matched may differ, because in UTF-8 there are some characters
whose upper and lower case versions code have different numbers of bytes.
For example, U+023A (2 bytes in UTF-8) is the upper case version of U+2C65
(3 bytes in UTF-8); a sequence of 3 of the former uses 6 bytes, as does a
@@ -207,21 +185,21 @@ if (caseless)
length along the reference, not along the subject (earlier code did this
wrong). */
- PCRE_PUCHAR endptr = p + length;
+ PCRE2_SPTR endptr = p + length;
while (p < endptr)
{
- pcre_uint32 c, d;
+ uint32_t c, d;
const ucd_record *ur;
- if (eptr >= md->end_subject) return -2; /* Partial match */
+ if (eptr >= mb->end_subject) return 1; /* Partial match */
GETCHARINC(c, eptr);
GETCHARINC(d, p);
ur = GET_UCD(d);
- if (c != d && c != d + ur->other_case)
+ if (c != d && c != (uint32_t)((int)d + ur->other_case))
{
- const pcre_uint32 *pp = PRIV(ucd_caseless_sets) + ur->caseset;
+ const uint32_t *pp = PRIV(ucd_caseless_sets) + ur->caseset;
for (;;)
{
- if (c < *pp) return -1;
+ if (c < *pp) return -1; /* No match */
if (c == *pp++) break;
}
}
@@ -230,35 +208,37 @@ if (caseless)
else
#endif
- /* The same code works when not in UTF-8 mode and in UTF-8 mode when there
- is no UCP support. */
+ /* Not in UTF mode */
+
{
- while (length-- > 0)
+ for (; length > 0; length--)
{
- pcre_uint32 cc, cp;
- if (eptr >= md->end_subject) return -2; /* Partial match */
+ uint32_t cc, cp;
+ if (eptr >= mb->end_subject) return 1; /* Partial match */
cc = UCHAR21TEST(eptr);
cp = UCHAR21TEST(p);
- if (TABLE_GET(cp, md->lcc, cp) != TABLE_GET(cc, md->lcc, cc)) return -1;
+ if (TABLE_GET(cp, mb->lcc, cp) != TABLE_GET(cc, mb->lcc, cc))
+ return -1; /* No match */
p++;
eptr++;
}
}
}
-/* In the caseful case, we can just compare the bytes, whether or not we
-are in UTF-8 mode. */
+/* In the caseful case, we can just compare the code units, whether or not we
+are in UTF mode. */
else
{
- while (length-- > 0)
+ for (; length > 0; length--)
{
- if (eptr >= md->end_subject) return -2; /* Partial match */
- if (UCHAR21INCTEST(p) != UCHAR21INCTEST(eptr)) return -1;
+ if (eptr >= mb->end_subject) return 1; /* Partial match */
+ if (UCHAR21INCTEST(p) != UCHAR21INCTEST(eptr)) return -1; /*No match */
}
}
-return (int)(eptr - eptr_start);
+*lengthptr = eptr - eptr_start;
+return 0; /* Match */
}
@@ -268,7 +248,7 @@ return (int)(eptr - eptr_start);
RECURSION IN THE match() FUNCTION
The match() function is highly recursive, though not every recursive call
-increases the recursive depth. Nevertheless, some regular expressions can cause
+increases the recursion depth. Nevertheless, some regular expressions can cause
it to recurse to a great depth. I was writing for Unix, so I just let it call
itself recursively. This uses the stack for saving everything that has to be
saved for a recursive call. On Unix, the stack can be large, and this works
@@ -279,9 +259,9 @@ programs that use a lot of stack. (This despite the fact that every last chip
has oodles of memory these days, and techniques for extending the stack have
been known for decades.) So....
-There is a fudge, triggered by defining NO_RECURSE, which avoids recursive
-calls by keeping local variables that need to be preserved in blocks of memory
-obtained from malloc() instead instead of on the stack. Macros are used to
+There is a fudge, triggered by defining HEAP_MATCH_RECURSE, which avoids
+recursive calls by keeping local variables that need to be preserved in blocks
+of memory on the heap instead instead of on the stack. Macros are used to
achieve this so that the actual code doesn't look very different to what it
always used to.
@@ -310,38 +290,20 @@ enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10,
RM31, RM32, RM33, RM34, RM35, RM36, RM37, RM38, RM39, RM40,
RM41, RM42, RM43, RM44, RM45, RM46, RM47, RM48, RM49, RM50,
RM51, RM52, RM53, RM54, RM55, RM56, RM57, RM58, RM59, RM60,
- RM61, RM62, RM63, RM64, RM65, RM66, RM67 };
+ RM61, RM62, RM63, RM64, RM65, RM66, RM67, RM68 };
-/* These versions of the macros use the stack, as normal. There are debugging
-versions and production versions. Note that the "rw" argument of RMATCH isn't
-actually used in this definition. */
+/* These versions of the macros use the stack, as normal. Note that the "rw"
+argument of RMATCH isn't actually used in this definition. */
-#ifndef NO_RECURSE
+#ifndef HEAP_MATCH_RECURSE
#define REGISTER register
-
-#ifdef PCRE_DEBUG
-#define RMATCH(ra,rb,rc,rd,re,rw) \
- { \
- printf("match() called in line %d\n", __LINE__); \
- rrc = match(ra,rb,mstart,rc,rd,re,rdepth+1); \
- printf("to line %d\n", __LINE__); \
- }
-#define RRETURN(ra) \
- { \
- printf("match() returned %d from line %d\n", ra, __LINE__); \
- return ra; \
- }
-#else
#define RMATCH(ra,rb,rc,rd,re,rw) \
rrc = match(ra,rb,mstart,rc,rd,re,rdepth+1)
#define RRETURN(ra) return ra
-#endif
-
#else
-
/* These versions of the macros manage a private stack on the heap. Note that
-the "rd" argument of RMATCH isn't actually used in this definition. It's the md
+the "rd" argument of RMATCH isn't actually used in this definition. It's the mb
argument of match(), which never changes. */
#define REGISTER
@@ -351,8 +313,9 @@ argument of match(), which never changes. */
heapframe *newframe = frame->Xnextframe;\
if (newframe == NULL)\
{\
- newframe = (heapframe *)(PUBL(stack_malloc))(sizeof(heapframe));\
- if (newframe == NULL) RRETURN(PCRE_ERROR_NOMEMORY);\
+ newframe = (heapframe *)(mb->stack_memctl.malloc)\
+ (sizeof(heapframe), mb->stack_memctl.memory_data);\
+ if (newframe == NULL) RRETURN(PCRE2_ERROR_NOMEMORY);\
newframe->Xnextframe = NULL;\
frame->Xnextframe = newframe;\
}\
@@ -365,10 +328,8 @@ argument of match(), which never changes. */
newframe->Xrdepth = frame->Xrdepth + 1;\
newframe->Xprevframe = frame;\
frame = newframe;\
- DPRINTF(("restarting from line %d\n", __LINE__));\
goto HEAP_RECURSE;\
- L_##rw:\
- DPRINTF(("jumped back to line %d\n", __LINE__));\
+ L_##rw:;\
}
#define RRETURN(ra)\
@@ -384,67 +345,63 @@ argument of match(), which never changes. */
}
-/* Structure for remembering the local variables in a private frame */
+/* Structure for remembering the local variables in a private frame. Arrange it
+so as to minimize the number of holes. */
typedef struct heapframe {
struct heapframe *Xprevframe;
struct heapframe *Xnextframe;
- /* Function arguments that may change */
+#ifdef SUPPORT_UNICODE
+ PCRE2_SPTR Xcharptr;
+#endif
+ PCRE2_SPTR Xeptr;
+ PCRE2_SPTR Xecode;
+ PCRE2_SPTR Xmstart;
+ PCRE2_SPTR Xcallpat;
+ PCRE2_SPTR Xdata;
+ PCRE2_SPTR Xnext_ecode;
+ PCRE2_SPTR Xpp;
+ PCRE2_SPTR Xprev;
+ PCRE2_SPTR Xsaved_eptr;
- PCRE_PUCHAR Xeptr;
- const pcre_uchar *Xecode;
- PCRE_PUCHAR Xmstart;
- int Xoffset_top;
eptrblock *Xeptrb;
- unsigned int Xrdepth;
-
- /* Function local variables */
-
- PCRE_PUCHAR Xcallpat;
-#ifdef SUPPORT_UTF
- PCRE_PUCHAR Xcharptr;
-#endif
- PCRE_PUCHAR Xdata;
- PCRE_PUCHAR Xnext;
- PCRE_PUCHAR Xpp;
- PCRE_PUCHAR Xprev;
- PCRE_PUCHAR Xsaved_eptr;
- recursion_info Xnew_recursive;
+ PCRE2_SIZE Xlength;
+ PCRE2_SIZE Xoffset;
+ PCRE2_SIZE Xoffset_top;
+ PCRE2_SIZE Xsave_offset1, Xsave_offset2, Xsave_offset3;
- BOOL Xcur_is_word;
- BOOL Xcondition;
- BOOL Xprev_is_word;
+ uint32_t Xfc;
+ uint32_t Xnumber;
+ uint32_t Xrdepth;
+ uint32_t Xop;
+ uint32_t Xsave_capture_last;
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
+ uint32_t Xprop_value;
int Xprop_type;
- unsigned int Xprop_value;
int Xprop_fail_result;
int Xoclength;
- pcre_uchar Xocchars[6];
#endif
int Xcodelink;
int Xctype;
- unsigned int Xfc;
int Xfi;
- int Xlength;
int Xmax;
int Xmin;
- unsigned int Xnumber;
- int Xoffset;
- unsigned int Xop;
- pcre_int32 Xsave_capture_last;
- int Xsave_offset1, Xsave_offset2, Xsave_offset3;
- int Xstacksave[REC_STACK_SAVE_MAX];
-
- eptrblock Xnewptrb;
+ int Xwhere; /* Where to jump back to */
- /* Where to jump back to */
+ BOOL Xcondition;
+ BOOL Xcur_is_word;
+ BOOL Xprev_is_word;
- int Xwhere;
+ eptrblock Xnewptrb;
+ recursion_info Xnew_recursive;
+#ifdef SUPPORT_UNICODE
+ PCRE2_UCHAR Xocchars[6];
+#endif
} heapframe;
#endif
@@ -454,6 +411,115 @@ typedef struct heapframe {
***************************************************************************/
+/* When HEAP_MATCH_RECURSE is not defined, the match() function implements
+backtrack points by calling itself recursively in all but one case. The one
+special case is when processing OP_RECURSE, which specifies recursion in the
+pattern. The entire ovector must be saved and restored while processing
+OP_RECURSE. If the ovector is small enough, instead of calling match()
+directly, op_recurse_ovecsave() is called. This function uses the system stack
+to save the ovector while calling match() to process the pattern recursion. */
+
+#ifndef HEAP_MATCH_RECURSE
+
+/* We need a prototype for match() because it is mutually recursive with
+op_recurse_ovecsave(). */
+
+static int
+match(REGISTER PCRE2_SPTR eptr, REGISTER PCRE2_SPTR ecode, PCRE2_SPTR mstart,
+ PCRE2_SIZE offset_top, match_block *mb, eptrblock *eptrb, uint32_t rdepth);
+
+
+/*************************************************
+* Process OP_RECURSE, stacking ovector *
+*************************************************/
+
+/* When this function is called, mb->recursive has already been updated to
+point to a new recursion data block, and all its fields other than ovec_save
+have been set.
+
+This function exists so that the local vector variable ovecsave is no longer
+defined in the match() function, as it was in PCRE1. It is used only when there
+is recursion in the pattern, so it wastes a lot of stack to have it defined for
+every call of match(). We now use this function as an indirect way of calling
+match() only in the case when ovecsave is needed. (David Wheeler used to say
+"All problems in computer science can be solved by another level of
+indirection.")
+
+HOWEVER: when this file is compiled by gcc in an optimizing mode, because this
+function is called only once, and only from within match(), gcc will "inline"
+it - that is, move it inside match() - and this completely negates its reason
+for existence. Therefore, we mark it as non-inline when gcc is in use.
+
+Arguments:
+ eptr pointer to current character in subject
+ callpat the recursion point in the pattern
+ mstart pointer to the current match start position (can be modified
+ by encountering \K)
+ offset_top current top pointer (highest ovector offset used + 1)
+ mb pointer to "static" info block for the match
+ eptrb pointer to chain of blocks containing eptr at start of
+ brackets - for testing for empty matches
+ rdepth the recursion depth
+
+Returns: a match() return code
+*/
+
+static int
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+__attribute__ ((noinline))
+#endif
+op_recurse_ovecsave(REGISTER PCRE2_SPTR eptr, PCRE2_SPTR callpat,
+ PCRE2_SPTR mstart, PCRE2_SIZE offset_top, match_block *mb, eptrblock *eptrb,
+ uint32_t rdepth)
+{
+register int rrc;
+BOOL cbegroup = *callpat >= OP_SBRA;
+recursion_info *new_recursive = mb->recursive;
+PCRE2_SIZE ovecsave[OP_RECURSE_STACK_SAVE_MAX];
+
+/* Save the ovector */
+
+new_recursive->ovec_save = ovecsave;
+memcpy(ovecsave, mb->ovector, mb->offset_end * sizeof(PCRE2_SIZE));
+
+/* Do the recursion. After processing each alternative, restore the ovector
+data and the last captured value. */
+
+do
+ {
+ if (cbegroup) mb->match_function_type |= MATCH_CBEGROUP;
+ rrc = match(eptr, callpat + PRIV(OP_lengths)[*callpat], mstart, offset_top,
+ mb, eptrb, rdepth + 1);
+ memcpy(mb->ovector, new_recursive->ovec_save,
+ mb->offset_end * sizeof(PCRE2_SIZE));
+ mb->capture_last = new_recursive->saved_capture_last;
+ if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) return rrc;
+
+ /* PCRE does not allow THEN, SKIP, PRUNE or COMMIT to escape beyond a
+ recursion; they cause a NOMATCH for the entire recursion. These codes
+ are defined in a range that can be tested for. */
+
+ if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX)
+ return MATCH_NOMATCH;
+
+ /* Any return code other than NOMATCH is an error. Otherwise, advance to the
+ next alternative or to the end of the recursing subpattern. If there were
+ nested recursions, mb->recursive might be changed, so reset it before
+ looping. */
+
+ if (rrc != MATCH_NOMATCH) return rrc;
+ mb->recursive = new_recursive;
+ callpat += GET(callpat, 1);
+ }
+while (*callpat == OP_ALT); /* Loop for the alternatives */
+
+/* None of the alternatives matched. */
+
+return MATCH_NOMATCH;
+}
+#endif /* HEAP_MATCH_RECURSE */
+
+
/*************************************************
* Match from current position *
@@ -465,29 +531,29 @@ same response. */
/* These macros pack up tests that are used for partial matching, and which
appear several times in the code. We set the "hit end" flag if the pointer is
-at the end of the subject and also past the start of the subject (i.e.
-something has been matched). For hard partial matching, we then return
-immediately. The second one is used when we already know we are past the end of
-the subject. */
+at the end of the subject and also past the earliest inspected character (i.e.
+something has been matched, even if not part of the actual matched string). For
+hard partial matching, we then return immediately. The second one is used when
+we already know we are past the end of the subject. */
#define CHECK_PARTIAL()\
- if (md->partial != 0 && eptr >= md->end_subject && \
- eptr > md->start_used_ptr) \
+ if (mb->partial != 0 && eptr >= mb->end_subject && \
+ eptr > mb->start_used_ptr) \
{ \
- md->hitend = TRUE; \
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); \
+ mb->hitend = TRUE; \
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); \
}
#define SCHECK_PARTIAL()\
- if (md->partial != 0 && eptr > md->start_used_ptr) \
+ if (mb->partial != 0 && eptr > mb->start_used_ptr) \
{ \
- md->hitend = TRUE; \
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL); \
+ mb->hitend = TRUE; \
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL); \
}
/* Performance note: It might be tempting to extract commonly used fields from
-the md structure (e.g. utf, end_subject) into individual variables to improve
+the mb structure (e.g. utf, end_subject) into individual variables to improve
performance. Tests using gcc on a SPARC disproved this; in the first case, it
made performance worse.
@@ -496,8 +562,8 @@ Arguments:
ecode pointer to current position in compiled code
mstart pointer to the current match start position (can be modified
by encountering \K)
- offset_top current top pointer
- md pointer to "static" info for the match
+ offset_top current top pointer (highest ovector offset used + 1)
+ mb pointer to "static" info block for the match
eptrb pointer to chain of blocks containing eptr at start of
brackets - for testing for empty matches
rdepth the recursion depth
@@ -505,14 +571,13 @@ Arguments:
Returns: MATCH_MATCH if matched ) these values are >= 0
MATCH_NOMATCH if failed to match )
a negative MATCH_xxx value for PRUNE, SKIP, etc
- a negative PCRE_ERROR_xxx value if aborted by an error condition
+ a negative PCRE2_ERROR_xxx value if aborted by an error condition
(e.g. stopped by repeated call or recursion limit)
*/
static int
-match(REGISTER PCRE_PUCHAR eptr, REGISTER const pcre_uchar *ecode,
- PCRE_PUCHAR mstart, int offset_top, match_data *md, eptrblock *eptrb,
- unsigned int rdepth)
+match(REGISTER PCRE2_SPTR eptr, REGISTER PCRE2_SPTR ecode, PCRE2_SPTR mstart,
+ PCRE2_SIZE offset_top, match_block *mb, eptrblock *eptrb, uint32_t rdepth)
{
/* These variables do not need to be preserved over recursion in this function,
so they can be ordinary variables in all cases. Mark some of them with
@@ -520,7 +585,7 @@ so they can be ordinary variables in all cases. Mark some of them with
register int rrc; /* Returns from recursive calls */
register int i; /* Used for loops not involving calls to RMATCH() */
-register pcre_uint32 c; /* Character values not kept over RMATCH() calls */
+register uint32_t c; /* Character values not kept over RMATCH() calls */
register BOOL utf; /* Local copy of UTF flag for speed */
BOOL minimize, possessive; /* Quantifier options */
@@ -534,8 +599,8 @@ whenever RMATCH() does a "recursion". See the macro definitions above. Putting
the top-level on the stack rather than malloc-ing them all gives a performance
boost in many cases where there is not much "recursion". */
-#ifdef NO_RECURSE
-heapframe *frame = (heapframe *)md->match_frames_base;
+#ifdef HEAP_MATCH_RECURSE
+heapframe *frame = (heapframe *)mb->match_frames_base;
/* Copy in the original argument variables */
@@ -561,31 +626,26 @@ HEAP_RECURSE:
/* Ditto for the local variables */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
#define charptr frame->Xcharptr
+#define prop_value frame->Xprop_value
+#define prop_type frame->Xprop_type
+#define prop_fail_result frame->Xprop_fail_result
+#define oclength frame->Xoclength
+#define occhars frame->Xocchars
#endif
+
+
#define callpat frame->Xcallpat
#define codelink frame->Xcodelink
#define data frame->Xdata
-#define next frame->Xnext
+#define next_ecode frame->Xnext_ecode
#define pp frame->Xpp
#define prev frame->Xprev
#define saved_eptr frame->Xsaved_eptr
#define new_recursive frame->Xnew_recursive
-#define cur_is_word frame->Xcur_is_word
-#define condition frame->Xcondition
-#define prev_is_word frame->Xprev_is_word
-
-#ifdef SUPPORT_UCP
-#define prop_type frame->Xprop_type
-#define prop_value frame->Xprop_value
-#define prop_fail_result frame->Xprop_fail_result
-#define oclength frame->Xoclength
-#define occhars frame->Xocchars
-#endif
-
#define ctype frame->Xctype
#define fc frame->Xfc
#define fi frame->Xfi
@@ -599,15 +659,18 @@ HEAP_RECURSE:
#define save_offset1 frame->Xsave_offset1
#define save_offset2 frame->Xsave_offset2
#define save_offset3 frame->Xsave_offset3
-#define stacksave frame->Xstacksave
+
+#define condition frame->Xcondition
+#define cur_is_word frame->Xcur_is_word
+#define prev_is_word frame->Xprev_is_word
#define newptrb frame->Xnewptrb
-/* When recursion is being used, local variables are allocated on the stack and
-get preserved during recursion in the normal way. In this environment, fi and
-i, and fc and c, can be the same variables. */
+/* When normal stack-based recursion is being used for match(), local variables
+are allocated on the stack and get preserved during recursion in the usual way.
+In this environment, fi and i, and fc and c, can be the same variables. */
-#else /* NO_RECURSE not defined */
+#else /* HEAP_MATCH_RECURSE not defined */
#define fi i
#define fc c
@@ -619,101 +682,84 @@ declarations can be cut out in a block. The only declarations within blocks
below are for variables that do not have to be preserved over a recursive call
to RMATCH(). */
-#ifdef SUPPORT_UTF
-const pcre_uchar *charptr;
+#ifdef SUPPORT_UNICODE
+PCRE2_SPTR charptr;
#endif
-const pcre_uchar *callpat;
-const pcre_uchar *data;
-const pcre_uchar *next;
-PCRE_PUCHAR pp;
-const pcre_uchar *prev;
-PCRE_PUCHAR saved_eptr;
-
-recursion_info new_recursive;
-
-BOOL cur_is_word;
-BOOL condition;
-BOOL prev_is_word;
-
-#ifdef SUPPORT_UCP
+PCRE2_SPTR callpat;
+PCRE2_SPTR data;
+PCRE2_SPTR next_ecode;
+PCRE2_SPTR pp;
+PCRE2_SPTR prev;
+PCRE2_SPTR saved_eptr;
+
+PCRE2_SIZE length;
+PCRE2_SIZE offset;
+PCRE2_SIZE save_offset1, save_offset2, save_offset3;
+
+uint32_t number;
+uint32_t op;
+uint32_t save_capture_last;
+
+#ifdef SUPPORT_UNICODE
+uint32_t prop_value;
int prop_type;
-unsigned int prop_value;
int prop_fail_result;
int oclength;
-pcre_uchar occhars[6];
+PCRE2_UCHAR occhars[6];
#endif
int codelink;
int ctype;
-int length;
int max;
int min;
-unsigned int number;
-int offset;
-unsigned int op;
-pcre_int32 save_capture_last;
-int save_offset1, save_offset2, save_offset3;
-int stacksave[REC_STACK_SAVE_MAX];
-eptrblock newptrb;
-
-/* There is a special fudge for calling match() in a way that causes it to
-measure the size of its basic stack frame when the stack is being used for
-recursion. The second argument (ecode) being NULL triggers this behaviour. It
-cannot normally ever be NULL. The return is the negated value of the frame
-size. */
+BOOL condition;
+BOOL cur_is_word;
+BOOL prev_is_word;
-if (ecode == NULL)
- {
- if (rdepth == 0)
- return match((PCRE_PUCHAR)&rdepth, NULL, NULL, 0, NULL, NULL, 1);
- else
- {
- int len = (char *)&rdepth - (char *)eptr;
- return (len > 0)? -len : len;
- }
- }
-#endif /* NO_RECURSE */
+eptrblock newptrb;
+recursion_info new_recursive;
+#endif /* HEAP_MATCH_RECURSE not defined */
/* To save space on the stack and in the heap frame, I have doubled up on some
of the local variables that are used only in localised parts of the code, but
still need to be preserved over recursive calls of match(). These macros define
the alternative names that are used. */
-#define allow_zero cur_is_word
-#define cbegroup condition
-#define code_offset codelink
-#define condassert condition
-#define matched_once prev_is_word
-#define foc number
-#define save_mark data
+#define allow_zero cur_is_word
+#define cbegroup condition
+#define code_offset codelink
+#define condassert condition
+#define foc number
+#define matched_once prev_is_word
+#define save_mark data
/* These statements are here to stop the compiler complaining about unitialized
variables. */
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
prop_value = 0;
prop_fail_result = 0;
#endif
/* This label is used for tail recursion, which is used in a few cases even
-when NO_RECURSE is not defined, in order to reduce the amount of stack that is
-used. Thanks to Ian Taylor for noticing this possibility and sending the
-original patch. */
+when HEAP_MATCH_RECURSE is not defined, in order to reduce the amount of stack
+that is used. Thanks to Ian Taylor for noticing this possibility and sending
+the original patch. */
TAIL_RECURSE:
/* OK, now we can get on with the real code of the function. Recursive calls
are specified by the macro RMATCH and RRETURN is used to return. When
-NO_RECURSE is *not* defined, these just turn into a recursive call to match()
-and a "return", respectively (possibly with some debugging if PCRE_DEBUG is
-defined). However, RMATCH isn't like a function call because it's quite a
-complicated macro. It has to be used in one particular way. This shouldn't,
-however, impact performance when true recursion is being used. */
-
-#ifdef SUPPORT_UTF
-utf = md->utf; /* Local copy of the flag */
+HEAP_MATCH_RECURSE is *not* defined, these just turn into a recursive call to
+match() and a "return", respectively. However, RMATCH isn't like a function
+call because it's quite a complicated macro. It has to be used in one
+particular way. This shouldn't, however, impact performance when true recursion
+is being used. */
+
+#ifdef SUPPORT_UNICODE
+utf = (mb->poptions & PCRE2_UTF) != 0;
#else
utf = FALSE;
#endif
@@ -721,13 +767,13 @@ utf = FALSE;
/* First check that we haven't called match() too many times, or that we
haven't exceeded the recursive call limit. */
-if (md->match_call_count++ >= md->match_limit) RRETURN(PCRE_ERROR_MATCHLIMIT);
-if (rdepth >= md->match_limit_recursion) RRETURN(PCRE_ERROR_RECURSIONLIMIT);
+if (mb->match_call_count++ >= mb->match_limit) RRETURN(PCRE2_ERROR_MATCHLIMIT);
+if (rdepth >= mb->match_limit_recursion) RRETURN(PCRE2_ERROR_RECURSIONLIMIT);
/* At the start of a group with an unlimited repeat that may match an empty
-string, the variable md->match_function_type is set to MATCH_CBEGROUP. It is
-done this way to save having to use another function argument, which would take
-up space on the stack. See also MATCH_CONDASSERT below.
+string, the variable mb->match_function_type contains the MATCH_CBEGROUP bit.
+It is done this way to save having to use another function argument, which
+would take up space on the stack. See also MATCH_CONDASSERT below.
When MATCH_CBEGROUP is set, add the current subject pointer to the chain of
such remembered pointers, to be checked when we hit the closing ket, in order
@@ -736,15 +782,15 @@ other circumstances, don't add to the chain. The MATCH_CBEGROUP feature must
NOT be used with tail recursion, because the memory block that is used is on
the stack, so a new one may be required for each match(). */
-if (md->match_function_type == MATCH_CBEGROUP)
+if ((mb->match_function_type & MATCH_CBEGROUP) != 0)
{
newptrb.epb_saved_eptr = eptr;
newptrb.epb_prev = eptrb;
eptrb = &newptrb;
- md->match_function_type = 0;
+ mb->match_function_type &= ~MATCH_CBEGROUP;
}
-/* Now start processing the opcodes. */
+/* Now, at last, we can start processing the opcodes. */
for (;;)
{
@@ -754,24 +800,24 @@ for (;;)
switch(op)
{
case OP_MARK:
- md->nomatch_mark = ecode + 2;
- md->mark = NULL; /* In case previously set by assertion */
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md,
+ mb->nomatch_mark = ecode + 2;
+ mb->mark = NULL; /* In case previously set by assertion */
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, mb,
eptrb, RM55);
if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) &&
- md->mark == NULL) md->mark = ecode + 2;
+ mb->mark == NULL) mb->mark = ecode + 2;
/* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an
argument, and we must check whether that argument matches this MARK's
- argument. It is passed back in md->start_match_ptr (an overloading of that
+ argument. It is passed back in mb->start_match_ptr (an overloading of that
variable). If it does match, we reset that variable to the current subject
position and return MATCH_SKIP. Otherwise, pass back the return code
unaltered. */
else if (rrc == MATCH_SKIP_ARG &&
- STRCMP_UC_UC_TEST(ecode + 2, md->start_match_ptr) == 0)
+ PRIV(strcmp)(ecode + 2, mb->start_match_ptr) == 0)
{
- md->start_match_ptr = eptr;
+ mb->start_match_ptr = eptr;
RRETURN(MATCH_SKIP);
}
RRETURN(rrc);
@@ -780,32 +826,32 @@ for (;;)
RRETURN(MATCH_NOMATCH);
case OP_COMMIT:
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md,
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb,
eptrb, RM52);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
RRETURN(MATCH_COMMIT);
case OP_PRUNE:
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md,
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb,
eptrb, RM51);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
RRETURN(MATCH_PRUNE);
case OP_PRUNE_ARG:
- md->nomatch_mark = ecode + 2;
- md->mark = NULL; /* In case previously set by assertion */
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md,
+ mb->nomatch_mark = ecode + 2;
+ mb->mark = NULL; /* In case previously set by assertion */
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, mb,
eptrb, RM56);
if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) &&
- md->mark == NULL) md->mark = ecode + 2;
+ mb->mark == NULL) mb->mark = ecode + 2;
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
RRETURN(MATCH_PRUNE);
case OP_SKIP:
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md,
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb,
eptrb, RM53);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- md->start_match_ptr = eptr; /* Pass back current position */
+ mb->start_match_ptr = eptr; /* Pass back current position */
RRETURN(MATCH_SKIP);
/* Note that, for Perl compatibility, SKIP with an argument does NOT set
@@ -813,26 +859,26 @@ for (;;)
not a matching mark, we have to re-run the match, ignoring the SKIP_ARG
that failed and any that precede it (either they also failed, or were not
triggered). To do this, we maintain a count of executed SKIP_ARGs. If a
- SKIP_ARG gets to top level, the match is re-run with md->ignore_skip_arg
+ SKIP_ARG gets to top level, the match is re-run with mb->ignore_skip_arg
set to the count of the one that failed. */
case OP_SKIP_ARG:
- md->skip_arg_count++;
- if (md->skip_arg_count <= md->ignore_skip_arg)
+ mb->skip_arg_count++;
+ if (mb->skip_arg_count <= mb->ignore_skip_arg)
{
ecode += PRIV(OP_lengths)[*ecode] + ecode[1];
break;
}
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, md,
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top, mb,
eptrb, RM57);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- /* Pass back the current skip name by overloading md->start_match_ptr and
+ /* Pass back the current skip name by overloading mb->start_match_ptr and
returning the special MATCH_SKIP_ARG return code. This will either be
caught by a matching MARK, or get to the top, where it causes a rematch
- with md->ignore_skip_arg set to the value of md->skip_arg_count. */
+ with mb->ignore_skip_arg set to the value of mb->skip_arg_count. */
- md->start_match_ptr = ecode + 2;
+ mb->start_match_ptr = ecode + 2;
RRETURN(MATCH_SKIP_ARG);
/* For THEN (and THEN_ARG) we pass back the address of the opcode, so that
@@ -840,21 +886,21 @@ for (;;)
match pointer to do this. */
case OP_THEN:
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md,
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb,
eptrb, RM54);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- md->start_match_ptr = ecode;
+ mb->start_match_ptr = ecode;
RRETURN(MATCH_THEN);
case OP_THEN_ARG:
- md->nomatch_mark = ecode + 2;
- md->mark = NULL; /* In case previously set by assertion */
+ mb->nomatch_mark = ecode + 2;
+ mb->mark = NULL; /* In case previously set by assertion */
RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode] + ecode[1], offset_top,
- md, eptrb, RM58);
+ mb, eptrb, RM58);
if ((rrc == MATCH_MATCH || rrc == MATCH_ACCEPT) &&
- md->mark == NULL) md->mark = ecode + 2;
+ mb->mark == NULL) mb->mark = ecode + 2;
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- md->start_match_ptr = ecode;
+ mb->start_match_ptr = ecode;
RRETURN(MATCH_THEN);
/* Handle an atomic group that does not contain any capturing parentheses.
@@ -873,26 +919,26 @@ for (;;)
case OP_ONCE_NC:
prev = ecode;
saved_eptr = eptr;
- save_mark = md->mark;
+ save_mark = mb->mark;
do
{
- RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM64);
+ RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM64);
if (rrc == MATCH_MATCH) /* Note: _not_ MATCH_ACCEPT */
{
- mstart = md->start_match_ptr;
+ mstart = mb->start_match_ptr;
break;
}
if (rrc == MATCH_THEN)
{
- next = ecode + GET(ecode,1);
- if (md->start_match_ptr < next &&
- (*ecode == OP_ALT || *next == OP_ALT))
+ next_ecode = ecode + GET(ecode,1);
+ if (mb->start_match_ptr < next_ecode &&
+ (*ecode == OP_ALT || *next_ecode == OP_ALT))
rrc = MATCH_NOMATCH;
}
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
ecode += GET(ecode,1);
- md->mark = save_mark;
+ mb->mark = save_mark;
}
while (*ecode == OP_ALT);
@@ -905,8 +951,8 @@ for (;;)
do ecode += GET(ecode, 1); while (*ecode == OP_ALT);
- offset_top = md->end_offset_top;
- eptr = md->end_match_ptr;
+ offset_top = mb->end_offset_top;
+ eptr = mb->end_match_ptr;
/* For a non-repeating ket, just continue at this level. This also
happens for a repeating ket if no characters were matched in the group.
@@ -925,14 +971,14 @@ for (;;)
if (*ecode == OP_KETRMIN)
{
- RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM65);
+ RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM65);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
ecode = prev;
goto TAIL_RECURSE;
}
else /* OP_KETRMAX */
{
- RMATCH(eptr, prev, offset_top, md, eptrb, RM66);
+ RMATCH(eptr, prev, offset_top, mb, eptrb, RM66);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
ecode += 1 + LINK_SIZE;
goto TAIL_RECURSE;
@@ -958,29 +1004,20 @@ for (;;)
number = GET2(ecode, 1+LINK_SIZE);
offset = number << 1;
-#ifdef PCRE_DEBUG
- printf("start bracket %d\n", number);
- printf("subject=");
- pchars(eptr, 16, TRUE, md);
- printf("\n");
-#endif
-
- if (offset < md->offset_max)
+ if (offset < mb->offset_max)
{
- save_offset1 = md->offset_vector[offset];
- save_offset2 = md->offset_vector[offset+1];
- save_offset3 = md->offset_vector[md->offset_end - number];
- save_capture_last = md->capture_last;
- save_mark = md->mark;
+ save_offset1 = mb->ovector[offset];
+ save_offset2 = mb->ovector[offset+1];
+ save_offset3 = mb->ovector[mb->offset_end - number];
+ save_capture_last = mb->capture_last;
+ save_mark = mb->mark;
- DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
- md->offset_vector[md->offset_end - number] =
- (int)(eptr - md->start_subject);
+ mb->ovector[mb->offset_end - number] = eptr - mb->start_subject;
for (;;)
{
- if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP;
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md,
+ if (op >= OP_SBRA) mb->match_function_type |= MATCH_CBEGROUP;
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb,
eptrb, RM1);
if (rrc == MATCH_ONCE) break; /* Backing up through an atomic group */
@@ -997,25 +1034,24 @@ for (;;)
if (rrc == MATCH_THEN)
{
- next = ecode + GET(ecode,1);
- if (md->start_match_ptr < next &&
- (*ecode == OP_ALT || *next == OP_ALT))
+ next_ecode = ecode + GET(ecode,1);
+ if (mb->start_match_ptr < next_ecode &&
+ (*ecode == OP_ALT || *next_ecode == OP_ALT))
rrc = MATCH_NOMATCH;
}
/* Anything other than NOMATCH is passed back. */
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- md->capture_last = save_capture_last;
+ mb->capture_last = save_capture_last;
ecode += GET(ecode, 1);
- md->mark = save_mark;
+ mb->mark = save_mark;
if (*ecode != OP_ALT) break;
}
- DPRINTF(("bracket %d failed\n", number));
- md->offset_vector[offset] = save_offset1;
- md->offset_vector[offset+1] = save_offset2;
- md->offset_vector[md->offset_end - number] = save_offset3;
+ mb->ovector[offset] = save_offset1;
+ mb->ovector[offset+1] = save_offset2;
+ mb->ovector[mb->offset_end - number] = save_offset3;
/* At this point, rrc will be one of MATCH_ONCE or MATCH_NOMATCH. */
@@ -1028,11 +1064,6 @@ for (;;)
/* VVVVVVVVVVVVVVVVVVVVVVVVV */
/* VVVVVVVVVVVVVVVVVVVVVVVVV */
- DPRINTF(("insufficient capture room: treat as non-capturing\n"));
-
- /* VVVVVVVVVVVVVVVVVVVVVVVVV */
- /* VVVVVVVVVVVVVVVVVVVVVVVVV */
-
/* Non-capturing or atomic group, except for possessive with unlimited
repeat and ONCE group with no captures. Loop for all the alternatives.
@@ -1049,25 +1080,24 @@ for (;;)
MATCH_ONCE is returned when the end of an atomic group is successfully
reached, but subsequent matching fails. It passes back up the tree (causing
captured values to be reset) until the original atomic group level is
- reached. This is tested by comparing md->once_target with the start of the
+ reached. This is tested by comparing mb->once_target with the start of the
group. At this point, the return is converted into MATCH_NOMATCH so that
previous backup points can be taken. */
case OP_ONCE:
case OP_BRA:
case OP_SBRA:
- DPRINTF(("start non-capturing bracket\n"));
for (;;)
{
if (op >= OP_SBRA || op == OP_ONCE)
- md->match_function_type = MATCH_CBEGROUP;
+ mb->match_function_type |= MATCH_CBEGROUP;
/* If this is not a possibly empty group, and there are no (*THEN)s in
the pattern, and this is the final alternative, optimize as described
above. */
- else if (!md->hasthen && ecode[GET(ecode, 1)] != OP_ALT)
+ else if (!mb->hasthen && ecode[GET(ecode, 1)] != OP_ALT)
{
ecode += PRIV(OP_lengths)[*ecode];
goto TAIL_RECURSE;
@@ -1075,9 +1105,9 @@ for (;;)
/* In all other cases, we have to make another call to match(). */
- save_mark = md->mark;
- save_capture_last = md->capture_last;
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md, eptrb,
+ save_mark = mb->mark;
+ save_capture_last = mb->capture_last;
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb, eptrb,
RM2);
/* See comment in the code for capturing groups above about handling
@@ -1085,9 +1115,9 @@ for (;;)
if (rrc == MATCH_THEN)
{
- next = ecode + GET(ecode,1);
- if (md->start_match_ptr < next &&
- (*ecode == OP_ALT || *next == OP_ALT))
+ next_ecode = ecode + GET(ecode,1);
+ if (mb->start_match_ptr < next_ecode &&
+ (*ecode == OP_ALT || *next_ecode == OP_ALT))
rrc = MATCH_NOMATCH;
}
@@ -1095,31 +1125,32 @@ for (;;)
{
if (rrc == MATCH_ONCE)
{
- const pcre_uchar *scode = ecode;
+ PCRE2_SPTR scode = ecode;
if (*scode != OP_ONCE) /* If not at start, find it */
{
while (*scode == OP_ALT) scode += GET(scode, 1);
scode -= GET(scode, 1);
}
- if (md->once_target == scode) rrc = MATCH_NOMATCH;
+ if (mb->once_target == scode) rrc = MATCH_NOMATCH;
}
RRETURN(rrc);
}
ecode += GET(ecode, 1);
- md->mark = save_mark;
+ mb->mark = save_mark;
if (*ecode != OP_ALT) break;
- md->capture_last = save_capture_last;
+ mb->capture_last = save_capture_last;
}
RRETURN(MATCH_NOMATCH);
/* Handle possessive capturing brackets with an unlimited repeat. We come
- here from BRAZERO with allow_zero set TRUE. The offset_vector values are
+ here from BRAZERO with allow_zero set TRUE. The ovector values are
handled similarly to the normal case above. However, the matching is
different. The end of these brackets will always be OP_KETRPOS, which
returns MATCH_KETRPOS without going further in the pattern. By this means
we can handle the group by iteration rather than recursion, thereby
- reducing the amount of stack needed. */
+ reducing the amount of stack needed. If the ovector is too small for
+ capturing, treat as non-capturing. */
case OP_CBRAPOS:
case OP_SCBRAPOS:
@@ -1128,25 +1159,15 @@ for (;;)
POSSESSIVE_CAPTURE:
number = GET2(ecode, 1+LINK_SIZE);
offset = number << 1;
-
-#ifdef PCRE_DEBUG
- printf("start possessive bracket %d\n", number);
- printf("subject=");
- pchars(eptr, 16, TRUE, md);
- printf("\n");
-#endif
-
- if (offset >= md->offset_max) goto POSSESSIVE_NON_CAPTURE;
+ if (offset >= mb->offset_max) goto POSSESSIVE_NON_CAPTURE;
matched_once = FALSE;
- code_offset = (int)(ecode - md->start_code);
-
- save_offset1 = md->offset_vector[offset];
- save_offset2 = md->offset_vector[offset+1];
- save_offset3 = md->offset_vector[md->offset_end - number];
- save_capture_last = md->capture_last;
+ code_offset = (int)(ecode - mb->start_code);
- DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
+ save_offset1 = mb->ovector[offset];
+ save_offset2 = mb->ovector[offset+1];
+ save_offset3 = mb->ovector[mb->offset_end - number];
+ save_capture_last = mb->capture_last;
/* Each time round the loop, save the current subject position for use
when the group matches. For MATCH_MATCH, the group has matched, so we
@@ -1159,24 +1180,23 @@ for (;;)
for (;;)
{
- md->offset_vector[md->offset_end - number] =
- (int)(eptr - md->start_subject);
- if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP;
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md,
+ mb->ovector[mb->offset_end - number] = eptr - mb->start_subject;
+ if (op >= OP_SBRA) mb->match_function_type |= MATCH_CBEGROUP;
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb,
eptrb, RM63);
if (rrc == MATCH_KETRPOS)
{
- offset_top = md->end_offset_top;
- ecode = md->start_code + code_offset;
- save_capture_last = md->capture_last;
+ offset_top = mb->end_offset_top;
+ ecode = mb->start_code + code_offset;
+ save_capture_last = mb->capture_last;
matched_once = TRUE;
- mstart = md->start_match_ptr; /* In case \K changed it */
- if (eptr == md->end_match_ptr) /* Matched an empty string */
+ mstart = mb->start_match_ptr; /* In case \K changed it */
+ if (eptr == mb->end_match_ptr) /* Matched an empty string */
{
do ecode += GET(ecode, 1); while (*ecode == OP_ALT);
break;
}
- eptr = md->end_match_ptr;
+ eptr = mb->end_match_ptr;
continue;
}
@@ -1185,23 +1205,23 @@ for (;;)
if (rrc == MATCH_THEN)
{
- next = ecode + GET(ecode,1);
- if (md->start_match_ptr < next &&
- (*ecode == OP_ALT || *next == OP_ALT))
+ next_ecode = ecode + GET(ecode,1);
+ if (mb->start_match_ptr < next_ecode &&
+ (*ecode == OP_ALT || *next_ecode == OP_ALT))
rrc = MATCH_NOMATCH;
}
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- md->capture_last = save_capture_last;
+ mb->capture_last = save_capture_last;
ecode += GET(ecode, 1);
if (*ecode != OP_ALT) break;
}
if (!matched_once)
{
- md->offset_vector[offset] = save_offset1;
- md->offset_vector[offset+1] = save_offset2;
- md->offset_vector[md->offset_end - number] = save_offset3;
+ mb->ovector[offset] = save_offset1;
+ mb->ovector[offset+1] = save_offset2;
+ mb->ovector[mb->offset_end - number] = save_offset3;
}
if (allow_zero || matched_once)
@@ -1209,7 +1229,6 @@ for (;;)
ecode += 1 + LINK_SIZE;
break;
}
-
RRETURN(MATCH_NOMATCH);
/* Non-capturing possessive bracket with unlimited repeat. We come here
@@ -1223,26 +1242,26 @@ for (;;)
POSSESSIVE_NON_CAPTURE:
matched_once = FALSE;
- code_offset = (int)(ecode - md->start_code);
- save_capture_last = md->capture_last;
+ code_offset = (int)(ecode - mb->start_code);
+ save_capture_last = mb->capture_last;
for (;;)
{
- if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP;
- RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md,
+ if (op >= OP_SBRA) mb->match_function_type |= MATCH_CBEGROUP;
+ RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, mb,
eptrb, RM48);
if (rrc == MATCH_KETRPOS)
{
- offset_top = md->end_offset_top;
- ecode = md->start_code + code_offset;
+ offset_top = mb->end_offset_top;
+ ecode = mb->start_code + code_offset;
matched_once = TRUE;
- mstart = md->start_match_ptr; /* In case \K reset it */
- if (eptr == md->end_match_ptr) /* Matched an empty string */
+ mstart = mb->start_match_ptr; /* In case \K reset it */
+ if (eptr == mb->end_match_ptr) /* Matched an empty string */
{
do ecode += GET(ecode, 1); while (*ecode == OP_ALT);
break;
}
- eptr = md->end_match_ptr;
+ eptr = mb->end_match_ptr;
continue;
}
@@ -1251,16 +1270,16 @@ for (;;)
if (rrc == MATCH_THEN)
{
- next = ecode + GET(ecode,1);
- if (md->start_match_ptr < next &&
- (*ecode == OP_ALT || *next == OP_ALT))
+ next_ecode = ecode + GET(ecode,1);
+ if (mb->start_match_ptr < next_ecode &&
+ (*ecode == OP_ALT || *next_ecode == OP_ALT))
rrc = MATCH_NOMATCH;
}
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
ecode += GET(ecode, 1);
if (*ecode != OP_ALT) break;
- md->capture_last = save_capture_last;
+ mb->capture_last = save_capture_last;
}
if (matched_once || allow_zero)
@@ -1291,41 +1310,52 @@ for (;;)
/* Because of the way auto-callout works during compile, a callout item is
inserted between OP_COND and an assertion condition. */
- if (*ecode == OP_CALLOUT)
+ if (*ecode == OP_CALLOUT || *ecode == OP_CALLOUT_STR)
{
- if (PUBL(callout) != NULL)
+ unsigned int callout_length = (*ecode == OP_CALLOUT)
+ ? PRIV(OP_lengths)[OP_CALLOUT] : GET(ecode, 1 + 2*LINK_SIZE);
+
+ if (mb->callout != NULL)
{
- PUBL(callout_block) cb;
- cb.version = 2; /* Version 1 of the callout block */
- cb.callout_number = ecode[1];
- cb.offset_vector = md->offset_vector;
-#if defined COMPILE_PCRE8
- cb.subject = (PCRE_SPTR)md->start_subject;
-#elif defined COMPILE_PCRE16
- cb.subject = (PCRE_SPTR16)md->start_subject;
-#elif defined COMPILE_PCRE32
- cb.subject = (PCRE_SPTR32)md->start_subject;
-#endif
- cb.subject_length = (int)(md->end_subject - md->start_subject);
- cb.start_match = (int)(mstart - md->start_subject);
- cb.current_position = (int)(eptr - md->start_subject);
- cb.pattern_position = GET(ecode, 2);
- cb.next_item_length = GET(ecode, 2 + LINK_SIZE);
+ pcre2_callout_block cb;
+ cb.version = 1;
cb.capture_top = offset_top/2;
- cb.capture_last = md->capture_last & CAPLMASK;
- /* Internal change requires this for API compatibility. */
- if (cb.capture_last == 0) cb.capture_last = -1;
- cb.callout_data = md->callout_data;
- cb.mark = md->nomatch_mark;
- if ((rrc = (*PUBL(callout))(&cb)) > 0) RRETURN(MATCH_NOMATCH);
+ cb.capture_last = mb->capture_last & CAPLMASK;
+ cb.offset_vector = mb->ovector;
+ cb.mark = mb->nomatch_mark;
+ cb.subject = mb->start_subject;
+ cb.subject_length = (PCRE2_SIZE)(mb->end_subject - mb->start_subject);
+ cb.start_match = (PCRE2_SIZE)(mstart - mb->start_subject);
+ cb.current_position = (PCRE2_SIZE)(eptr - mb->start_subject);
+ cb.pattern_position = GET(ecode, 1);
+ cb.next_item_length = GET(ecode, 1 + LINK_SIZE);
+
+ if (*ecode == OP_CALLOUT)
+ {
+ cb.callout_number = ecode[1 + 2*LINK_SIZE];
+ cb.callout_string_offset = 0;
+ cb.callout_string = NULL;
+ cb.callout_string_length = 0;
+ }
+ else
+ {
+ cb.callout_number = 0;
+ cb.callout_string_offset = GET(ecode, 1 + 3*LINK_SIZE);
+ cb.callout_string = ecode + (1 + 4*LINK_SIZE) + 1;
+ cb.callout_string_length =
+ callout_length - (1 + 4*LINK_SIZE) - 2;
+ }
+
+ if ((rrc = mb->callout(&cb, mb->callout_data)) > 0)
+ RRETURN(MATCH_NOMATCH);
if (rrc < 0) RRETURN(rrc);
}
/* Advance ecode past the callout, so it now points to the condition. We
must adjust codelink so that the value of ecode+codelink is unchanged. */
- ecode += PRIV(OP_lengths)[OP_CALLOUT];
- codelink -= PRIV(OP_lengths)[OP_CALLOUT];
+ ecode += callout_length;
+ codelink -= callout_length;
}
/* Test the various possible conditions */
@@ -1333,63 +1363,69 @@ for (;;)
condition = FALSE;
switch(condcode = *ecode)
{
- case OP_RREF: /* Numbered group recursion test */
- if (md->recursive != NULL) /* Not recursing => FALSE */
+ case OP_RREF: /* Numbered group recursion test */
+ if (mb->recursive != NULL) /* Not recursing => FALSE */
{
- unsigned int recno = GET2(ecode, 1); /* Recursion group number*/
- condition = (recno == RREF_ANY || recno == md->recursive->group_num);
+ uint32_t recno = GET2(ecode, 1); /* Recursion group number*/
+ condition = (recno == RREF_ANY || recno == mb->recursive->group_num);
}
break;
case OP_DNRREF: /* Duplicate named group recursion test */
- if (md->recursive != NULL)
+ if (mb->recursive != NULL)
{
int count = GET2(ecode, 1 + IMM2_SIZE);
- pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size;
+ PCRE2_SPTR slot = mb->name_table + GET2(ecode, 1) * mb->name_entry_size;
while (count-- > 0)
{
- unsigned int recno = GET2(slot, 0);
- condition = recno == md->recursive->group_num;
+ uint32_t recno = GET2(slot, 0);
+ condition = recno == mb->recursive->group_num;
if (condition) break;
- slot += md->name_entry_size;
+ slot += mb->name_entry_size;
}
}
break;
- case OP_CREF: /* Numbered group used test */
+ case OP_CREF: /* Numbered group used test */
offset = GET2(ecode, 1) << 1; /* Doubled ref number */
- condition = offset < offset_top && md->offset_vector[offset] >= 0;
+ condition = offset < offset_top &&
+ mb->ovector[offset] != PCRE2_UNSET;
break;
case OP_DNCREF: /* Duplicate named group used test */
{
int count = GET2(ecode, 1 + IMM2_SIZE);
- pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size;
+ PCRE2_SPTR slot = mb->name_table + GET2(ecode, 1) * mb->name_entry_size;
while (count-- > 0)
{
offset = GET2(slot, 0) << 1;
- condition = offset < offset_top && md->offset_vector[offset] >= 0;
+ condition = offset < offset_top &&
+ mb->ovector[offset] != PCRE2_UNSET;
if (condition) break;
- slot += md->name_entry_size;
+ slot += mb->name_entry_size;
}
}
break;
- case OP_DEF: /* DEFINE - always false */
- case OP_FAIL: /* From optimized (?!) condition */
+ case OP_FALSE:
+ case OP_FAIL: /* The assertion (?!) becomes OP_FAIL */
+ break;
+
+ case OP_TRUE:
+ condition = TRUE;
break;
/* The condition is an assertion. Call match() to evaluate it - setting
- md->match_function_type to MATCH_CONDASSERT causes it to stop at the end
- of an assertion. */
+ the MATCH_CONDASSERT bit in mb->match_function_type causes it to stop at
+ the end of an assertion. */
default:
- md->match_function_type = MATCH_CONDASSERT;
- RMATCH(eptr, ecode, offset_top, md, NULL, RM3);
+ mb->match_function_type |= MATCH_CONDASSERT;
+ RMATCH(eptr, ecode, offset_top, mb, NULL, RM3);
if (rrc == MATCH_MATCH)
{
- if (md->end_offset_top > offset_top)
- offset_top = md->end_offset_top; /* Captures may have happened */
+ if (mb->end_offset_top > offset_top)
+ offset_top = mb->end_offset_top; /* Captures may have happened */
condition = TRUE;
/* Advance ecode past the assertion to the start of the first branch,
@@ -1435,8 +1471,8 @@ for (;;)
goto TAIL_RECURSE;
}
- md->match_function_type = MATCH_CBEGROUP;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM49);
+ mb->match_function_type |= MATCH_CBEGROUP;
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM49);
RRETURN(rrc);
}
@@ -1454,18 +1490,12 @@ for (;;)
case OP_CLOSE:
number = GET2(ecode, 1); /* Must be less than 65536 */
offset = number << 1;
-
-#ifdef PCRE_DEBUG
- printf("end bracket %d at *ACCEPT", number);
- printf("\n");
-#endif
-
- md->capture_last = (md->capture_last & OVFLMASK) | number;
- if (offset >= md->offset_max) md->capture_last |= OVFLBIT; else
+ mb->capture_last = (mb->capture_last & OVFLMASK) | number;
+ if (offset >= mb->offset_max) mb->capture_last |= OVFLBIT; else
{
- md->offset_vector[offset] =
- md->offset_vector[md->offset_end - number];
- md->offset_vector[offset+1] = (int)(eptr - md->start_subject);
+ mb->ovector[offset] =
+ mb->ovector[mb->offset_end - number];
+ mb->ovector[offset+1] = eptr - mb->start_subject;
/* If this group is at or above the current highwater mark, ensure that
any groups between the current high water mark and this group are marked
@@ -1473,9 +1503,9 @@ for (;;)
if (offset >= offset_top)
{
- register int *iptr = md->offset_vector + offset_top;
- register int *iend = md->offset_vector + offset;
- while (iptr < iend) *iptr++ = -1;
+ register PCRE2_SIZE *iptr = mb->ovector + offset_top;
+ register PCRE2_SIZE *iend = mb->ovector + offset;
+ while (iptr < iend) *iptr++ = PCRE2_UNSET;
offset_top = offset + 2;
}
}
@@ -1483,29 +1513,32 @@ for (;;)
break;
- /* End of the pattern, either real or forced. */
+ /* End of the pattern, either real or forced. In an assertion ACCEPT,
+ update the last used pointer. */
- case OP_END:
- case OP_ACCEPT:
case OP_ASSERT_ACCEPT:
+ if (eptr > mb->last_used_ptr) mb->last_used_ptr = eptr;
+
+ case OP_ACCEPT:
+ case OP_END:
/* If we have matched an empty string, fail if not in an assertion and not
- in a recursion if either PCRE_NOTEMPTY is set, or if PCRE_NOTEMPTY_ATSTART
+ in a recursion if either PCRE2_NOTEMPTY is set, or if PCRE2_NOTEMPTY_ATSTART
is set and we have matched at the start of the subject. In both cases,
backtracking will then try other alternatives, if any. */
if (eptr == mstart && op != OP_ASSERT_ACCEPT &&
- md->recursive == NULL &&
- (md->notempty ||
- (md->notempty_atstart &&
- mstart == md->start_subject + md->start_offset)))
+ mb->recursive == NULL &&
+ ((mb->moptions & PCRE2_NOTEMPTY) != 0 ||
+ ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) != 0 &&
+ mstart == mb->start_subject + mb->start_offset)))
RRETURN(MATCH_NOMATCH);
/* Otherwise, we have a match. */
- md->end_match_ptr = eptr; /* Record where we ended */
- md->end_offset_top = offset_top; /* and how many extracts were taken */
- md->start_match_ptr = mstart; /* and the start (\K can modify) */
+ mb->end_match_ptr = eptr; /* Record where we ended */
+ mb->end_offset_top = offset_top; /* and how many extracts were taken */
+ mb->start_match_ptr = mstart; /* and the start (\K can modify) */
/* For some reason, the macros don't work properly if an expression is
given as the argument to RRETURN when the heap is in use. */
@@ -1520,17 +1553,17 @@ for (;;)
this level is identical to the lookahead case. When the assertion is part
of a condition, we want to return immediately afterwards. The caller of
this incarnation of the match() function will have set MATCH_CONDASSERT in
- md->match_function type, and one of these opcodes will be the first opcode
+ mb->match_function type, and one of these opcodes will be the first opcode
that is processed. We use a local variable that is preserved over calls to
match() to remember this case. */
case OP_ASSERT:
case OP_ASSERTBACK:
- save_mark = md->mark;
- if (md->match_function_type == MATCH_CONDASSERT)
+ save_mark = mb->mark;
+ if ((mb->match_function_type & MATCH_CONDASSERT) != 0)
{
condassert = TRUE;
- md->match_function_type = 0;
+ mb->match_function_type &= ~MATCH_CONDASSERT;
}
else condassert = FALSE;
@@ -1538,29 +1571,29 @@ for (;;)
do
{
- RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM4);
+ RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, NULL, RM4);
/* A match means that the assertion is true; break out of the loop
that matches its alternatives. */
if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT)
{
- mstart = md->start_match_ptr; /* In case \K reset it */
+ mstart = mb->start_match_ptr; /* In case \K reset it */
break;
}
/* If not matched, restore the previous mark setting. */
- md->mark = save_mark;
+ mb->mark = save_mark;
/* See comment in the code for capturing groups above about handling
THEN. */
if (rrc == MATCH_THEN)
{
- next = ecode + GET(ecode,1);
- if (md->start_match_ptr < next &&
- (*ecode == OP_ALT || *next == OP_ALT))
+ next_ecode = ecode + GET(ecode,1);
+ if (mb->start_match_ptr < next_ecode &&
+ (*ecode == OP_ALT || *next_ecode == OP_ALT))
rrc = MATCH_NOMATCH;
}
@@ -1589,7 +1622,7 @@ for (;;)
do ecode += GET(ecode,1); while (*ecode == OP_ALT);
ecode += 1 + LINK_SIZE;
- offset_top = md->end_offset_top;
+ offset_top = mb->end_offset_top;
continue;
/* Negative assertion: all branches must fail to match for the assertion to
@@ -1597,11 +1630,11 @@ for (;;)
case OP_ASSERT_NOT:
case OP_ASSERTBACK_NOT:
- save_mark = md->mark;
- if (md->match_function_type == MATCH_CONDASSERT)
+ save_mark = mb->mark;
+ if ((mb->match_function_type & MATCH_CONDASSERT) != 0)
{
condassert = TRUE;
- md->match_function_type = 0;
+ mb->match_function_type &= ~MATCH_CONDASSERT;
}
else condassert = FALSE;
@@ -1609,8 +1642,8 @@ for (;;)
do
{
- RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, NULL, RM5);
- md->mark = save_mark; /* Always restore the mark setting */
+ RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, NULL, RM5);
+ mb->mark = save_mark; /* Always restore the mark setting */
switch(rrc)
{
@@ -1625,9 +1658,9 @@ for (;;)
THEN. */
case MATCH_THEN:
- next = ecode + GET(ecode,1);
- if (md->start_match_ptr < next &&
- (*ecode == OP_ALT || *next == OP_ALT))
+ next_ecode = ecode + GET(ecode,1);
+ if (mb->start_match_ptr < next_ecode &&
+ (*ecode == OP_ALT || *next_ecode == OP_ALT))
{
rrc = MATCH_NOMATCH;
break;
@@ -1671,14 +1704,14 @@ for (;;)
back a number of characters, not bytes. */
case OP_REVERSE:
-#ifdef SUPPORT_UTF
+ i = GET(ecode, 1);
+#ifdef SUPPORT_UNICODE
if (utf)
{
- i = GET(ecode, 1);
while (i-- > 0)
{
+ if (eptr <= mb->start_subject) RRETURN(MATCH_NOMATCH);
eptr--;
- if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH);
BACKCHAR(eptr);
}
}
@@ -1688,13 +1721,13 @@ for (;;)
/* No UTF-8 support, or not in UTF-8 mode: count is byte count */
{
- eptr -= GET(ecode, 1);
- if (eptr < md->start_subject) RRETURN(MATCH_NOMATCH);
+ if (i > eptr - mb->start_subject) RRETURN(MATCH_NOMATCH);
+ eptr -= i;
}
/* Save the earliest consulted character, then skip to next op code */
- if (eptr < md->start_used_ptr) md->start_used_ptr = eptr;
+ if (eptr < mb->start_used_ptr) mb->start_used_ptr = eptr;
ecode += 1 + LINK_SIZE;
break;
@@ -1703,34 +1736,49 @@ for (;;)
function is able to force a failure. */
case OP_CALLOUT:
- if (PUBL(callout) != NULL)
+ case OP_CALLOUT_STR:
{
- PUBL(callout_block) cb;
- cb.version = 2; /* Version 1 of the callout block */
- cb.callout_number = ecode[1];
- cb.offset_vector = md->offset_vector;
-#if defined COMPILE_PCRE8
- cb.subject = (PCRE_SPTR)md->start_subject;
-#elif defined COMPILE_PCRE16
- cb.subject = (PCRE_SPTR16)md->start_subject;
-#elif defined COMPILE_PCRE32
- cb.subject = (PCRE_SPTR32)md->start_subject;
-#endif
- cb.subject_length = (int)(md->end_subject - md->start_subject);
- cb.start_match = (int)(mstart - md->start_subject);
- cb.current_position = (int)(eptr - md->start_subject);
- cb.pattern_position = GET(ecode, 2);
- cb.next_item_length = GET(ecode, 2 + LINK_SIZE);
- cb.capture_top = offset_top/2;
- cb.capture_last = md->capture_last & CAPLMASK;
- /* Internal change requires this for API compatibility. */
- if (cb.capture_last == 0) cb.capture_last = -1;
- cb.callout_data = md->callout_data;
- cb.mark = md->nomatch_mark;
- if ((rrc = (*PUBL(callout))(&cb)) > 0) RRETURN(MATCH_NOMATCH);
- if (rrc < 0) RRETURN(rrc);
+ unsigned int callout_length = (*ecode == OP_CALLOUT)
+ ? PRIV(OP_lengths)[OP_CALLOUT] : GET(ecode, 1 + 2*LINK_SIZE);
+
+ if (mb->callout != NULL)
+ {
+ pcre2_callout_block cb;
+ cb.version = 1;
+ cb.callout_number = ecode[LINK_SIZE + 1];
+ cb.capture_top = offset_top/2;
+ cb.capture_last = mb->capture_last & CAPLMASK;
+ cb.offset_vector = mb->ovector;
+ cb.mark = mb->nomatch_mark;
+ cb.subject = mb->start_subject;
+ cb.subject_length = (PCRE2_SIZE)(mb->end_subject - mb->start_subject);
+ cb.start_match = (PCRE2_SIZE)(mstart - mb->start_subject);
+ cb.current_position = (PCRE2_SIZE)(eptr - mb->start_subject);
+ cb.pattern_position = GET(ecode, 1);
+ cb.next_item_length = GET(ecode, 1 + LINK_SIZE);
+
+ if (*ecode == OP_CALLOUT)
+ {
+ cb.callout_number = ecode[1 + 2*LINK_SIZE];
+ cb.callout_string_offset = 0;
+ cb.callout_string = NULL;
+ cb.callout_string_length = 0;
+ }
+ else
+ {
+ cb.callout_number = 0;
+ cb.callout_string_offset = GET(ecode, 1 + 3*LINK_SIZE);
+ cb.callout_string = ecode + (1 + 4*LINK_SIZE) + 1;
+ cb.callout_string_length =
+ callout_length - (1 + 4*LINK_SIZE) - 2;
+ }
+
+ if ((rrc = mb->callout(&cb, mb->callout_data)) > 0)
+ RRETURN(MATCH_NOMATCH);
+ if (rrc < 0) RRETURN(rrc);
+ }
+ ecode += callout_length;
}
- ecode += 2 + 2*LINK_SIZE;
break;
/* Recursion either matches the current regex, or some subexpression. The
@@ -1743,7 +1791,7 @@ for (;;)
all the potential data. There may be up to 65535 such values, which is too
large to put on the stack, but using malloc for small numbers seems
expensive. As a compromise, the stack is used when there are no more than
- REC_STACK_SAVE_MAX values to store; otherwise malloc is used.
+ OP_RECURSE_STACK_SAVE_MAX values to store; otherwise malloc is used.
There are also other values that have to be saved. We use a chained
sequence of blocks that actually live on the stack. Thanks to Robin Houston
@@ -1752,75 +1800,106 @@ for (;;)
case OP_RECURSE:
{
+ ovecsave_frame *fr;
recursion_info *ri;
- unsigned int recno;
+ uint32_t recno;
- callpat = md->start_code + GET(ecode, 1);
- recno = (callpat == md->start_code)? 0 :
- GET2(callpat, 1 + LINK_SIZE);
+ callpat = mb->start_code + GET(ecode, 1);
+ recno = (callpat == mb->start_code)? 0 : GET2(callpat, 1 + LINK_SIZE);
- /* Check for repeating a recursion without advancing the subject pointer.
- This should catch convoluted mutual recursions. (Some simple cases are
- caught at compile time.) */
+ /* Check for repeating a pattern recursion without advancing the subject
+ pointer. This should catch convoluted mutual recursions. (Some simple
+ cases are caught at compile time.) */
- for (ri = md->recursive; ri != NULL; ri = ri->prevrec)
+ for (ri = mb->recursive; ri != NULL; ri = ri->prevrec)
if (recno == ri->group_num && eptr == ri->subject_position)
- RRETURN(PCRE_ERROR_RECURSELOOP);
+ RRETURN(PCRE2_ERROR_RECURSELOOP);
/* Add to "recursing stack" */
new_recursive.group_num = recno;
- new_recursive.saved_capture_last = md->capture_last;
+ new_recursive.saved_capture_last = mb->capture_last;
new_recursive.subject_position = eptr;
- new_recursive.prevrec = md->recursive;
- md->recursive = &new_recursive;
+ new_recursive.prevrec = mb->recursive;
+ mb->recursive = &new_recursive;
/* Where to continue from afterwards */
ecode += 1 + LINK_SIZE;
- /* Now save the offset data */
+ /* When we are using the system stack for match() recursion we can call a
+ function that uses the system stack for preserving the ovector while
+ processing the pattern recursion, but only if the ovector is small
+ enough. */
- new_recursive.saved_max = md->offset_end;
- if (new_recursive.saved_max <= REC_STACK_SAVE_MAX)
- new_recursive.offset_save = stacksave;
+#ifndef HEAP_MATCH_RECURSE
+ if (mb->offset_end <= OP_RECURSE_STACK_SAVE_MAX)
+ {
+ rrc = op_recurse_ovecsave(eptr, callpat, mstart, offset_top, mb,
+ eptrb, rdepth);
+ mb->recursive = new_recursive.prevrec;
+ if (rrc != MATCH_MATCH && rrc != MATCH_ACCEPT) RRETURN(rrc);
+
+ /* Set where we got to in the subject, and reset the start, in case
+ it was changed by \K. This *is* propagated back out of a recursion,
+ for Perl compatibility. */
+
+ eptr = mb->end_match_ptr;
+ mstart = mb->start_match_ptr;
+ break; /* End of processing OP_RECURSE */
+ }
+#endif
+ /* If the ovector is too big, or if we are using the heap for match()
+ recursion, we have to use the heap for saving the ovector. Used ovecsave
+ frames are kept on a chain and re-used. This makes a small improvement in
+ execution time on Linux. */
+
+ if (mb->ovecsave_chain != NULL)
+ {
+ new_recursive.ovec_save = mb->ovecsave_chain->saved_ovec;
+ mb->ovecsave_chain = mb->ovecsave_chain->next;
+ }
else
{
- new_recursive.offset_save =
- (int *)(PUBL(malloc))(new_recursive.saved_max * sizeof(int));
- if (new_recursive.offset_save == NULL) RRETURN(PCRE_ERROR_NOMEMORY);
+ fr = (ovecsave_frame *)(mb->memctl.malloc(sizeof(ovecsave_frame *) +
+ mb->offset_end * sizeof(PCRE2_SIZE), mb->memctl.memory_data));
+ if (fr == NULL) RRETURN(PCRE2_ERROR_NOMEMORY);
+ new_recursive.ovec_save = fr->saved_ovec;
}
- memcpy(new_recursive.offset_save, md->offset_vector,
- new_recursive.saved_max * sizeof(int));
- /* OK, now we can do the recursion. After processing each alternative,
- restore the offset data and the last captured value. If there were nested
- recursions, md->recursive might be changed, so reset it before looping.
- */
+ memcpy(new_recursive.ovec_save, mb->ovector,
+ mb->offset_end * sizeof(PCRE2_SIZE));
+
+ /* Do the recursion. After processing each alternative, restore the
+ ovector data and the last captured value. This code has the same overall
+ logic as the code in the op_recurse_ovecsave() function, but is adapted
+ to use RMATCH/RRETURN and to release the heap block containing the saved
+ ovector. */
- DPRINTF(("Recursing into group %d\n", new_recursive.group_num));
cbegroup = (*callpat >= OP_SBRA);
do
{
- if (cbegroup) md->match_function_type = MATCH_CBEGROUP;
+ if (cbegroup) mb->match_function_type |= MATCH_CBEGROUP;
RMATCH(eptr, callpat + PRIV(OP_lengths)[*callpat], offset_top,
- md, eptrb, RM6);
- memcpy(md->offset_vector, new_recursive.offset_save,
- new_recursive.saved_max * sizeof(int));
- md->capture_last = new_recursive.saved_capture_last;
- md->recursive = new_recursive.prevrec;
+ mb, eptrb, RM6);
+ memcpy(mb->ovector, new_recursive.ovec_save,
+ mb->offset_end * sizeof(PCRE2_SIZE));
+ mb->capture_last = new_recursive.saved_capture_last;
+ mb->recursive = new_recursive.prevrec;
+
if (rrc == MATCH_MATCH || rrc == MATCH_ACCEPT)
{
- DPRINTF(("Recursion matched\n"));
- if (new_recursive.offset_save != stacksave)
- (PUBL(free))(new_recursive.offset_save);
+ fr = (ovecsave_frame *)
+ ((uint8_t *)new_recursive.ovec_save - sizeof(ovecsave_frame *));
+ fr->next = mb->ovecsave_chain;
+ mb->ovecsave_chain = fr;
- /* Set where we got to in the subject, and reset the start in case
+ /* Set where we got to in the subject, and reset the start, in case
it was changed by \K. This *is* propagated back out of a recursion,
for Perl compatibility. */
- eptr = md->end_match_ptr;
- mstart = md->start_match_ptr;
+ eptr = mb->end_match_ptr;
+ mstart = mb->start_match_ptr;
goto RECURSION_MATCHED; /* Exit loop; end processing */
}
@@ -1830,31 +1909,25 @@ for (;;)
if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX)
{
- if (new_recursive.offset_save != stacksave)
- (PUBL(free))(new_recursive.offset_save);
- RRETURN(MATCH_NOMATCH);
+ rrc = MATCH_NOMATCH;
+ goto RECURSION_RETURN;
}
/* Any return code other than NOMATCH is an error. */
- if (rrc != MATCH_NOMATCH)
- {
- DPRINTF(("Recursion gave error %d\n", rrc));
- if (new_recursive.offset_save != stacksave)
- (PUBL(free))(new_recursive.offset_save);
- RRETURN(rrc);
- }
-
- md->recursive = &new_recursive;
+ if (rrc != MATCH_NOMATCH) goto RECURSION_RETURN;
+ mb->recursive = &new_recursive;
callpat += GET(callpat, 1);
}
while (*callpat == OP_ALT);
- DPRINTF(("Recursion didn't match\n"));
- md->recursive = new_recursive.prevrec;
- if (new_recursive.offset_save != stacksave)
- (PUBL(free))(new_recursive.offset_save);
- RRETURN(MATCH_NOMATCH);
+ RECURSION_RETURN:
+ mb->recursive = new_recursive.prevrec;
+ fr = (ovecsave_frame *)
+ ((uint8_t *)new_recursive.ovec_save - sizeof(ovecsave_frame *));
+ fr->next = mb->ovecsave_chain;
+ mb->ovecsave_chain = fr;
+ RRETURN(rrc);
}
RECURSION_MATCHED:
@@ -1874,25 +1947,25 @@ for (;;)
optional ones preceded by BRAZERO or BRAMINZERO. */
case OP_BRAZERO:
- next = ecode + 1;
- RMATCH(eptr, next, offset_top, md, eptrb, RM10);
+ next_ecode = ecode + 1;
+ RMATCH(eptr, next_ecode, offset_top, mb, eptrb, RM10);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- do next += GET(next, 1); while (*next == OP_ALT);
- ecode = next + 1 + LINK_SIZE;
+ do next_ecode += GET(next_ecode, 1); while (*next_ecode == OP_ALT);
+ ecode = next_ecode + 1 + LINK_SIZE;
break;
case OP_BRAMINZERO:
- next = ecode + 1;
- do next += GET(next, 1); while (*next == OP_ALT);
- RMATCH(eptr, next + 1+LINK_SIZE, offset_top, md, eptrb, RM11);
+ next_ecode = ecode + 1;
+ do next_ecode += GET(next_ecode, 1); while (*next_ecode == OP_ALT);
+ RMATCH(eptr, next_ecode + 1+LINK_SIZE, offset_top, mb, eptrb, RM11);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
ecode++;
break;
case OP_SKIPZERO:
- next = ecode+1;
- do next += GET(next,1); while (*next == OP_ALT);
- ecode = next + 1 + LINK_SIZE;
+ next_ecode = ecode+1;
+ do next_ecode += GET(next_ecode,1); while (*next_ecode == OP_ALT);
+ ecode = next_ecode + 1 + LINK_SIZE;
break;
/* BRAPOSZERO occurs before a possessive bracket group. Don't do anything
@@ -1931,10 +2004,11 @@ for (;;)
if ((*prev >= OP_ASSERT && *prev <= OP_ASSERTBACK_NOT) ||
*prev == OP_ONCE_NC)
{
- md->end_match_ptr = eptr; /* For ONCE_NC */
- md->end_offset_top = offset_top;
- md->start_match_ptr = mstart;
- RRETURN(MATCH_MATCH); /* Sets md->mark */
+ mb->end_match_ptr = eptr; /* For ONCE_NC */
+ mb->end_offset_top = offset_top;
+ mb->start_match_ptr = mstart;
+ if (eptr > mb->last_used_ptr) mb->last_used_ptr = eptr;
+ RRETURN(MATCH_MATCH); /* Sets mb->mark */
}
/* For capturing groups we have to check the group number back at the start
@@ -1951,24 +2025,20 @@ for (;;)
number = GET2(prev, 1+LINK_SIZE);
offset = number << 1;
-#ifdef PCRE_DEBUG
- printf("end bracket %d", number);
- printf("\n");
-#endif
-
/* Handle a recursively called group. */
- if (md->recursive != NULL && md->recursive->group_num == number)
+ if (mb->recursive != NULL && mb->recursive->group_num == number)
{
- md->end_match_ptr = eptr;
- md->start_match_ptr = mstart;
+ mb->end_match_ptr = eptr;
+ mb->start_match_ptr = mstart;
+ if (eptr > mb->last_used_ptr) mb->last_used_ptr = eptr;
RRETURN(MATCH_MATCH);
}
/* Deal with capturing */
- md->capture_last = (md->capture_last & OVFLMASK) | number;
- if (offset >= md->offset_max) md->capture_last |= OVFLBIT; else
+ mb->capture_last = (mb->capture_last & OVFLMASK) | number;
+ if (offset >= mb->offset_max) mb->capture_last |= OVFLBIT; else
{
/* If offset is greater than offset_top, it means that we are
"skipping" a capturing group, and that group's offsets must be marked
@@ -1982,16 +2052,15 @@ for (;;)
if (offset > offset_top)
{
- register int *iptr = md->offset_vector + offset_top;
- register int *iend = md->offset_vector + offset;
- while (iptr < iend) *iptr++ = -1;
+ register PCRE2_SIZE *iptr = mb->ovector + offset_top;
+ register PCRE2_SIZE *iend = mb->ovector + offset;
+ while (iptr < iend) *iptr++ = PCRE2_UNSET;
}
/* Now make the extraction */
- md->offset_vector[offset] =
- md->offset_vector[md->offset_end - number];
- md->offset_vector[offset+1] = (int)(eptr - md->start_subject);
+ mb->ovector[offset] = mb->ovector[mb->offset_end - number];
+ mb->ovector[offset+1] = eptr - mb->start_subject;
if (offset_top <= offset) offset_top = offset + 2;
}
}
@@ -2003,9 +2072,10 @@ for (;;)
if (*ecode == OP_KETRPOS)
{
- md->start_match_ptr = mstart; /* In case \K reset it */
- md->end_match_ptr = eptr;
- md->end_offset_top = offset_top;
+ mb->start_match_ptr = mstart; /* In case \K reset it */
+ mb->end_match_ptr = eptr;
+ mb->end_offset_top = offset_top;
+ if (eptr > mb->last_used_ptr) mb->last_used_ptr = eptr;
RRETURN(MATCH_KETRPOS);
}
@@ -2022,9 +2092,9 @@ for (;;)
{
if (*prev == OP_ONCE)
{
- RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM12);
+ RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM12);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- md->once_target = prev; /* Level at which to change to MATCH_NOMATCH */
+ mb->once_target = prev; /* Level at which to change to MATCH_NOMATCH */
RRETURN(MATCH_ONCE);
}
ecode += 1 + LINK_SIZE; /* Carry on at this level */
@@ -2039,18 +2109,18 @@ for (;;)
if (*ecode == OP_KETRMIN)
{
- RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM7);
+ RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM7);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (*prev == OP_ONCE)
{
- RMATCH(eptr, prev, offset_top, md, eptrb, RM8);
+ RMATCH(eptr, prev, offset_top, mb, eptrb, RM8);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- md->once_target = prev; /* Level at which to change to MATCH_NOMATCH */
+ mb->once_target = prev; /* Level at which to change to MATCH_NOMATCH */
RRETURN(MATCH_ONCE);
}
if (*prev >= OP_SBRA) /* Could match an empty string */
{
- RMATCH(eptr, prev, offset_top, md, eptrb, RM50);
+ RMATCH(eptr, prev, offset_top, mb, eptrb, RM50);
RRETURN(rrc);
}
ecode = prev;
@@ -2058,14 +2128,14 @@ for (;;)
}
else /* OP_KETRMAX */
{
- RMATCH(eptr, prev, offset_top, md, eptrb, RM13);
- if (rrc == MATCH_ONCE && md->once_target == prev) rrc = MATCH_NOMATCH;
+ RMATCH(eptr, prev, offset_top, mb, eptrb, RM13);
+ if (rrc == MATCH_ONCE && mb->once_target == prev) rrc = MATCH_NOMATCH;
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (*prev == OP_ONCE)
{
- RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, md, eptrb, RM9);
+ RMATCH(eptr, ecode + 1 + LINK_SIZE, offset_top, mb, eptrb, RM9);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- md->once_target = prev;
+ mb->once_target = prev;
RRETURN(MATCH_ONCE);
}
ecode += 1 + LINK_SIZE;
@@ -2076,21 +2146,26 @@ for (;;)
/* Not multiline mode: start of subject assertion, unless notbol. */
case OP_CIRC:
- if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH);
+ if ((mb->moptions & PCRE2_NOTBOL) != 0 && eptr == mb->start_subject)
+ RRETURN(MATCH_NOMATCH);
/* Start of subject assertion */
case OP_SOD:
- if (eptr != md->start_subject) RRETURN(MATCH_NOMATCH);
+ if (eptr != mb->start_subject) RRETURN(MATCH_NOMATCH);
ecode++;
break;
- /* Multiline mode: start of subject unless notbol, or after any newline. */
+ /* Multiline mode: start of subject unless notbol, or after any newline
+ except for one at the very end, unless PCRE2_ALT_CIRCUMFLEX is set. */
case OP_CIRCM:
- if (md->notbol && eptr == md->start_subject) RRETURN(MATCH_NOMATCH);
- if (eptr != md->start_subject &&
- (eptr == md->end_subject || !WAS_NEWLINE(eptr)))
+ if ((mb->moptions & PCRE2_NOTBOL) != 0 && eptr == mb->start_subject)
+ RRETURN(MATCH_NOMATCH);
+ if (eptr != mb->start_subject &&
+ ((eptr == mb->end_subject &&
+ (mb->poptions & PCRE2_ALT_CIRCUMFLEX) == 0) ||
+ !WAS_NEWLINE(eptr)))
RRETURN(MATCH_NOMATCH);
ecode++;
break;
@@ -2098,7 +2173,7 @@ for (;;)
/* Start of match assertion */
case OP_SOM:
- if (eptr != md->start_subject + md->start_offset) RRETURN(MATCH_NOMATCH);
+ if (eptr != mb->start_subject + mb->start_offset) RRETURN(MATCH_NOMATCH);
ecode++;
break;
@@ -2113,25 +2188,25 @@ for (;;)
unless noteol is set. */
case OP_DOLLM:
- if (eptr < md->end_subject)
+ if (eptr < mb->end_subject)
{
if (!IS_NEWLINE(eptr))
{
- if (md->partial != 0 &&
- eptr + 1 >= md->end_subject &&
+ if (mb->partial != 0 &&
+ eptr + 1 >= mb->end_subject &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
UCHAR21TEST(eptr) == NLBLOCK->nl[0])
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
RRETURN(MATCH_NOMATCH);
}
}
else
{
- if (md->noteol) RRETURN(MATCH_NOMATCH);
+ if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH);
SCHECK_PARTIAL();
}
ecode++;
@@ -2141,15 +2216,15 @@ for (;;)
subject unless noteol is set. */
case OP_DOLL:
- if (md->noteol) RRETURN(MATCH_NOMATCH);
- if (!md->endonly) goto ASSERT_NL_OR_EOS;
+ if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH);
+ if ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0) goto ASSERT_NL_OR_EOS;
/* ... else fall through for endonly */
/* End of subject assertion (\z) */
case OP_EOD:
- if (eptr < md->end_subject) RRETURN(MATCH_NOMATCH);
+ if (eptr < mb->end_subject) RRETURN(MATCH_NOMATCH);
SCHECK_PARTIAL();
ecode++;
break;
@@ -2158,17 +2233,17 @@ for (;;)
case OP_EODN:
ASSERT_NL_OR_EOS:
- if (eptr < md->end_subject &&
- (!IS_NEWLINE(eptr) || eptr != md->end_subject - md->nllen))
+ if (eptr < mb->end_subject &&
+ (!IS_NEWLINE(eptr) || eptr != mb->end_subject - mb->nllen))
{
- if (md->partial != 0 &&
- eptr + 1 >= md->end_subject &&
+ if (mb->partial != 0 &&
+ eptr + 1 >= mb->end_subject &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
UCHAR21TEST(eptr) == NLBLOCK->nl[0])
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
RRETURN(MATCH_NOMATCH);
}
@@ -2190,19 +2265,18 @@ for (;;)
be "non-word" characters. Remember the earliest consulted character for
partial matching. */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
/* Get status of previous character */
- if (eptr == md->start_subject) prev_is_word = FALSE; else
+ if (eptr == mb->start_subject) prev_is_word = FALSE; else
{
- PCRE_PUCHAR lastptr = eptr - 1;
+ PCRE2_SPTR lastptr = eptr - 1;
BACKCHAR(lastptr);
- if (lastptr < md->start_used_ptr) md->start_used_ptr = lastptr;
+ if (lastptr < mb->start_used_ptr) mb->start_used_ptr = lastptr;
GETCHAR(c, lastptr);
-#ifdef SUPPORT_UCP
- if (md->use_ucp)
+ if ((mb->poptions & PCRE2_UCP) != 0)
{
if (c == '_') prev_is_word = TRUE; else
{
@@ -2211,22 +2285,23 @@ for (;;)
}
}
else
-#endif
- prev_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0;
+ prev_is_word = c < 256 && (mb->ctypes[c] & ctype_word) != 0;
}
/* Get status of next character */
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
cur_is_word = FALSE;
}
else
{
+ PCRE2_SPTR nextptr = eptr + 1;
+ FORWARDCHARTEST(nextptr, mb->end_subject);
+ if (nextptr > mb->last_used_ptr) mb->last_used_ptr = nextptr;
GETCHAR(c, eptr);
-#ifdef SUPPORT_UCP
- if (md->use_ucp)
+ if ((mb->poptions & PCRE2_UCP) != 0)
{
if (c == '_') cur_is_word = TRUE; else
{
@@ -2235,24 +2310,23 @@ for (;;)
}
}
else
-#endif
- cur_is_word = c < 256 && (md->ctypes[c] & ctype_word) != 0;
+ cur_is_word = c < 256 && (mb->ctypes[c] & ctype_word) != 0;
}
}
else
-#endif
+#endif /* SUPPORT UTF */
- /* Not in UTF-8 mode, but we may still have PCRE_UCP set, and for
+ /* Not in UTF-8 mode, but we may still have PCRE2_UCP set, and for
consistency with the behaviour of \w we do use it in this case. */
{
/* Get status of previous character */
- if (eptr == md->start_subject) prev_is_word = FALSE; else
+ if (eptr == mb->start_subject) prev_is_word = FALSE; else
{
- if (eptr <= md->start_used_ptr) md->start_used_ptr = eptr - 1;
-#ifdef SUPPORT_UCP
- if (md->use_ucp)
+ if (eptr <= mb->start_used_ptr) mb->start_used_ptr = eptr - 1;
+#ifdef SUPPORT_UNICODE
+ if ((mb->poptions & PCRE2_UCP) != 0)
{
c = eptr[-1];
if (c == '_') prev_is_word = TRUE; else
@@ -2264,31 +2338,34 @@ for (;;)
else
#endif
prev_is_word = MAX_255(eptr[-1])
- && ((md->ctypes[eptr[-1]] & ctype_word) != 0);
+ && ((mb->ctypes[eptr[-1]] & ctype_word) != 0);
}
/* Get status of next character */
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
cur_is_word = FALSE;
}
else
-#ifdef SUPPORT_UCP
- if (md->use_ucp)
{
- c = *eptr;
- if (c == '_') cur_is_word = TRUE; else
+ if (eptr >= mb->last_used_ptr) mb->last_used_ptr = eptr + 1;
+#ifdef SUPPORT_UNICODE
+ if ((mb->poptions & PCRE2_UCP) != 0)
{
- int cat = UCD_CATEGORY(c);
- cur_is_word = (cat == ucp_L || cat == ucp_N);
+ c = *eptr;
+ if (c == '_') cur_is_word = TRUE; else
+ {
+ int cat = UCD_CATEGORY(c);
+ cur_is_word = (cat == ucp_L || cat == ucp_N);
+ }
}
- }
- else
+ else
#endif
- cur_is_word = MAX_255(*eptr)
- && ((md->ctypes[*eptr] & ctype_word) != 0);
+ cur_is_word = MAX_255(*eptr)
+ && ((mb->ctypes[*eptr] & ctype_word) != 0);
+ }
}
/* Now see if the situation is what we want */
@@ -2304,14 +2381,14 @@ for (;;)
case OP_ANY:
if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH);
- if (md->partial != 0 &&
- eptr + 1 >= md->end_subject &&
+ if (mb->partial != 0 &&
+ eptr + 1 >= mb->end_subject &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
UCHAR21TEST(eptr) == NLBLOCK->nl[0])
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
/* Fall through */
@@ -2319,23 +2396,24 @@ for (;;)
/* Match any single character whatsoever. */
case OP_ALLANY:
- if (eptr >= md->end_subject) /* DO NOT merge the eptr++ here; it must */
+ if (eptr >= mb->end_subject) /* DO NOT merge the eptr++ here; it must */
{ /* not be updated before SCHECK_PARTIAL. */
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
eptr++;
-#ifdef SUPPORT_UTF
- if (utf) ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++);
+#ifdef SUPPORT_UNICODE
+ if (utf) ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++);
#endif
ecode++;
break;
- /* Match a single byte, even in UTF-8 mode. This opcode really does match
- any byte, even newline, independent of the setting of PCRE_DOTALL. */
+ /* Match a single code unit, even in UTF-8 mode. This opcode really does
+ match any code unit, even newline. (It really should be called ANYCODEUNIT,
+ of course - the byte name is from pre-16 bit days.) */
case OP_ANYBYTE:
- if (eptr >= md->end_subject) /* DO NOT merge the eptr++ here; it must */
+ if (eptr >= mb->end_subject) /* DO NOT merge the eptr++ here; it must */
{ /* not be updated before SCHECK_PARTIAL. */
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -2345,109 +2423,109 @@ for (;;)
break;
case OP_NOT_DIGIT:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(c, eptr);
if (
-#if defined SUPPORT_UTF || !(defined COMPILE_PCRE8)
+#ifdef SUPPORT_WIDE_CHARS
c < 256 &&
#endif
- (md->ctypes[c] & ctype_digit) != 0
+ (mb->ctypes[c] & ctype_digit) != 0
)
RRETURN(MATCH_NOMATCH);
ecode++;
break;
case OP_DIGIT:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(c, eptr);
if (
-#if defined SUPPORT_UTF || !(defined COMPILE_PCRE8)
+#ifdef SUPPORT_WIDE_CHARS
c > 255 ||
#endif
- (md->ctypes[c] & ctype_digit) == 0
+ (mb->ctypes[c] & ctype_digit) == 0
)
RRETURN(MATCH_NOMATCH);
ecode++;
break;
case OP_NOT_WHITESPACE:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(c, eptr);
if (
-#if defined SUPPORT_UTF || !(defined COMPILE_PCRE8)
+#ifdef SUPPORT_WIDE_CHARS
c < 256 &&
#endif
- (md->ctypes[c] & ctype_space) != 0
+ (mb->ctypes[c] & ctype_space) != 0
)
RRETURN(MATCH_NOMATCH);
ecode++;
break;
case OP_WHITESPACE:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(c, eptr);
if (
-#if defined SUPPORT_UTF || !(defined COMPILE_PCRE8)
+#ifdef SUPPORT_WIDE_CHARS
c > 255 ||
#endif
- (md->ctypes[c] & ctype_space) == 0
+ (mb->ctypes[c] & ctype_space) == 0
)
RRETURN(MATCH_NOMATCH);
ecode++;
break;
case OP_NOT_WORDCHAR:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(c, eptr);
if (
-#if defined SUPPORT_UTF || !(defined COMPILE_PCRE8)
+#ifdef SUPPORT_WIDE_CHARS
c < 256 &&
#endif
- (md->ctypes[c] & ctype_word) != 0
+ (mb->ctypes[c] & ctype_word) != 0
)
RRETURN(MATCH_NOMATCH);
ecode++;
break;
case OP_WORDCHAR:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(c, eptr);
if (
-#if defined SUPPORT_UTF || !(defined COMPILE_PCRE8)
+#ifdef SUPPORT_WIDE_CHARS
c > 255 ||
#endif
- (md->ctypes[c] & ctype_word) == 0
+ (mb->ctypes[c] & ctype_word) == 0
)
RRETURN(MATCH_NOMATCH);
ecode++;
break;
case OP_ANYNL:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -2458,7 +2536,7 @@ for (;;)
default: RRETURN(MATCH_NOMATCH);
case CHAR_CR:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
}
@@ -2475,14 +2553,14 @@ for (;;)
case 0x2028:
case 0x2029:
#endif /* Not EBCDIC */
- if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH);
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
break;
}
ecode++;
break;
case OP_NOT_HSPACE:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -2497,7 +2575,7 @@ for (;;)
break;
case OP_HSPACE:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -2512,7 +2590,7 @@ for (;;)
break;
case OP_NOT_VSPACE:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -2527,7 +2605,7 @@ for (;;)
break;
case OP_VSPACE:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -2541,20 +2619,20 @@ for (;;)
ecode++;
break;
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
/* Check the next character by Unicode property. We will get here only
if the support is in the binary; otherwise a compile-time error occurs. */
case OP_PROP:
case OP_NOTPROP:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(c, eptr);
{
- const pcre_uint32 *cp;
+ const uint32_t *cp;
const ucd_record *prop = GET_UCD(c);
switch(ecode[1])
@@ -2641,7 +2719,7 @@ for (;;)
/* This should never occur */
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
ecode += 3;
@@ -2652,7 +2730,7 @@ for (;;)
is in the binary; otherwise a compile-time error occurs. */
case OP_EXTUNI:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -2662,7 +2740,7 @@ for (;;)
int lgb, rgb;
GETCHARINCTEST(c, eptr);
lgb = UCD_GRAPHBREAK(c);
- while (eptr < md->end_subject)
+ while (eptr < mb->end_subject)
{
int len = 1;
if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); }
@@ -2675,26 +2753,11 @@ for (;;)
CHECK_PARTIAL();
ecode++;
break;
-#endif /* SUPPORT_UCP */
+#endif /* SUPPORT_UNICODE */
/* Match a back reference, possibly repeatedly. Look past the end of the
- item to see if there is repeat information following. The code is similar
- to that for character classes, but repeated for efficiency. Then obey
- similar code to character type repeats - written out again for speed.
- However, if the referenced string is the empty string, always treat
- it as matched, any number of times (otherwise there could be infinite
- loops). If the reference is unset, there are two possibilities:
-
- (a) In the default, Perl-compatible state, set the length negative;
- this ensures that every attempt at a match fails. We can't just fail
- here, because of the possibility of quantifiers with zero minima.
-
- (b) If the JavaScript compatibility flag is set, set the length to zero
- so that the back reference matches an empty string.
-
- Otherwise, set the length to the length of what was matched by the
- referenced subpattern.
+ item to see if there is repeat information following.
The OP_REF and OP_REFI opcodes are used for a reference to a numbered group
or to a non-duplicated named group. For a duplicated named group, OP_DNREF
@@ -2706,24 +2769,18 @@ for (;;)
caseless = op == OP_DNREFI;
{
int count = GET2(ecode, 1+IMM2_SIZE);
- pcre_uchar *slot = md->name_table + GET2(ecode, 1) * md->name_entry_size;
+ PCRE2_SPTR slot = mb->name_table + GET2(ecode, 1) * mb->name_entry_size;
ecode += 1 + 2*IMM2_SIZE;
- /* Setting the default length first and initializing 'offset' avoids
- compiler warnings in the REF_REPEAT code. */
+ /* Initializing 'offset' avoids a compiler warning in the REF_REPEAT
+ code. */
- length = (md->jscript_compat)? 0 : -1;
offset = 0;
-
while (count-- > 0)
{
offset = GET2(slot, 0) << 1;
- if (offset < offset_top && md->offset_vector[offset] >= 0)
- {
- length = md->offset_vector[offset+1] - md->offset_vector[offset];
- break;
- }
- slot += md->name_entry_size;
+ if (offset < offset_top && mb->ovector[offset] != PCRE2_UNSET) break;
+ slot += mb->name_entry_size;
}
}
goto REF_REPEAT;
@@ -2733,10 +2790,6 @@ for (;;)
caseless = op == OP_REFI;
offset = GET2(ecode, 1) << 1; /* Doubled ref number */
ecode += 1 + IMM2_SIZE;
- if (offset >= offset_top || md->offset_vector[offset] < 0)
- length = (md->jscript_compat)? 0 : -1;
- else
- length = md->offset_vector[offset+1] - md->offset_vector[offset];
/* Set up for repetition, or handle the non-repeated case */
@@ -2765,25 +2818,36 @@ for (;;)
ecode += 1 + 2 * IMM2_SIZE;
break;
- default: /* No repeat follows */
- if ((length = match_ref(offset, eptr, length, md, caseless)) < 0)
+ default: /* No repeat follows */
{
- if (length == -2) eptr = md->end_subject; /* Partial match */
- CHECK_PARTIAL();
- RRETURN(MATCH_NOMATCH);
+ int rc = match_ref(offset, offset_top, eptr, mb, caseless, &length);
+ if (rc != 0)
+ {
+ if (rc > 0) eptr = mb->end_subject; /* Partial match */
+ CHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
}
eptr += length;
continue; /* With the main loop */
}
- /* Handle repeated back references. If the length of the reference is
- zero, just continue with the main loop. If the length is negative, it
- means the reference is unset in non-Java-compatible mode. If the minimum is
- zero, we can continue at the same level without recursion. For any other
- minimum, carrying on will result in NOMATCH. */
+ /* Handle repeated back references. If a set group has length zero, just
+ continue with the main loop, because it matches however many times. For an
+ unset reference, if the minimum is zero, we can also just continue. We an
+ also continue if PCRE2_MATCH_UNSET_BACKREF is set, because this makes unset
+ group be have as a zero-length group. For any other unset cases, carrying
+ on will result in NOMATCH. */
- if (length == 0) continue;
- if (length < 0 && min == 0) continue;
+ if (offset < offset_top && mb->ovector[offset] != PCRE2_UNSET)
+ {
+ if (mb->ovector[offset] == mb->ovector[offset + 1]) continue;
+ }
+ else /* Group is not set */
+ {
+ if (min == 0 || (mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0)
+ continue;
+ }
/* First, ensure the minimum number of matches are present. We get back
the length of the reference string explicitly rather than passing the
@@ -2791,10 +2855,11 @@ for (;;)
for (i = 1; i <= min; i++)
{
- int slength;
- if ((slength = match_ref(offset, eptr, length, md, caseless)) < 0)
+ PCRE2_SIZE slength;
+ int rc = match_ref(offset, offset_top, eptr, mb, caseless, &slength);
+ if (rc != 0)
{
- if (slength == -2) eptr = md->end_subject; /* Partial match */
+ if (rc > 0) eptr = mb->end_subject; /* Partial match */
CHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
@@ -2812,13 +2877,15 @@ for (;;)
{
for (fi = min;; fi++)
{
- int slength;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM14);
+ int rc;
+ PCRE2_SIZE slength;
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM14);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if ((slength = match_ref(offset, eptr, length, md, caseless)) < 0)
+ rc = match_ref(offset, offset_top, eptr, mb, caseless, &slength);
+ if (rc != 0)
{
- if (slength == -2) eptr = md->end_subject; /* Partial match */
+ if (rc > 0) eptr = mb->end_subject; /* Partial match */
CHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
@@ -2827,36 +2894,76 @@ for (;;)
/* Control never gets here */
}
- /* If maximizing, find the longest string and work backwards */
+ /* If maximizing, find the longest string and work backwards, as long as
+ the matched lengths for each iteration are the same. */
else
{
+ BOOL samelengths = TRUE;
pp = eptr;
+ length = mb->ovector[offset+1] - mb->ovector[offset];
+
for (i = min; i < max; i++)
{
- int slength;
- if ((slength = match_ref(offset, eptr, length, md, caseless)) < 0)
+ PCRE2_SIZE slength;
+ int rc = match_ref(offset, offset_top, eptr, mb, caseless, &slength);
+
+ if (rc != 0)
{
/* Can't use CHECK_PARTIAL because we don't want to update eptr in
the soft partial matching case. */
- if (slength == -2 && md->partial != 0 &&
- md->end_subject > md->start_used_ptr)
+ if (rc > 0 && mb->partial != 0 &&
+ mb->end_subject > mb->start_used_ptr)
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
break;
}
+
+ if (slength != length) samelengths = FALSE;
eptr += slength;
}
- while (eptr >= pp)
+ /* If the length matched for each repetition is the same as the length of
+ the captured group, we can easily work backwards. This is the normal
+ case. However, in caseless UTF-8 mode there are pairs of case-equivalent
+ characters whose lengths (in terms of code units) differ. However, this
+ is very rare, so we handle it by re-matching fewer and fewer times. */
+
+ if (samelengths)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM15);
- if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- eptr -= length;
+ while (eptr >= pp)
+ {
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM15);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ eptr -= length;
+ }
+ }
+
+ /* The rare case of non-matching lengths. Re-scan the repetition for each
+ iteration. We know that match_ref() will succeed every time. */
+
+ else
+ {
+ max = i;
+ for (;;)
+ {
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM68);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (eptr == pp) break; /* Failed after minimal repetition */
+ eptr = pp;
+ max--;
+ for (i = min; i < max; i++)
+ {
+ PCRE2_SIZE slength;
+ (void)match_ref(offset, offset_top, eptr, mb, caseless, &slength);
+ eptr += slength;
+ }
+ }
}
+
RRETURN(MATCH_NOMATCH);
}
/* Control never gets here */
@@ -2877,9 +2984,9 @@ for (;;)
{
/* The data variable is saved across frames, so the byte map needs to
be stored there. */
-#define BYTE_MAP ((pcre_uint8 *)data)
+#define BYTE_MAP ((uint8_t *)data)
data = ecode + 1; /* Save for matching */
- ecode += 1 + (32 / sizeof(pcre_uchar)); /* Advance past the item */
+ ecode += 1 + (32 / sizeof(PCRE2_UCHAR)); /* Advance past the item */
switch (*ecode)
{
@@ -2918,12 +3025,12 @@ for (;;)
/* First, ensure the minimum number of matches are present. */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -2943,13 +3050,13 @@ for (;;)
{
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
c = *eptr++;
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
if (c > 255)
{
if (op == OP_CLASS) RRETURN(MATCH_NOMATCH);
@@ -2970,15 +3077,15 @@ for (;;)
if (minimize)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM16);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM16);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -2998,16 +3105,16 @@ for (;;)
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM17);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM17);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
c = *eptr++;
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
if (c > 255)
{
if (op == OP_CLASS) RRETURN(MATCH_NOMATCH);
@@ -3026,13 +3133,13 @@ for (;;)
{
pp = eptr;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -3051,7 +3158,7 @@ for (;;)
for (;;)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM18);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM18);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (eptr-- == pp) break; /* Stop if tried at original pos */
BACKCHAR(eptr);
@@ -3063,13 +3170,13 @@ for (;;)
{
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
c = *eptr;
-#ifndef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH != 8
if (c > 255)
{
if (op == OP_CLASS) break;
@@ -3084,7 +3191,7 @@ for (;;)
while (eptr >= pp)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM19);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM19);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
}
@@ -3102,7 +3209,7 @@ for (;;)
32-bit libraries, codepoints greater than 255 may be encountered even when
UTF is not supported. */
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#ifdef SUPPORT_WIDE_CHARS
case OP_XCLASS:
{
data = ecode + 1 + LINK_SIZE; /* Save for matching */
@@ -3147,7 +3254,7 @@ for (;;)
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3168,10 +3275,10 @@ for (;;)
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM20);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM20);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3190,12 +3297,12 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
GETCHARLENTEST(c, eptr, len);
#else
c = *eptr;
@@ -3208,10 +3315,10 @@ for (;;)
for(;;)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM21);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM21);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (eptr-- == pp) break; /* Stop if tried at original pos */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf) BACKCHAR(eptr);
#endif
}
@@ -3225,24 +3332,27 @@ for (;;)
/* Match a single character, casefully */
case OP_CHAR:
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
length = 1;
ecode++;
GETCHARLEN(fc, ecode, length);
- if (length > md->end_subject - eptr)
+ if (length > (PCRE2_SIZE)(mb->end_subject - eptr))
{
CHECK_PARTIAL(); /* Not SCHECK_PARTIAL() */
RRETURN(MATCH_NOMATCH);
}
- while (length-- > 0) if (*ecode++ != UCHAR21INC(eptr)) RRETURN(MATCH_NOMATCH);
+ for (; length > 0; length--)
+ {
+ if (*ecode++ != UCHAR21INC(eptr)) RRETURN(MATCH_NOMATCH);
+ }
}
else
#endif
/* Not UTF mode */
{
- if (md->end_subject - eptr < 1)
+ if (mb->end_subject - eptr < 1)
{
SCHECK_PARTIAL(); /* This one can use SCHECK_PARTIAL() */
RRETURN(MATCH_NOMATCH);
@@ -3256,13 +3366,13 @@ for (;;)
subject, give up immediately. */
case OP_CHARI:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
length = 1;
@@ -3276,8 +3386,8 @@ for (;;)
if (fc < 128)
{
- pcre_uint32 cc = UCHAR21(eptr);
- if (md->lcc[fc] != TABLE_GET(cc, md->lcc, cc)) RRETURN(MATCH_NOMATCH);
+ uint32_t cc = UCHAR21(eptr);
+ if (mb->lcc[fc] != TABLE_GET(cc, mb->lcc, cc)) RRETURN(MATCH_NOMATCH);
ecode++;
eptr++;
}
@@ -3288,7 +3398,7 @@ for (;;)
else
{
- pcre_uint32 dc;
+ uint32_t dc;
GETCHARINC(dc, eptr);
ecode += length;
@@ -3297,7 +3407,7 @@ for (;;)
if (fc != dc)
{
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (dc != UCD_OTHERCASE(fc))
#endif
RRETURN(MATCH_NOMATCH);
@@ -3305,12 +3415,12 @@ for (;;)
}
}
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
/* Not UTF mode */
{
- if (TABLE_GET(ecode[1], md->lcc, ecode[1])
- != TABLE_GET(*eptr, md->lcc, *eptr)) RRETURN(MATCH_NOMATCH);
+ if (TABLE_GET(ecode[1], mb->lcc, ecode[1])
+ != TABLE_GET(*eptr, mb->lcc, *eptr)) RRETURN(MATCH_NOMATCH);
eptr++;
ecode += 2;
}
@@ -3399,7 +3509,7 @@ for (;;)
for speed. */
REPEATCHAR:
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
length = 1;
@@ -3412,23 +3522,19 @@ for (;;)
if (length > 1)
{
-#ifdef SUPPORT_UCP
- pcre_uint32 othercase;
+ uint32_t othercase;
if (op >= OP_STARI && /* Caseless */
(othercase = UCD_OTHERCASE(fc)) != fc)
oclength = PRIV(ord2utf)(othercase, occhars);
else oclength = 0;
-#endif /* SUPPORT_UCP */
for (i = 1; i <= min; i++)
{
- if (eptr <= md->end_subject - length &&
- memcmp(eptr, charptr, IN_UCHARS(length)) == 0) eptr += length;
-#ifdef SUPPORT_UCP
+ if (eptr <= mb->end_subject - length &&
+ memcmp(eptr, charptr, CU2BYTES(length)) == 0) eptr += length;
else if (oclength > 0 &&
- eptr <= md->end_subject - oclength &&
- memcmp(eptr, occhars, IN_UCHARS(oclength)) == 0) eptr += oclength;
-#endif /* SUPPORT_UCP */
+ eptr <= mb->end_subject - oclength &&
+ memcmp(eptr, occhars, CU2BYTES(oclength)) == 0) eptr += oclength;
else
{
CHECK_PARTIAL();
@@ -3442,16 +3548,14 @@ for (;;)
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM22);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM22);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr <= md->end_subject - length &&
- memcmp(eptr, charptr, IN_UCHARS(length)) == 0) eptr += length;
-#ifdef SUPPORT_UCP
+ if (eptr <= mb->end_subject - length &&
+ memcmp(eptr, charptr, CU2BYTES(length)) == 0) eptr += length;
else if (oclength > 0 &&
- eptr <= md->end_subject - oclength &&
- memcmp(eptr, occhars, IN_UCHARS(oclength)) == 0) eptr += oclength;
-#endif /* SUPPORT_UCP */
+ eptr <= mb->end_subject - oclength &&
+ memcmp(eptr, occhars, CU2BYTES(oclength)) == 0) eptr += oclength;
else
{
CHECK_PARTIAL();
@@ -3466,13 +3570,11 @@ for (;;)
pp = eptr;
for (i = min; i < max; i++)
{
- if (eptr <= md->end_subject - length &&
- memcmp(eptr, charptr, IN_UCHARS(length)) == 0) eptr += length;
-#ifdef SUPPORT_UCP
+ if (eptr <= mb->end_subject - length &&
+ memcmp(eptr, charptr, CU2BYTES(length)) == 0) eptr += length;
else if (oclength > 0 &&
- eptr <= md->end_subject - oclength &&
- memcmp(eptr, occhars, IN_UCHARS(oclength)) == 0) eptr += oclength;
-#endif /* SUPPORT_UCP */
+ eptr <= mb->end_subject - oclength &&
+ memcmp(eptr, occhars, CU2BYTES(oclength)) == 0) eptr += oclength;
else
{
CHECK_PARTIAL();
@@ -3481,17 +3583,17 @@ for (;;)
}
if (possessive) continue; /* No backtracking */
+
+ /* After \C in UTF mode, pp might be in the middle of a Unicode
+ character. Use <= pp to ensure backtracking doesn't go too far. */
+
for(;;)
{
if (eptr <= pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM23);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM23);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
-#ifdef SUPPORT_UCP
eptr--;
BACKCHAR(eptr);
-#else /* without SUPPORT_UCP */
- eptr -= length;
-#endif /* SUPPORT_UCP */
}
}
/* Control never gets here */
@@ -3502,7 +3604,8 @@ for (;;)
value of fc will always be < 128. */
}
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
+
/* When not in UTF-8 mode, load a single-byte character. */
fc = *ecode++;
@@ -3515,32 +3618,24 @@ for (;;)
matching character if failing, up to the maximum. Alternatively, if
maximizing, find the maximum number of characters and work backwards. */
- DPRINTF(("matching %c{%d,%d} against subject %.*s\n", fc, min, max,
- max, (char *)eptr));
-
if (op >= OP_STARI) /* Caseless */
{
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
/* fc must be < 128 if UTF is enabled. */
- foc = md->fcc[fc];
+ foc = mb->fcc[fc];
#else
-#ifdef SUPPORT_UTF
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (utf && fc > 127)
foc = UCD_OTHERCASE(fc);
-#else
- if (utf && fc > 127)
- foc = fc;
-#endif /* SUPPORT_UCP */
else
-#endif /* SUPPORT_UTF */
- foc = TABLE_GET(fc, md->fcc, fc);
-#endif /* COMPILE_PCRE8 */
+#endif /* SUPPORT_UNICODE */
+ foc = TABLE_GET(fc, mb->fcc, fc);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
for (i = 1; i <= min; i++)
{
- pcre_uint32 cc; /* Faster than pcre_uchar */
- if (eptr >= md->end_subject)
+ uint32_t cc; /* Faster than PCRE2_UCHAR */
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3554,11 +3649,11 @@ for (;;)
{
for (fi = min;; fi++)
{
- pcre_uint32 cc; /* Faster than pcre_uchar */
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM24);
+ uint32_t cc; /* Faster than PCRE2_UCHAR */
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM24);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3574,8 +3669,8 @@ for (;;)
pp = eptr;
for (i = min; i < max; i++)
{
- pcre_uint32 cc; /* Faster than pcre_uchar */
- if (eptr >= md->end_subject)
+ uint32_t cc; /* Faster than PCRE2_UCHAR */
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -3588,7 +3683,7 @@ for (;;)
for (;;)
{
if (eptr == pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM25);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM25);
eptr--;
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
}
@@ -3602,7 +3697,7 @@ for (;;)
{
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3616,10 +3711,10 @@ for (;;)
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM26);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM26);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3633,7 +3728,7 @@ for (;;)
pp = eptr;
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -3645,7 +3740,7 @@ for (;;)
for (;;)
{
if (eptr == pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM27);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM27);
eptr--;
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
}
@@ -3659,15 +3754,15 @@ for (;;)
case OP_NOT:
case OP_NOTI:
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
- register pcre_uint32 ch, och;
+ register uint32_t ch, och;
ecode++;
GETCHARINC(ch, ecode);
@@ -3679,24 +3774,19 @@ for (;;)
}
else
{
-#ifdef SUPPORT_UCP
if (ch > 127)
och = UCD_OTHERCASE(ch);
-#else
- if (ch > 127)
- och = ch;
-#endif /* SUPPORT_UCP */
else
- och = TABLE_GET(ch, md->fcc, ch);
+ och = TABLE_GET(ch, mb->fcc, ch);
if (ch == c || och == c) RRETURN(MATCH_NOMATCH);
}
}
else
-#endif
+#endif /* SUPPORT_UNICODE */
{
- register pcre_uint32 ch = ecode[1];
+ register uint32_t ch = ecode[1];
c = *eptr++;
- if (ch == c || (op == OP_NOTI && TABLE_GET(ch, md->fcc, ch) == c))
+ if (ch == c || (op == OP_NOTI && TABLE_GET(ch, mb->fcc, ch) == c))
RRETURN(MATCH_NOMATCH);
ecode += 2;
}
@@ -3788,45 +3878,37 @@ for (;;)
maximum. Alternatively, if maximizing, find the maximum number of
characters and work backwards. */
- DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", fc, min, max,
- max, (char *)eptr));
-
if (op >= OP_NOTSTARI) /* Caseless */
{
-#ifdef SUPPORT_UTF
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (utf && fc > 127)
foc = UCD_OTHERCASE(fc);
-#else
- if (utf && fc > 127)
- foc = fc;
-#endif /* SUPPORT_UCP */
else
-#endif /* SUPPORT_UTF */
- foc = TABLE_GET(fc, md->fcc, fc);
+#endif /* SUPPORT_UNICODE */
+ foc = TABLE_GET(fc, mb->fcc, fc);
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
- register pcre_uint32 d;
+ register uint32_t d;
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINC(d, eptr);
- if (fc == d || (unsigned int)foc == d) RRETURN(MATCH_NOMATCH);
+ if (fc == d || (uint32_t)foc == d) RRETURN(MATCH_NOMATCH);
}
}
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
/* Not UTF mode */
{
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3840,34 +3922,34 @@ for (;;)
if (minimize)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
- register pcre_uint32 d;
+ register uint32_t d;
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM28);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM28);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINC(d, eptr);
- if (fc == d || (unsigned int)foc == d) RRETURN(MATCH_NOMATCH);
+ if (fc == d || (uint32_t)foc == d) RRETURN(MATCH_NOMATCH);
}
}
else
-#endif /*SUPPORT_UTF */
+#endif /*SUPPORT_UNICODE */
/* Not UTF mode */
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM29);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM29);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3885,39 +3967,43 @@ for (;;)
{
pp = eptr;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
- register pcre_uint32 d;
+ register uint32_t d;
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
GETCHARLEN(d, eptr, len);
- if (fc == d || (unsigned int)foc == d) break;
+ if (fc == d || (uint32_t)foc == d) break;
eptr += len;
}
if (possessive) continue; /* No backtracking */
+
+ /* After \C in UTF mode, pp might be in the middle of a Unicode
+ character. Use <= pp to ensure backtracking doesn't go too far. */
+
for(;;)
{
if (eptr <= pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM30);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM30);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
BACKCHAR(eptr);
}
}
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
/* Not UTF mode */
{
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -3929,7 +4015,7 @@ for (;;)
for (;;)
{
if (eptr == pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM31);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM31);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
}
@@ -3942,13 +4028,13 @@ for (;;)
else
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
- register pcre_uint32 d;
+ register uint32_t d;
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3963,7 +4049,7 @@ for (;;)
{
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -3976,16 +4062,16 @@ for (;;)
if (minimize)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
- register pcre_uint32 d;
+ register uint32_t d;
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM32);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM32);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4000,10 +4086,10 @@ for (;;)
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM33);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM33);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4020,14 +4106,14 @@ for (;;)
{
pp = eptr;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
- register pcre_uint32 d;
+ register uint32_t d;
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -4037,10 +4123,14 @@ for (;;)
eptr += len;
}
if (possessive) continue; /* No backtracking */
+
+ /* After \C in UTF mode, pp might be in the middle of a Unicode
+ character. Use <= pp to ensure backtracking doesn't go too far. */
+
for(;;)
{
if (eptr <= pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM34);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM34);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
BACKCHAR(eptr);
@@ -4052,7 +4142,7 @@ for (;;)
{
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -4064,7 +4154,7 @@ for (;;)
for (;;)
{
if (eptr == pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM35);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM35);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
}
@@ -4139,7 +4229,7 @@ for (;;)
REPEATTYPE:
ctype = *ecode++; /* Code for the character type */
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (ctype == OP_PROP || ctype == OP_NOTPROP)
{
prop_fail_result = ctype == OP_NOTPROP;
@@ -4157,7 +4247,7 @@ for (;;)
if (min > 0)
{
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (prop_type >= 0)
{
switch(prop_type)
@@ -4166,7 +4256,7 @@ for (;;)
if (prop_fail_result) RRETURN(MATCH_NOMATCH);
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4179,7 +4269,7 @@ for (;;)
for (i = 1; i <= min; i++)
{
int chartype;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4196,7 +4286,7 @@ for (;;)
case PT_GC:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4210,7 +4300,7 @@ for (;;)
case PT_PC:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4224,7 +4314,7 @@ for (;;)
case PT_SC:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4239,7 +4329,7 @@ for (;;)
for (i = 1; i <= min; i++)
{
int category;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4259,7 +4349,7 @@ for (;;)
case PT_PXSPACE: /* POSIX space */
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4284,7 +4374,7 @@ for (;;)
for (i = 1; i <= min; i++)
{
int category;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4300,8 +4390,8 @@ for (;;)
case PT_CLIST:
for (i = 1; i <= min; i++)
{
- const pcre_uint32 *cp;
- if (eptr >= md->end_subject)
+ const uint32_t *cp;
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4321,7 +4411,7 @@ for (;;)
case PT_UCNC:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4337,7 +4427,7 @@ for (;;)
/* This should not occur */
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
}
@@ -4348,7 +4438,7 @@ for (;;)
{
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4358,7 +4448,7 @@ for (;;)
int lgb, rgb;
GETCHARINCTEST(c, eptr);
lgb = UCD_GRAPHBREAK(c);
- while (eptr < md->end_subject)
+ while (eptr < mb->end_subject)
{
int len = 1;
if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); }
@@ -4373,58 +4463,58 @@ for (;;)
}
else
-#endif /* SUPPORT_UCP */
+#endif /* SUPPORT_UNICODE */
/* Handle all other cases when the coding is UTF-8 */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf) switch(ctype)
{
case OP_ANY:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH);
- if (md->partial != 0 &&
- eptr + 1 >= md->end_subject &&
+ if (mb->partial != 0 &&
+ eptr + 1 >= mb->end_subject &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
UCHAR21(eptr) == NLBLOCK->nl[0])
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
eptr++;
- ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++);
+ ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++);
}
break;
case OP_ALLANY:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
eptr++;
- ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++);
+ ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++);
}
break;
case OP_ANYBYTE:
- if (eptr > md->end_subject - min) RRETURN(MATCH_NOMATCH);
+ if (eptr > mb->end_subject - min) RRETURN(MATCH_NOMATCH);
eptr += min;
break;
case OP_ANYNL:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4435,7 +4525,7 @@ for (;;)
default: RRETURN(MATCH_NOMATCH);
case CHAR_CR:
- if (eptr < md->end_subject && UCHAR21(eptr) == CHAR_LF) eptr++;
+ if (eptr < mb->end_subject && UCHAR21(eptr) == CHAR_LF) eptr++;
break;
case CHAR_LF:
@@ -4448,7 +4538,7 @@ for (;;)
case 0x2028:
case 0x2029:
#endif /* Not EBCDIC */
- if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH);
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
break;
}
}
@@ -4457,7 +4547,7 @@ for (;;)
case OP_NOT_HSPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4474,7 +4564,7 @@ for (;;)
case OP_HSPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4491,7 +4581,7 @@ for (;;)
case OP_NOT_VSPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4508,7 +4598,7 @@ for (;;)
case OP_VSPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4525,13 +4615,13 @@ for (;;)
case OP_NOT_DIGIT:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINC(c, eptr);
- if (c < 128 && (md->ctypes[c] & ctype_digit) != 0)
+ if (c < 128 && (mb->ctypes[c] & ctype_digit) != 0)
RRETURN(MATCH_NOMATCH);
}
break;
@@ -4539,14 +4629,14 @@ for (;;)
case OP_DIGIT:
for (i = 1; i <= min; i++)
{
- pcre_uint32 cc;
- if (eptr >= md->end_subject)
+ uint32_t cc;
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
cc = UCHAR21(eptr);
- if (cc >= 128 || (md->ctypes[cc] & ctype_digit) == 0)
+ if (cc >= 128 || (mb->ctypes[cc] & ctype_digit) == 0)
RRETURN(MATCH_NOMATCH);
eptr++;
/* No need to skip more bytes - we know it's a 1-byte character */
@@ -4556,31 +4646,31 @@ for (;;)
case OP_NOT_WHITESPACE:
for (i = 1; i <= min; i++)
{
- pcre_uint32 cc;
- if (eptr >= md->end_subject)
+ uint32_t cc;
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
cc = UCHAR21(eptr);
- if (cc < 128 && (md->ctypes[cc] & ctype_space) != 0)
+ if (cc < 128 && (mb->ctypes[cc] & ctype_space) != 0)
RRETURN(MATCH_NOMATCH);
eptr++;
- ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++);
+ ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++);
}
break;
case OP_WHITESPACE:
for (i = 1; i <= min; i++)
{
- pcre_uint32 cc;
- if (eptr >= md->end_subject)
+ uint32_t cc;
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
cc = UCHAR21(eptr);
- if (cc >= 128 || (md->ctypes[cc] & ctype_space) == 0)
+ if (cc >= 128 || (mb->ctypes[cc] & ctype_space) == 0)
RRETURN(MATCH_NOMATCH);
eptr++;
/* No need to skip more bytes - we know it's a 1-byte character */
@@ -4590,31 +4680,31 @@ for (;;)
case OP_NOT_WORDCHAR:
for (i = 1; i <= min; i++)
{
- pcre_uint32 cc;
- if (eptr >= md->end_subject)
+ uint32_t cc;
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
cc = UCHAR21(eptr);
- if (cc < 128 && (md->ctypes[cc] & ctype_word) != 0)
+ if (cc < 128 && (mb->ctypes[cc] & ctype_word) != 0)
RRETURN(MATCH_NOMATCH);
eptr++;
- ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++);
+ ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++);
}
break;
case OP_WORDCHAR:
for (i = 1; i <= min; i++)
{
- pcre_uint32 cc;
- if (eptr >= md->end_subject)
+ uint32_t cc;
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
cc = UCHAR21(eptr);
- if (cc >= 128 || (md->ctypes[cc] & ctype_word) == 0)
+ if (cc >= 128 || (mb->ctypes[cc] & ctype_word) == 0)
RRETURN(MATCH_NOMATCH);
eptr++;
/* No need to skip more bytes - we know it's a 1-byte character */
@@ -4622,11 +4712,11 @@ for (;;)
break;
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
} /* End switch(ctype) */
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
/* Code for the non-UTF-8 case for minimum matching of operators other
than OP_PROP and OP_NOTPROP. */
@@ -4636,27 +4726,27 @@ for (;;)
case OP_ANY:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH);
- if (md->partial != 0 &&
- eptr + 1 >= md->end_subject &&
+ if (mb->partial != 0 &&
+ eptr + 1 >= mb->end_subject &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
*eptr == NLBLOCK->nl[0])
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
eptr++;
}
break;
case OP_ALLANY:
- if (eptr > md->end_subject - min)
+ if (eptr > mb->end_subject - min)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4665,7 +4755,7 @@ for (;;)
break;
case OP_ANYBYTE:
- if (eptr > md->end_subject - min)
+ if (eptr > mb->end_subject - min)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4676,7 +4766,7 @@ for (;;)
case OP_ANYNL:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4686,7 +4776,7 @@ for (;;)
default: RRETURN(MATCH_NOMATCH);
case CHAR_CR:
- if (eptr < md->end_subject && *eptr == CHAR_LF) eptr++;
+ if (eptr < mb->end_subject && *eptr == CHAR_LF) eptr++;
break;
case CHAR_LF:
@@ -4695,11 +4785,11 @@ for (;;)
case CHAR_VT:
case CHAR_FF:
case CHAR_NEL:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
case 0x2028:
case 0x2029:
#endif
- if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH);
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
break;
}
}
@@ -4708,7 +4798,7 @@ for (;;)
case OP_NOT_HSPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4717,7 +4807,7 @@ for (;;)
{
default: break;
HSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
HSPACE_MULTIBYTE_CASES:
#endif
RRETURN(MATCH_NOMATCH);
@@ -4728,7 +4818,7 @@ for (;;)
case OP_HSPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4737,7 +4827,7 @@ for (;;)
{
default: RRETURN(MATCH_NOMATCH);
HSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
HSPACE_MULTIBYTE_CASES:
#endif
break;
@@ -4748,7 +4838,7 @@ for (;;)
case OP_NOT_VSPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4756,7 +4846,7 @@ for (;;)
switch(*eptr++)
{
VSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
VSPACE_MULTIBYTE_CASES:
#endif
RRETURN(MATCH_NOMATCH);
@@ -4768,7 +4858,7 @@ for (;;)
case OP_VSPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4777,7 +4867,7 @@ for (;;)
{
default: RRETURN(MATCH_NOMATCH);
VSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
VSPACE_MULTIBYTE_CASES:
#endif
break;
@@ -4788,12 +4878,12 @@ for (;;)
case OP_NOT_DIGIT:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
- if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_digit) != 0)
+ if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_digit) != 0)
RRETURN(MATCH_NOMATCH);
eptr++;
}
@@ -4802,12 +4892,12 @@ for (;;)
case OP_DIGIT:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
- if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_digit) == 0)
+ if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_digit) == 0)
RRETURN(MATCH_NOMATCH);
eptr++;
}
@@ -4816,12 +4906,12 @@ for (;;)
case OP_NOT_WHITESPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
- if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_space) != 0)
+ if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_space) != 0)
RRETURN(MATCH_NOMATCH);
eptr++;
}
@@ -4830,12 +4920,12 @@ for (;;)
case OP_WHITESPACE:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
- if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_space) == 0)
+ if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_space) == 0)
RRETURN(MATCH_NOMATCH);
eptr++;
}
@@ -4844,12 +4934,12 @@ for (;;)
case OP_NOT_WORDCHAR:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
- if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_word) != 0)
+ if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_word) != 0)
RRETURN(MATCH_NOMATCH);
eptr++;
}
@@ -4858,19 +4948,19 @@ for (;;)
case OP_WORDCHAR:
for (i = 1; i <= min; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
- if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_word) == 0)
+ if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_word) == 0)
RRETURN(MATCH_NOMATCH);
eptr++;
}
break;
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
}
@@ -4884,7 +4974,7 @@ for (;;)
if (minimize)
{
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (prop_type >= 0)
{
switch(prop_type)
@@ -4892,10 +4982,10 @@ for (;;)
case PT_ANY:
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM36);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM36);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4909,10 +4999,10 @@ for (;;)
for (fi = min;; fi++)
{
int chartype;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM37);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM37);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4929,10 +5019,10 @@ for (;;)
case PT_GC:
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM38);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM38);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4946,10 +5036,10 @@ for (;;)
case PT_PC:
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM39);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM39);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4963,10 +5053,10 @@ for (;;)
case PT_SC:
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM40);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM40);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -4981,10 +5071,10 @@ for (;;)
for (fi = min;; fi++)
{
int category;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM59);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM59);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -5004,10 +5094,10 @@ for (;;)
case PT_PXSPACE: /* POSIX space */
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM61);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM61);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -5032,10 +5122,10 @@ for (;;)
for (fi = min;; fi++)
{
int category;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM62);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM62);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -5053,11 +5143,11 @@ for (;;)
case PT_CLIST:
for (fi = min;; fi++)
{
- const pcre_uint32 *cp;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM67);
+ const uint32_t *cp;
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM67);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -5077,10 +5167,10 @@ for (;;)
case PT_UCNC:
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM60);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM60);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -5095,7 +5185,7 @@ for (;;)
/* This should never occur */
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
}
@@ -5106,10 +5196,10 @@ for (;;)
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM41);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM41);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -5119,7 +5209,7 @@ for (;;)
int lgb, rgb;
GETCHARINCTEST(c, eptr);
lgb = UCD_GRAPHBREAK(c);
- while (eptr < md->end_subject)
+ while (eptr < mb->end_subject)
{
int len = 1;
if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); }
@@ -5133,17 +5223,17 @@ for (;;)
}
}
else
-#endif /* SUPPORT_UCP */
+#endif /* SUPPORT_UNICODE */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM42);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM42);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -5154,14 +5244,14 @@ for (;;)
switch(ctype)
{
case OP_ANY: /* This is the non-NL case */
- if (md->partial != 0 && /* Take care with CRLF partial */
- eptr >= md->end_subject &&
+ if (mb->partial != 0 && /* Take care with CRLF partial */
+ eptr >= mb->end_subject &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
break;
@@ -5174,7 +5264,7 @@ for (;;)
{
default: RRETURN(MATCH_NOMATCH);
case CHAR_CR:
- if (eptr < md->end_subject && UCHAR21(eptr) == CHAR_LF) eptr++;
+ if (eptr < mb->end_subject && UCHAR21(eptr) == CHAR_LF) eptr++;
break;
case CHAR_LF:
@@ -5187,7 +5277,7 @@ for (;;)
case 0x2028:
case 0x2029:
#endif /* Not EBCDIC */
- if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH);
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
break;
}
break;
@@ -5225,37 +5315,37 @@ for (;;)
break;
case OP_NOT_DIGIT:
- if (c < 256 && (md->ctypes[c] & ctype_digit) != 0)
+ if (c < 256 && (mb->ctypes[c] & ctype_digit) != 0)
RRETURN(MATCH_NOMATCH);
break;
case OP_DIGIT:
- if (c >= 256 || (md->ctypes[c] & ctype_digit) == 0)
+ if (c >= 256 || (mb->ctypes[c] & ctype_digit) == 0)
RRETURN(MATCH_NOMATCH);
break;
case OP_NOT_WHITESPACE:
- if (c < 256 && (md->ctypes[c] & ctype_space) != 0)
+ if (c < 256 && (mb->ctypes[c] & ctype_space) != 0)
RRETURN(MATCH_NOMATCH);
break;
case OP_WHITESPACE:
- if (c >= 256 || (md->ctypes[c] & ctype_space) == 0)
+ if (c >= 256 || (mb->ctypes[c] & ctype_space) == 0)
RRETURN(MATCH_NOMATCH);
break;
case OP_NOT_WORDCHAR:
- if (c < 256 && (md->ctypes[c] & ctype_word) != 0)
+ if (c < 256 && (mb->ctypes[c] & ctype_word) != 0)
RRETURN(MATCH_NOMATCH);
break;
case OP_WORDCHAR:
- if (c >= 256 || (md->ctypes[c] & ctype_word) == 0)
+ if (c >= 256 || (mb->ctypes[c] & ctype_word) == 0)
RRETURN(MATCH_NOMATCH);
break;
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
}
}
@@ -5265,10 +5355,10 @@ for (;;)
{
for (fi = min;; fi++)
{
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM43);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM43);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (fi >= max) RRETURN(MATCH_NOMATCH);
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
@@ -5279,14 +5369,14 @@ for (;;)
switch(ctype)
{
case OP_ANY: /* This is the non-NL case */
- if (md->partial != 0 && /* Take care with CRLF partial */
- eptr >= md->end_subject &&
+ if (mb->partial != 0 && /* Take care with CRLF partial */
+ eptr >= mb->end_subject &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
c == NLBLOCK->nl[0])
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
break;
@@ -5299,7 +5389,7 @@ for (;;)
{
default: RRETURN(MATCH_NOMATCH);
case CHAR_CR:
- if (eptr < md->end_subject && *eptr == CHAR_LF) eptr++;
+ if (eptr < mb->end_subject && *eptr == CHAR_LF) eptr++;
break;
case CHAR_LF:
@@ -5308,11 +5398,11 @@ for (;;)
case CHAR_VT:
case CHAR_FF:
case CHAR_NEL:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
case 0x2028:
case 0x2029:
#endif
- if (md->bsr_anycrlf) RRETURN(MATCH_NOMATCH);
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
break;
}
break;
@@ -5322,7 +5412,7 @@ for (;;)
{
default: break;
HSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
HSPACE_MULTIBYTE_CASES:
#endif
RRETURN(MATCH_NOMATCH);
@@ -5334,7 +5424,7 @@ for (;;)
{
default: RRETURN(MATCH_NOMATCH);
HSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
HSPACE_MULTIBYTE_CASES:
#endif
break;
@@ -5346,7 +5436,7 @@ for (;;)
{
default: break;
VSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
VSPACE_MULTIBYTE_CASES:
#endif
RRETURN(MATCH_NOMATCH);
@@ -5358,7 +5448,7 @@ for (;;)
{
default: RRETURN(MATCH_NOMATCH);
VSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
VSPACE_MULTIBYTE_CASES:
#endif
break;
@@ -5366,31 +5456,31 @@ for (;;)
break;
case OP_NOT_DIGIT:
- if (MAX_255(c) && (md->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH);
+ if (MAX_255(c) && (mb->ctypes[c] & ctype_digit) != 0) RRETURN(MATCH_NOMATCH);
break;
case OP_DIGIT:
- if (!MAX_255(c) || (md->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH);
+ if (!MAX_255(c) || (mb->ctypes[c] & ctype_digit) == 0) RRETURN(MATCH_NOMATCH);
break;
case OP_NOT_WHITESPACE:
- if (MAX_255(c) && (md->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH);
+ if (MAX_255(c) && (mb->ctypes[c] & ctype_space) != 0) RRETURN(MATCH_NOMATCH);
break;
case OP_WHITESPACE:
- if (!MAX_255(c) || (md->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH);
+ if (!MAX_255(c) || (mb->ctypes[c] & ctype_space) == 0) RRETURN(MATCH_NOMATCH);
break;
case OP_NOT_WORDCHAR:
- if (MAX_255(c) && (md->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH);
+ if (MAX_255(c) && (mb->ctypes[c] & ctype_word) != 0) RRETURN(MATCH_NOMATCH);
break;
case OP_WORDCHAR:
- if (!MAX_255(c) || (md->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH);
+ if (!MAX_255(c) || (mb->ctypes[c] & ctype_word) == 0) RRETURN(MATCH_NOMATCH);
break;
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
}
}
@@ -5405,7 +5495,7 @@ for (;;)
{
pp = eptr; /* Remember where we started */
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
if (prop_type >= 0)
{
switch(prop_type)
@@ -5414,7 +5504,7 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5430,7 +5520,7 @@ for (;;)
{
int chartype;
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5449,7 +5539,7 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5464,7 +5554,7 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5479,7 +5569,7 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5495,7 +5585,7 @@ for (;;)
{
int category;
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5517,7 +5607,7 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5545,7 +5635,7 @@ for (;;)
{
int category;
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5562,9 +5652,9 @@ for (;;)
case PT_CLIST:
for (i = min; i < max; i++)
{
- const pcre_uint32 *cp;
+ const uint32_t *cp;
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5587,7 +5677,7 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5602,16 +5692,20 @@ for (;;)
break;
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
/* eptr is now past the end of the maximum run */
if (possessive) continue; /* No backtracking */
+
+ /* After \C in UTF mode, pp might be in the middle of a Unicode
+ character. Use <= pp to ensure backtracking doesn't go too far. */
+
for(;;)
{
if (eptr <= pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM44);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM44);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
if (utf) BACKCHAR(eptr);
@@ -5625,7 +5719,7 @@ for (;;)
{
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5635,7 +5729,7 @@ for (;;)
int lgb, rgb;
GETCHARINCTEST(c, eptr);
lgb = UCD_GRAPHBREAK(c);
- while (eptr < md->end_subject)
+ while (eptr < mb->end_subject)
{
int len = 1;
if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); }
@@ -5660,10 +5754,10 @@ for (;;)
for(;;)
{
int lgb, rgb;
- PCRE_PUCHAR fptr;
+ PCRE2_SPTR fptr;
if (eptr <= pp) goto TAIL_RECURSE; /* At start of char run */
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM45);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM45);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
/* Backtracking over an extended grapheme cluster involves inspecting
@@ -5696,9 +5790,9 @@ for (;;)
}
else
-#endif /* SUPPORT_UCP */
+#endif /* SUPPORT_UNICODE */
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
switch(ctype)
@@ -5706,23 +5800,23 @@ for (;;)
case OP_ANY:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
if (IS_NEWLINE(eptr)) break;
- if (md->partial != 0 && /* Take care with CRLF partial */
- eptr + 1 >= md->end_subject &&
+ if (mb->partial != 0 && /* Take care with CRLF partial */
+ eptr + 1 >= mb->end_subject &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
UCHAR21(eptr) == NLBLOCK->nl[0])
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
eptr++;
- ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++);
+ ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++);
}
break;
@@ -5731,18 +5825,18 @@ for (;;)
{
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
eptr++;
- ACROSSCHAR(eptr < md->end_subject, *eptr, eptr++);
+ ACROSSCHAR(eptr < mb->end_subject, *eptr, eptr++);
}
}
else
{
- eptr = md->end_subject; /* Unlimited UTF-8 repeat */
+ eptr = mb->end_subject; /* Unlimited UTF-8 repeat */
SCHECK_PARTIAL();
}
break;
@@ -5751,9 +5845,9 @@ for (;;)
case OP_ANYBYTE:
c = max - min;
- if (c > (unsigned int)(md->end_subject - eptr))
+ if (c > (uint32_t)(mb->end_subject - eptr))
{
- eptr = md->end_subject;
+ eptr = mb->end_subject;
SCHECK_PARTIAL();
}
else eptr += c;
@@ -5763,7 +5857,7 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5771,13 +5865,13 @@ for (;;)
GETCHARLEN(c, eptr, len);
if (c == CHAR_CR)
{
- if (++eptr >= md->end_subject) break;
+ if (++eptr >= mb->end_subject) break;
if (UCHAR21(eptr) == CHAR_LF) eptr++;
}
else
{
if (c != CHAR_LF &&
- (md->bsr_anycrlf ||
+ (mb->bsr_convention == PCRE2_BSR_ANYCRLF ||
(c != CHAR_VT && c != CHAR_FF && c != CHAR_NEL
#ifndef EBCDIC
&& c != 0x2028 && c != 0x2029
@@ -5795,7 +5889,7 @@ for (;;)
{
BOOL gotspace;
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5817,7 +5911,7 @@ for (;;)
{
BOOL gotspace;
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5837,13 +5931,13 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
GETCHARLEN(c, eptr, len);
- if (c < 256 && (md->ctypes[c] & ctype_digit) != 0) break;
+ if (c < 256 && (mb->ctypes[c] & ctype_digit) != 0) break;
eptr+= len;
}
break;
@@ -5852,13 +5946,13 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
GETCHARLEN(c, eptr, len);
- if (c >= 256 ||(md->ctypes[c] & ctype_digit) == 0) break;
+ if (c >= 256 ||(mb->ctypes[c] & ctype_digit) == 0) break;
eptr+= len;
}
break;
@@ -5867,13 +5961,13 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
GETCHARLEN(c, eptr, len);
- if (c < 256 && (md->ctypes[c] & ctype_space) != 0) break;
+ if (c < 256 && (mb->ctypes[c] & ctype_space) != 0) break;
eptr+= len;
}
break;
@@ -5882,13 +5976,13 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
GETCHARLEN(c, eptr, len);
- if (c >= 256 ||(md->ctypes[c] & ctype_space) == 0) break;
+ if (c >= 256 ||(mb->ctypes[c] & ctype_space) == 0) break;
eptr+= len;
}
break;
@@ -5897,13 +5991,13 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
GETCHARLEN(c, eptr, len);
- if (c < 256 && (md->ctypes[c] & ctype_word) != 0) break;
+ if (c < 256 && (mb->ctypes[c] & ctype_word) != 0) break;
eptr+= len;
}
break;
@@ -5912,26 +6006,30 @@ for (;;)
for (i = min; i < max; i++)
{
int len = 1;
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
GETCHARLEN(c, eptr, len);
- if (c >= 256 || (md->ctypes[c] & ctype_word) == 0) break;
+ if (c >= 256 || (mb->ctypes[c] & ctype_word) == 0) break;
eptr+= len;
}
break;
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
if (possessive) continue; /* No backtracking */
+
+ /* After \C in UTF mode, pp might be in the middle of a Unicode
+ character. Use <= pp to ensure backtracking doesn't go too far. */
+
for(;;)
{
if (eptr <= pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM46);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM46);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
BACKCHAR(eptr);
@@ -5940,7 +6038,7 @@ for (;;)
}
}
else
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
/* Not UTF mode */
{
switch(ctype)
@@ -5948,20 +6046,20 @@ for (;;)
case OP_ANY:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
if (IS_NEWLINE(eptr)) break;
- if (md->partial != 0 && /* Take care with CRLF partial */
- eptr + 1 >= md->end_subject &&
+ if (mb->partial != 0 && /* Take care with CRLF partial */
+ eptr + 1 >= mb->end_subject &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
*eptr == NLBLOCK->nl[0])
{
- md->hitend = TRUE;
- if (md->partial > 1) RRETURN(PCRE_ERROR_PARTIAL);
+ mb->hitend = TRUE;
+ if (mb->partial > 1) RRETURN(PCRE2_ERROR_PARTIAL);
}
eptr++;
}
@@ -5970,9 +6068,9 @@ for (;;)
case OP_ALLANY:
case OP_ANYBYTE:
c = max - min;
- if (c > (unsigned int)(md->end_subject - eptr))
+ if (c > (uint32_t)(mb->end_subject - eptr))
{
- eptr = md->end_subject;
+ eptr = mb->end_subject;
SCHECK_PARTIAL();
}
else eptr += c;
@@ -5981,7 +6079,7 @@ for (;;)
case OP_ANYNL:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -5989,14 +6087,14 @@ for (;;)
c = *eptr;
if (c == CHAR_CR)
{
- if (++eptr >= md->end_subject) break;
+ if (++eptr >= mb->end_subject) break;
if (*eptr == CHAR_LF) eptr++;
}
else
{
- if (c != CHAR_LF && (md->bsr_anycrlf ||
+ if (c != CHAR_LF && (mb->bsr_convention == PCRE2_BSR_ANYCRLF ||
(c != CHAR_VT && c != CHAR_FF && c != CHAR_NEL
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
&& c != 0x2028 && c != 0x2029
#endif
))) break;
@@ -6008,7 +6106,7 @@ for (;;)
case OP_NOT_HSPACE:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -6017,7 +6115,7 @@ for (;;)
{
default: eptr++; break;
HSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
HSPACE_MULTIBYTE_CASES:
#endif
goto ENDLOOP00;
@@ -6029,7 +6127,7 @@ for (;;)
case OP_HSPACE:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -6038,7 +6136,7 @@ for (;;)
{
default: goto ENDLOOP01;
HSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
HSPACE_MULTIBYTE_CASES:
#endif
eptr++; break;
@@ -6050,7 +6148,7 @@ for (;;)
case OP_NOT_VSPACE:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -6059,7 +6157,7 @@ for (;;)
{
default: eptr++; break;
VSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
VSPACE_MULTIBYTE_CASES:
#endif
goto ENDLOOP02;
@@ -6071,7 +6169,7 @@ for (;;)
case OP_VSPACE:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
@@ -6080,7 +6178,7 @@ for (;;)
{
default: goto ENDLOOP03;
VSPACE_BYTE_CASES:
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#if PCRE2_CODE_UNIT_WIDTH != 8
VSPACE_MULTIBYTE_CASES:
#endif
eptr++; break;
@@ -6092,12 +6190,12 @@ for (;;)
case OP_NOT_DIGIT:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
- if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_digit) != 0) break;
+ if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_digit) != 0) break;
eptr++;
}
break;
@@ -6105,12 +6203,12 @@ for (;;)
case OP_DIGIT:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
- if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_digit) == 0) break;
+ if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_digit) == 0) break;
eptr++;
}
break;
@@ -6118,12 +6216,12 @@ for (;;)
case OP_NOT_WHITESPACE:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
- if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_space) != 0) break;
+ if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_space) != 0) break;
eptr++;
}
break;
@@ -6131,12 +6229,12 @@ for (;;)
case OP_WHITESPACE:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
- if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_space) == 0) break;
+ if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_space) == 0) break;
eptr++;
}
break;
@@ -6144,12 +6242,12 @@ for (;;)
case OP_NOT_WORDCHAR:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
- if (MAX_255(*eptr) && (md->ctypes[*eptr] & ctype_word) != 0) break;
+ if (MAX_255(*eptr) && (mb->ctypes[*eptr] & ctype_word) != 0) break;
eptr++;
}
break;
@@ -6157,25 +6255,25 @@ for (;;)
case OP_WORDCHAR:
for (i = min; i < max; i++)
{
- if (eptr >= md->end_subject)
+ if (eptr >= mb->end_subject)
{
SCHECK_PARTIAL();
break;
}
- if (!MAX_255(*eptr) || (md->ctypes[*eptr] & ctype_word) == 0) break;
+ if (!MAX_255(*eptr) || (mb->ctypes[*eptr] & ctype_word) == 0) break;
eptr++;
}
break;
default:
- RRETURN(PCRE_ERROR_INTERNAL);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
if (possessive) continue; /* No backtracking */
for (;;)
{
if (eptr == pp) goto TAIL_RECURSE;
- RMATCH(eptr, ecode, offset_top, md, eptrb, RM47);
+ RMATCH(eptr, ecode, offset_top, mb, eptrb, RM47);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
if (ctype == OP_ANYNL && eptr > pp && *eptr == CHAR_LF &&
@@ -6190,8 +6288,7 @@ for (;;)
something seriously wrong in the code above or the OP_xxx definitions. */
default:
- DPRINTF(("Unknown opcode %d\n", *ecode));
- RRETURN(PCRE_ERROR_UNKNOWN_OPCODE);
+ RRETURN(PCRE2_ERROR_INTERNAL);
}
/* Do not stick any code in here without much thought; it is assumed
@@ -6206,7 +6303,7 @@ for (;;)
match(), the RRETURN() macro jumps here. The number that is saved in
frame->Xwhere indicates which label we actually want to return to. */
-#ifdef NO_RECURSE
+#ifdef HEAP_MATCH_RECURSE
#define LBL(val) case val: goto L_RM##val;
HEAP_RETURN:
switch (frame->Xwhere)
@@ -6216,25 +6313,22 @@ switch (frame->Xwhere)
LBL(19) LBL(24) LBL(25) LBL(26) LBL(27) LBL(29) LBL(31) LBL(33)
LBL(35) LBL(43) LBL(47) LBL(48) LBL(49) LBL(50) LBL(51) LBL(52)
LBL(53) LBL(54) LBL(55) LBL(56) LBL(57) LBL(58) LBL(63) LBL(64)
- LBL(65) LBL(66)
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+ LBL(65) LBL(66) LBL(68)
+#ifdef SUPPORT_WIDE_CHARS
LBL(20) LBL(21)
#endif
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
LBL(16) LBL(18)
LBL(22) LBL(23) LBL(28) LBL(30)
LBL(32) LBL(34) LBL(42) LBL(46)
-#ifdef SUPPORT_UCP
LBL(36) LBL(37) LBL(38) LBL(39) LBL(40) LBL(41) LBL(44) LBL(45)
LBL(59) LBL(60) LBL(61) LBL(62) LBL(67)
-#endif /* SUPPORT_UCP */
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
default:
- DPRINTF(("jump error in pcre match: label %d non-existent\n", frame->Xwhere));
- return PCRE_ERROR_INTERNAL;
+ return PCRE2_ERROR_INTERNAL;
}
#undef LBL
-#endif /* NO_RECURSE */
+#endif /* HEAP_MATCH_RECURSE */
}
@@ -6244,7 +6338,7 @@ switch (frame->Xwhere)
Undefine all the macros that were defined above to handle this. */
-#ifdef NO_RECURSE
+#ifdef HEAP_MATCH_RECURSE
#undef eptr
#undef ecode
#undef mstart
@@ -6255,7 +6349,7 @@ Undefine all the macros that were defined above to handle this. */
#undef callpat
#undef charptr
#undef data
-#undef next
+#undef next_ecode
#undef pp
#undef prev
#undef saved_eptr
@@ -6277,11 +6371,9 @@ Undefine all the macros that were defined above to handle this. */
#undef save_offset1
#undef save_offset2
#undef save_offset3
-#undef stacksave
#undef newptrb
-
-#endif
+#endif /* HEAP_MATCH_RECURSE */
/* These two are defined as macros in both cases */
@@ -6292,7 +6384,7 @@ Undefine all the macros that were defined above to handle this. */
***************************************************************************/
-#ifdef NO_RECURSE
+#ifdef HEAP_MATCH_RECURSE
/*************************************************
* Release allocated heap frames *
*************************************************/
@@ -6300,378 +6392,336 @@ Undefine all the macros that were defined above to handle this. */
/* This function releases all the allocated frames. The base frame is on the
machine stack, and so must not be freed.
-Argument: the address of the base frame
+Argument:
+ frame_base the address of the base frame
+ mb the match block
+
Returns: nothing
*/
static void
-release_match_heapframes (heapframe *frame_base)
+release_match_heapframes (heapframe *frame_base, match_block *mb)
{
heapframe *nextframe = frame_base->Xnextframe;
while (nextframe != NULL)
{
heapframe *oldframe = nextframe;
nextframe = nextframe->Xnextframe;
- (PUBL(stack_free))(oldframe);
+ mb->stack_memctl.free(oldframe, mb->stack_memctl.memory_data);
}
}
-#endif
+#endif /* HEAP_MATCH_RECURSE */
+
/*************************************************
-* Execute a Regular Expression *
+* Match a Regular Expression *
*************************************************/
-/* This function applies a compiled re to a subject string and picks out
+/* This function applies a compiled pattern to a subject string and picks out
portions of the string if it matches. Two elements in the vector are set for
each substring: the offsets to the start and end of the substring.
Arguments:
- argument_re points to the compiled expression
- extra_data points to extra data or is NULL
+ code points to the compiled expression
subject points to the subject string
length length of subject string (may contain binary zeros)
start_offset where to start in the subject string
options option bits
- offsets points to a vector of ints to be filled in with offsets
- offsetcount the number of elements in the vector
-
-Returns: > 0 => success; value is the number of elements filled in
- = 0 => success, but offsets is not big enough
- -1 => failed to match
- < -1 => some kind of unexpected problem
+ match_data points to a match_data block
+ mcontext points a PCRE2 context
+
+Returns: > 0 => success; value is the number of ovector pairs filled
+ = 0 => success, but ovector is not big enough
+ -1 => failed to match (PCRE2_ERROR_NOMATCH)
+ -2 => partial match (PCRE2_ERROR_PARTIAL)
+ < -2 => some kind of unexpected problem
*/
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre_exec(const pcre *argument_re, const pcre_extra *extra_data,
- PCRE_SPTR subject, int length, int start_offset, int options, int *offsets,
- int offsetcount)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre16_exec(const pcre16 *argument_re, const pcre16_extra *extra_data,
- PCRE_SPTR16 subject, int length, int start_offset, int options, int *offsets,
- int offsetcount)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN int PCRE_CALL_CONVENTION
-pcre32_exec(const pcre32 *argument_re, const pcre32_extra *extra_data,
- PCRE_SPTR32 subject, int length, int start_offset, int options, int *offsets,
- int offsetcount)
-#endif
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+ PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+ pcre2_match_context *mcontext)
{
-int rc, ocount, arg_offset_max;
-int newline;
-BOOL using_temporary_offsets = FALSE;
+int rc;
+int ocount;
+
+const uint8_t *start_bits = NULL;
+
+const pcre2_real_code *re = (const pcre2_real_code *)code;
+
BOOL anchored;
-BOOL startline;
BOOL firstline;
+BOOL has_first_cu = FALSE;
+BOOL has_req_cu = FALSE;
+BOOL startline;
+BOOL using_temporary_offsets = FALSE;
BOOL utf;
-BOOL has_first_char = FALSE;
-BOOL has_req_char = FALSE;
-pcre_uchar first_char = 0;
-pcre_uchar first_char2 = 0;
-pcre_uchar req_char = 0;
-pcre_uchar req_char2 = 0;
-match_data match_block;
-match_data *md = &match_block;
-const pcre_uint8 *tables;
-const pcre_uint8 *start_bits = NULL;
-PCRE_PUCHAR start_match = (PCRE_PUCHAR)subject + start_offset;
-PCRE_PUCHAR end_subject;
-PCRE_PUCHAR start_partial = NULL;
-PCRE_PUCHAR match_partial = NULL;
-PCRE_PUCHAR req_char_ptr = start_match - 1;
-
-const pcre_study_data *study;
-const REAL_PCRE *re = (const REAL_PCRE *)argument_re;
-
-#ifdef NO_RECURSE
+
+PCRE2_UCHAR first_cu = 0;
+PCRE2_UCHAR first_cu2 = 0;
+PCRE2_UCHAR req_cu = 0;
+PCRE2_UCHAR req_cu2 = 0;
+
+PCRE2_SPTR bumpalong_limit;
+PCRE2_SPTR end_subject;
+PCRE2_SPTR start_match = subject + start_offset;
+PCRE2_SPTR req_cu_ptr = start_match - 1;
+PCRE2_SPTR start_partial = NULL;
+PCRE2_SPTR match_partial = NULL;
+
+/* We need to have mb pointing to a match block, because the IS_NEWLINE macro
+is used below, and it expects NLBLOCK to be defined as a pointer. */
+
+match_block actual_match_block;
+match_block *mb = &actual_match_block;
+
+#ifdef HEAP_MATCH_RECURSE
heapframe frame_zero;
frame_zero.Xprevframe = NULL; /* Marks the top level */
frame_zero.Xnextframe = NULL; /* None are allocated yet */
-md->match_frames_base = &frame_zero;
+mb->match_frames_base = &frame_zero;
#endif
-/* Check for the special magic call that measures the size of the stack used
-per recursive call of match(). Without the funny casting for sizeof, a Windows
-compiler gave this error: "unary minus operator applied to unsigned type,
-result still unsigned". Hopefully the cast fixes that. */
+/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
+subject string. */
-if (re == NULL && extra_data == NULL && subject == NULL && length == -999 &&
- start_offset == -999)
-#ifdef NO_RECURSE
- return -((int)sizeof(heapframe));
-#else
- return match(NULL, NULL, NULL, 0, NULL, NULL, 0);
-#endif
+if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
+end_subject = subject + length;
/* Plausibility checks */
-if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION;
-if (re == NULL || subject == NULL || (offsets == NULL && offsetcount > 0))
- return PCRE_ERROR_NULL;
-if (offsetcount < 0) return PCRE_ERROR_BADCOUNT;
-if (length < 0) return PCRE_ERROR_BADLENGTH;
-if (start_offset < 0 || start_offset > length) return PCRE_ERROR_BADOFFSET;
-
-/* Check that the first field in the block is the magic number. If it is not,
-return with PCRE_ERROR_BADMAGIC. However, if the magic number is equal to
-REVERSED_MAGIC_NUMBER we return with PCRE_ERROR_BADENDIANNESS, which
-means that the pattern is likely compiled with different endianness. */
-
-if (re->magic_number != MAGIC_NUMBER)
- return re->magic_number == REVERSED_MAGIC_NUMBER?
- PCRE_ERROR_BADENDIANNESS:PCRE_ERROR_BADMAGIC;
-if ((re->flags & PCRE_MODE) == 0) return PCRE_ERROR_BADMODE;
-
-/* These two settings are used in the code for checking a UTF-8 string that
-follows immediately afterwards. Other values in the md block are used only
-during "normal" pcre_exec() processing, not when the JIT support is in use,
-so they are set up later. */
-
-/* PCRE_UTF16 has the same value as PCRE_UTF8. */
-utf = md->utf = (re->options & PCRE_UTF8) != 0;
-md->partial = ((options & PCRE_PARTIAL_HARD) != 0)? 2 :
- ((options & PCRE_PARTIAL_SOFT) != 0)? 1 : 0;
-
-/* Check a UTF-8 string if required. Pass back the character offset and error
-code for an invalid string if a results vector is available. */
-
-#ifdef SUPPORT_UTF
-if (utf && (options & PCRE_NO_UTF8_CHECK) == 0)
+if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
+if (code == NULL || subject == NULL || match_data == NULL)
+ return PCRE2_ERROR_NULL;
+if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
+
+/* Check that the first field in the block is the magic number. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check the code unit width. */
+
+if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
+ return PCRE2_ERROR_BADMODE;
+
+/* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the
+options variable for this function. Users of PCRE2 who are not calling the
+function directly would like to have a way of setting these flags, in the same
+way that they can set pcre2_compile() flags like PCRE2_NO_AUTOPOSSESS with
+constructions like (*NO_AUTOPOSSESS). To enable this, (*NOTEMPTY) and
+(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which can now be
+transferred to the options for this function. The bits are guaranteed to be
+adjacent, but do not have the same values. This bit of Boolean trickery assumes
+that the match-time bits are not more significant than the flag bits. If by
+accident this is not the case, a compile-time division by zero error will
+occur. */
+
+#define FF (PCRE2_NOTEMPTY_SET|PCRE2_NE_ATST_SET)
+#define OO (PCRE2_NOTEMPTY|PCRE2_NOTEMPTY_ATSTART)
+options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1)));
+#undef FF
+#undef OO
+
+/* A NULL match context means "use a default context" */
+
+if (mcontext == NULL)
+ mcontext = (pcre2_match_context *)(&PRIV(default_match_context));
+
+/* These two settings are used in the code for checking a UTF string that
+follows immediately afterwards. Other values in the mb block are used only
+during interpretive pcre_match() processing, not when the JIT support is in
+use, so they are set up later. */
+
+utf = (re->overall_options & PCRE2_UTF) != 0;
+mb->partial = ((options & PCRE2_PARTIAL_HARD) != 0)? 2 :
+ ((options & PCRE2_PARTIAL_SOFT) != 0)? 1 : 0;
+
+/* Check a UTF string for validity if required. For 8-bit and 16-bit strings,
+we must also check that a starting offset does not point into the middle of a
+multiunit character. We check only the portion of the subject that is going to
+be inspected during matching - from the offset minus the maximum back reference
+to the given length. This saves time when a small part of a large subject is
+being matched by the use of a starting offset. Note that the maximum lookbehind
+is a number of characters, not code units. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
{
- int erroroffset;
- int errorcode = PRIV(valid_utf)((PCRE_PUCHAR)subject, length, &erroroffset);
- if (errorcode != 0)
+ PCRE2_SPTR check_subject = start_match; /* start_match includes offset */
+
+ if (start_offset > 0)
{
- if (offsetcount >= 2)
+#if PCRE2_CODE_UNIT_WIDTH != 32
+ unsigned int i;
+ if (start_match < end_subject && NOT_FIRSTCU(*start_match))
+ return PCRE2_ERROR_BADUTFOFFSET;
+ for (i = re->max_lookbehind; i > 0 && check_subject > subject; i--)
{
- offsets[0] = erroroffset;
- offsets[1] = errorcode;
+ check_subject--;
+ while (check_subject > subject &&
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ (*check_subject & 0xc0) == 0x80)
+#else /* 16-bit */
+ (*check_subject & 0xfc00) == 0xdc00)
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ check_subject--;
}
-#if defined COMPILE_PCRE8
- return (errorcode <= PCRE_UTF8_ERR5 && md->partial > 1)?
- PCRE_ERROR_SHORTUTF8 : PCRE_ERROR_BADUTF8;
-#elif defined COMPILE_PCRE16
- return (errorcode <= PCRE_UTF16_ERR1 && md->partial > 1)?
- PCRE_ERROR_SHORTUTF16 : PCRE_ERROR_BADUTF16;
-#elif defined COMPILE_PCRE32
- return PCRE_ERROR_BADUTF32;
-#endif
+#else
+ /* In the 32-bit library, one code unit equals one character. However,
+ we cannot just subtract the lookbehind and then compare pointers, because
+ a very large lookbehind could create an invalid pointer. */
+
+ if (start_offset >= re->max_lookbehind)
+ check_subject -= re->max_lookbehind;
+ else
+ check_subject = subject;
+#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
+ }
+
+ /* Validate the relevant portion of the subject. After an error, adjust the
+ offset to be an absolute offset in the whole string. */
+
+ match_data->rc = PRIV(valid_utf)(check_subject,
+ length - (check_subject - subject), &(match_data->startchar));
+ if (match_data->rc != 0)
+ {
+ match_data->startchar += check_subject - subject;
+ return match_data->rc;
}
-#if defined COMPILE_PCRE8 || defined COMPILE_PCRE16
- /* Check that a start_offset points to the start of a UTF character. */
- if (start_offset > 0 && start_offset < length &&
- NOT_FIRSTCHAR(((PCRE_PUCHAR)subject)[start_offset]))
- return PCRE_ERROR_BADUTF8_OFFSET;
-#endif
}
-#endif
+#endif /* SUPPORT_UNICODE */
+
+/* It is an error to set an offset limit without setting the flag at compile
+time. */
+
+if (mcontext->offset_limit != PCRE2_UNSET &&
+ (re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0)
+ return PCRE2_ERROR_BADOFFSETLIMIT;
/* If the pattern was successfully studied with JIT support, run the JIT
executable instead of the rest of this function. Most options must be set at
compile time for the JIT code to be usable. Fallback to the normal code path if
-an unsupported flag is set. */
+an unsupported option is set or if JIT returns BADOPTION (which means that the
+selected normal or partial matching mode was not compiled). */
#ifdef SUPPORT_JIT
-if (extra_data != NULL
- && (extra_data->flags & (PCRE_EXTRA_EXECUTABLE_JIT |
- PCRE_EXTRA_TABLES)) == PCRE_EXTRA_EXECUTABLE_JIT
- && extra_data->executable_jit != NULL
- && (options & ~PUBLIC_JIT_EXEC_OPTIONS) == 0)
+if (re->executable_jit != NULL && (options & ~PUBLIC_JIT_MATCH_OPTIONS) == 0)
{
- rc = PRIV(jit_exec)(extra_data, (const pcre_uchar *)subject, length,
- start_offset, options, offsets, offsetcount);
-
- /* PCRE_ERROR_NULL means that the selected normal or partial matching
- mode is not compiled. In this case we simply fallback to interpreter. */
-
- if (rc != PCRE_ERROR_JIT_BADOPTION) return rc;
+ rc = pcre2_jit_match(code, subject, length, start_offset, options,
+ match_data, mcontext);
+ if (rc != PCRE2_ERROR_JIT_BADOPTION) return rc;
}
#endif
-/* Carry on with non-JIT matching. This information is for finding all the
-numbers associated with a given name, for condition testing. */
-
-md->name_table = (pcre_uchar *)re + re->name_table_offset;
-md->name_count = re->name_count;
-md->name_entry_size = re->name_entry_size;
-
-/* Fish out the optional data from the extra_data structure, first setting
-the default values. */
-
-study = NULL;
-md->match_limit = MATCH_LIMIT;
-md->match_limit_recursion = MATCH_LIMIT_RECURSION;
-md->callout_data = NULL;
-
-/* The table pointer is always in native byte order. */
-
-tables = re->tables;
-
-/* The two limit values override the defaults, whatever their value. */
+/* Carry on with non-JIT matching. */
-if (extra_data != NULL)
- {
- unsigned long int flags = extra_data->flags;
- if ((flags & PCRE_EXTRA_STUDY_DATA) != 0)
- study = (const pcre_study_data *)extra_data->study_data;
- if ((flags & PCRE_EXTRA_MATCH_LIMIT) != 0)
- md->match_limit = extra_data->match_limit;
- if ((flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) != 0)
- md->match_limit_recursion = extra_data->match_limit_recursion;
- if ((flags & PCRE_EXTRA_CALLOUT_DATA) != 0)
- md->callout_data = extra_data->callout_data;
- if ((flags & PCRE_EXTRA_TABLES) != 0) tables = extra_data->tables;
- }
-
-/* Limits in the regex override only if they are smaller. */
-
-if ((re->flags & PCRE_MLSET) != 0 && re->limit_match < md->match_limit)
- md->match_limit = re->limit_match;
-
-if ((re->flags & PCRE_RLSET) != 0 &&
- re->limit_recursion < md->match_limit_recursion)
- md->match_limit_recursion = re->limit_recursion;
-
-/* If the exec call supplied NULL for tables, use the inbuilt ones. This
-is a feature that makes it possible to save compiled regex and re-use them
-in other programs later. */
-
-if (tables == NULL) tables = PRIV(default_tables);
+anchored = ((re->overall_options | options) & PCRE2_ANCHORED) != 0;
+firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+startline = (re->flags & PCRE2_STARTLINE) != 0;
+bumpalong_limit = (mcontext->offset_limit == PCRE2_UNSET)?
+ end_subject : subject + mcontext->offset_limit;
-/* Set up other data */
+/* Fill in the fields in the match block. */
-anchored = ((re->options | options) & PCRE_ANCHORED) != 0;
-startline = (re->flags & PCRE_STARTLINE) != 0;
-firstline = (re->options & PCRE_FIRSTLINE) != 0;
+mb->callout = mcontext->callout;
+mb->callout_data = mcontext->callout_data;
+mb->memctl = mcontext->memctl;
+#ifdef HEAP_MATCH_RECURSE
+mb->stack_memctl = mcontext->stack_memctl;
+#endif
-/* The code starts after the real_pcre block and the capture name table. */
+mb->start_subject = subject;
+mb->start_offset = start_offset;
+mb->end_subject = end_subject;
+mb->hasthen = (re->flags & PCRE2_HASTHEN) != 0;
-md->start_code = (const pcre_uchar *)re + re->name_table_offset +
- re->name_count * re->name_entry_size;
+mb->moptions = options; /* Match options */
+mb->poptions = re->overall_options; /* Pattern options */
-md->start_subject = (PCRE_PUCHAR)subject;
-md->start_offset = start_offset;
-md->end_subject = md->start_subject + length;
-end_subject = md->end_subject;
+mb->ignore_skip_arg = 0;
+mb->mark = mb->nomatch_mark = NULL; /* In case never set */
+mb->recursive = NULL; /* No recursion at top level */
+mb->ovecsave_chain = NULL; /* No ovecsave blocks yet */
+mb->hitend = FALSE;
-md->endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
-md->use_ucp = (re->options & PCRE_UCP) != 0;
-md->jscript_compat = (re->options & PCRE_JAVASCRIPT_COMPAT) != 0;
-md->ignore_skip_arg = 0;
+/* The name table is needed for finding all the numbers associated with a
+given name, for condition testing. The code follows the name table. */
-/* Some options are unpacked into BOOL variables in the hope that testing
-them will be faster than individual option bits. */
+mb->name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code));
+mb->name_count = re->name_count;
+mb->name_entry_size = re->name_entry_size;
+mb->start_code = mb->name_table + re->name_count * re->name_entry_size;
-md->notbol = (options & PCRE_NOTBOL) != 0;
-md->noteol = (options & PCRE_NOTEOL) != 0;
-md->notempty = (options & PCRE_NOTEMPTY) != 0;
-md->notempty_atstart = (options & PCRE_NOTEMPTY_ATSTART) != 0;
+/* Limits set in the pattern override the match context only if they are
+smaller. */
-md->hitend = FALSE;
-md->mark = md->nomatch_mark = NULL; /* In case never set */
+mb->match_limit = (mcontext->match_limit < re->limit_match)?
+ mcontext->match_limit : re->limit_match;
+mb->match_limit_recursion = (mcontext->recursion_limit < re->limit_recursion)?
+ mcontext->recursion_limit : re->limit_recursion;
-md->recursive = NULL; /* No recursion at top level */
-md->hasthen = (re->flags & PCRE_HASTHEN) != 0;
+/* Pointers to the individual character tables */
-md->lcc = tables + lcc_offset;
-md->fcc = tables + fcc_offset;
-md->ctypes = tables + ctypes_offset;
+mb->lcc = re->tables + lcc_offset;
+mb->fcc = re->tables + fcc_offset;
+mb->ctypes = re->tables + ctypes_offset;
-/* Handle different \R options. */
+/* Process the \R and newline settings. */
-switch (options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE))
+mb->bsr_convention = re->bsr_convention;
+mb->nltype = NLTYPE_FIXED;
+switch(re->newline_convention)
{
- case 0:
- if ((re->options & (PCRE_BSR_ANYCRLF|PCRE_BSR_UNICODE)) != 0)
- md->bsr_anycrlf = (re->options & PCRE_BSR_ANYCRLF) != 0;
- else
-#ifdef BSR_ANYCRLF
- md->bsr_anycrlf = TRUE;
-#else
- md->bsr_anycrlf = FALSE;
-#endif
+ case PCRE2_NEWLINE_CR:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_CR;
break;
- case PCRE_BSR_ANYCRLF:
- md->bsr_anycrlf = TRUE;
+ case PCRE2_NEWLINE_LF:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_NL;
break;
- case PCRE_BSR_UNICODE:
- md->bsr_anycrlf = FALSE;
+ case PCRE2_NEWLINE_CRLF:
+ mb->nllen = 2;
+ mb->nl[0] = CHAR_CR;
+ mb->nl[1] = CHAR_NL;
break;
- default: return PCRE_ERROR_BADNEWLINE;
- }
-
-/* Handle different types of newline. The three bits give eight cases. If
-nothing is set at run time, whatever was used at compile time applies. */
+ case PCRE2_NEWLINE_ANY:
+ mb->nltype = NLTYPE_ANY;
+ break;
-switch ((((options & PCRE_NEWLINE_BITS) == 0)? re->options :
- (pcre_uint32)options) & PCRE_NEWLINE_BITS)
- {
- case 0: newline = NEWLINE; break; /* Compile-time default */
- case PCRE_NEWLINE_CR: newline = CHAR_CR; break;
- case PCRE_NEWLINE_LF: newline = CHAR_NL; break;
- case PCRE_NEWLINE_CR+
- PCRE_NEWLINE_LF: newline = (CHAR_CR << 8) | CHAR_NL; break;
- case PCRE_NEWLINE_ANY: newline = -1; break;
- case PCRE_NEWLINE_ANYCRLF: newline = -2; break;
- default: return PCRE_ERROR_BADNEWLINE;
- }
+ case PCRE2_NEWLINE_ANYCRLF:
+ mb->nltype = NLTYPE_ANYCRLF;
+ break;
-if (newline == -2)
- {
- md->nltype = NLTYPE_ANYCRLF;
- }
-else if (newline < 0)
- {
- md->nltype = NLTYPE_ANY;
- }
-else
- {
- md->nltype = NLTYPE_FIXED;
- if (newline > 255)
- {
- md->nllen = 2;
- md->nl[0] = (newline >> 8) & 255;
- md->nl[1] = newline & 255;
- }
- else
- {
- md->nllen = 1;
- md->nl[0] = newline;
- }
+ default: return PCRE2_ERROR_INTERNAL;
}
-/* Partial matching was originally supported only for a restricted set of
-regexes; from release 8.00 there are no restrictions, but the bits are still
-defined (though never set). So there's no harm in leaving this code. */
-
-if (md->partial && (re->flags & PCRE_NOPARTIAL) != 0)
- return PCRE_ERROR_BADPARTIAL;
-
/* If the expression has got more back references than the offsets supplied can
-hold, we get a temporary chunk of working store to use during the matching.
-Otherwise, we can use the vector supplied, rounding down its size to a multiple
-of 3. */
+hold, we get a temporary chunk of memory to use during the matching. Otherwise,
+we can use the vector supplied. The size of the ovector is three times the
+value in the oveccount field. Two-thirds of it is pairs for storing matching
+offsets, and the top third is working space. */
-ocount = offsetcount - (offsetcount % 3);
-arg_offset_max = (2*ocount)/3;
-
-if (re->top_backref > 0 && re->top_backref >= ocount/3)
+if (re->top_backref >= match_data->oveccount)
{
ocount = re->top_backref * 3 + 3;
- md->offset_vector = (int *)(PUBL(malloc))(ocount * sizeof(int));
- if (md->offset_vector == NULL) return PCRE_ERROR_NOMEMORY;
+ mb->ovector = (PCRE2_SIZE *)(mb->memctl.malloc(ocount * sizeof(PCRE2_SIZE),
+ mb->memctl.memory_data));
+ if (mb->ovector == NULL) return PCRE2_ERROR_NOMEMORY;
using_temporary_offsets = TRUE;
- DPRINTF(("Got memory to hold back references\n"));
}
-else md->offset_vector = offsets;
-md->offset_end = ocount;
-md->offset_max = (2*ocount)/3;
-md->capture_last = 0;
+else
+ {
+ ocount = 3 * match_data->oveccount;
+ mb->ovector = match_data->ovector;
+ }
+
+mb->offset_end = ocount;
+mb->offset_max = (2*ocount)/3;
/* Reset the working variable associated with each extraction. These should
never be used unless previously set, but they get saved and restored, and so we
@@ -6679,56 +6729,52 @@ initialize them to avoid reading uninitialized locations. Also, unset the
offsets for the matched string. This is really just for tidiness with callouts,
in case they inspect these fields. */
-if (md->offset_vector != NULL)
+if (ocount > 0)
{
- register int *iptr = md->offset_vector + ocount;
- register int *iend = iptr - re->top_bracket;
- if (iend < md->offset_vector + 2) iend = md->offset_vector + 2;
- while (--iptr >= iend) *iptr = -1;
- if (offsetcount > 0) md->offset_vector[0] = -1;
- if (offsetcount > 1) md->offset_vector[1] = -1;
+ register PCRE2_SIZE *iptr = mb->ovector + ocount;
+ register PCRE2_SIZE *iend = iptr - re->top_bracket;
+ if (iend < mb->ovector + 2) iend = mb->ovector + 2;
+ while (--iptr >= iend) *iptr = PCRE2_UNSET;
+ mb->ovector[0] = mb->ovector[1] = PCRE2_UNSET;
}
-/* Set up the first character to match, if available. The first_char value is
-never set for an anchored regular expression, but the anchoring may be forced
-at run time, so we have to test for anchoring. The first char may be unset for
-an unanchored pattern, of course. If there's no first char and the pattern was
-studied, there may be a bitmap of possible first characters. */
+/* Set up the first code unit to match, if available. The first_codeunit value
+is never set for an anchored regular expression, but the anchoring may be
+forced at run time, so we have to test for anchoring. The first code unit may
+be unset for an unanchored pattern, of course. If there's no first code unit
+there may be a bitmap of possible first characters. */
if (!anchored)
{
- if ((re->flags & PCRE_FIRSTSET) != 0)
+ if ((re->flags & PCRE2_FIRSTSET) != 0)
{
- has_first_char = TRUE;
- first_char = first_char2 = (pcre_uchar)(re->first_char);
- if ((re->flags & PCRE_FCH_CASELESS) != 0)
+ has_first_cu = TRUE;
+ first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit);
+ if ((re->flags & PCRE2_FIRSTCASELESS) != 0)
{
- first_char2 = TABLE_GET(first_char, md->fcc, first_char);
-#if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
- if (utf && first_char > 127)
- first_char2 = UCD_OTHERCASE(first_char);
+ first_cu2 = TABLE_GET(first_cu, mb->fcc, first_cu);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (utf && first_cu > 127) first_cu2 = UCD_OTHERCASE(first_cu);
#endif
}
}
else
- if (!startline && study != NULL &&
- (study->flags & PCRE_STUDY_MAPPED) != 0)
- start_bits = study->start_bits;
+ if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0)
+ start_bits = re->start_bitmap;
}
/* For anchored or unanchored matches, there may be a "last known required
character" set. */
-if ((re->flags & PCRE_REQCHSET) != 0)
+if ((re->flags & PCRE2_LASTSET) != 0)
{
- has_req_char = TRUE;
- req_char = req_char2 = (pcre_uchar)(re->req_char);
- if ((re->flags & PCRE_RCH_CASELESS) != 0)
+ has_req_cu = TRUE;
+ req_cu = req_cu2 = (PCRE2_UCHAR)(re->last_codeunit);
+ if ((re->flags & PCRE2_LASTCASELESS) != 0)
{
- req_char2 = TABLE_GET(req_char, md->fcc, req_char);
-#if defined SUPPORT_UCP && !(defined COMPILE_PCRE8)
- if (utf && req_char > 127)
- req_char2 = UCD_OTHERCASE(req_char);
+ req_cu2 = TABLE_GET(req_cu, mb->fcc, req_cu);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (utf && req_cu > 127) req_cu2 = UCD_OTHERCASE(req_cu);
#endif
}
}
@@ -6741,63 +6787,73 @@ the loop runs just once. */
for(;;)
{
- PCRE_PUCHAR save_end_subject = end_subject;
- PCRE_PUCHAR new_start_match;
+ PCRE2_SPTR new_start_match;
+ mb->capture_last = 0;
+
+ /* ----------------- Start of match optimizations ---------------- */
- /* If firstline is TRUE, the start of the match is constrained to the first
- line of a multiline string. That is, the match must be before or at the first
- newline. Implement this by temporarily adjusting end_subject so that we stop
- scanning at a newline. If the match fails at the newline, later code breaks
- this loop. */
+ /* There are some optimizations that avoid running the match if a known
+ starting point is not found, or if a known later code unit is not present.
+ However, there is an option (settable at compile time) that disables these,
+ for testing and for ensuring that all callouts do actually occur. */
- if (firstline)
+ if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
{
- PCRE_PUCHAR t = start_match;
-#ifdef SUPPORT_UTF
- if (utf)
+ PCRE2_SPTR save_end_subject = end_subject;
+
+ /* If firstline is TRUE, the start of the match is constrained to the first
+ line of a multiline string. That is, the match must be before or at the
+ first newline. Implement this by temporarily adjusting end_subject so that
+ we stop the optimization scans at a newline. If the match fails at the
+ newline, later code breaks this loop. */
+
+ if (firstline)
{
- while (t < md->end_subject && !IS_NEWLINE(t))
+ PCRE2_SPTR t = start_match;
+#ifdef SUPPORT_UNICODE
+ if (utf)
{
- t++;
- ACROSSCHAR(t < end_subject, *t, t++);
+ while (t < mb->end_subject && !IS_NEWLINE(t))
+ {
+ t++;
+ ACROSSCHAR(t < end_subject, *t, t++);
+ }
}
- }
- else
+ else
#endif
- while (t < md->end_subject && !IS_NEWLINE(t)) t++;
- end_subject = t;
- }
-
- /* There are some optimizations that avoid running the match if a known
- starting point is not found, or if a known later character is not present.
- However, there is an option that disables these, for testing and for ensuring
- that all callouts do actually occur. The option can be set in the regex by
- (*NO_START_OPT) or passed in match-time options. */
+ while (t < mb->end_subject && !IS_NEWLINE(t)) t++;
+ end_subject = t;
+ }
- if (((options | re->options) & PCRE_NO_START_OPTIMIZE) == 0)
- {
- /* Advance to a unique first char if there is one. */
+ /* Advance to a unique first code unit if there is one. In 8-bit mode, the
+ use of memchr() gives a big speed up. */
- if (has_first_char)
+ if (has_first_cu)
{
- pcre_uchar smc;
-
- if (first_char != first_char2)
+ PCRE2_UCHAR smc;
+ if (first_cu != first_cu2)
while (start_match < end_subject &&
- (smc = UCHAR21TEST(start_match)) != first_char && smc != first_char2)
+ (smc = UCHAR21TEST(start_match)) != first_cu && smc != first_cu2)
start_match++;
else
- while (start_match < end_subject && UCHAR21TEST(start_match) != first_char)
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ while (start_match < end_subject && UCHAR21TEST(start_match) != first_cu)
start_match++;
+#else
+ start_match = memchr(start_match, first_cu, end_subject - start_match);
+ if (start_match == NULL) start_match = end_subject;
+#endif
+ }
}
/* Or to just after a linebreak for a multiline match */
else if (startline)
{
- if (start_match > md->start_subject + start_offset)
+ if (start_match > mb->start_subject + start_offset)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
while (start_match < end_subject && !WAS_NEWLINE(start_match))
@@ -6812,131 +6868,137 @@ for(;;)
while (start_match < end_subject && !WAS_NEWLINE(start_match))
start_match++;
- /* If we have just passed a CR and the newline option is ANY or ANYCRLF,
- and we are now at a LF, advance the match position by one more character.
- */
+ /* If we have just passed a CR and the newline option is ANY or
+ ANYCRLF, and we are now at a LF, advance the match position by one more
+ code unit. */
if (start_match[-1] == CHAR_CR &&
- (md->nltype == NLTYPE_ANY || md->nltype == NLTYPE_ANYCRLF) &&
+ (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) &&
start_match < end_subject &&
UCHAR21TEST(start_match) == CHAR_NL)
start_match++;
}
}
- /* Or to a non-unique first byte after study */
+ /* Or to a non-unique first code unit if any have been identified. The
+ bitmap contains only 256 bits. When code units are 16 or 32 bits wide, all
+ code units greater than 254 set the 255 bit. */
else if (start_bits != NULL)
{
while (start_match < end_subject)
{
- register pcre_uint32 c = UCHAR21TEST(start_match);
-#ifndef COMPILE_PCRE8
+ register uint32_t c = UCHAR21TEST(start_match);
+#if PCRE2_CODE_UNIT_WIDTH != 8
if (c > 255) c = 255;
#endif
if ((start_bits[c/8] & (1 << (c&7))) != 0) break;
start_match++;
}
}
- } /* Starting optimizations */
- /* Restore fudged end_subject */
+ /* Restore fudged end_subject */
- end_subject = save_end_subject;
+ end_subject = save_end_subject;
- /* The following two optimizations are disabled for partial matching or if
- disabling is explicitly requested. */
+ /* The following two optimizations are disabled for partial matching. */
- if (((options | re->options) & PCRE_NO_START_OPTIMIZE) == 0 && !md->partial)
- {
- /* If the pattern was studied, a minimum subject length may be set. This is
- a lower bound; no actual string of that length may actually match the
- pattern. Although the value is, strictly, in characters, we treat it as
- bytes to avoid spending too much time in this optimization. */
-
- if (study != NULL && (study->flags & PCRE_STUDY_MINLEN) != 0 &&
- (pcre_uint32)(end_subject - start_match) < study->minlength)
+ if (!mb->partial)
{
- rc = MATCH_NOMATCH;
- break;
- }
-
- /* If req_char is set, we know that that character must appear in the
- subject for the match to succeed. If the first character is set, req_char
- must be later in the subject; otherwise the test starts at the match point.
- This optimization can save a huge amount of backtracking in patterns with
- nested unlimited repeats that aren't going to match. Writing separate code
- for cased/caseless versions makes it go faster, as does using an
- autoincrement and backing off on a match.
-
- HOWEVER: when the subject string is very, very long, searching to its end
- can take a long time, and give bad performance on quite ordinary patterns.
- This showed up when somebody was matching something like /^\d+C/ on a
- 32-megabyte string... so we don't do this when the string is sufficiently
- long. */
-
- if (has_req_char && end_subject - start_match < REQ_BYTE_MAX)
- {
- register PCRE_PUCHAR p = start_match + (has_first_char? 1:0);
+ /* The minimum matching length is a lower bound; no actual string of that
+ length may actually match the pattern. Although the value is, strictly,
+ in characters, we treat it as code units to avoid spending too much time
+ in this optimization. */
- /* We don't need to repeat the search if we haven't yet reached the
- place we found it at last time. */
+ if (end_subject - start_match < re->minlength)
+ {
+ rc = MATCH_NOMATCH;
+ break;
+ }
- if (p > req_char_ptr)
+ /* If req_cu is set, we know that that code unit must appear in the
+ subject for the match to succeed. If the first code unit is set, req_cu
+ must be later in the subject; otherwise the test starts at the match
+ point. This optimization can save a huge amount of backtracking in
+ patterns with nested unlimited repeats that aren't going to match.
+ Writing separate code for cased/caseless versions makes it go faster, as
+ does using an autoincrement and backing off on a match.
+
+ HOWEVER: when the subject string is very, very long, searching to its end
+ can take a long time, and give bad performance on quite ordinary
+ patterns. This showed up when somebody was matching something like
+ /^\d+C/ on a 32-megabyte string... so we don't do this when the string is
+ sufficiently long. */
+
+ if (has_req_cu && end_subject - start_match < REQ_CU_MAX)
{
- if (req_char != req_char2)
+ register PCRE2_SPTR p = start_match + (has_first_cu? 1:0);
+
+ /* We don't need to repeat the search if we haven't yet reached the
+ place we found it at last time. */
+
+ if (p > req_cu_ptr)
{
- while (p < end_subject)
+ if (req_cu != req_cu2)
{
- register pcre_uint32 pp = UCHAR21INCTEST(p);
- if (pp == req_char || pp == req_char2) { p--; break; }
+ while (p < end_subject)
+ {
+ register uint32_t pp = UCHAR21INCTEST(p);
+ if (pp == req_cu || pp == req_cu2) { p--; break; }
+ }
}
- }
- else
- {
- while (p < end_subject)
+ else
{
- if (UCHAR21INCTEST(p) == req_char) { p--; break; }
+ while (p < end_subject)
+ {
+ if (UCHAR21INCTEST(p) == req_cu) { p--; break; }
+ }
}
- }
- /* If we can't find the required character, break the matching loop,
- forcing a match failure. */
+ /* If we can't find the required code unit, break the matching loop,
+ forcing a match failure. */
- if (p >= end_subject)
- {
- rc = MATCH_NOMATCH;
- break;
- }
+ if (p >= end_subject)
+ {
+ rc = MATCH_NOMATCH;
+ break;
+ }
- /* If we have found the required character, save the point where we
- found it, so that we don't search again next time round the loop if
- the start hasn't passed this character yet. */
+ /* If we have found the required code unit, save the point where we
+ found it, so that we don't search again next time round the loop if
+ the start hasn't passed this code unit yet. */
- req_char_ptr = p;
+ req_cu_ptr = p;
+ }
}
}
}
-#ifdef PCRE_DEBUG /* Sigh. Some compilers never learn. */
- printf(">>>> Match against: ");
- pchars(start_match, end_subject - start_match, TRUE, md);
- printf("\n");
-#endif
+ /* ------------ End of start of match optimizations ------------ */
+
+ /* Give no match if we have passed the bumpalong limit. */
+
+ if (start_match > bumpalong_limit)
+ {
+ rc = MATCH_NOMATCH;
+ break;
+ }
/* OK, we can now run the match. If "hitend" is set afterwards, remember the
first starting point for which a partial match was found. */
- md->start_match_ptr = start_match;
- md->start_used_ptr = start_match;
- md->match_call_count = 0;
- md->match_function_type = 0;
- md->end_offset_top = 0;
- md->skip_arg_count = 0;
- rc = match(start_match, md->start_code, start_match, 2, md, NULL, 0);
- if (md->hitend && start_partial == NULL)
+ mb->start_match_ptr = start_match;
+ mb->start_used_ptr = start_match;
+ mb->last_used_ptr = start_match;
+ mb->match_call_count = 0;
+ mb->match_function_type = 0;
+ mb->end_offset_top = 0;
+ mb->skip_arg_count = 0;
+ rc = match(start_match, mb->start_code, start_match, 2, mb, NULL, 0);
+
+ if (mb->hitend && start_partial == NULL)
{
- start_partial = md->start_used_ptr;
+ start_partial = mb->start_used_ptr;
match_partial = start_match;
}
@@ -6951,16 +7013,16 @@ for(;;)
case MATCH_SKIP_ARG:
new_start_match = start_match;
- md->ignore_skip_arg = md->skip_arg_count;
+ mb->ignore_skip_arg = mb->skip_arg_count;
break;
/* SKIP passes back the next starting point explicitly, but if it is no
greater than the match we have just done, treat it as NOMATCH. */
case MATCH_SKIP:
- if (md->start_match_ptr > start_match)
+ if (mb->start_match_ptr > start_match)
{
- new_start_match = md->start_match_ptr;
+ new_start_match = mb->start_match_ptr;
break;
}
/* Fall through */
@@ -6971,9 +7033,9 @@ for(;;)
case MATCH_NOMATCH:
case MATCH_PRUNE:
case MATCH_THEN:
- md->ignore_skip_arg = 0;
+ mb->ignore_skip_arg = 0;
new_start_match = start_match + 1;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
ACROSSCHAR(new_start_match < end_subject, *new_start_match,
new_start_match++);
@@ -6997,7 +7059,7 @@ for(;;)
rc = MATCH_NOMATCH;
- /* If PCRE_FIRSTLINE is set, the match must happen before or at the first
+ /* If PCRE2_FIRSTLINE is set, the match must happen before or at the first
newline in the subject (though it may continue over the newline). Therefore,
if we have just failed to match, starting at a newline, do not continue. */
@@ -7014,160 +7076,168 @@ for(;;)
/* If we have just passed a CR and we are now at a LF, and the pattern does
not contain any explicit matches for \r or \n, and the newline option is CRLF
- or ANY or ANYCRLF, advance the match position by one more character. In
+ or ANY or ANYCRLF, advance the match position by one more code unit. In
normal matching start_match will aways be greater than the first position at
this stage, but a failed *SKIP can cause a return at the same point, which is
why the first test exists. */
- if (start_match > (PCRE_PUCHAR)subject + start_offset &&
+ if (start_match > subject + start_offset &&
start_match[-1] == CHAR_CR &&
start_match < end_subject &&
*start_match == CHAR_NL &&
- (re->flags & PCRE_HASCRORLF) == 0 &&
- (md->nltype == NLTYPE_ANY ||
- md->nltype == NLTYPE_ANYCRLF ||
- md->nllen == 2))
+ (re->flags & PCRE2_HASCRORLF) == 0 &&
+ (mb->nltype == NLTYPE_ANY ||
+ mb->nltype == NLTYPE_ANYCRLF ||
+ mb->nllen == 2))
start_match++;
- md->mark = NULL; /* Reset for start of next match attempt */
+ mb->mark = NULL; /* Reset for start of next match attempt */
} /* End of for(;;) "bumpalong" loop */
/* ==========================================================================*/
-/* We reach here when rc is not MATCH_NOMATCH, or if one of the stopping
-conditions is true:
+/* When we reach here, one of the stopping conditions is true:
-(1) The pattern is anchored or the match was failed by (*COMMIT);
+(1) The match succeeded, either completely, or partially;
-(2) We are past the end of the subject;
+(2) The pattern is anchored or the match was failed by (*COMMIT);
-(3) PCRE_FIRSTLINE is set and we have failed to match at a newline, because
+(3) We are past the end of the subject or the bumpalong limit;
+
+(4) PCRE2_FIRSTLINE is set and we have failed to match at a newline, because
this option requests that a match occur at or before the first newline in
the subject.
-When we have a match and the offset vector is big enough to deal with any
-backreferences, captured substring offsets will already be set up. In the case
-where we had to get some local store to hold offsets for backreference
-processing, copy those that we can. In this case there need not be overflow if
-certain parts of the pattern were not used, even though there are more
-capturing parentheses than vector slots. */
+(5) Some kind of error occurred.
+
+*/
ENDLOOP:
+#ifdef HEAP_MATCH_RECURSE
+release_match_heapframes(&frame_zero, mb);
+#endif
+
+/* Release any frames that were saved from recursions. */
+
+while (mb->ovecsave_chain != NULL)
+ {
+ ovecsave_frame *this = mb->ovecsave_chain;
+ mb->ovecsave_chain = this->next;
+ mb->memctl.free(this, mb->memctl.memory_data);
+ }
+
+/* Fill in fields that are always returned in the match data. */
+
+match_data->code = re;
+match_data->subject = subject;
+match_data->mark = mb->mark;
+match_data->matchedby = PCRE2_MATCHEDBY_INTERPRETER;
+
+/* Handle a fully successful match. */
+
if (rc == MATCH_MATCH || rc == MATCH_ACCEPT)
{
+ uint32_t arg_offset_max = 2 * match_data->oveccount;
+
+ /* When the offset vector is big enough to deal with any backreferences,
+ captured substring offsets will already be set up. In the case where we had
+ to get some local memory to hold offsets for backreference processing, copy
+ those that we can. In this case there need not be overflow if certain parts
+ of the pattern were not used, even though there are more capturing
+ parentheses than vector slots. */
+
if (using_temporary_offsets)
{
if (arg_offset_max >= 4)
{
- memcpy(offsets + 2, md->offset_vector + 2,
- (arg_offset_max - 2) * sizeof(int));
- DPRINTF(("Copied offsets from temporary memory\n"));
+ memcpy(match_data->ovector + 2, mb->ovector + 2,
+ (arg_offset_max - 2) * sizeof(PCRE2_SIZE));
}
- if (md->end_offset_top > arg_offset_max) md->capture_last |= OVFLBIT;
- DPRINTF(("Freeing temporary memory\n"));
- (PUBL(free))(md->offset_vector);
+ if (mb->end_offset_top > arg_offset_max) mb->capture_last |= OVFLBIT;
+ mb->memctl.free(mb->ovector, mb->memctl.memory_data);
}
/* Set the return code to the number of captured strings, or 0 if there were
- too many to fit into the vector. */
-
- rc = ((md->capture_last & OVFLBIT) != 0 &&
- md->end_offset_top >= arg_offset_max)?
- 0 : md->end_offset_top/2;
-
- /* If there is space in the offset vector, set any unused pairs at the end of
- the pattern to -1 for backwards compatibility. It is documented that this
- happens. In earlier versions, the whole set of potential capturing offsets
- was set to -1 each time round the loop, but this is handled differently now.
- "Gaps" are set to -1 dynamically instead (this fixes a bug). Thus, it is only
- those at the end that need unsetting here. We can't just unset them all at
- the start of the whole thing because they may get set in one branch that is
- not the final matching branch. */
-
- if (md->end_offset_top/2 <= re->top_bracket && offsets != NULL)
+ too many to fit into the ovector. */
+
+ match_data->rc = ((mb->capture_last & OVFLBIT) != 0)?
+ 0 : mb->end_offset_top/2;
+
+ /* If there is space in the offset vector, set any pairs that follow the
+ highest-numbered captured string but are less than the number of capturing
+ groups in the pattern (and are within the ovector) to PCRE2_UNSET. It is
+ documented that this happens. In earlier versions, the whole set of potential
+ capturing offsets was initialized each time round the loop, but this is
+ handled differently now. "Gaps" are set to PCRE2_UNSET dynamically instead
+ (this fixed a bug). Thus, it is only those at the end that need setting here.
+ We can't just mark them all unset at the start of the whole thing because
+ they may get set in one branch that is not the final matching branch. */
+
+ if (mb->end_offset_top/2 <= re->top_bracket)
{
- register int *iptr, *iend;
- int resetcount = 2 + re->top_bracket * 2;
- if (resetcount > offsetcount) resetcount = offsetcount;
- iptr = offsets + md->end_offset_top;
- iend = offsets + resetcount;
- while (iptr < iend) *iptr++ = -1;
+ register PCRE2_SIZE *iptr, *iend;
+ int resetcount = re->top_bracket + 1;
+ if (resetcount > match_data->oveccount) resetcount = match_data->oveccount;
+ iptr = match_data->ovector + mb->end_offset_top;
+ iend = match_data->ovector + 2 * resetcount;
+ while (iptr < iend) *iptr++ = PCRE2_UNSET;
}
/* If there is space, set up the whole thing as substring 0. The value of
- md->start_match_ptr might be modified if \K was encountered on the success
+ mb->start_match_ptr might be modified if \K was encountered on the success
matching path. */
- if (offsetcount < 2) rc = 0; else
+ if (match_data->oveccount < 1) rc = 0; else
{
- offsets[0] = (int)(md->start_match_ptr - md->start_subject);
- offsets[1] = (int)(md->end_match_ptr - md->start_subject);
+ match_data->ovector[0] = mb->start_match_ptr - mb->start_subject;
+ match_data->ovector[1] = mb->end_match_ptr - mb->start_subject;
}
- /* Return MARK data if requested */
+ /* Set the remaining returned values */
- if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_MARK) != 0)
- *(extra_data->mark) = (pcre_uchar *)md->mark;
- DPRINTF((">>>> returning %d\n", rc));
-#ifdef NO_RECURSE
- release_match_heapframes(&frame_zero);
-#endif
- return rc;
+ match_data->startchar = start_match - subject;
+ match_data->leftchar = mb->start_used_ptr - subject;
+ match_data->rightchar = ((mb->last_used_ptr > mb->end_match_ptr)?
+ mb->last_used_ptr : mb->end_match_ptr) - subject;
+ return match_data->rc;
}
-/* Control gets here if there has been an error, or if the overall match
-attempt has failed at all permitted starting positions. */
+/* Control gets here if there has been a partial match, an error, or if the
+overall match attempt has failed at all permitted starting positions. Any mark
+data is in the nomatch_mark field. */
-if (using_temporary_offsets)
- {
- DPRINTF(("Freeing temporary memory\n"));
- (PUBL(free))(md->offset_vector);
- }
+match_data->mark = mb->nomatch_mark;
/* For anything other than nomatch or partial match, just return the code. */
-if (rc != MATCH_NOMATCH && rc != PCRE_ERROR_PARTIAL)
- {
- DPRINTF((">>>> error: returning %d\n", rc));
-#ifdef NO_RECURSE
- release_match_heapframes(&frame_zero);
-#endif
- return rc;
- }
+if (rc != MATCH_NOMATCH && rc != PCRE2_ERROR_PARTIAL)
+ match_data->rc = rc;
-/* Handle partial matches - disable any mark data */
+/* Else handle a partial match. */
-if (match_partial != NULL)
+else if (match_partial != NULL)
{
- DPRINTF((">>>> returning PCRE_ERROR_PARTIAL\n"));
- md->mark = NULL;
- if (offsetcount > 1)
+ if (match_data->oveccount > 0)
{
- offsets[0] = (int)(start_partial - (PCRE_PUCHAR)subject);
- offsets[1] = (int)(end_subject - (PCRE_PUCHAR)subject);
- if (offsetcount > 2)
- offsets[2] = (int)(match_partial - (PCRE_PUCHAR)subject);
+ match_data->ovector[0] = match_partial - subject;
+ match_data->ovector[1] = end_subject - subject;
}
- rc = PCRE_ERROR_PARTIAL;
+ match_data->startchar = match_partial - subject;
+ match_data->leftchar = start_partial - subject;
+ match_data->rightchar = end_subject - subject;
+ match_data->rc = PCRE2_ERROR_PARTIAL;
}
-/* This is the classic nomatch case */
+/* Else this is the classic nomatch case. */
-else
- {
- DPRINTF((">>>> returning PCRE_ERROR_NOMATCH\n"));
- rc = PCRE_ERROR_NOMATCH;
- }
+else match_data->rc = PCRE2_ERROR_NOMATCH;
-/* Return the MARK data if it has been requested. */
+/* Free any temporary offsets. */
-if (extra_data != NULL && (extra_data->flags & PCRE_EXTRA_MARK) != 0)
- *(extra_data->mark) = (pcre_uchar *)md->nomatch_mark;
-#ifdef NO_RECURSE
- release_match_heapframes(&frame_zero);
-#endif
-return rc;
+if (using_temporary_offsets)
+ mb->memctl.free(mb->ovector, mb->memctl.memory_data);
+return match_data->rc;
}
-/* End of pcre_exec.c */
+/* End of pcre2_match.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_match_data.c b/src/3rdparty/pcre2/src/pcre2_match_data.c
new file mode 100644
index 0000000000..85ac998348
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_match_data.c
@@ -0,0 +1,147 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+* Create a match data block given ovector size *
+*************************************************/
+
+/* A minimum of 1 is imposed on the number of ovector triplets. */
+
+PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION
+pcre2_match_data_create(uint32_t oveccount, pcre2_general_context *gcontext)
+{
+pcre2_match_data *yield;
+if (oveccount < 1) oveccount = 1;
+yield = PRIV(memctl_malloc)(
+ sizeof(pcre2_match_data) + 3*oveccount*sizeof(PCRE2_SIZE),
+ (pcre2_memctl *)gcontext);
+if (yield == NULL) return NULL;
+yield->oveccount = oveccount;
+return yield;
+}
+
+
+
+/*************************************************
+* Create a match data block using pattern data *
+*************************************************/
+
+/* If no context is supplied, use the memory allocator from the code. */
+
+PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION
+pcre2_match_data_create_from_pattern(const pcre2_code *code,
+ pcre2_general_context *gcontext)
+{
+if (gcontext == NULL) gcontext = (pcre2_general_context *)code;
+return pcre2_match_data_create(((pcre2_real_code *)code)->top_bracket + 1,
+ gcontext);
+}
+
+
+
+/*************************************************
+* Free a match data block *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_match_data_free(pcre2_match_data *match_data)
+{
+if (match_data != NULL)
+ match_data->memctl.free(match_data, match_data->memctl.memory_data);
+}
+
+
+
+/*************************************************
+* Get last mark in match *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SPTR PCRE2_CALL_CONVENTION
+pcre2_get_mark(pcre2_match_data *match_data)
+{
+return match_data->mark;
+}
+
+
+
+/*************************************************
+* Get pointer to ovector *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SIZE * PCRE2_CALL_CONVENTION
+pcre2_get_ovector_pointer(pcre2_match_data *match_data)
+{
+return match_data->ovector;
+}
+
+
+
+/*************************************************
+* Get number of ovector slots *
+*************************************************/
+
+PCRE2_EXP_DEFN uint32_t PCRE2_CALL_CONVENTION
+pcre2_get_ovector_count(pcre2_match_data *match_data)
+{
+return match_data->oveccount;
+}
+
+
+
+/*************************************************
+* Get starting code unit in match *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SIZE PCRE2_CALL_CONVENTION
+pcre2_get_startchar(pcre2_match_data *match_data)
+{
+return match_data->startchar;
+}
+
+/* End of pcre2_match_data.c */
diff --git a/src/3rdparty/pcre/pcre_newline.c b/src/3rdparty/pcre2/src/pcre2_newline.c
index b8f5a4de19..6e9366db93 100644
--- a/src/3rdparty/pcre/pcre_newline.c
+++ b/src/3rdparty/pcre2/src/pcre2_newline.c
@@ -6,7 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -41,7 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
/* This module contains internal functions for testing newlines when more than
one kind of newline is to be recognized. When a newline is found, its length is
returned. In principle, we could implement several newline "types", each
-referring to a different set of newline characters. At present, PCRE supports
+referring to a different set of newline characters. At present, PCRE2 supports
only NLTYPE_FIXED, which gets handled without these functions, NLTYPE_ANYCRLF,
and NLTYPE_ANY. The full list of Unicode newline characters is taken from
http://unicode.org/unicode/reports/tr18/. */
@@ -51,7 +52,7 @@ http://unicode.org/unicode/reports/tr18/. */
#include "config.h"
#endif
-#include "pcre_internal.h"
+#include "pcre2_internal.h"
@@ -59,8 +60,10 @@ http://unicode.org/unicode/reports/tr18/. */
* Check for newline at given position *
*************************************************/
-/* It is guaranteed that the initial value of ptr is less than the end of the
-string that is being processed.
+/* This function is called only via the IS_NEWLINE macro, which does so only
+when the newline type is NLTYPE_ANY or NLTYPE_ANYCRLF. The case of a fixed
+newline (NLTYPE_FIXED) is handled inline. It is guaranteed that the code unit
+pointed to by ptr is less than the end of the string.
Arguments:
ptr pointer to possible newline
@@ -73,28 +76,30 @@ Returns: TRUE or FALSE
*/
BOOL
-PRIV(is_newline)(PCRE_PUCHAR ptr, int type, PCRE_PUCHAR endptr, int *lenptr,
- BOOL utf)
+PRIV(is_newline)(PCRE2_SPTR ptr, uint32_t type, PCRE2_SPTR endptr,
+ uint32_t *lenptr, BOOL utf)
{
-pcre_uint32 c;
-(void)utf;
-#ifdef SUPPORT_UTF
-if (utf)
- {
- GETCHAR(c, ptr);
- }
-else
-#endif /* SUPPORT_UTF */
- c = *ptr;
+uint32_t c;
-/* Note that this function is called only for ANY or ANYCRLF. */
+#ifdef SUPPORT_UNICODE
+if (utf) { GETCHAR(c, ptr); } else c = *ptr;
+#else
+(void)utf;
+c = *ptr;
+#endif /* SUPPORT_UNICODE */
if (type == NLTYPE_ANYCRLF) switch(c)
{
- case CHAR_LF: *lenptr = 1; return TRUE;
- case CHAR_CR: *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1;
- return TRUE;
- default: return FALSE;
+ case CHAR_LF:
+ *lenptr = 1;
+ return TRUE;
+
+ case CHAR_CR:
+ *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1;
+ return TRUE;
+
+ default:
+ return FALSE;
}
/* NLTYPE_ANY */
@@ -106,25 +111,36 @@ else switch(c)
#endif
case CHAR_LF:
case CHAR_VT:
- case CHAR_FF: *lenptr = 1; return TRUE;
+ case CHAR_FF:
+ *lenptr = 1;
+ return TRUE;
case CHAR_CR:
*lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1;
return TRUE;
#ifndef EBCDIC
-#ifdef COMPILE_PCRE8
- case CHAR_NEL: *lenptr = utf? 2 : 1; return TRUE;
- case 0x2028: /* LS */
- case 0x2029: *lenptr = 3; return TRUE; /* PS */
-#else /* COMPILE_PCRE16 || COMPILE_PCRE32 */
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ case CHAR_NEL:
+ *lenptr = utf? 2 : 1;
+ return TRUE;
+
+ case 0x2028: /* LS */
+ case 0x2029: /* PS */
+ *lenptr = 3;
+ return TRUE;
+
+#else /* 16-bit or 32-bit code units */
case CHAR_NEL:
- case 0x2028: /* LS */
- case 0x2029: *lenptr = 1; return TRUE; /* PS */
-#endif /* COMPILE_PCRE8 */
-#endif /* Not EBCDIC */
+ case 0x2028: /* LS */
+ case 0x2029: /* PS */
+ *lenptr = 1;
+ return TRUE;
+#endif
+#endif /* Not EBCDIC */
- default: return FALSE;
+ default:
+ return FALSE;
}
}
@@ -134,8 +150,10 @@ else switch(c)
* Check for newline at previous position *
*************************************************/
-/* It is guaranteed that the initial value of ptr is greater than the start of
-the string that is being processed.
+/* This function is called only via the WAS_NEWLINE macro, which does so only
+when the newline type is NLTYPE_ANY or NLTYPE_ANYCRLF. The case of a fixed
+newline (NLTYPE_FIXED) is handled inline. It is guaranteed that the initial
+value of ptr is greater than the start of the string that is being processed.
Arguments:
ptr pointer to possible newline
@@ -148,23 +166,23 @@ Returns: TRUE or FALSE
*/
BOOL
-PRIV(was_newline)(PCRE_PUCHAR ptr, int type, PCRE_PUCHAR startptr, int *lenptr,
- BOOL utf)
+PRIV(was_newline)(PCRE2_SPTR ptr, uint32_t type, PCRE2_SPTR startptr,
+ uint32_t *lenptr, BOOL utf)
{
-pcre_uint32 c;
-(void)utf;
+uint32_t c;
ptr--;
-#ifdef SUPPORT_UTF
+
+#ifdef SUPPORT_UNICODE
if (utf)
{
BACKCHAR(ptr);
GETCHAR(c, ptr);
}
-else
-#endif /* SUPPORT_UTF */
- c = *ptr;
-
-/* Note that this function is called only for ANY or ANYCRLF. */
+else c = *ptr;
+#else
+(void)utf;
+c = *ptr;
+#endif /* SUPPORT_UNICODE */
if (type == NLTYPE_ANYCRLF) switch(c)
{
@@ -172,8 +190,12 @@ if (type == NLTYPE_ANYCRLF) switch(c)
*lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1;
return TRUE;
- case CHAR_CR: *lenptr = 1; return TRUE;
- default: return FALSE;
+ case CHAR_CR:
+ *lenptr = 1;
+ return TRUE;
+
+ default:
+ return FALSE;
}
/* NLTYPE_ANY */
@@ -189,22 +211,33 @@ else switch(c)
#endif
case CHAR_VT:
case CHAR_FF:
- case CHAR_CR: *lenptr = 1; return TRUE;
+ case CHAR_CR:
+ *lenptr = 1;
+ return TRUE;
#ifndef EBCDIC
-#ifdef COMPILE_PCRE8
- case CHAR_NEL: *lenptr = utf? 2 : 1; return TRUE;
- case 0x2028: /* LS */
- case 0x2029: *lenptr = 3; return TRUE; /* PS */
-#else /* COMPILE_PCRE16 || COMPILE_PCRE32 */
+#if PCRE2_CODE_UNIT_WIDTH == 8
case CHAR_NEL:
- case 0x2028: /* LS */
- case 0x2029: *lenptr = 1; return TRUE; /* PS */
-#endif /* COMPILE_PCRE8 */
-#endif /* NotEBCDIC */
+ *lenptr = utf? 2 : 1;
+ return TRUE;
+
+ case 0x2028: /* LS */
+ case 0x2029: /* PS */
+ *lenptr = 3;
+ return TRUE;
+
+#else /* 16-bit or 32-bit code units */
+ case CHAR_NEL:
+ case 0x2028: /* LS */
+ case 0x2029: /* PS */
+ *lenptr = 1;
+ return TRUE;
+#endif
+#endif /* Not EBCDIC */
- default: return FALSE;
+ default:
+ return FALSE;
}
}
-/* End of pcre_newline.c */
+/* End of pcre2_newline.c */
diff --git a/src/3rdparty/pcre/pcre_ord2utf8.c b/src/3rdparty/pcre2/src/pcre2_ord2utf.c
index 95f1beb963..75252b763a 100644
--- a/src/3rdparty/pcre/pcre_ord2utf8.c
+++ b/src/3rdparty/pcre2/src/pcre2_ord2utf.c
@@ -6,7 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -38,39 +39,51 @@ POSSIBILITY OF SUCH DAMAGE.
*/
-/* This file contains a private PCRE function that converts an ordinal
-character value into a UTF8 string. */
+/* This file contains a function that converts a Unicode character code point
+into a UTF string. The behaviour is different for each code unit width. */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#define COMPILE_PCRE8
+#include "pcre2_internal.h"
+
+
+/* If SUPPORT_UNICODE is not defined, this function will never be called.
+Supply a dummy function because some compilers do not like empty source
+modules. */
+
+#ifndef SUPPORT_UNICODE
+unsigned int
+PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer)
+{
+(void)(cvalue);
+(void)(buffer);
+return 0;
+}
+#else /* SUPPORT_UNICODE */
-#include "pcre_internal.h"
/*************************************************
-* Convert character value to UTF-8 *
+* Convert code point to UTF *
*************************************************/
-/* This function takes an integer value in the range 0 - 0x10ffff
-and encodes it as a UTF-8 character in 1 to 4 pcre_uchars.
-
+/*
Arguments:
cvalue the character value
- buffer pointer to buffer for result - at least 6 pcre_uchars long
+ buffer pointer to buffer for result
-Returns: number of characters placed in the buffer
+Returns: number of code units placed in the buffer
*/
-unsigned
-int
-PRIV(ord2utf)(pcre_uint32 cvalue, pcre_uchar *buffer)
+unsigned int
+PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer)
{
-#ifdef SUPPORT_UTF
+/* Convert to UTF-8 */
+#if PCRE2_CODE_UNIT_WIDTH == 8
register int i, j;
-
for (i = 0; i < PRIV(utf8_table1_size); i++)
if ((int)cvalue <= PRIV(utf8_table1)[i]) break;
buffer += i;
@@ -82,13 +95,26 @@ for (j = i; j > 0; j--)
*buffer = PRIV(utf8_table2)[i] | cvalue;
return i + 1;
-#else
+/* Convert to UTF-16 */
-(void)(cvalue); /* Keep compiler happy; this function won't ever be */
-(void)(buffer); /* called when SUPPORT_UTF is not defined. */
-return 0;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (cvalue <= 0xffff)
+ {
+ *buffer = (PCRE2_UCHAR)cvalue;
+ return 1;
+ }
+cvalue -= 0x10000;
+*buffer++ = 0xd800 | (cvalue >> 10);
+*buffer = 0xdc00 | (cvalue & 0x3ff);
+return 2;
+
+/* Convert to UTF-32 */
+#else
+*buffer = (PCRE2_UCHAR)cvalue;
+return 1;
#endif
}
+#endif /* SUPPORT_UNICODE */
-/* End of pcre_ord2utf8.c */
+/* End of pcre_ord2utf.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_pattern_info.c b/src/3rdparty/pcre2/src/pcre2_pattern_info.c
new file mode 100644
index 0000000000..5b32a905b0
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_pattern_info.c
@@ -0,0 +1,410 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+* Return info about compiled pattern *
+*************************************************/
+
+/*
+Arguments:
+ code points to compiled code
+ what what information is required
+ where where to put the information; if NULL, return length
+
+Returns: 0 when data returned
+ > 0 when length requested
+ < 0 on error or unset value
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_pattern_info(const pcre2_code *code, uint32_t what, void *where)
+{
+const pcre2_real_code *re = (pcre2_real_code *)code;
+
+if (where == NULL) /* Requests field length */
+ {
+ switch(what)
+ {
+ case PCRE2_INFO_ALLOPTIONS:
+ case PCRE2_INFO_ARGOPTIONS:
+ case PCRE2_INFO_BACKREFMAX:
+ case PCRE2_INFO_BSR:
+ case PCRE2_INFO_CAPTURECOUNT:
+ case PCRE2_INFO_FIRSTCODETYPE:
+ case PCRE2_INFO_FIRSTCODEUNIT:
+ case PCRE2_INFO_HASBACKSLASHC:
+ case PCRE2_INFO_HASCRORLF:
+ case PCRE2_INFO_JCHANGED:
+ case PCRE2_INFO_LASTCODETYPE:
+ case PCRE2_INFO_LASTCODEUNIT:
+ case PCRE2_INFO_MATCHEMPTY:
+ case PCRE2_INFO_MATCHLIMIT:
+ case PCRE2_INFO_MAXLOOKBEHIND:
+ case PCRE2_INFO_MINLENGTH:
+ case PCRE2_INFO_NAMEENTRYSIZE:
+ case PCRE2_INFO_NAMECOUNT:
+ case PCRE2_INFO_NEWLINE:
+ case PCRE2_INFO_RECURSIONLIMIT:
+ return sizeof(uint32_t);
+
+ case PCRE2_INFO_FIRSTBITMAP:
+ return sizeof(const uint8_t *);
+
+ case PCRE2_INFO_JITSIZE:
+ case PCRE2_INFO_SIZE:
+ return sizeof(size_t);
+
+ case PCRE2_INFO_NAMETABLE:
+ return sizeof(PCRE2_SPTR);
+ }
+ }
+
+if (re == NULL) return PCRE2_ERROR_NULL;
+
+/* Check that the first field in the block is the magic number. If it is not,
+return with PCRE2_ERROR_BADMAGIC. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check that this pattern was compiled in the correct bit mode */
+
+if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE;
+
+switch(what)
+ {
+ case PCRE2_INFO_ALLOPTIONS:
+ *((uint32_t *)where) = re->overall_options;
+ break;
+
+ case PCRE2_INFO_ARGOPTIONS:
+ *((uint32_t *)where) = re->compile_options;
+ break;
+
+ case PCRE2_INFO_BACKREFMAX:
+ *((uint32_t *)where) = re->top_backref;
+ break;
+
+ case PCRE2_INFO_BSR:
+ *((uint32_t *)where) = re->bsr_convention;
+ break;
+
+ case PCRE2_INFO_CAPTURECOUNT:
+ *((uint32_t *)where) = re->top_bracket;
+ break;
+
+ case PCRE2_INFO_FIRSTCODETYPE:
+ *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)? 1 :
+ ((re->flags & PCRE2_STARTLINE) != 0)? 2 : 0;
+ break;
+
+ case PCRE2_INFO_FIRSTCODEUNIT:
+ *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)?
+ re->first_codeunit : 0;
+ break;
+
+ case PCRE2_INFO_FIRSTBITMAP:
+ *((const uint8_t **)where) = ((re->flags & PCRE2_FIRSTMAPSET) != 0)?
+ &(re->start_bitmap[0]) : NULL;
+ break;
+
+ case PCRE2_INFO_HASBACKSLASHC:
+ *((uint32_t *)where) = (re->flags & PCRE2_HASBKC) != 0;
+ break;
+
+ case PCRE2_INFO_HASCRORLF:
+ *((uint32_t *)where) = (re->flags & PCRE2_HASCRORLF) != 0;
+ break;
+
+ case PCRE2_INFO_JCHANGED:
+ *((uint32_t *)where) = (re->flags & PCRE2_JCHANGED) != 0;
+ break;
+
+ case PCRE2_INFO_JITSIZE:
+#ifdef SUPPORT_JIT
+ *((size_t *)where) = (re->executable_jit != NULL)?
+ PRIV(jit_get_size)(re->executable_jit) : 0;
+#else
+ *((size_t *)where) = 0;
+#endif
+ break;
+
+ case PCRE2_INFO_LASTCODETYPE:
+ *((uint32_t *)where) = ((re->flags & PCRE2_LASTSET) != 0)? 1 : 0;
+ break;
+
+ case PCRE2_INFO_LASTCODEUNIT:
+ *((uint32_t *)where) = ((re->flags & PCRE2_LASTSET) != 0)?
+ re->last_codeunit : 0;
+ break;
+
+ case PCRE2_INFO_MATCHEMPTY:
+ *((uint32_t *)where) = (re->flags & PCRE2_MATCH_EMPTY) != 0;
+ break;
+
+ case PCRE2_INFO_MATCHLIMIT:
+ *((uint32_t *)where) = re->limit_match;
+ if (re->limit_match == UINT32_MAX) return PCRE2_ERROR_UNSET;
+ break;
+
+ case PCRE2_INFO_MAXLOOKBEHIND:
+ *((uint32_t *)where) = re->max_lookbehind;
+ break;
+
+ case PCRE2_INFO_MINLENGTH:
+ *((uint32_t *)where) = re->minlength;
+ break;
+
+ case PCRE2_INFO_NAMEENTRYSIZE:
+ *((uint32_t *)where) = re->name_entry_size;
+ break;
+
+ case PCRE2_INFO_NAMECOUNT:
+ *((uint32_t *)where) = re->name_count;
+ break;
+
+ case PCRE2_INFO_NAMETABLE:
+ *((PCRE2_SPTR *)where) = (PCRE2_SPTR)((char *)re + sizeof(pcre2_real_code));
+ break;
+
+ case PCRE2_INFO_NEWLINE:
+ *((uint32_t *)where) = re->newline_convention;
+ break;
+
+ case PCRE2_INFO_RECURSIONLIMIT:
+ *((uint32_t *)where) = re->limit_recursion;
+ if (re->limit_recursion == UINT32_MAX) return PCRE2_ERROR_UNSET;
+ break;
+
+ case PCRE2_INFO_SIZE:
+ *((size_t *)where) = re->blocksize;
+ break;
+
+ default: return PCRE2_ERROR_BADOPTION;
+ }
+
+return 0;
+}
+
+
+
+/*************************************************
+* Callout enumerator *
+*************************************************/
+
+/*
+Arguments:
+ code points to compiled code
+ callback function called for each callout block
+ callout_data user data passed to the callback
+
+Returns: 0 when successfully completed
+ < 0 on local error
+ != 0 for callback error
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_callout_enumerate(const pcre2_code *code,
+ int (*callback)(pcre2_callout_enumerate_block *, void *), void *callout_data)
+{
+pcre2_real_code *re = (pcre2_real_code *)code;
+pcre2_callout_enumerate_block cb;
+PCRE2_SPTR cc;
+#ifdef SUPPORT_UNICODE
+BOOL utf = (re->overall_options & PCRE2_UTF) != 0;
+#endif
+
+if (re == NULL) return PCRE2_ERROR_NULL;
+
+/* Check that the first field in the block is the magic number. If it is not,
+return with PCRE2_ERROR_BADMAGIC. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check that this pattern was compiled in the correct bit mode */
+
+if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE;
+
+cb.version = 0;
+cc = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code))
+ + re->name_count * re->name_entry_size;
+
+while (TRUE)
+ {
+ int rc;
+ switch (*cc)
+ {
+ case OP_END:
+ return 0;
+
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_EXACT:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+ case OP_POSQUERY:
+ case OP_POSUPTO:
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_EXACTI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+ case OP_POSQUERYI:
+ case OP_POSUPTOI:
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTEXACT:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSUPTO:
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTEXACTI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSUPTOI:
+ cc += PRIV(OP_lengths)[*cc];
+#ifdef SUPPORT_UNICODE
+ if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ case OP_TYPEPOSUPTO:
+ cc += PRIV(OP_lengths)[*cc];
+#ifdef SUPPORT_UNICODE
+ if (cc[-1] == OP_PROP || cc[-1] == OP_NOTPROP) cc += 2;
+#endif
+ break;
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ case OP_XCLASS:
+ cc += GET(cc, 1);
+ break;
+#endif
+
+ case OP_MARK:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ cc += PRIV(OP_lengths)[*cc] + cc[1];
+ break;
+
+ case OP_CALLOUT:
+ cb.pattern_position = GET(cc, 1);
+ cb.next_item_length = GET(cc, 1 + LINK_SIZE);
+ cb.callout_number = cc[1 + 2*LINK_SIZE];
+ cb.callout_string_offset = 0;
+ cb.callout_string_length = 0;
+ cb.callout_string = NULL;
+ rc = callback(&cb, callout_data);
+ if (rc != 0) return rc;
+ cc += PRIV(OP_lengths)[*cc];
+ break;
+
+ case OP_CALLOUT_STR:
+ cb.pattern_position = GET(cc, 1);
+ cb.next_item_length = GET(cc, 1 + LINK_SIZE);
+ cb.callout_number = 0;
+ cb.callout_string_offset = GET(cc, 1 + 3*LINK_SIZE);
+ cb.callout_string_length =
+ GET(cc, 1 + 2*LINK_SIZE) - (1 + 4*LINK_SIZE) - 2;
+ cb.callout_string = cc + (1 + 4*LINK_SIZE) + 1;
+ rc = callback(&cb, callout_data);
+ if (rc != 0) return rc;
+ cc += GET(cc, 1 + 2*LINK_SIZE);
+ break;
+
+ default:
+ cc += PRIV(OP_lengths)[*cc];
+ break;
+ }
+ }
+}
+
+/* End of pcre2_pattern_info.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_printint.c b/src/3rdparty/pcre2/src/pcre2_printint.c
new file mode 100644
index 0000000000..2d30926a74
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_printint.c
@@ -0,0 +1,832 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains a PCRE private debugging function for printing out the
+internal form of a compiled regular expression, along with some supporting
+local functions. This source file is #included in pcre2test.c at each supported
+code unit width, with PCRE2_SUFFIX set appropriately, just like the functions
+that comprise the library. It can also optionally be included in
+pcre2_compile.c for detailed debugging in error situations. */
+
+
+/* Tables of operator names. The same 8-bit table is used for all code unit
+widths, so it must be defined only once. The list itself is defined in
+pcre2_internal.h, which is #included by pcre2test before this file. */
+
+#ifndef OP_LISTS_DEFINED
+static const char *OP_names[] = { OP_NAME_LIST };
+#define OP_LISTS_DEFINED
+#endif
+
+/* The functions and tables herein must all have mode-dependent names. */
+
+#define OP_lengths PCRE2_SUFFIX(OP_lengths_)
+#define get_ucpname PCRE2_SUFFIX(get_ucpname_)
+#define pcre2_printint PCRE2_SUFFIX(pcre2_printint_)
+#define print_char PCRE2_SUFFIX(print_char_)
+#define print_custring PCRE2_SUFFIX(print_custring_)
+#define print_custring_bylen PCRE2_SUFFIX(print_custring_bylen_)
+#define print_prop PCRE2_SUFFIX(print_prop_)
+
+/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
+the definition is next to the definition of the opcodes in pcre2_internal.h.
+The contents of the table are, however, mode-dependent. */
+
+static const uint8_t OP_lengths[] = { OP_LENGTHS };
+
+
+
+/*************************************************
+* Print one character from a string *
+*************************************************/
+
+/* In UTF mode the character may occupy more than one code unit.
+
+Arguments:
+ f file to write to
+ ptr pointer to first code unit of the character
+ utf TRUE if string is UTF (will be FALSE if UTF is not supported)
+
+Returns: number of additional code units used
+*/
+
+static unsigned int
+print_char(FILE *f, PCRE2_SPTR ptr, BOOL utf)
+{
+uint32_t c = *ptr;
+BOOL one_code_unit = !utf;
+
+/* If UTF is supported and requested, check for a valid single code unit. */
+
+#ifdef SUPPORT_UNICODE
+if (utf)
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ one_code_unit = c < 0x80;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ one_code_unit = (c & 0xfc00) != 0xd800;
+#else
+ one_code_unit = (c & 0xfffff800u) != 0xd800u;
+#endif /* CODE_UNIT_WIDTH */
+ }
+#endif /* SUPPORT_UNICODE */
+
+/* Handle a valid one-code-unit character at any width. */
+
+if (one_code_unit)
+ {
+ if (PRINTABLE(c)) fprintf(f, "%c", (char)c);
+ else if (c < 0x80) fprintf(f, "\\x%02x", c);
+ else fprintf(f, "\\x{%02x}", c);
+ return 0;
+ }
+
+/* Code for invalid UTF code units and multi-unit UTF characters is different
+for each width. If UTF is not supported, control should never get here, but we
+need a return statement to keep the compiler happy. */
+
+#ifndef SUPPORT_UNICODE
+return 0;
+#else
+
+/* Malformed UTF-8 should occur only if the sanity check has been turned off.
+Rather than swallow random bytes, just stop if we hit a bad one. Print it with
+\X instead of \x as an indication. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if ((c & 0xc0) != 0xc0)
+ {
+ fprintf(f, "\\X{%x}", c); /* Invalid starting byte */
+ return 0;
+ }
+else
+ {
+ int i;
+ int a = PRIV(utf8_table4)[c & 0x3f]; /* Number of additional bytes */
+ int s = 6*a;
+ c = (c & PRIV(utf8_table3)[a]) << s;
+ for (i = 1; i <= a; i++)
+ {
+ if ((ptr[i] & 0xc0) != 0x80)
+ {
+ fprintf(f, "\\X{%x}", c); /* Invalid secondary byte */
+ return i - 1;
+ }
+ s -= 6;
+ c |= (ptr[i] & 0x3f) << s;
+ }
+ fprintf(f, "\\x{%x}", c);
+ return a;
+}
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+
+/* UTF-16: rather than swallow a low surrogate, just stop if we hit a bad one.
+Print it with \X instead of \x as an indication. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 16
+if ((ptr[1] & 0xfc00) != 0xdc00)
+ {
+ fprintf(f, "\\X{%x}", c);
+ return 0;
+ }
+c = (((c & 0x3ff) << 10) | (ptr[1] & 0x3ff)) + 0x10000;
+fprintf(f, "\\x{%x}", c);
+return 1;
+#endif /* PCRE2_CODE_UNIT_WIDTH == 16 */
+
+/* For UTF-32 we get here only for a malformed code unit, which should only
+occur if the sanity check has been turned off. Print it with \X instead of \x
+as an indication. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+fprintf(f, "\\X{%x}", c);
+return 0;
+#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */
+#endif /* SUPPORT_UNICODE */
+}
+
+
+
+/*************************************************
+* Print string as a list of code units *
+*************************************************/
+
+/* These take no account of UTF as they always print each individual code unit.
+The string is zero-terminated for print_custring(); the length is given for
+print_custring_bylen().
+
+Arguments:
+ f file to write to
+ ptr point to the string
+ len length for print_custring_bylen()
+
+Returns: nothing
+*/
+
+static void
+print_custring(FILE *f, PCRE2_SPTR ptr)
+{
+while (*ptr != '\0')
+ {
+ register uint32_t c = *ptr++;
+ if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c);
+ }
+}
+
+static void
+print_custring_bylen(FILE *f, PCRE2_SPTR ptr, PCRE2_UCHAR len)
+{
+for (; len > 0; len--)
+ {
+ register uint32_t c = *ptr++;
+ if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c);
+ }
+}
+
+
+
+/*************************************************
+* Find Unicode property name *
+*************************************************/
+
+/* When there is no UTF/UCP support, the table of names does not exist. This
+function should not be called in such configurations, because a pattern that
+tries to use Unicode properties won't compile. Rather than put lots of #ifdefs
+into the main code, however, we just put one into this function. */
+
+static const char *
+get_ucpname(unsigned int ptype, unsigned int pvalue)
+{
+#ifdef SUPPORT_UNICODE
+int i;
+for (i = PRIV(utt_size) - 1; i >= 0; i--)
+ {
+ if (ptype == PRIV(utt)[i].type && pvalue == PRIV(utt)[i].value) break;
+ }
+return (i >= 0)? PRIV(utt_names) + PRIV(utt)[i].name_offset : "??";
+#else /* No UTF support */
+(void)ptype;
+(void)pvalue;
+return "??";
+#endif /* SUPPORT_UNICODE */
+}
+
+
+
+/*************************************************
+* Print Unicode property value *
+*************************************************/
+
+/* "Normal" properties can be printed from tables. The PT_CLIST property is a
+pseudo-property that contains a pointer to a list of case-equivalent
+characters.
+
+Arguments:
+ f file to write to
+ code pointer in the compiled code
+ before text to print before
+ after text to print after
+
+Returns: nothing
+*/
+
+static void
+print_prop(FILE *f, PCRE2_SPTR code, const char *before, const char *after)
+{
+if (code[1] != PT_CLIST)
+ {
+ fprintf(f, "%s%s %s%s", before, OP_names[*code], get_ucpname(code[1],
+ code[2]), after);
+ }
+else
+ {
+ const char *not = (*code == OP_PROP)? "" : "not ";
+ const uint32_t *p = PRIV(ucd_caseless_sets) + code[2];
+ fprintf (f, "%s%sclist", before, not);
+ while (*p < NOTACHAR) fprintf(f, " %04x", *p++);
+ fprintf(f, "%s", after);
+ }
+}
+
+
+
+/*************************************************
+* Print compiled pattern *
+*************************************************/
+
+/* The print_lengths flag controls whether offsets and lengths of items are
+printed. Lenths can be turned off from pcre2test so that automatic tests on
+bytecode can be written that do not depend on the value of LINK_SIZE.
+
+Arguments:
+ re a compiled pattern
+ f the file to write to
+ print_lengths show various lengths
+
+Returns: nothing
+*/
+
+static void
+pcre2_printint(pcre2_code *re, FILE *f, BOOL print_lengths)
+{
+PCRE2_SPTR codestart, nametable, code;
+uint32_t nesize = re->name_entry_size;
+BOOL utf = (re->overall_options & PCRE2_UTF) != 0;
+
+nametable = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code));
+code = codestart = nametable + re->name_count * re->name_entry_size;
+
+for(;;)
+ {
+ PCRE2_SPTR ccode;
+ uint32_t c;
+ int i;
+ const char *flag = " ";
+ unsigned int extra = 0;
+
+ if (print_lengths)
+ fprintf(f, "%3d ", (int)(code - codestart));
+ else
+ fprintf(f, " ");
+
+ switch(*code)
+ {
+/* ========================================================================== */
+ /* These cases are never obeyed. This is a fudge that causes a compile-
+ time error if the vectors OP_names or OP_lengths, which are indexed
+ by opcode, are not the correct length. It seems to be the only way to do
+ such a check at compile time, as the sizeof() operator does not work in
+ the C preprocessor. */
+
+ case OP_TABLE_LENGTH:
+ case OP_TABLE_LENGTH +
+ ((sizeof(OP_names)/sizeof(const char *) == OP_TABLE_LENGTH) &&
+ (sizeof(OP_lengths) == OP_TABLE_LENGTH)):
+ break;
+/* ========================================================================== */
+
+ case OP_END:
+ fprintf(f, " %s\n", OP_names[*code]);
+ fprintf(f, "------------------------------------------------------------------\n");
+ return;
+
+ case OP_CHAR:
+ fprintf(f, " ");
+ do
+ {
+ code++;
+ code += 1 + print_char(f, code, utf);
+ }
+ while (*code == OP_CHAR);
+ fprintf(f, "\n");
+ continue;
+
+ case OP_CHARI:
+ fprintf(f, " /i ");
+ do
+ {
+ code++;
+ code += 1 + print_char(f, code, utf);
+ }
+ while (*code == OP_CHARI);
+ fprintf(f, "\n");
+ continue;
+
+ case OP_CBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRA:
+ case OP_SCBRAPOS:
+ if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
+ else fprintf(f, " ");
+ fprintf(f, "%s %d", OP_names[*code], GET2(code, 1+LINK_SIZE));
+ break;
+
+ case OP_BRA:
+ case OP_BRAPOS:
+ case OP_SBRA:
+ case OP_SBRAPOS:
+ case OP_KETRMAX:
+ case OP_KETRMIN:
+ case OP_KETRPOS:
+ case OP_ALT:
+ case OP_KET:
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+ case OP_ONCE_NC:
+ case OP_COND:
+ case OP_SCOND:
+ case OP_REVERSE:
+ if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
+ else fprintf(f, " ");
+ fprintf(f, "%s", OP_names[*code]);
+ break;
+
+ case OP_CLOSE:
+ fprintf(f, " %s %d", OP_names[*code], GET2(code, 1));
+ break;
+
+ case OP_CREF:
+ fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]);
+ break;
+
+ case OP_DNCREF:
+ {
+ PCRE2_SPTR entry = nametable + (GET2(code, 1) * nesize) + IMM2_SIZE;
+ fprintf(f, " %s Cond ref <", flag);
+ print_custring(f, entry);
+ fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
+ }
+ break;
+
+ case OP_RREF:
+ c = GET2(code, 1);
+ if (c == RREF_ANY)
+ fprintf(f, " Cond recurse any");
+ else
+ fprintf(f, " Cond recurse %d", c);
+ break;
+
+ case OP_DNRREF:
+ {
+ PCRE2_SPTR entry = nametable + (GET2(code, 1) * nesize) + IMM2_SIZE;
+ fprintf(f, " %s Cond recurse <", flag);
+ print_custring(f, entry);
+ fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
+ }
+ break;
+
+ case OP_FALSE:
+ fprintf(f, " Cond false");
+ break;
+
+ case OP_TRUE:
+ fprintf(f, " Cond true");
+ break;
+
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_POSSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_POSPLUSI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_POSQUERYI:
+ flag = "/i";
+ /* Fall through */
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_POSSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_POSPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_POSQUERY:
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSQUERY:
+ fprintf(f, " %s ", flag);
+
+ if (*code >= OP_TYPESTAR)
+ {
+ if (code[1] == OP_PROP || code[1] == OP_NOTPROP)
+ {
+ print_prop(f, code + 1, "", " ");
+ extra = 2;
+ }
+ else fprintf(f, "%s", OP_names[code[1]]);
+ }
+ else extra = print_char(f, code+1, utf);
+ fprintf(f, "%s", OP_names[*code]);
+ break;
+
+ case OP_EXACTI:
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_POSUPTOI:
+ flag = "/i";
+ /* Fall through */
+ case OP_EXACT:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_POSUPTO:
+ fprintf(f, " %s ", flag);
+ extra = print_char(f, code + 1 + IMM2_SIZE, utf);
+ fprintf(f, "{");
+ if (*code != OP_EXACT && *code != OP_EXACTI) fprintf(f, "0,");
+ fprintf(f, "%d}", GET2(code,1));
+ if (*code == OP_MINUPTO || *code == OP_MINUPTOI) fprintf(f, "?");
+ else if (*code == OP_POSUPTO || *code == OP_POSUPTOI) fprintf(f, "+");
+ break;
+
+ case OP_TYPEEXACT:
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEPOSUPTO:
+ if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+ {
+ print_prop(f, code + IMM2_SIZE + 1, " ", " ");
+ extra = 2;
+ }
+ else fprintf(f, " %s", OP_names[code[1 + IMM2_SIZE]]);
+ fprintf(f, "{");
+ if (*code != OP_TYPEEXACT) fprintf(f, "0,");
+ fprintf(f, "%d}", GET2(code,1));
+ if (*code == OP_TYPEMINUPTO) fprintf(f, "?");
+ else if (*code == OP_TYPEPOSUPTO) fprintf(f, "+");
+ break;
+
+ case OP_NOTI:
+ flag = "/i";
+ /* Fall through */
+ case OP_NOT:
+ fprintf(f, " %s [^", flag);
+ extra = print_char(f, code + 1, utf);
+ fprintf(f, "]");
+ break;
+
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTPOSQUERYI:
+ flag = "/i";
+ /* Fall through */
+
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTPOSPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTPOSQUERY:
+ fprintf(f, " %s [^", flag);
+ extra = print_char(f, code + 1, utf);
+ fprintf(f, "]%s", OP_names[*code]);
+ break;
+
+ case OP_NOTEXACTI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTPOSUPTOI:
+ flag = "/i";
+ /* Fall through */
+
+ case OP_NOTEXACT:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTPOSUPTO:
+ fprintf(f, " %s [^", flag);
+ extra = print_char(f, code + 1 + IMM2_SIZE, utf);
+ fprintf(f, "]{");
+ if (*code != OP_NOTEXACT && *code != OP_NOTEXACTI) fprintf(f, "0,");
+ fprintf(f, "%d}", GET2(code,1));
+ if (*code == OP_NOTMINUPTO || *code == OP_NOTMINUPTOI) fprintf(f, "?");
+ else
+ if (*code == OP_NOTPOSUPTO || *code == OP_NOTPOSUPTOI) fprintf(f, "+");
+ break;
+
+ case OP_RECURSE:
+ if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
+ else fprintf(f, " ");
+ fprintf(f, "%s", OP_names[*code]);
+ break;
+
+ case OP_REFI:
+ flag = "/i";
+ /* Fall through */
+ case OP_REF:
+ fprintf(f, " %s \\%d", flag, GET2(code,1));
+ ccode = code + OP_lengths[*code];
+ goto CLASS_REF_REPEAT;
+
+ case OP_DNREFI:
+ flag = "/i";
+ /* Fall through */
+ case OP_DNREF:
+ {
+ PCRE2_SPTR entry = nametable + (GET2(code, 1) * nesize) + IMM2_SIZE;
+ fprintf(f, " %s \\k<", flag);
+ print_custring(f, entry);
+ fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
+ }
+ ccode = code + OP_lengths[*code];
+ goto CLASS_REF_REPEAT;
+
+ case OP_CALLOUT:
+ fprintf(f, " %s %d %d %d", OP_names[*code], code[1 + 2*LINK_SIZE],
+ GET(code, 1), GET(code, 1 + LINK_SIZE));
+ break;
+
+ case OP_CALLOUT_STR:
+ c = code[1 + 4*LINK_SIZE];
+ fprintf(f, " %s %c", OP_names[*code], c);
+ extra = GET(code, 1 + 2*LINK_SIZE);
+ print_custring_bylen(f, code + 2 + 4*LINK_SIZE, extra - 3 - 4*LINK_SIZE);
+ for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
+ if (c == PRIV(callout_start_delims)[i])
+ {
+ c = PRIV(callout_end_delims)[i];
+ break;
+ }
+ fprintf(f, "%c %d %d %d", c, GET(code, 1 + 3*LINK_SIZE), GET(code, 1),
+ GET(code, 1 + LINK_SIZE));
+ break;
+
+ case OP_PROP:
+ case OP_NOTPROP:
+ print_prop(f, code, " ", "");
+ break;
+
+ /* OP_XCLASS cannot occur in 8-bit, non-UTF mode. However, there's no harm
+ in having this code always here, and it makes it less messy without all
+ those #ifdefs. */
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ case OP_XCLASS:
+ {
+ unsigned int min, max;
+ BOOL printmap;
+ BOOL invertmap = FALSE;
+ uint8_t *map;
+ uint8_t inverted_map[32];
+
+ fprintf(f, " [");
+
+ if (*code == OP_XCLASS)
+ {
+ extra = GET(code, 1);
+ ccode = code + LINK_SIZE + 1;
+ printmap = (*ccode & XCL_MAP) != 0;
+ if ((*ccode & XCL_NOT) != 0)
+ {
+ invertmap = (*ccode & XCL_HASPROP) == 0;
+ fprintf(f, "^");
+ }
+ ccode++;
+ }
+ else
+ {
+ printmap = TRUE;
+ ccode = code + 1;
+ }
+
+ /* Print a bit map */
+
+ if (printmap)
+ {
+ map = (uint8_t *)ccode;
+ if (invertmap)
+ {
+ for (i = 0; i < 32; i++) inverted_map[i] = ~map[i];
+ map = inverted_map;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ if ((map[i/8] & (1 << (i&7))) != 0)
+ {
+ int j;
+ for (j = i+1; j < 256; j++)
+ if ((map[j/8] & (1 << (j&7))) == 0) break;
+ if (i == '-' || i == ']') fprintf(f, "\\");
+ if (PRINTABLE(i)) fprintf(f, "%c", i);
+ else fprintf(f, "\\x%02x", i);
+ if (--j > i)
+ {
+ if (j != i + 1) fprintf(f, "-");
+ if (j == '-' || j == ']') fprintf(f, "\\");
+ if (PRINTABLE(j)) fprintf(f, "%c", j);
+ else fprintf(f, "\\x%02x", j);
+ }
+ i = j;
+ }
+ }
+ ccode += 32 / sizeof(PCRE2_UCHAR);
+ }
+
+ /* For an XCLASS there is always some additional data */
+
+ if (*code == OP_XCLASS)
+ {
+ PCRE2_UCHAR ch;
+ while ((ch = *ccode++) != XCL_END)
+ {
+ BOOL not = FALSE;
+ const char *notch = "";
+
+ switch(ch)
+ {
+ case XCL_NOTPROP:
+ not = TRUE;
+ notch = "^";
+ /* Fall through */
+
+ case XCL_PROP:
+ {
+ unsigned int ptype = *ccode++;
+ unsigned int pvalue = *ccode++;
+
+ switch(ptype)
+ {
+ case PT_PXGRAPH:
+ fprintf(f, "[:%sgraph:]", notch);
+ break;
+
+ case PT_PXPRINT:
+ fprintf(f, "[:%sprint:]", notch);
+ break;
+
+ case PT_PXPUNCT:
+ fprintf(f, "[:%spunct:]", notch);
+ break;
+
+ default:
+ fprintf(f, "\\%c{%s}", (not? 'P':'p'),
+ get_ucpname(ptype, pvalue));
+ break;
+ }
+ }
+ break;
+
+ default:
+ ccode += 1 + print_char(f, ccode, utf);
+ if (ch == XCL_RANGE)
+ {
+ fprintf(f, "-");
+ ccode += 1 + print_char(f, ccode, utf);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Indicate a non-UTF class which was created by negation */
+
+ fprintf(f, "]%s", (*code == OP_NCLASS)? " (neg)" : "");
+
+ /* Handle repeats after a class or a back reference */
+
+ CLASS_REF_REPEAT:
+ switch(*ccode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSPLUS:
+ case OP_CRPOSQUERY:
+ fprintf(f, "%s", OP_names[*ccode]);
+ extra += OP_lengths[*ccode];
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ min = GET2(ccode,1);
+ max = GET2(ccode,1 + IMM2_SIZE);
+ if (max == 0) fprintf(f, "{%u,}", min);
+ else fprintf(f, "{%u,%u}", min, max);
+ if (*ccode == OP_CRMINRANGE) fprintf(f, "?");
+ else if (*ccode == OP_CRPOSRANGE) fprintf(f, "+");
+ extra += OP_lengths[*ccode];
+ break;
+
+ /* Do nothing if it's not a repeat; this code stops picky compilers
+ warning about the lack of a default code path. */
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case OP_MARK:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ fprintf(f, " %s ", OP_names[*code]);
+ print_custring_bylen(f, code + 2, code[1]);
+ extra += code[1];
+ break;
+
+ case OP_THEN:
+ fprintf(f, " %s", OP_names[*code]);
+ break;
+
+ case OP_CIRCM:
+ case OP_DOLLM:
+ flag = "/m";
+ /* Fall through */
+
+ /* Anything else is just an item with no data, but possibly a flag. */
+
+ default:
+ fprintf(f, " %s %s", flag, OP_names[*code]);
+ break;
+ }
+
+ code += OP_lengths[*code] + extra;
+ fprintf(f, "\n");
+ }
+}
+
+/* End of pcre2_printint.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_serialize.c b/src/3rdparty/pcre2/src/pcre2_serialize.c
new file mode 100644
index 0000000000..0af26d8fc3
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_serialize.c
@@ -0,0 +1,265 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains functions for serializing and deserializing
+a sequence of compiled codes. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+/* Magic number to provide a small check against being handed junk. */
+
+#define SERIALIZED_DATA_MAGIC 0x50523253u
+
+/* Deserialization is limited to the current PCRE version and
+character width. */
+
+#define SERIALIZED_DATA_VERSION \
+ ((PCRE2_MAJOR) | ((PCRE2_MINOR) << 16))
+
+#define SERIALIZED_DATA_CONFIG \
+ (sizeof(PCRE2_UCHAR) | ((sizeof(void*)) << 8) | ((sizeof(PCRE2_SIZE)) << 16))
+
+
+
+/*************************************************
+* Serialize compiled patterns *
+*************************************************/
+
+PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
+pcre2_serialize_encode(const pcre2_code **codes, int32_t number_of_codes,
+ uint8_t **serialized_bytes, PCRE2_SIZE *serialized_size,
+ pcre2_general_context *gcontext)
+{
+uint8_t *bytes;
+uint8_t *dst_bytes;
+int32_t i;
+PCRE2_SIZE total_size;
+const pcre2_real_code *re;
+const uint8_t *tables;
+pcre2_serialized_data *data;
+
+const pcre2_memctl *memctl = (gcontext != NULL) ?
+ &gcontext->memctl : &PRIV(default_compile_context).memctl;
+
+if (codes == NULL || serialized_bytes == NULL || serialized_size == NULL)
+ return PCRE2_ERROR_NULL;
+
+if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA;
+
+/* Compute total size. */
+total_size = sizeof(pcre2_serialized_data) + tables_length;
+tables = NULL;
+
+for (i = 0; i < number_of_codes; i++)
+ {
+ if (codes[i] == NULL) return PCRE2_ERROR_NULL;
+ re = (const pcre2_real_code *)(codes[i]);
+ if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+ if (tables == NULL)
+ tables = re->tables;
+ else if (tables != re->tables)
+ return PCRE2_ERROR_MIXEDTABLES;
+ total_size += re->blocksize;
+ }
+
+/* Initialize the byte stream. */
+bytes = memctl->malloc(total_size + sizeof(pcre2_memctl), memctl->memory_data);
+if (bytes == NULL) return PCRE2_ERROR_NOMEMORY;
+
+/* The controller is stored as a hidden parameter. */
+memcpy(bytes, memctl, sizeof(pcre2_memctl));
+bytes += sizeof(pcre2_memctl);
+
+data = (pcre2_serialized_data *)bytes;
+data->magic = SERIALIZED_DATA_MAGIC;
+data->version = SERIALIZED_DATA_VERSION;
+data->config = SERIALIZED_DATA_CONFIG;
+data->number_of_codes = number_of_codes;
+
+/* Copy all compiled code data. */
+dst_bytes = bytes + sizeof(pcre2_serialized_data);
+memcpy(dst_bytes, tables, tables_length);
+dst_bytes += tables_length;
+
+for (i = 0; i < number_of_codes; i++)
+ {
+ re = (const pcre2_real_code *)(codes[i]);
+ memcpy(dst_bytes, (char *)re, re->blocksize);
+ dst_bytes += re->blocksize;
+ }
+
+*serialized_bytes = bytes;
+*serialized_size = total_size;
+return number_of_codes;
+}
+
+
+/*************************************************
+* Deserialize compiled patterns *
+*************************************************/
+
+PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
+pcre2_serialize_decode(pcre2_code **codes, int32_t number_of_codes,
+ const uint8_t *bytes, pcre2_general_context *gcontext)
+{
+const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes;
+const pcre2_memctl *memctl = (gcontext != NULL) ?
+ &gcontext->memctl : &PRIV(default_compile_context).memctl;
+
+const uint8_t *src_bytes;
+pcre2_real_code *dst_re;
+uint8_t *tables;
+int32_t i, j;
+
+/* Sanity checks. */
+
+if (data == NULL || codes == NULL) return PCRE2_ERROR_NULL;
+if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA;
+if (data->number_of_codes <= 0) return PCRE2_ERROR_BADSERIALIZEDDATA;
+if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC;
+if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE;
+if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE;
+
+if (number_of_codes > data->number_of_codes)
+ number_of_codes = data->number_of_codes;
+
+src_bytes = bytes + sizeof(pcre2_serialized_data);
+
+/* Decode tables. The reference count for the tables is stored immediately
+following them. */
+
+tables = memctl->malloc(tables_length + sizeof(PCRE2_SIZE), memctl->memory_data);
+if (tables == NULL) return PCRE2_ERROR_NOMEMORY;
+
+memcpy(tables, src_bytes, tables_length);
+*(PCRE2_SIZE *)(tables + tables_length) = number_of_codes;
+src_bytes += tables_length;
+
+/* Decode the byte stream. We must not try to read the size from the compiled
+code block in the stream, because it might be unaligned, which causes errors on
+hardware such as Sparc-64 that doesn't like unaligned memory accesses. The type
+of the blocksize field is given its own name to ensure that it is the same here
+as in the block. */
+
+for (i = 0; i < number_of_codes; i++)
+ {
+ CODE_BLOCKSIZE_TYPE blocksize;
+ memcpy(&blocksize, src_bytes + offsetof(pcre2_real_code, blocksize),
+ sizeof(CODE_BLOCKSIZE_TYPE));
+ if (blocksize <= sizeof(pcre2_real_code))
+ return PCRE2_ERROR_BADSERIALIZEDDATA;
+
+ /* The allocator provided by gcontext replaces the original one. */
+
+ dst_re = (pcre2_real_code *)PRIV(memctl_malloc)(blocksize,
+ (pcre2_memctl *)gcontext);
+ if (dst_re == NULL)
+ {
+ memctl->free(tables, memctl->memory_data);
+ for (j = 0; j < i; j++)
+ {
+ memctl->free(codes[j], memctl->memory_data);
+ codes[j] = NULL;
+ }
+ return PCRE2_ERROR_NOMEMORY;
+ }
+
+ /* The new allocator must be preserved. */
+
+ memcpy(((uint8_t *)dst_re) + sizeof(pcre2_memctl),
+ src_bytes + sizeof(pcre2_memctl), blocksize - sizeof(pcre2_memctl));
+ if (dst_re->magic_number != MAGIC_NUMBER ||
+ dst_re->name_entry_size > MAX_NAME_SIZE + IMM2_SIZE + 1 ||
+ dst_re->name_count > MAX_NAME_COUNT)
+ return PCRE2_ERROR_BADSERIALIZEDDATA;
+
+ /* At the moment only one table is supported. */
+
+ dst_re->tables = tables;
+ dst_re->executable_jit = NULL;
+ dst_re->flags |= PCRE2_DEREF_TABLES;
+
+ codes[i] = dst_re;
+ src_bytes += blocksize;
+ }
+
+return number_of_codes;
+}
+
+
+/*************************************************
+* Get the number of serialized patterns *
+*************************************************/
+
+PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
+pcre2_serialize_get_number_of_codes(const uint8_t *bytes)
+{
+const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes;
+
+if (data == NULL) return PCRE2_ERROR_NULL;
+if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC;
+if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE;
+if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE;
+
+return data->number_of_codes;
+}
+
+
+/*************************************************
+* Free the allocated stream *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_serialize_free(uint8_t *bytes)
+{
+if (bytes != NULL)
+ {
+ pcre2_memctl *memctl = (pcre2_memctl *)(bytes - sizeof(pcre2_memctl));
+ memctl->free(memctl, memctl->memory_data);
+ }
+}
+
+/* End of pcre2_serialize.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_string_utils.c b/src/3rdparty/pcre2/src/pcre2_string_utils.c
new file mode 100644
index 0000000000..2a1f282629
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_string_utils.c
@@ -0,0 +1,201 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains internal functions for comparing and finding the length
+of strings. These are used instead of strcmp() etc because the standard
+functions work only on 8-bit data. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+* Compare two zero-terminated PCRE2 strings *
+*************************************************/
+
+/*
+Arguments:
+ str1 first string
+ str2 second string
+
+Returns: 0, 1, or -1
+*/
+
+int
+PRIV(strcmp)(PCRE2_SPTR str1, PCRE2_SPTR str2)
+{
+PCRE2_UCHAR c1, c2;
+while (*str1 != '\0' || *str2 != '\0')
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 != c2) return ((c1 > c2) << 1) - 1;
+ }
+return 0;
+}
+
+
+/*************************************************
+* Compare zero-terminated PCRE2 & 8-bit strings *
+*************************************************/
+
+/* As the 8-bit string is almost always a literal, its type is specified as
+const char *.
+
+Arguments:
+ str1 first string
+ str2 second string
+
+Returns: 0, 1, or -1
+*/
+
+int
+PRIV(strcmp_c8)(PCRE2_SPTR str1, const char *str2)
+{
+PCRE2_UCHAR c1, c2;
+while (*str1 != '\0' || *str2 != '\0')
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 != c2) return ((c1 > c2) << 1) - 1;
+ }
+return 0;
+}
+
+
+/*************************************************
+* Compare two PCRE2 strings, given a length *
+*************************************************/
+
+/*
+Arguments:
+ str1 first string
+ str2 second string
+ len the length
+
+Returns: 0, 1, or -1
+*/
+
+int
+PRIV(strncmp)(PCRE2_SPTR str1, PCRE2_SPTR str2, size_t len)
+{
+PCRE2_UCHAR c1, c2;
+for (; len > 0; len--)
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 != c2) return ((c1 > c2) << 1) - 1;
+ }
+return 0;
+}
+
+
+/*************************************************
+* Compare PCRE2 string to 8-bit string by length *
+*************************************************/
+
+/* As the 8-bit string is almost always a literal, its type is specified as
+const char *.
+
+Arguments:
+ str1 first string
+ str2 second string
+ len the length
+
+Returns: 0, 1, or -1
+*/
+
+int
+PRIV(strncmp_c8)(PCRE2_SPTR str1, const char *str2, size_t len)
+{
+PCRE2_UCHAR c1, c2;
+for (; len > 0; len--)
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 != c2) return ((c1 > c2) << 1) - 1;
+ }
+return 0;
+}
+
+
+/*************************************************
+* Find the length of a PCRE2 string *
+*************************************************/
+
+/*
+Argument: the string
+Returns: the length
+*/
+
+PCRE2_SIZE
+PRIV(strlen)(PCRE2_SPTR str)
+{
+PCRE2_SIZE c = 0;
+while (*str++ != 0) c++;
+return c;
+}
+
+
+/*************************************************
+* Copy 8-bit 0-terminated string to PCRE2 string *
+*************************************************/
+
+/* Arguments:
+ str1 buffer to receive the string
+ str2 8-bit string to be copied
+
+Returns: the number of code units used (excluding trailing zero)
+*/
+
+PCRE2_SIZE
+PRIV(strcpy_c8)(PCRE2_UCHAR *str1, const char *str2)
+{
+PCRE2_UCHAR *t = str1;
+while (*str2 != 0) *t++ = *str2++;
+*t = 0;
+return t - str1;
+}
+
+/* End of pcre2_string_utils.c */
diff --git a/src/3rdparty/pcre/pcre_study.c b/src/3rdparty/pcre2/src/pcre2_study.c
index d9d4960d84..db08266745 100644
--- a/src/3rdparty/pcre/pcre_study.c
+++ b/src/3rdparty/pcre2/src/pcre2_study.c
@@ -6,7 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -37,74 +38,95 @@ POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
-
-/* This module contains the external function pcre_study(), along with local
-supporting functions. */
+/* This module contains functions for scanning a compiled pattern and
+collecting data (e.g. minimum matching length). */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include "pcre_internal.h"
-#define SET_BIT(c) start_bits[c/8] |= (1 << (c&7))
+#include "pcre2_internal.h"
+
+
+/* Set a bit in the starting code unit bit map. */
+
+#define SET_BIT(c) re->start_bitmap[(c)/8] |= (1 << ((c)&7))
/* Returns from set_start_bits() */
enum { SSB_FAIL, SSB_DONE, SSB_CONTINUE, SSB_UNKNOWN };
-
/*************************************************
* Find the minimum subject length for a group *
*************************************************/
/* Scan a parenthesized group and compute the minimum length of subject that
is needed to match it. This is a lower bound; it does not mean there is a
-string of that length that matches. In UTF8 mode, the result is in characters
-rather than bytes.
+string of that length that matches. In UTF mode, the result is in characters
+rather than code units. The field in a compiled pattern for storing the minimum
+length is 16-bits long (on the grounds that anything longer than that is
+pathological), so we give up when we reach that amount. This also means that
+integer overflow for really crazy patterns cannot happen.
Arguments:
re compiled pattern block
code pointer to start of group (the bracket)
startcode pointer to start of the whole pattern's code
- options the compiling options
+ utf UTF flag
recurses chain of recurse_check to catch mutual recursion
countptr pointer to call count (to catch over complexity)
Returns: the minimum length
- -1 if \C in UTF-8 mode or (*ACCEPT) was encountered
+ -1 \C in UTF-8 mode
+ or (*ACCEPT)
+ or pattern too complicated
+ or back reference to duplicate name/number
-2 internal error (missing capturing bracket)
-3 internal error (opcode not listed)
*/
static int
-find_minlength(const REAL_PCRE *re, const pcre_uchar *code,
- const pcre_uchar *startcode, int options, recurse_check *recurses,
- int *countptr)
+find_minlength(const pcre2_real_code *re, PCRE2_SPTR code,
+ PCRE2_SPTR startcode, BOOL utf, recurse_check *recurses, int *countptr)
{
int length = -1;
-/* PCRE_UTF16 has the same value as PCRE_UTF8. */
-BOOL utf = (options & PCRE_UTF8) != 0;
+int prev_cap_recno = -1;
+int prev_cap_d = 0;
+int prev_recurse_recno = -1;
+int prev_recurse_d = 0;
+uint32_t once_fudge = 0;
BOOL had_recurse = FALSE;
+BOOL dupcapused = (re->flags & PCRE2_DUPCAPUSED) != 0;
recurse_check this_recurse;
register int branchlength = 0;
-register pcre_uchar *cc = (pcre_uchar *)code + 1 + LINK_SIZE;
+register PCRE2_UCHAR *cc = (PCRE2_UCHAR *)code + 1 + LINK_SIZE;
+
+/* If this is a "could be empty" group, its minimum length is 0. */
+
+if (*code >= OP_SBRA && *code <= OP_SCOND) return 0;
-if ((*countptr)++ > 1000) return -1; /* too complex */
+/* Skip over capturing bracket number */
-if (*code == OP_CBRA || *code == OP_SCBRA ||
- *code == OP_CBRAPOS || *code == OP_SCBRAPOS) cc += IMM2_SIZE;
+if (*code == OP_CBRA || *code == OP_CBRAPOS) cc += IMM2_SIZE;
-/* Scan along the opcodes for this branch. If we get to the end of the
-branch, check the length against that of the other branches. */
+/* A large and/or complex regex can take too long to process. */
+
+if ((*countptr)++ > 1000) return -1;
+
+/* Scan along the opcodes for this branch. If we get to the end of the branch,
+check the length against that of the other branches. If the accumulated length
+passes 16-bits, stop. */
for (;;)
{
- int d, min;
- pcre_uchar *cs, *ce;
- register pcre_uchar op = *cc;
+ int d, min, recno;
+ PCRE2_UCHAR *cs, *ce;
+ register PCRE2_UCHAR op = *cc;
+
+ if (branchlength >= UINT16_MAX) return UINT16_MAX;
switch (op)
{
@@ -113,7 +135,8 @@ for (;;)
/* If there is only one branch in a condition, the implied branch has zero
length, so we don't add anything. This covers the DEFINE "condition"
- automatically. */
+ automatically. If there are two branches we can treat it the same as any
+ other non-capturing subpattern. */
cs = cc + GET(cc, 1);
if (*cs != OP_ALT)
@@ -121,27 +144,56 @@ for (;;)
cc = cs + 1 + LINK_SIZE;
break;
}
+ goto PROCESS_NON_CAPTURE;
- /* Otherwise we can fall through and treat it the same as any other
- subpattern. */
+ /* There's a special case of OP_ONCE, when it is wrapped round an
+ OP_RECURSE. We'd like to process the latter at this level so that
+ remembering the value works for repeated cases. So we do nothing, but
+ set a fudge value to skip over the OP_KET after the recurse. */
- case OP_CBRA:
- case OP_SCBRA:
+ case OP_ONCE:
+ if (cc[1+LINK_SIZE] == OP_RECURSE && cc[2*(1+LINK_SIZE)] == OP_KET)
+ {
+ once_fudge = 1 + LINK_SIZE;
+ cc += 1 + LINK_SIZE;
+ break;
+ }
+ /* Fall through */
+
+ case OP_ONCE_NC:
case OP_BRA:
case OP_SBRA:
- case OP_CBRAPOS:
- case OP_SCBRAPOS:
case OP_BRAPOS:
case OP_SBRAPOS:
- case OP_ONCE:
- case OP_ONCE_NC:
- d = find_minlength(re, cc, startcode, options, recurses, countptr);
+ PROCESS_NON_CAPTURE:
+ d = find_minlength(re, cc, startcode, utf, recurses, countptr);
if (d < 0) return d;
branchlength += d;
do cc += GET(cc, 1); while (*cc == OP_ALT);
cc += 1 + LINK_SIZE;
break;
+ /* To save time for repeated capturing subpatterns, we remember the
+ length of the previous one. Unfortunately we can't do the same for
+ the unnumbered ones above. Nor can we do this if (?| is present in the
+ pattern because captures with the same number are not then identical. */
+
+ case OP_CBRA:
+ case OP_SCBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ recno = dupcapused? prev_cap_recno - 1 : (int)GET2(cc, 1+LINK_SIZE);
+ if (recno != prev_cap_recno)
+ {
+ prev_cap_recno = recno;
+ prev_cap_d = find_minlength(re, cc, startcode, utf, recurses, countptr);
+ if (prev_cap_d < 0) return prev_cap_d;
+ }
+ branchlength += prev_cap_d;
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ cc += 1 + LINK_SIZE;
+ break;
+
/* ACCEPT makes things far too complicated; we have to give up. */
case OP_ACCEPT:
@@ -184,7 +236,8 @@ for (;;)
case OP_DNCREF:
case OP_RREF:
case OP_DNRREF:
- case OP_DEF:
+ case OP_FALSE:
+ case OP_TRUE:
case OP_CALLOUT:
case OP_SOD:
case OP_SOM:
@@ -199,6 +252,10 @@ for (;;)
cc += PRIV(OP_lengths)[*cc];
break;
+ case OP_CALLOUT_STR:
+ cc += GET(cc, 1 + 2*LINK_SIZE);
+ break;
+
/* Skip over a subpattern that has a {0} or {0,x} quantifier */
case OP_BRAZERO:
@@ -230,7 +287,7 @@ for (;;)
case OP_NOTPOSPLUSI:
branchlength++;
cc += 2;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -243,7 +300,7 @@ for (;;)
break;
/* Handle exact repetitions. The count is already in characters, but we
- need to skip over a multibyte character in UTF8 mode. */
+ may need to skip over a multibyte character in UTF mode. */
case OP_EXACT:
case OP_EXACTI:
@@ -251,7 +308,7 @@ for (;;)
case OP_NOTEXACTI:
branchlength += GET2(cc,1);
cc += 2 + IMM2_SIZE;
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -294,12 +351,12 @@ for (;;)
cc++;
break;
- /* The single-byte matcher means we can't proceed in UTF-8 mode. (In
- non-UTF-8 mode \C will actually be turned into OP_ALLANY, so won't ever
+ /* The single-byte matcher means we can't proceed in UTF mode. (In
+ non-UTF mode \C will actually be turned into OP_ALLANY, so won't ever
appear, but leave the code, just in case.) */
case OP_ANYBYTE:
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf) return -1;
#endif
branchlength++;
@@ -331,7 +388,7 @@ for (;;)
case OP_CLASS:
case OP_NCLASS:
-#if defined SUPPORT_UTF || defined COMPILE_PCRE16 || defined COMPILE_PCRE32
+#ifdef SUPPORT_WIDE_CHARS
case OP_XCLASS:
/* The original code caused an unsigned overflow in 64 bit systems,
so now we use a conditional statement. */
@@ -373,32 +430,40 @@ for (;;)
}
break;
- /* Backreferences and subroutine calls are treated in the same way: we find
- the minimum length for the subpattern. A recursion, however, causes an
- a flag to be set that causes the length of this branch to be ignored. The
- logic is that a recursion can only make sense if there is another
- alternation that stops the recursing. That will provide the minimum length
- (when no recursion happens). A backreference within the group that it is
- referencing behaves in the same way.
+ /* Backreferences and subroutine calls (OP_RECURSE) are treated in the same
+ way: we find the minimum length for the subpattern. A recursion
+ (backreference or subroutine) causes an a flag to be set that causes the
+ length of this branch to be ignored. The logic is that a recursion can only
+ make sense if there is another alternative that stops the recursing. That
+ will provide the minimum length (when no recursion happens).
- If PCRE_JAVASCRIPT_COMPAT is set, a backreference to an unset bracket
+ If PCRE2_MATCH_UNSET_BACKREF is set, a backreference to an unset bracket
matches an empty string (by default it causes a matching failure), so in
that case we must set the minimum length to zero. */
- case OP_DNREF: /* Duplicate named pattern back reference */
+ /* Duplicate named pattern back reference. We cannot reliably find a length
+ for this if duplicate numbers are present in the pattern. */
+
+ case OP_DNREF:
case OP_DNREFI:
- if ((options & PCRE_JAVASCRIPT_COMPAT) == 0)
+ if (dupcapused) return -1;
+ if ((re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0)
{
int count = GET2(cc, 1+IMM2_SIZE);
- pcre_uchar *slot = (pcre_uchar *)re +
- re->name_table_offset + GET2(cc, 1) * re->name_entry_size;
+ PCRE2_UCHAR *slot =
+ (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) +
+ GET2(cc, 1) * re->name_entry_size;
+
d = INT_MAX;
+
+ /* Scan all groups with the same name */
+
while (count-- > 0)
{
- ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(slot, 0));
+ ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, GET2(slot, 0));
if (cs == NULL) return -2;
do ce += GET(ce, 1); while (*ce == OP_ALT);
- if (cc > cs && cc < ce) /* Simple recursion */
+ if (cc > cs && cc < ce) /* Simple recursion */
{
d = 0;
had_recurse = TRUE;
@@ -419,8 +484,7 @@ for (;;)
int dd;
this_recurse.prev = recurses;
this_recurse.group = cs;
- dd = find_minlength(re, cs, startcode, options, &this_recurse,
- countptr);
+ dd = find_minlength(re, cs, startcode, utf, &this_recurse, countptr);
if (dd < d) d = dd;
}
}
@@ -431,11 +495,15 @@ for (;;)
cc += 1 + 2*IMM2_SIZE;
goto REPEAT_BACK_REFERENCE;
- case OP_REF: /* Single back reference */
+ /* Single back reference. We cannot find a length for this if duplicate
+ numbers are present in the pattern. */
+
+ case OP_REF:
case OP_REFI:
- if ((options & PCRE_JAVASCRIPT_COMPAT) == 0)
+ if (dupcapused) return -1;
+ if ((re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0)
{
- ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(cc, 1));
+ ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, GET2(cc, 1));
if (cs == NULL) return -2;
do ce += GET(ce, 1); while (*ce == OP_ALT);
if (cc > cs && cc < ce) /* Simple recursion */
@@ -456,8 +524,7 @@ for (;;)
{
this_recurse.prev = recurses;
this_recurse.group = cs;
- d = find_minlength(re, cs, startcode, options, &this_recurse,
- countptr);
+ d = find_minlength(re, cs, startcode, utf, &this_recurse, countptr);
}
}
}
@@ -498,32 +565,51 @@ for (;;)
break;
}
- branchlength += min * d;
+ /* Take care not to overflow: (1) min and d are ints, so check that their
+ product is not greater than INT_MAX. (2) branchlength is limited to
+ UINT16_MAX (checked at the top of the loop). */
+
+ if ((d > 0 && (INT_MAX/d) < min) || UINT16_MAX - branchlength < min*d)
+ branchlength = UINT16_MAX;
+ else branchlength += min * d;
break;
- /* We can easily detect direct recursion, but not mutual recursion. This is
- caught by a recursion depth count. */
+ /* Recursion always refers to the first occurrence of a subpattern with a
+ given number. Therefore, we can always make use of caching, even when the
+ pattern contains multiple subpatterns with the same number. */
case OP_RECURSE:
- cs = ce = (pcre_uchar *)startcode + GET(cc, 1);
- do ce += GET(ce, 1); while (*ce == OP_ALT);
- if (cc > cs && cc < ce) /* Simple recursion */
- had_recurse = TRUE;
+ cs = ce = (PCRE2_UCHAR *)startcode + GET(cc, 1);
+ recno = GET2(cs, 1+LINK_SIZE);
+ if (recno == prev_recurse_recno)
+ {
+ branchlength += prev_recurse_d;
+ }
else
{
- recurse_check *r = recurses;
- for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
- if (r != NULL) /* Mutual recursion */
+ do ce += GET(ce, 1); while (*ce == OP_ALT);
+ if (cc > cs && cc < ce) /* Simple recursion */
had_recurse = TRUE;
else
{
- this_recurse.prev = recurses;
- this_recurse.group = cs;
- branchlength += find_minlength(re, cs, startcode, options,
- &this_recurse, countptr);
+ recurse_check *r = recurses;
+ for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
+ if (r != NULL) /* Mutual recursion */
+ had_recurse = TRUE;
+ else
+ {
+ this_recurse.prev = recurses;
+ this_recurse.group = cs;
+ prev_recurse_d = find_minlength(re, cs, startcode, utf, &this_recurse,
+ countptr);
+ if (prev_recurse_d < 0) return prev_recurse_d;
+ prev_recurse_recno = recno;
+ branchlength += prev_recurse_d;
+ }
}
}
- cc += 1 + LINK_SIZE;
+ cc += 1 + LINK_SIZE + once_fudge;
+ once_fudge = 0;
break;
/* Anything else does not or need not match a character. We can get the
@@ -574,7 +660,7 @@ for (;;)
case OP_NOTPOSQUERYI:
cc += PRIV(OP_lengths)[op];
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
break;
@@ -616,85 +702,70 @@ for (;;)
* Set a bit and maybe its alternate case *
*************************************************/
-/* Given a character, set its first byte's bit in the table, and also the
-corresponding bit for the other version of a letter if we are caseless. In
-UTF-8 mode, for characters greater than 127, we can only do the caseless thing
-when Unicode property support is available.
+/* Given a character, set its first code unit's bit in the table, and also the
+corresponding bit for the other version of a letter if we are caseless.
Arguments:
- start_bits points to the bit map
- p points to the character
- caseless the caseless flag
- cd the block with char table pointers
- utf TRUE for UTF-8 / UTF-16 / UTF-32 mode
+ re points to the regex block
+ p points to the first code unit of the character
+ caseless TRUE if caseless
+ utf TRUE for UTF mode
Returns: pointer after the character
*/
-static const pcre_uchar *
-set_table_bit(pcre_uint8 *start_bits, const pcre_uchar *p, BOOL caseless,
- compile_data *cd, BOOL utf)
+static PCRE2_SPTR
+set_table_bit(pcre2_real_code *re, PCRE2_SPTR p, BOOL caseless, BOOL utf)
{
-pcre_uint32 c = *p;
+uint32_t c = *p++; /* First code unit */
+(void)utf; /* Stop compiler warning when UTF not supported */
-#ifdef COMPILE_PCRE8
-SET_BIT(c);
+/* In 16-bit and 32-bit modes, code units greater than 0xff set the bit for
+0xff. */
-#ifdef SUPPORT_UTF
-if (utf && c > 127)
- {
- GETCHARINC(c, p);
-#ifdef SUPPORT_UCP
- if (caseless)
- {
- pcre_uchar buff[6];
- c = UCD_OTHERCASE(c);
- (void)PRIV(ord2utf)(c, buff);
- SET_BIT(buff[0]);
- }
-#endif /* Not SUPPORT_UCP */
- return p;
- }
-#else /* Not SUPPORT_UTF */
-(void)(utf); /* Stops warning for unused parameter */
-#endif /* SUPPORT_UTF */
+#if PCRE2_CODE_UNIT_WIDTH != 8
+if (c > 0xff) SET_BIT(0xff); else
+#endif
-/* Not UTF-8 mode, or character is less than 127. */
+SET_BIT(c);
-if (caseless && (cd->ctypes[c] & ctype_letter) != 0) SET_BIT(cd->fcc[c]);
-return p + 1;
-#endif /* COMPILE_PCRE8 */
+/* In UTF-8 or UTF-16 mode, pick up the remaining code units in order to find
+the end of the character, even when caseless. */
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
-if (c > 0xff)
+#ifdef SUPPORT_UNICODE
+if (utf)
{
- c = 0xff;
- caseless = FALSE;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (c >= 0xc0) GETUTF8INC(c, p);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ if ((c & 0xfc00) == 0xd800) GETUTF16INC(c, p);
+#endif
}
-SET_BIT(c);
+#endif /* SUPPORT_UNICODE */
-#ifdef SUPPORT_UTF
-if (utf && c > 127)
+/* If caseless, handle the other case of the character. */
+
+if (caseless)
{
- GETCHARINC(c, p);
-#ifdef SUPPORT_UCP
- if (caseless)
+ if (utf)
{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ PCRE2_UCHAR buff[6];
c = UCD_OTHERCASE(c);
- if (c > 0xff)
- c = 0xff;
- SET_BIT(c);
+ (void)PRIV(ord2utf)(c, buff);
+ SET_BIT(buff[0]);
+#else /* 16-bit or 32-bit mode */
+ c = UCD_OTHERCASE(c);
+ if (c > 0xff) SET_BIT(0xff); else SET_BIT(c);
+#endif
}
-#endif /* SUPPORT_UCP */
- return p;
+
+ /* Not UTF */
+
+ else if (MAX_255(c)) SET_BIT(re->tables[fcc_offset + c]);
}
-#else /* Not SUPPORT_UTF */
-(void)(utf); /* Stops warning for unused parameter */
-#endif /* SUPPORT_UTF */
-if (caseless && (cd->ctypes[c] & ctype_letter) != 0) SET_BIT(cd->fcc[c]);
-return p + 1;
-#endif
+return p;
}
@@ -711,32 +782,31 @@ least one Windows environment, some higher bytes bits were set in the tables.
So we deal with that case by considering the UTF-8 encoding.
Arguments:
- start_bits the starting bitmap
+ re the regex block
cbit type the type of character wanted
table_limit 32 for non-UTF-8; 16 for UTF-8
- cd the block with char table pointers
Returns: nothing
*/
static void
-set_type_bits(pcre_uint8 *start_bits, int cbit_type, unsigned int table_limit,
- compile_data *cd)
+set_type_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit)
{
-register pcre_uint32 c;
-for (c = 0; c < table_limit; c++) start_bits[c] |= cd->cbits[c+cbit_type];
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+register uint32_t c;
+for (c = 0; c < table_limit; c++)
+ re->start_bitmap[c] |= re->tables[c+cbits_offset+cbit_type];
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (table_limit == 32) return;
for (c = 128; c < 256; c++)
{
- if ((cd->cbits[c/8] & (1 << (c&7))) != 0)
+ if ((re->tables[cbits_offset + c/8] & (1 << (c&7))) != 0)
{
- pcre_uchar buff[6];
+ PCRE2_UCHAR buff[6];
(void)PRIV(ord2utf)(c, buff);
SET_BIT(buff[0]);
}
}
-#endif
+#endif /* UTF-8 */
}
@@ -753,22 +823,21 @@ all high-valued characters. The lowest is 0xc2, but we overkill by starting at
0xc0 (192) for simplicity.
Arguments:
- start_bits the starting bitmap
+ re the regex block
cbit type the type of character wanted
table_limit 32 for non-UTF-8; 16 for UTF-8
- cd the block with char table pointers
Returns: nothing
*/
static void
-set_nottype_bits(pcre_uint8 *start_bits, int cbit_type, unsigned int table_limit,
- compile_data *cd)
+set_nottype_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit)
{
-register pcre_uint32 c;
-for (c = 0; c < table_limit; c++) start_bits[c] |= ~cd->cbits[c+cbit_type];
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
-if (table_limit != 32) for (c = 24; c < 32; c++) start_bits[c] = 0xff;
+register uint32_t c;
+for (c = 0; c < table_limit; c++)
+ re->start_bitmap[c] |= ~(re->tables[c+cbits_offset+cbit_type]);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+if (table_limit != 32) for (c = 24; c < 32; c++) re->start_bitmap[c] = 0xff;
#endif
}
@@ -779,58 +848,44 @@ if (table_limit != 32) for (c = 24; c < 32; c++) start_bits[c] = 0xff;
*************************************************/
/* This function scans a compiled unanchored expression recursively and
-attempts to build a bitmap of the set of possible starting bytes. As time goes
-by, we may be able to get more clever at doing this. The SSB_CONTINUE return is
-useful for parenthesized groups in patterns such as (a*)b where the group
-provides some optional starting bytes but scanning must continue at the outer
-level to find at least one mandatory byte. At the outermost level, this
-function fails unless the result is SSB_DONE.
+attempts to build a bitmap of the set of possible starting code units whose
+values are less than 256. In 16-bit and 32-bit mode, values above 255 all cause
+the 255 bit to be set. When calling set[_not]_type_bits() in UTF-8 (sic) mode
+we pass a value of 16 rather than 32 as the final argument. (See comments in
+those functions for the reason.)
+
+The SSB_CONTINUE return is useful for parenthesized groups in patterns such as
+(a*)b where the group provides some optional starting code units but scanning
+must continue at the outer level to find at least one mandatory code unit. At
+the outermost level, this function fails unless the result is SSB_DONE.
Arguments:
+ re points to the compiled regex block
code points to an expression
- start_bits points to a 32-byte table, initialized to 0
- utf TRUE if in UTF-8 / UTF-16 / UTF-32 mode
- cd the block with char table pointers
+ utf TRUE if in UTF mode
-Returns: SSB_FAIL => Failed to find any starting bytes
- SSB_DONE => Found mandatory starting bytes
- SSB_CONTINUE => Found optional starting bytes
+Returns: SSB_FAIL => Failed to find any starting code units
+ SSB_DONE => Found mandatory starting code units
+ SSB_CONTINUE => Found optional starting code units
SSB_UNKNOWN => Hit an unrecognized opcode
*/
static int
-set_start_bits(const pcre_uchar *code, pcre_uint8 *start_bits, BOOL utf,
- compile_data *cd)
+set_start_bits(pcre2_real_code *re, PCRE2_SPTR code, BOOL utf)
{
-register pcre_uint32 c;
+register uint32_t c;
int yield = SSB_DONE;
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
int table_limit = utf? 16:32;
#else
int table_limit = 32;
#endif
-#if 0
-/* ========================================================================= */
-/* The following comment and code was inserted in January 1999. In May 2006,
-when it was observed to cause compiler warnings about unused values, I took it
-out again. If anybody is still using OS/2, they will have to put it back
-manually. */
-
-/* This next statement and the later reference to dummy are here in order to
-trick the optimizer of the IBM C compiler for OS/2 into generating correct
-code. Apparently IBM isn't going to fix the problem, and we would rather not
-disable optimization (in this module it actually makes a big difference, and
-the pcre module can use all the optimization it can get). */
-
-volatile int dummy;
-/* ========================================================================= */
-#endif
-
do
{
BOOL try_next = TRUE;
- const pcre_uchar *tcode = code + 1 + LINK_SIZE;
+ PCRE2_SPTR tcode = code + 1 + LINK_SIZE;
if (*code == OP_CBRA || *code == OP_SCBRA ||
*code == OP_CBRAPOS || *code == OP_SCBRAPOS) tcode += IMM2_SIZE;
@@ -838,12 +893,13 @@ do
while (try_next) /* Loop for items in this branch */
{
int rc;
+ uint8_t *classmap = NULL;
switch(*tcode)
{
/* If we reach something we don't understand, it means a new opcode has
- been created that hasn't been added to this code. Hopefully this problem
- will be discovered during testing. */
+ been created that hasn't been added to this function. Hopefully this
+ problem will be discovered during testing. */
default:
return SSB_UNKNOWN;
@@ -861,7 +917,8 @@ do
case OP_COMMIT:
case OP_COND:
case OP_CREF:
- case OP_DEF:
+ case OP_FALSE:
+ case OP_TRUE:
case OP_DNCREF:
case OP_DNREF:
case OP_DNREFI:
@@ -930,13 +987,13 @@ do
case OP_PROP:
if (tcode[1] != PT_CLIST) return SSB_FAIL;
{
- const pcre_uint32 *p = PRIV(ucd_caseless_sets) + tcode[2];
+ const uint32_t *p = PRIV(ucd_caseless_sets) + tcode[2];
while ((c = *p++) < NOTACHAR)
{
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (utf)
{
- pcre_uchar buff[6];
+ PCRE2_UCHAR buff[6];
(void)PRIV(ord2utf)(c, buff);
c = buff[0];
}
@@ -970,7 +1027,7 @@ do
case OP_ONCE:
case OP_ONCE_NC:
case OP_ASSERT:
- rc = set_start_bits(tcode, start_bits, utf, cd);
+ rc = set_start_bits(re, tcode, utf);
if (rc == SSB_FAIL || rc == SSB_UNKNOWN) return rc;
if (rc == SSB_DONE) try_next = FALSE; else
{
@@ -1000,7 +1057,11 @@ do
/* Skip over callout */
case OP_CALLOUT:
- tcode += 2 + 2*LINK_SIZE;
+ tcode += PRIV(OP_lengths)[OP_CALLOUT];
+ break;
+
+ case OP_CALLOUT_STR:
+ tcode += GET(tcode, 1 + 2*LINK_SIZE);
break;
/* Skip over lookbehind and negative lookahead assertions */
@@ -1017,13 +1078,8 @@ do
case OP_BRAZERO:
case OP_BRAMINZERO:
case OP_BRAPOSZERO:
- rc = set_start_bits(++tcode, start_bits, utf, cd);
+ rc = set_start_bits(re, ++tcode, utf);
if (rc == SSB_FAIL || rc == SSB_UNKNOWN) return rc;
-/* =========================================================================
- See the comment at the head of this function concerning the next line,
- which was an old fudge for the benefit of OS/2.
- dummy = 1;
- ========================================================================= */
do tcode += GET(tcode,1); while (*tcode == OP_ALT);
tcode += 1 + LINK_SIZE;
break;
@@ -1044,7 +1100,7 @@ do
case OP_QUERY:
case OP_MINQUERY:
case OP_POSQUERY:
- tcode = set_table_bit(start_bits, tcode + 1, FALSE, cd, utf);
+ tcode = set_table_bit(re, tcode + 1, FALSE, utf);
break;
case OP_STARI:
@@ -1053,7 +1109,7 @@ do
case OP_QUERYI:
case OP_MINQUERYI:
case OP_POSQUERYI:
- tcode = set_table_bit(start_bits, tcode + 1, TRUE, cd, utf);
+ tcode = set_table_bit(re, tcode + 1, TRUE, utf);
break;
/* Single-char upto sets the bit and tries the next */
@@ -1061,13 +1117,13 @@ do
case OP_UPTO:
case OP_MINUPTO:
case OP_POSUPTO:
- tcode = set_table_bit(start_bits, tcode + 1 + IMM2_SIZE, FALSE, cd, utf);
+ tcode = set_table_bit(re, tcode + 1 + IMM2_SIZE, FALSE, utf);
break;
case OP_UPTOI:
case OP_MINUPTOI:
case OP_POSUPTOI:
- tcode = set_table_bit(start_bits, tcode + 1 + IMM2_SIZE, TRUE, cd, utf);
+ tcode = set_table_bit(re, tcode + 1 + IMM2_SIZE, TRUE, utf);
break;
/* At least one single char sets the bit and stops */
@@ -1079,7 +1135,7 @@ do
case OP_PLUS:
case OP_MINPLUS:
case OP_POSPLUS:
- (void)set_table_bit(start_bits, tcode + 1, FALSE, cd, utf);
+ (void)set_table_bit(re, tcode + 1, FALSE, utf);
try_next = FALSE;
break;
@@ -1090,7 +1146,7 @@ do
case OP_PLUSI:
case OP_MINPLUSI:
case OP_POSPLUSI:
- (void)set_table_bit(start_bits, tcode + 1, TRUE, cd, utf);
+ (void)set_table_bit(re, tcode + 1, TRUE, utf);
try_next = FALSE;
break;
@@ -1103,29 +1159,36 @@ do
case OP_HSPACE:
SET_BIT(CHAR_HT);
SET_BIT(CHAR_SPACE);
-#ifdef SUPPORT_UTF
+
+ /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+ the bits for 0xA0 and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(0xA0);
+ SET_BIT(0xFF);
+#else
+ /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+ units of horizontal space characters. */
+
+#ifdef SUPPORT_UNICODE
if (utf)
{
-#ifdef COMPILE_PCRE8
SET_BIT(0xC2); /* For U+00A0 */
SET_BIT(0xE1); /* For U+1680, U+180E */
SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */
SET_BIT(0xE3); /* For U+3000 */
-#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32
- SET_BIT(0xA0);
- SET_BIT(0xFF); /* For characters > 255 */
-#endif /* COMPILE_PCRE[8|16|32] */
}
else
-#endif /* SUPPORT_UTF */
+#endif
+ /* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless
+ the code is EBCDIC. */
{
#ifndef EBCDIC
SET_BIT(0xA0);
#endif /* Not EBCDIC */
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
- SET_BIT(0xFF); /* For characters > 255 */
-#endif /* COMPILE_PCRE[16|32] */
}
+#endif /* 8-bit support */
+
try_next = FALSE;
break;
@@ -1135,64 +1198,66 @@ do
SET_BIT(CHAR_VT);
SET_BIT(CHAR_FF);
SET_BIT(CHAR_CR);
-#ifdef SUPPORT_UTF
+
+ /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+ the bits for NEL and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(CHAR_NEL);
+ SET_BIT(0xFF);
+#else
+ /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+ units of vertical space characters. */
+
+#ifdef SUPPORT_UNICODE
if (utf)
{
-#ifdef COMPILE_PCRE8
- SET_BIT(0xC2); /* For U+0085 */
+ SET_BIT(0xC2); /* For U+0085 (NEL) */
SET_BIT(0xE2); /* For U+2028, U+2029 */
-#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32
- SET_BIT(CHAR_NEL);
- SET_BIT(0xFF); /* For characters > 255 */
-#endif /* COMPILE_PCRE[8|16|32] */
}
else
-#endif /* SUPPORT_UTF */
+#endif
+ /* For the 8-bit library not in UTF-8 mode, set the bit for NEL. */
{
SET_BIT(CHAR_NEL);
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
- SET_BIT(0xFF); /* For characters > 255 */
-#endif
}
+#endif /* 8-bit support */
+
try_next = FALSE;
break;
- /* Single character types set the bits and stop. Note that if PCRE_UCP
+ /* Single character types set the bits and stop. Note that if PCRE2_UCP
is set, we do not see these op codes because \d etc are converted to
properties. Therefore, these apply in the case when only characters less
than 256 are recognized to match the types. */
case OP_NOT_DIGIT:
- set_nottype_bits(start_bits, cbit_digit, table_limit, cd);
+ set_nottype_bits(re, cbit_digit, table_limit);
try_next = FALSE;
break;
case OP_DIGIT:
- set_type_bits(start_bits, cbit_digit, table_limit, cd);
+ set_type_bits(re, cbit_digit, table_limit);
try_next = FALSE;
break;
- /* The cbit_space table has vertical tab as whitespace; we no longer
- have to play fancy tricks because Perl added VT to its whitespace at
- release 5.18. PCRE added it at release 8.34. */
-
case OP_NOT_WHITESPACE:
- set_nottype_bits(start_bits, cbit_space, table_limit, cd);
+ set_nottype_bits(re, cbit_space, table_limit);
try_next = FALSE;
break;
case OP_WHITESPACE:
- set_type_bits(start_bits, cbit_space, table_limit, cd);
+ set_type_bits(re, cbit_space, table_limit);
try_next = FALSE;
break;
case OP_NOT_WORDCHAR:
- set_nottype_bits(start_bits, cbit_word, table_limit, cd);
+ set_nottype_bits(re, cbit_word, table_limit);
try_next = FALSE;
break;
case OP_WORDCHAR:
- set_type_bits(start_bits, cbit_word, table_limit, cd);
+ set_type_bits(re, cbit_word, table_limit);
try_next = FALSE;
break;
@@ -1233,24 +1298,35 @@ do
case OP_HSPACE:
SET_BIT(CHAR_HT);
SET_BIT(CHAR_SPACE);
-#ifdef SUPPORT_UTF
+
+ /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+ the bits for 0xA0 and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(0xA0);
+ SET_BIT(0xFF);
+#else
+ /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+ units of horizontal space characters. */
+
+#ifdef SUPPORT_UNICODE
if (utf)
{
-#ifdef COMPILE_PCRE8
SET_BIT(0xC2); /* For U+00A0 */
SET_BIT(0xE1); /* For U+1680, U+180E */
SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */
SET_BIT(0xE3); /* For U+3000 */
-#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32
- SET_BIT(0xA0);
- SET_BIT(0xFF); /* For characters > 255 */
-#endif /* COMPILE_PCRE[8|16|32] */
}
else
-#endif /* SUPPORT_UTF */
+#endif
+ /* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless
+ the code is EBCDIC. */
+ {
#ifndef EBCDIC
SET_BIT(0xA0);
#endif /* Not EBCDIC */
+ }
+#endif /* 8-bit support */
break;
case OP_ANYNL:
@@ -1259,428 +1335,241 @@ do
SET_BIT(CHAR_VT);
SET_BIT(CHAR_FF);
SET_BIT(CHAR_CR);
-#ifdef SUPPORT_UTF
+
+ /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+ the bits for NEL and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(CHAR_NEL);
+ SET_BIT(0xFF);
+#else
+ /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+ units of vertical space characters. */
+
+#ifdef SUPPORT_UNICODE
if (utf)
{
-#ifdef COMPILE_PCRE8
- SET_BIT(0xC2); /* For U+0085 */
+ SET_BIT(0xC2); /* For U+0085 (NEL) */
SET_BIT(0xE2); /* For U+2028, U+2029 */
-#elif defined COMPILE_PCRE16 || defined COMPILE_PCRE32
- SET_BIT(CHAR_NEL);
- SET_BIT(0xFF); /* For characters > 255 */
-#endif /* COMPILE_PCRE16 */
}
else
-#endif /* SUPPORT_UTF */
+#endif
+ /* For the 8-bit library not in UTF-8 mode, set the bit for NEL. */
+ {
SET_BIT(CHAR_NEL);
+ }
+#endif /* 8-bit support */
break;
case OP_NOT_DIGIT:
- set_nottype_bits(start_bits, cbit_digit, table_limit, cd);
+ set_nottype_bits(re, cbit_digit, table_limit);
break;
case OP_DIGIT:
- set_type_bits(start_bits, cbit_digit, table_limit, cd);
+ set_type_bits(re, cbit_digit, table_limit);
break;
- /* The cbit_space table has vertical tab as whitespace; we no longer
- have to play fancy tricks because Perl added VT to its whitespace at
- release 5.18. PCRE added it at release 8.34. */
-
case OP_NOT_WHITESPACE:
- set_nottype_bits(start_bits, cbit_space, table_limit, cd);
+ set_nottype_bits(re, cbit_space, table_limit);
break;
case OP_WHITESPACE:
- set_type_bits(start_bits, cbit_space, table_limit, cd);
+ set_type_bits(re, cbit_space, table_limit);
break;
case OP_NOT_WORDCHAR:
- set_nottype_bits(start_bits, cbit_word, table_limit, cd);
+ set_nottype_bits(re, cbit_word, table_limit);
break;
case OP_WORDCHAR:
- set_type_bits(start_bits, cbit_word, table_limit, cd);
+ set_type_bits(re, cbit_word, table_limit);
break;
}
tcode += 2;
break;
- /* Character class where all the information is in a bit map: set the
- bits and either carry on or not, according to the repeat count. If it was
- a negative class, and we are operating with UTF-8 characters, any byte
- with a value >= 0xc4 is a potentially valid starter because it starts a
- character with a value > 255. */
+ /* Extended class: if there are any property checks, or if this is a
+ negative XCLASS without a map, give up. If there are no property checks,
+ there must be wide characters on the XCLASS list, because otherwise an
+ XCLASS would not have been created. This means that code points >= 255
+ are always potential starters. */
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
+#ifdef SUPPORT_WIDE_CHARS
case OP_XCLASS:
- if ((tcode[1 + LINK_SIZE] & XCL_HASPROP) != 0)
- return SSB_FAIL;
- /* All bits are set. */
- if ((tcode[1 + LINK_SIZE] & XCL_MAP) == 0 && (tcode[1 + LINK_SIZE] & XCL_NOT) != 0)
+ if ((tcode[1 + LINK_SIZE] & XCL_HASPROP) != 0 ||
+ (tcode[1 + LINK_SIZE] & (XCL_MAP|XCL_NOT)) == XCL_NOT)
return SSB_FAIL;
+
+ /* We have a positive XCLASS or a negative one without a map. Set up the
+ map pointer if there is one, and fall through. */
+
+ classmap = ((tcode[1 + LINK_SIZE] & XCL_MAP) == 0)? NULL :
+ (uint8_t *)(tcode + 1 + LINK_SIZE + 1);
#endif
- /* Fall through */
+
+ /* Enter here for a negative non-XCLASS. In the 8-bit library, if we are
+ in UTF mode, any byte with a value >= 0xc4 is a potentially valid starter
+ because it starts a character with a value > 255. In 8-bit non-UTF mode,
+ there is no difference between CLASS and NCLASS. In all other wide
+ character modes, set the 0xFF bit to indicate code units >= 255. */
case OP_NCLASS:
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
if (utf)
{
- start_bits[24] |= 0xf0; /* Bits for 0xc4 - 0xc8 */
- memset(start_bits+25, 0xff, 7); /* Bits for 0xc9 - 0xff */
+ re->start_bitmap[24] |= 0xf0; /* Bits for 0xc4 - 0xc8 */
+ memset(re->start_bitmap+25, 0xff, 7); /* Bits for 0xc9 - 0xff */
}
-#endif
-#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
- SET_BIT(0xFF); /* For characters > 255 */
+#elif PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(0xFF); /* For characters >= 255 */
#endif
/* Fall through */
+ /* Enter here for a positive non-XCLASS. If we have fallen through from
+ an XCLASS, classmap will already be set; just advance the code pointer.
+ Otherwise, set up classmap for a a non-XCLASS and advance past it. */
+
case OP_CLASS:
+ if (*tcode == OP_XCLASS) tcode += GET(tcode, 1); else
{
- pcre_uint8 *map;
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- map = NULL;
- if (*tcode == OP_XCLASS)
- {
- if ((tcode[1 + LINK_SIZE] & XCL_MAP) != 0)
- map = (pcre_uint8 *)(tcode + 1 + LINK_SIZE + 1);
- tcode += GET(tcode, 1);
- }
- else
-#endif
- {
- tcode++;
- map = (pcre_uint8 *)tcode;
- tcode += 32 / sizeof(pcre_uchar);
- }
+ classmap = (uint8_t *)(++tcode);
+ tcode += 32 / sizeof(PCRE2_UCHAR);
+ }
- /* In UTF-8 mode, the bits in a bit map correspond to character
- values, not to byte values. However, the bit map we are constructing is
- for byte values. So we have to do a conversion for characters whose
- value is > 127. In fact, there are only two possible starting bytes for
- characters in the range 128 - 255. */
+ /* When wide characters are supported, classmap may be NULL. In UTF-8
+ (sic) mode, the bits in a class bit map correspond to character values,
+ not to byte values. However, the bit map we are constructing is for byte
+ values. So we have to do a conversion for characters whose code point is
+ greater than 127. In fact, there are only two possible starting bytes for
+ characters in the range 128 - 255. */
-#if defined SUPPORT_UTF || !defined COMPILE_PCRE8
- if (map != NULL)
-#endif
+ if (classmap != NULL)
+ {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (utf)
{
-#if defined SUPPORT_UTF && defined COMPILE_PCRE8
- if (utf)
+ for (c = 0; c < 16; c++) re->start_bitmap[c] |= classmap[c];
+ for (c = 128; c < 256; c++)
{
- for (c = 0; c < 16; c++) start_bits[c] |= map[c];
- for (c = 128; c < 256; c++)
+ if ((classmap[c/8] & (1 << (c&7))) != 0)
{
- if ((map[c/8] & (1 << (c&7))) != 0)
- {
- int d = (c >> 6) | 0xc0; /* Set bit for this starter */
- start_bits[d/8] |= (1 << (d&7)); /* and then skip on to the */
- c = (c & 0xc0) + 0x40 - 1; /* next relevant character. */
- }
+ int d = (c >> 6) | 0xc0; /* Set bit for this starter */
+ re->start_bitmap[d/8] |= (1 << (d&7)); /* and then skip on to the */
+ c = (c & 0xc0) + 0x40 - 1; /* next relevant character. */
}
}
- else
+ }
+ else
#endif
- {
- /* In non-UTF-8 mode, the two bit maps are completely compatible. */
- for (c = 0; c < 32; c++) start_bits[c] |= map[c];
- }
+ /* In all modes except UTF-8, the two bit maps are compatible. */
+
+ {
+ for (c = 0; c < 32; c++) re->start_bitmap[c] |= classmap[c];
}
+ }
- /* Advance past the bit map, and act on what follows. For a zero
- minimum repeat, continue; otherwise stop processing. */
+ /* Act on what follows the class. For a zero minimum repeat, continue;
+ otherwise stop processing. */
- switch (*tcode)
- {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- case OP_CRPOSSTAR:
- case OP_CRPOSQUERY:
- tcode++;
- break;
+ switch (*tcode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSQUERY:
+ tcode++;
+ break;
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- case OP_CRPOSRANGE:
- if (GET2(tcode, 1) == 0) tcode += 1 + 2 * IMM2_SIZE;
- else try_next = FALSE;
- break;
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ if (GET2(tcode, 1) == 0) tcode += 1 + 2 * IMM2_SIZE;
+ else try_next = FALSE;
+ break;
- default:
- try_next = FALSE;
- break;
- }
+ default:
+ try_next = FALSE;
+ break;
}
- break; /* End of bitmap class handling */
-
- } /* End of switch */
+ break; /* End of class handling case */
+ } /* End of switch for opcodes */
} /* End of try_next loop */
code += GET(code, 1); /* Advance to next branch */
}
while (*code == OP_ALT);
+
return yield;
}
-
-
/*************************************************
* Study a compiled expression *
*************************************************/
/* This function is handed a compiled expression that it must study to produce
-information that will speed up the matching. It returns a pcre[16]_extra block
-which then gets handed back to pcre_exec().
+information that will speed up the matching.
-Arguments:
- re points to the compiled expression
- options contains option bits
- errorptr points to where to place error messages;
- set NULL unless error
-
-Returns: pointer to a pcre[16]_extra block, with study_data filled in and
- the appropriate flags set;
- NULL on error or if no optimization possible
+Argument: points to the compiled expression
+Returns: 0 normally; non-zero should never normally occur
+ 1 unknown opcode in set_start_bits
+ 2 missing capturing bracket
+ 3 unknown opcode in find_minlength
*/
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN pcre_extra * PCRE_CALL_CONVENTION
-pcre_study(const pcre *external_re, int options, const char **errorptr)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN pcre16_extra * PCRE_CALL_CONVENTION
-pcre16_study(const pcre16 *external_re, int options, const char **errorptr)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN pcre32_extra * PCRE_CALL_CONVENTION
-pcre32_study(const pcre32 *external_re, int options, const char **errorptr)
-#endif
+int
+PRIV(study)(pcre2_real_code *re)
{
int min;
int count = 0;
-BOOL bits_set = FALSE;
-pcre_uint8 start_bits[32];
-PUBL(extra) *extra = NULL;
-pcre_study_data *study;
-const pcre_uint8 *tables;
-pcre_uchar *code;
-compile_data compile_block;
-const REAL_PCRE *re = (const REAL_PCRE *)external_re;
+PCRE2_UCHAR *code;
+BOOL utf = (re->overall_options & PCRE2_UTF) != 0;
+/* Find start of compiled code */
-*errorptr = NULL;
+code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) +
+ re->name_entry_size * re->name_count;
-if (re == NULL || re->magic_number != MAGIC_NUMBER)
- {
- *errorptr = "argument is not a compiled regular expression";
- return NULL;
- }
-
-if ((re->flags & PCRE_MODE) == 0)
- {
-#if defined COMPILE_PCRE8
- *errorptr = "argument not compiled in 8 bit mode";
-#elif defined COMPILE_PCRE16
- *errorptr = "argument not compiled in 16 bit mode";
-#elif defined COMPILE_PCRE32
- *errorptr = "argument not compiled in 32 bit mode";
-#endif
- return NULL;
- }
+/* For an anchored pattern, or an unanchored pattern that has a first code
+unit, or a multiline pattern that matches only at "line start", there is no
+point in seeking a list of starting code units. */
-if ((options & ~PUBLIC_STUDY_OPTIONS) != 0)
+if ((re->overall_options & PCRE2_ANCHORED) == 0 &&
+ (re->flags & (PCRE2_FIRSTSET|PCRE2_STARTLINE)) == 0)
{
- *errorptr = "unknown or incorrect option bit(s) set";
- return NULL;
+ int rc = set_start_bits(re, code, utf);
+ if (rc == SSB_UNKNOWN) return 1;
+ if (rc == SSB_DONE) re->flags |= PCRE2_FIRSTMAPSET;
}
-code = (pcre_uchar *)re + re->name_table_offset +
- (re->name_count * re->name_entry_size);
-
-/* For an anchored pattern, or an unanchored pattern that has a first char, or
-a multiline pattern that matches only at "line starts", there is no point in
-seeking a list of starting bytes. */
+/* Find the minimum length of subject string. If it can match an empty string,
+the minimum length is already known. */
-if ((re->options & PCRE_ANCHORED) == 0 &&
- (re->flags & (PCRE_FIRSTSET|PCRE_STARTLINE)) == 0)
+if ((re->flags & PCRE2_MATCH_EMPTY) == 0)
{
- int rc;
-
- /* Set the character tables in the block that is passed around */
-
- tables = re->tables;
-
-#if defined COMPILE_PCRE8
- if (tables == NULL)
- (void)pcre_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES,
- (void *)(&tables));
-#elif defined COMPILE_PCRE16
- if (tables == NULL)
- (void)pcre16_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES,
- (void *)(&tables));
-#elif defined COMPILE_PCRE32
- if (tables == NULL)
- (void)pcre32_fullinfo(external_re, NULL, PCRE_INFO_DEFAULT_TABLES,
- (void *)(&tables));
-#endif
-
- compile_block.lcc = tables + lcc_offset;
- compile_block.fcc = tables + fcc_offset;
- compile_block.cbits = tables + cbits_offset;
- compile_block.ctypes = tables + ctypes_offset;
-
- /* See if we can find a fixed set of initial characters for the pattern. */
-
- memset(start_bits, 0, 32 * sizeof(pcre_uint8));
- rc = set_start_bits(code, start_bits, (re->options & PCRE_UTF8) != 0,
- &compile_block);
- bits_set = rc == SSB_DONE;
- if (rc == SSB_UNKNOWN)
+ switch(min = find_minlength(re, code, code, utf, NULL, &count))
{
- *errorptr = "internal error: opcode not recognized";
- return NULL;
- }
- }
+ case -1: /* \C in UTF mode or (*ACCEPT) or over-complex regex */
+ break; /* Leave minlength unchanged (will be zero) */
-/* Find the minimum length of subject string. */
+ case -2:
+ return 2; /* missing capturing bracket */
-switch(min = find_minlength(re, code, code, re->options, NULL, &count))
- {
- case -2: *errorptr = "internal error: missing capturing bracket"; return NULL;
- case -3: *errorptr = "internal error: opcode not recognized"; return NULL;
- default: break;
- }
+ case -3:
+ return 3; /* unrecognized opcode */
-/* If a set of starting bytes has been identified, or if the minimum length is
-greater than zero, or if JIT optimization has been requested, or if
-PCRE_STUDY_EXTRA_NEEDED is set, get a pcre[16]_extra block and a
-pcre_study_data block. The study data is put in the latter, which is pointed to
-by the former, which may also get additional data set later by the calling
-program. At the moment, the size of pcre_study_data is fixed. We nevertheless
-save it in a field for returning via the pcre_fullinfo() function so that if it
-becomes variable in the future, we don't have to change that code. */
-
-if (bits_set || min > 0 || (options & (
-#ifdef SUPPORT_JIT
- PCRE_STUDY_JIT_COMPILE | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE |
- PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE |
-#endif
- PCRE_STUDY_EXTRA_NEEDED)) != 0)
- {
- extra = (PUBL(extra) *)(PUBL(malloc))
- (sizeof(PUBL(extra)) + sizeof(pcre_study_data));
- if (extra == NULL)
- {
- *errorptr = "failed to get memory";
- return NULL;
- }
-
- study = (pcre_study_data *)((char *)extra + sizeof(PUBL(extra)));
- extra->flags = PCRE_EXTRA_STUDY_DATA;
- extra->study_data = study;
-
- study->size = sizeof(pcre_study_data);
- study->flags = 0;
-
- /* Set the start bits always, to avoid unset memory errors if the
- study data is written to a file, but set the flag only if any of the bits
- are set, to save time looking when none are. */
-
- if (bits_set)
- {
- study->flags |= PCRE_STUDY_MAPPED;
- memcpy(study->start_bits, start_bits, sizeof(start_bits));
- }
- else memset(study->start_bits, 0, 32 * sizeof(pcre_uint8));
-
-#ifdef PCRE_DEBUG
- if (bits_set)
- {
- pcre_uint8 *ptr = start_bits;
- int i;
-
- printf("Start bits:\n");
- for (i = 0; i < 32; i++)
- printf("%3d: %02x%s", i * 8, *ptr++, ((i + 1) & 0x7) != 0? " " : "\n");
- }
-#endif
-
- /* Always set the minlength value in the block, because the JIT compiler
- makes use of it. However, don't set the bit unless the length is greater than
- zero - the interpretive pcre_exec() and pcre_dfa_exec() needn't waste time
- checking the zero case. */
-
- if (min > 0)
- {
- study->flags |= PCRE_STUDY_MINLEN;
- study->minlength = min;
- }
- else study->minlength = 0;
-
- /* If JIT support was compiled and requested, attempt the JIT compilation.
- If no starting bytes were found, and the minimum length is zero, and JIT
- compilation fails, abandon the extra block and return NULL, unless
- PCRE_STUDY_EXTRA_NEEDED is set. */
-
-#ifdef SUPPORT_JIT
- extra->executable_jit = NULL;
- if ((options & PCRE_STUDY_JIT_COMPILE) != 0)
- PRIV(jit_compile)(re, extra, JIT_COMPILE);
- if ((options & PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE) != 0)
- PRIV(jit_compile)(re, extra, JIT_PARTIAL_SOFT_COMPILE);
- if ((options & PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE) != 0)
- PRIV(jit_compile)(re, extra, JIT_PARTIAL_HARD_COMPILE);
-
- if (study->flags == 0 && (extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) == 0 &&
- (options & PCRE_STUDY_EXTRA_NEEDED) == 0)
- {
-#if defined COMPILE_PCRE8
- pcre_free_study(extra);
-#elif defined COMPILE_PCRE16
- pcre16_free_study(extra);
-#elif defined COMPILE_PCRE32
- pcre32_free_study(extra);
-#endif
- extra = NULL;
+ default:
+ if (min > UINT16_MAX) min = UINT16_MAX;
+ re->minlength = min;
+ break;
}
-#endif
}
-return extra;
-}
-
-
-/*************************************************
-* Free the study data *
-*************************************************/
-
-/* This function frees the memory that was obtained by pcre_study().
-
-Argument: a pointer to the pcre[16]_extra block
-Returns: nothing
-*/
-
-#if defined COMPILE_PCRE8
-PCRE_EXP_DEFN void
-pcre_free_study(pcre_extra *extra)
-#elif defined COMPILE_PCRE16
-PCRE_EXP_DEFN void
-pcre16_free_study(pcre16_extra *extra)
-#elif defined COMPILE_PCRE32
-PCRE_EXP_DEFN void
-pcre32_free_study(pcre32_extra *extra)
-#endif
-{
-if (extra == NULL)
- return;
-#ifdef SUPPORT_JIT
-if ((extra->flags & PCRE_EXTRA_EXECUTABLE_JIT) != 0 &&
- extra->executable_jit != NULL)
- PRIV(jit_free)(extra->executable_jit);
-#endif
-PUBL(free)(extra);
+return 0;
}
-/* End of pcre_study.c */
+/* End of pcre2_study.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_substitute.c b/src/3rdparty/pcre2/src/pcre2_substitute.c
new file mode 100644
index 0000000000..0bf781efc1
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_substitute.c
@@ -0,0 +1,850 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#define PTR_STACK_SIZE 20
+
+#define SUBSTITUTE_OPTIONS \
+ (PCRE2_SUBSTITUTE_EXTENDED|PCRE2_SUBSTITUTE_GLOBAL| \
+ PCRE2_SUBSTITUTE_OVERFLOW_LENGTH|PCRE2_SUBSTITUTE_UNKNOWN_UNSET| \
+ PCRE2_SUBSTITUTE_UNSET_EMPTY)
+
+
+
+/*************************************************
+* Find end of substitute text *
+*************************************************/
+
+/* In extended mode, we recognize ${name:+set text:unset text} and similar
+constructions. This requires the identification of unescaped : and }
+characters. This function scans for such. It must deal with nested ${
+constructions. The pointer to the text is updated, either to the required end
+character, or to where an error was detected.
+
+Arguments:
+ code points to the compiled expression (for options)
+ ptrptr points to the pointer to the start of the text (updated)
+ ptrend end of the whole string
+ last TRUE if the last expected string (only } recognized)
+
+Returns: 0 on success
+ negative error code on failure
+*/
+
+static int
+find_text_end(const pcre2_code *code, PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend,
+ BOOL last)
+{
+int rc = 0;
+uint32_t nestlevel = 0;
+BOOL literal = FALSE;
+PCRE2_SPTR ptr = *ptrptr;
+
+for (; ptr < ptrend; ptr++)
+ {
+ if (literal)
+ {
+ if (ptr[0] == CHAR_BACKSLASH && ptr < ptrend - 1 && ptr[1] == CHAR_E)
+ {
+ literal = FALSE;
+ ptr += 1;
+ }
+ }
+
+ else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ if (nestlevel == 0) goto EXIT;
+ nestlevel--;
+ }
+
+ else if (*ptr == CHAR_COLON && !last && nestlevel == 0) goto EXIT;
+
+ else if (*ptr == CHAR_DOLLAR_SIGN)
+ {
+ if (ptr < ptrend - 1 && ptr[1] == CHAR_LEFT_CURLY_BRACKET)
+ {
+ nestlevel++;
+ ptr += 1;
+ }
+ }
+
+ else if (*ptr == CHAR_BACKSLASH)
+ {
+ int erc;
+ int errorcode = 0;
+ uint32_t ch;
+
+ if (ptr < ptrend - 1) switch (ptr[1])
+ {
+ case CHAR_L:
+ case CHAR_l:
+ case CHAR_U:
+ case CHAR_u:
+ ptr += 1;
+ continue;
+ }
+
+ erc = PRIV(check_escape)(&ptr, ptrend, &ch, &errorcode,
+ code->overall_options, FALSE, NULL);
+ if (errorcode != 0)
+ {
+ rc = errorcode;
+ goto EXIT;
+ }
+
+ switch(erc)
+ {
+ case 0: /* Data character */
+ case ESC_E: /* Isolated \E is ignored */
+ break;
+
+ case ESC_Q:
+ literal = TRUE;
+ break;
+
+ default:
+ rc = PCRE2_ERROR_BADREPESCAPE;
+ goto EXIT;
+ }
+ }
+ }
+
+rc = PCRE2_ERROR_REPMISSINGBRACE; /* Terminator not found */
+
+EXIT:
+*ptrptr = ptr;
+return rc;
+}
+
+
+
+/*************************************************
+* Match and substitute *
+*************************************************/
+
+/* This function applies a compiled re to a subject string and creates a new
+string with substitutions. The first 7 arguments are the same as for
+pcre2_match(). Either string length may be PCRE2_ZERO_TERMINATED.
+
+Arguments:
+ code points to the compiled expression
+ subject points to the subject string
+ length length of subject string (may contain binary zeros)
+ start_offset where to start in the subject string
+ options option bits
+ match_data points to a match_data block, or is NULL
+ context points a PCRE2 context
+ replacement points to the replacement string
+ rlength length of replacement string
+ buffer where to put the substituted string
+ blength points to length of buffer; updated to length of string
+
+Returns: >= 0 number of substitutions made
+ < 0 an error code
+ PCRE2_ERROR_BADREPLACEMENT means invalid use of $
+*/
+
+/* This macro checks for space in the buffer before copying into it. On
+overflow, either give an error immediately, or keep on, accumulating the
+length. */
+
+#define CHECKMEMCPY(from,length) \
+ if (!overflowed && lengthleft < length) \
+ { \
+ if ((suboptions & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) == 0) goto NOROOM; \
+ overflowed = TRUE; \
+ extra_needed = length - lengthleft; \
+ } \
+ else if (overflowed) \
+ { \
+ extra_needed += length; \
+ } \
+ else \
+ { \
+ memcpy(buffer + buff_offset, from, CU2BYTES(length)); \
+ buff_offset += length; \
+ lengthleft -= length; \
+ }
+
+/* Here's the function */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substitute(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+ PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+ pcre2_match_context *mcontext, PCRE2_SPTR replacement, PCRE2_SIZE rlength,
+ PCRE2_UCHAR *buffer, PCRE2_SIZE *blength)
+{
+int rc;
+int subs;
+int forcecase = 0;
+int forcecasereset = 0;
+uint32_t ovector_count;
+uint32_t goptions = 0;
+uint32_t suboptions;
+BOOL match_data_created = FALSE;
+BOOL literal = FALSE;
+BOOL overflowed = FALSE;
+#ifdef SUPPORT_UNICODE
+BOOL utf = (code->overall_options & PCRE2_UTF) != 0;
+#endif
+PCRE2_UCHAR temp[6];
+PCRE2_SPTR ptr;
+PCRE2_SPTR repend;
+PCRE2_SIZE extra_needed = 0;
+PCRE2_SIZE buff_offset, buff_length, lengthleft, fraglength;
+PCRE2_SIZE *ovector;
+
+buff_offset = 0;
+lengthleft = buff_length = *blength;
+*blength = PCRE2_UNSET;
+
+/* Partial matching is not valid. */
+
+if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0)
+ return PCRE2_ERROR_BADOPTION;
+
+/* If no match data block is provided, create one. */
+
+if (match_data == NULL)
+ {
+ pcre2_general_context *gcontext = (mcontext == NULL)?
+ (pcre2_general_context *)code :
+ (pcre2_general_context *)mcontext;
+ match_data = pcre2_match_data_create_from_pattern(code, gcontext);
+ if (match_data == NULL) return PCRE2_ERROR_NOMEMORY;
+ match_data_created = TRUE;
+ }
+ovector = pcre2_get_ovector_pointer(match_data);
+ovector_count = pcre2_get_ovector_count(match_data);
+
+/* Find lengths of zero-terminated strings and the end of the replacement. */
+
+if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
+if (rlength == PCRE2_ZERO_TERMINATED) rlength = PRIV(strlen)(replacement);
+repend = replacement + rlength;
+
+/* Check UTF replacement string if necessary. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
+ {
+ rc = PRIV(valid_utf)(replacement, rlength, &(match_data->rightchar));
+ if (rc != 0)
+ {
+ match_data->leftchar = 0;
+ goto EXIT;
+ }
+ }
+#endif /* SUPPORT_UNICODE */
+
+/* Save the substitute options and remove them from the match options. */
+
+suboptions = options & SUBSTITUTE_OPTIONS;
+options &= ~SUBSTITUTE_OPTIONS;
+
+/* Copy up to the start offset */
+
+CHECKMEMCPY(subject, start_offset);
+
+/* Loop for global substituting. */
+
+subs = 0;
+do
+ {
+ PCRE2_SPTR ptrstack[PTR_STACK_SIZE];
+ uint32_t ptrstackptr = 0;
+
+ rc = pcre2_match(code, subject, length, start_offset, options|goptions,
+ match_data, mcontext);
+
+#ifdef SUPPORT_UNICODE
+ if (utf) options |= PCRE2_NO_UTF_CHECK; /* Only need to check once */
+#endif
+
+ /* Any error other than no match returns the error code. No match when not
+ doing the special after-empty-match global rematch, or when at the end of the
+ subject, breaks the global loop. Otherwise, advance the starting point by one
+ character, copying it to the output, and try again. */
+
+ if (rc < 0)
+ {
+ PCRE2_SIZE save_start;
+
+ if (rc != PCRE2_ERROR_NOMATCH) goto EXIT;
+ if (goptions == 0 || start_offset >= length) break;
+
+ /* Advance by one code point. Then, if CRLF is a valid newline sequence and
+ we have advanced into the middle of it, advance one more code point. In
+ other words, do not start in the middle of CRLF, even if CR and LF on their
+ own are valid newlines. */
+
+ save_start = start_offset++;
+ if (subject[start_offset-1] == CHAR_CR &&
+ code->newline_convention != PCRE2_NEWLINE_CR &&
+ code->newline_convention != PCRE2_NEWLINE_LF &&
+ start_offset < length &&
+ subject[start_offset] == CHAR_LF)
+ start_offset++;
+
+ /* Otherwise, in UTF mode, advance past any secondary code points. */
+
+ else if ((code->overall_options & PCRE2_UTF) != 0)
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ while (start_offset < length && (subject[start_offset] & 0xc0) == 0x80)
+ start_offset++;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ while (start_offset < length &&
+ (subject[start_offset] & 0xfc00) == 0xdc00)
+ start_offset++;
+#endif
+ }
+
+ /* Copy what we have advanced past, reset the special global options, and
+ continue to the next match. */
+
+ fraglength = start_offset - save_start;
+ CHECKMEMCPY(subject + save_start, fraglength);
+ goptions = 0;
+ continue;
+ }
+
+ /* Handle a successful match. Matches that use \K to end before they start
+ are not supported. */
+
+ if (ovector[1] < ovector[0])
+ {
+ rc = PCRE2_ERROR_BADSUBSPATTERN;
+ goto EXIT;
+ }
+
+ /* Count substitutions with a paranoid check for integer overflow; surely no
+ real call to this function would ever hit this! */
+
+ if (subs == INT_MAX)
+ {
+ rc = PCRE2_ERROR_TOOMANYREPLACE;
+ goto EXIT;
+ }
+ subs++;
+
+ /* Copy the text leading up to the match. */
+
+ if (rc == 0) rc = ovector_count;
+ fraglength = ovector[0] - start_offset;
+ CHECKMEMCPY(subject + start_offset, fraglength);
+
+ /* Process the replacement string. Literal mode is set by \Q, but only in
+ extended mode when backslashes are being interpreted. In extended mode we
+ must handle nested substrings that are to be reprocessed. */
+
+ ptr = replacement;
+ for (;;)
+ {
+ uint32_t ch;
+ unsigned int chlen;
+
+ /* If at the end of a nested substring, pop the stack. */
+
+ if (ptr >= repend)
+ {
+ if (ptrstackptr <= 0) break; /* End of replacement string */
+ repend = ptrstack[--ptrstackptr];
+ ptr = ptrstack[--ptrstackptr];
+ continue;
+ }
+
+ /* Handle the next character */
+
+ if (literal)
+ {
+ if (ptr[0] == CHAR_BACKSLASH && ptr < repend - 1 && ptr[1] == CHAR_E)
+ {
+ literal = FALSE;
+ ptr += 2;
+ continue;
+ }
+ goto LOADLITERAL;
+ }
+
+ /* Not in literal mode. */
+
+ if (*ptr == CHAR_DOLLAR_SIGN)
+ {
+ int group, n;
+ uint32_t special = 0;
+ BOOL inparens;
+ BOOL star;
+ PCRE2_SIZE sublength;
+ PCRE2_SPTR text1_start = NULL;
+ PCRE2_SPTR text1_end = NULL;
+ PCRE2_SPTR text2_start = NULL;
+ PCRE2_SPTR text2_end = NULL;
+ PCRE2_UCHAR next;
+ PCRE2_UCHAR name[33];
+
+ if (++ptr >= repend) goto BAD;
+ if ((next = *ptr) == CHAR_DOLLAR_SIGN) goto LOADLITERAL;
+
+ group = -1;
+ n = 0;
+ inparens = FALSE;
+ star = FALSE;
+
+ if (next == CHAR_LEFT_CURLY_BRACKET)
+ {
+ if (++ptr >= repend) goto BAD;
+ next = *ptr;
+ inparens = TRUE;
+ }
+
+ if (next == CHAR_ASTERISK)
+ {
+ if (++ptr >= repend) goto BAD;
+ next = *ptr;
+ star = TRUE;
+ }
+
+ if (!star && next >= CHAR_0 && next <= CHAR_9)
+ {
+ group = next - CHAR_0;
+ while (++ptr < repend)
+ {
+ next = *ptr;
+ if (next < CHAR_0 || next > CHAR_9) break;
+ group = group * 10 + next - CHAR_0;
+
+ /* A check for a number greater than the hightest captured group
+ is sufficient here; no need for a separate overflow check. If unknown
+ groups are to be treated as unset, just skip over any remaining
+ digits and carry on. */
+
+ if (group > code->top_bracket)
+ {
+ if ((suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+ {
+ while (++ptr < repend && *ptr >= CHAR_0 && *ptr <= CHAR_9);
+ break;
+ }
+ else
+ {
+ rc = PCRE2_ERROR_NOSUBSTRING;
+ goto PTREXIT;
+ }
+ }
+ }
+ }
+ else
+ {
+ const uint8_t *ctypes = code->tables + ctypes_offset;
+ while (MAX_255(next) && (ctypes[next] & ctype_word) != 0)
+ {
+ name[n++] = next;
+ if (n > 32) goto BAD;
+ if (++ptr >= repend) break;
+ next = *ptr;
+ }
+ if (n == 0) goto BAD;
+ name[n] = 0;
+ }
+
+ /* In extended mode we recognize ${name:+set text:unset text} and
+ ${name:-default text}. */
+
+ if (inparens)
+ {
+ if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 &&
+ !star && ptr < repend - 2 && next == CHAR_COLON)
+ {
+ special = *(++ptr);
+ if (special != CHAR_PLUS && special != CHAR_MINUS)
+ {
+ rc = PCRE2_ERROR_BADSUBSTITUTION;
+ goto PTREXIT;
+ }
+
+ text1_start = ++ptr;
+ rc = find_text_end(code, &ptr, repend, special == CHAR_MINUS);
+ if (rc != 0) goto PTREXIT;
+ text1_end = ptr;
+
+ if (special == CHAR_PLUS && *ptr == CHAR_COLON)
+ {
+ text2_start = ++ptr;
+ rc = find_text_end(code, &ptr, repend, TRUE);
+ if (rc != 0) goto PTREXIT;
+ text2_end = ptr;
+ }
+ }
+
+ else
+ {
+ if (ptr >= repend || *ptr != CHAR_RIGHT_CURLY_BRACKET)
+ {
+ rc = PCRE2_ERROR_REPMISSINGBRACE;
+ goto PTREXIT;
+ }
+ }
+
+ ptr++;
+ }
+
+ /* Have found a syntactically correct group number or name, or *name.
+ Only *MARK is currently recognized. */
+
+ if (star)
+ {
+ if (PRIV(strcmp_c8)(name, STRING_MARK) == 0)
+ {
+ PCRE2_SPTR mark = pcre2_get_mark(match_data);
+ if (mark != NULL)
+ {
+ PCRE2_SPTR mark_start = mark;
+ while (*mark != 0) mark++;
+ fraglength = mark - mark_start;
+ CHECKMEMCPY(mark_start, fraglength);
+ }
+ }
+ else goto BAD;
+ }
+
+ /* Substitute the contents of a group. We don't use substring_copy
+ functions any more, in order to support case forcing. */
+
+ else
+ {
+ PCRE2_SPTR subptr, subptrend;
+
+ /* Find a number for a named group. In case there are duplicate names,
+ search for the first one that is set. If the name is not found when
+ PCRE2_SUBSTITUTE_UNKNOWN_EMPTY is set, set the group number to a
+ non-existent group. */
+
+ if (group < 0)
+ {
+ PCRE2_SPTR first, last, entry;
+ rc = pcre2_substring_nametable_scan(code, name, &first, &last);
+ if (rc == PCRE2_ERROR_NOSUBSTRING &&
+ (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+ {
+ group = code->top_bracket + 1;
+ }
+ else
+ {
+ if (rc < 0) goto PTREXIT;
+ for (entry = first; entry <= last; entry += rc)
+ {
+ uint32_t ng = GET2(entry, 0);
+ if (ng < ovector_count)
+ {
+ if (group < 0) group = ng; /* First in ovector */
+ if (ovector[ng*2] != PCRE2_UNSET)
+ {
+ group = ng; /* First that is set */
+ break;
+ }
+ }
+ }
+
+ /* If group is still negative, it means we did not find a group
+ that is in the ovector. Just set the first group. */
+
+ if (group < 0) group = GET2(first, 0);
+ }
+ }
+
+ /* We now have a group that is identified by number. Find the length of
+ the captured string. If a group in a non-special substitution is unset
+ when PCRE2_SUBSTITUTE_UNSET_EMPTY is set, substitute nothing. */
+
+ rc = pcre2_substring_length_bynumber(match_data, group, &sublength);
+ if (rc < 0)
+ {
+ if (rc == PCRE2_ERROR_NOSUBSTRING &&
+ (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+ {
+ rc = PCRE2_ERROR_UNSET;
+ }
+ if (rc != PCRE2_ERROR_UNSET) goto PTREXIT; /* Non-unset errors */
+ if (special == 0) /* Plain substitution */
+ {
+ if ((suboptions & PCRE2_SUBSTITUTE_UNSET_EMPTY) != 0) continue;
+ goto PTREXIT; /* Else error */
+ }
+ }
+
+ /* If special is '+' we have a 'set' and possibly an 'unset' text,
+ both of which are reprocessed when used. If special is '-' we have a
+ default text for when the group is unset; it must be reprocessed. */
+
+ if (special != 0)
+ {
+ if (special == CHAR_MINUS)
+ {
+ if (rc == 0) goto LITERAL_SUBSTITUTE;
+ text2_start = text1_start;
+ text2_end = text1_end;
+ }
+
+ if (ptrstackptr >= PTR_STACK_SIZE) goto BAD;
+ ptrstack[ptrstackptr++] = ptr;
+ ptrstack[ptrstackptr++] = repend;
+
+ if (rc == 0)
+ {
+ ptr = text1_start;
+ repend = text1_end;
+ }
+ else
+ {
+ ptr = text2_start;
+ repend = text2_end;
+ }
+ continue;
+ }
+
+ /* Otherwise we have a literal substitution of a group's contents. */
+
+ LITERAL_SUBSTITUTE:
+ subptr = subject + ovector[group*2];
+ subptrend = subject + ovector[group*2 + 1];
+
+ /* Substitute a literal string, possibly forcing alphabetic case. */
+
+ while (subptr < subptrend)
+ {
+ GETCHARINCTEST(ch, subptr);
+ if (forcecase != 0)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t type = UCD_CHARTYPE(ch);
+ if (PRIV(ucp_gentype)[type] == ucp_L &&
+ type != ((forcecase > 0)? ucp_Lu : ucp_Ll))
+ ch = UCD_OTHERCASE(ch);
+ }
+ else
+#endif
+ {
+ if (((code->tables + cbits_offset +
+ ((forcecase > 0)? cbit_upper:cbit_lower)
+ )[ch/8] & (1 << (ch%8))) == 0)
+ ch = (code->tables + fcc_offset)[ch];
+ }
+ forcecase = forcecasereset;
+ }
+
+#ifdef SUPPORT_UNICODE
+ if (utf) chlen = PRIV(ord2utf)(ch, temp); else
+#endif
+ {
+ temp[0] = ch;
+ chlen = 1;
+ }
+ CHECKMEMCPY(temp, chlen);
+ }
+ }
+ }
+
+ /* Handle an escape sequence in extended mode. We can use check_escape()
+ to process \Q, \E, \c, \o, \x and \ followed by non-alphanumerics, but
+ the case-forcing escapes are not supported in pcre2_compile() so must be
+ recognized here. */
+
+ else if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 &&
+ *ptr == CHAR_BACKSLASH)
+ {
+ int errorcode = 0;
+
+ if (ptr < repend - 1) switch (ptr[1])
+ {
+ case CHAR_L:
+ forcecase = forcecasereset = -1;
+ ptr += 2;
+ continue;
+
+ case CHAR_l:
+ forcecase = -1;
+ forcecasereset = 0;
+ ptr += 2;
+ continue;
+
+ case CHAR_U:
+ forcecase = forcecasereset = 1;
+ ptr += 2;
+ continue;
+
+ case CHAR_u:
+ forcecase = 1;
+ forcecasereset = 0;
+ ptr += 2;
+ continue;
+
+ default:
+ break;
+ }
+
+ rc = PRIV(check_escape)(&ptr, repend, &ch, &errorcode,
+ code->overall_options, FALSE, NULL);
+ if (errorcode != 0) goto BADESCAPE;
+ ptr++;
+
+ switch(rc)
+ {
+ case ESC_E:
+ forcecase = forcecasereset = 0;
+ continue;
+
+ case ESC_Q:
+ literal = TRUE;
+ continue;
+
+ case 0: /* Data character */
+ goto LITERAL;
+
+ default:
+ goto BADESCAPE;
+ }
+ }
+
+ /* Handle a literal code unit */
+
+ else
+ {
+ LOADLITERAL:
+ GETCHARINCTEST(ch, ptr); /* Get character value, increment pointer */
+
+ LITERAL:
+ if (forcecase != 0)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t type = UCD_CHARTYPE(ch);
+ if (PRIV(ucp_gentype)[type] == ucp_L &&
+ type != ((forcecase > 0)? ucp_Lu : ucp_Ll))
+ ch = UCD_OTHERCASE(ch);
+ }
+ else
+#endif
+ {
+ if (((code->tables + cbits_offset +
+ ((forcecase > 0)? cbit_upper:cbit_lower)
+ )[ch/8] & (1 << (ch%8))) == 0)
+ ch = (code->tables + fcc_offset)[ch];
+ }
+ forcecase = forcecasereset;
+ }
+
+#ifdef SUPPORT_UNICODE
+ if (utf) chlen = PRIV(ord2utf)(ch, temp); else
+#endif
+ {
+ temp[0] = ch;
+ chlen = 1;
+ }
+ CHECKMEMCPY(temp, chlen);
+ } /* End handling a literal code unit */
+ } /* End of loop for scanning the replacement. */
+
+ /* The replacement has been copied to the output. Update the start offset to
+ point to the rest of the subject string. If we matched an empty string,
+ do the magic for global matches. */
+
+ start_offset = ovector[1];
+ goptions = (ovector[0] != ovector[1])? 0 :
+ PCRE2_ANCHORED|PCRE2_NOTEMPTY_ATSTART;
+ } while ((suboptions & PCRE2_SUBSTITUTE_GLOBAL) != 0); /* Repeat "do" loop */
+
+/* Copy the rest of the subject. */
+
+fraglength = length - start_offset;
+CHECKMEMCPY(subject + start_offset, fraglength);
+temp[0] = 0;
+CHECKMEMCPY(temp , 1);
+
+/* If overflowed is set it means the PCRE2_SUBSTITUTE_OVERFLOW_LENGTH is set,
+and matching has carried on after a full buffer, in order to compute the length
+needed. Otherwise, an overflow generates an immediate error return. */
+
+if (overflowed)
+ {
+ rc = PCRE2_ERROR_NOMEMORY;
+ *blength = buff_length + extra_needed;
+ }
+
+/* After a successful execution, return the number of substitutions and set the
+length of buffer used, excluding the trailing zero. */
+
+else
+ {
+ rc = subs;
+ *blength = buff_offset - 1;
+ }
+
+EXIT:
+if (match_data_created) pcre2_match_data_free(match_data);
+ else match_data->rc = rc;
+return rc;
+
+NOROOM:
+rc = PCRE2_ERROR_NOMEMORY;
+goto EXIT;
+
+BAD:
+rc = PCRE2_ERROR_BADREPLACEMENT;
+goto PTREXIT;
+
+BADESCAPE:
+rc = PCRE2_ERROR_BADREPESCAPE;
+
+PTREXIT:
+*blength = (PCRE2_SIZE)(ptr - replacement);
+goto EXIT;
+}
+
+/* End of pcre2_substitute.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_substring.c b/src/3rdparty/pcre2/src/pcre2_substring.c
new file mode 100644
index 0000000000..f6d7c39722
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_substring.c
@@ -0,0 +1,542 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+* Copy named captured string to given buffer *
+*************************************************/
+
+/* This function copies a single captured substring into a given buffer,
+identifying it by name. If the regex permits duplicate names, the first
+substring that is set is chosen.
+
+Arguments:
+ match_data points to the match data
+ stringname the name of the required substring
+ buffer where to put the substring
+ sizeptr the size of the buffer, updated to the size of the substring
+
+Returns: if successful: zero
+ if not successful, a negative error code:
+ (1) an error from nametable_scan()
+ (2) an error from copy_bynumber()
+ (3) PCRE2_ERROR_UNAVAILABLE: no group is in ovector
+ (4) PCRE2_ERROR_UNSET: all named groups in ovector are unset
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_copy_byname(pcre2_match_data *match_data, PCRE2_SPTR stringname,
+ PCRE2_UCHAR *buffer, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SPTR first, last, entry;
+int failrc, entrysize;
+if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
+ return PCRE2_ERROR_DFA_UFUNC;
+entrysize = pcre2_substring_nametable_scan(match_data->code, stringname,
+ &first, &last);
+if (entrysize < 0) return entrysize;
+failrc = PCRE2_ERROR_UNAVAILABLE;
+for (entry = first; entry <= last; entry += entrysize)
+ {
+ uint32_t n = GET2(entry, 0);
+ if (n < match_data->oveccount)
+ {
+ if (match_data->ovector[n*2] != PCRE2_UNSET)
+ return pcre2_substring_copy_bynumber(match_data, n, buffer, sizeptr);
+ failrc = PCRE2_ERROR_UNSET;
+ }
+ }
+return failrc;
+}
+
+
+
+/*************************************************
+* Copy numbered captured string to given buffer *
+*************************************************/
+
+/* This function copies a single captured substring into a given buffer,
+identifying it by number.
+
+Arguments:
+ match_data points to the match data
+ stringnumber the number of the required substring
+ buffer where to put the substring
+ sizeptr the size of the buffer, updated to the size of the substring
+
+Returns: if successful: 0
+ if not successful, a negative error code:
+ PCRE2_ERROR_NOMEMORY: buffer too small
+ PCRE2_ERROR_NOSUBSTRING: no such substring
+ PCRE2_ERROR_UNAVAILABLE: ovector too small
+ PCRE2_ERROR_UNSET: substring is not set
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_copy_bynumber(pcre2_match_data *match_data,
+ uint32_t stringnumber, PCRE2_UCHAR *buffer, PCRE2_SIZE *sizeptr)
+{
+int rc;
+PCRE2_SIZE size;
+rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size);
+if (rc < 0) return rc;
+if (size + 1 > *sizeptr) return PCRE2_ERROR_NOMEMORY;
+memcpy(buffer, match_data->subject + match_data->ovector[stringnumber*2],
+ CU2BYTES(size));
+buffer[size] = 0;
+*sizeptr = size;
+return 0;
+}
+
+
+
+/*************************************************
+* Extract named captured string *
+*************************************************/
+
+/* This function copies a single captured substring, identified by name, into
+new memory. If the regex permits duplicate names, the first substring that is
+set is chosen.
+
+Arguments:
+ match_data pointer to match_data
+ stringname the name of the required substring
+ stringptr where to put the pointer to the new memory
+ sizeptr where to put the length of the substring
+
+Returns: if successful: zero
+ if not successful, a negative value:
+ (1) an error from nametable_scan()
+ (2) an error from get_bynumber()
+ (3) PCRE2_ERROR_UNAVAILABLE: no group is in ovector
+ (4) PCRE2_ERROR_UNSET: all named groups in ovector are unset
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_get_byname(pcre2_match_data *match_data,
+ PCRE2_SPTR stringname, PCRE2_UCHAR **stringptr, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SPTR first, last, entry;
+int failrc, entrysize;
+if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
+ return PCRE2_ERROR_DFA_UFUNC;
+entrysize = pcre2_substring_nametable_scan(match_data->code, stringname,
+ &first, &last);
+if (entrysize < 0) return entrysize;
+failrc = PCRE2_ERROR_UNAVAILABLE;
+for (entry = first; entry <= last; entry += entrysize)
+ {
+ uint32_t n = GET2(entry, 0);
+ if (n < match_data->oveccount)
+ {
+ if (match_data->ovector[n*2] != PCRE2_UNSET)
+ return pcre2_substring_get_bynumber(match_data, n, stringptr, sizeptr);
+ failrc = PCRE2_ERROR_UNSET;
+ }
+ }
+return failrc;
+}
+
+
+
+/*************************************************
+* Extract captured string to new memory *
+*************************************************/
+
+/* This function copies a single captured substring into a piece of new
+memory.
+
+Arguments:
+ match_data points to match data
+ stringnumber the number of the required substring
+ stringptr where to put a pointer to the new memory
+ sizeptr where to put the size of the substring
+
+Returns: if successful: 0
+ if not successful, a negative error code:
+ PCRE2_ERROR_NOMEMORY: failed to get memory
+ PCRE2_ERROR_NOSUBSTRING: no such substring
+ PCRE2_ERROR_UNAVAILABLE: ovector too small
+ PCRE2_ERROR_UNSET: substring is not set
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_get_bynumber(pcre2_match_data *match_data,
+ uint32_t stringnumber, PCRE2_UCHAR **stringptr, PCRE2_SIZE *sizeptr)
+{
+int rc;
+PCRE2_SIZE size;
+PCRE2_UCHAR *yield;
+rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size);
+if (rc < 0) return rc;
+yield = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
+ (size + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)match_data);
+if (yield == NULL) return PCRE2_ERROR_NOMEMORY;
+yield = (PCRE2_UCHAR *)(((char *)yield) + sizeof(pcre2_memctl));
+memcpy(yield, match_data->subject + match_data->ovector[stringnumber*2],
+ CU2BYTES(size));
+yield[size] = 0;
+*stringptr = yield;
+*sizeptr = size;
+return 0;
+}
+
+
+
+/*************************************************
+* Free memory obtained by get_substring *
+*************************************************/
+
+/*
+Argument: the result of a previous pcre2_substring_get_byxxx()
+Returns: nothing
+*/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_substring_free(PCRE2_UCHAR *string)
+{
+if (string != NULL)
+ {
+ pcre2_memctl *memctl = (pcre2_memctl *)((char *)string - sizeof(pcre2_memctl));
+ memctl->free(memctl, memctl->memory_data);
+ }
+}
+
+
+
+/*************************************************
+* Get length of a named substring *
+*************************************************/
+
+/* This function returns the length of a named captured substring. If the regex
+permits duplicate names, the first substring that is set is chosen.
+
+Arguments:
+ match_data pointer to match data
+ stringname the name of the required substring
+ sizeptr where to put the length
+
+Returns: 0 if successful, else a negative error number
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_length_byname(pcre2_match_data *match_data,
+ PCRE2_SPTR stringname, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SPTR first, last, entry;
+int failrc, entrysize;
+if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
+ return PCRE2_ERROR_DFA_UFUNC;
+entrysize = pcre2_substring_nametable_scan(match_data->code, stringname,
+ &first, &last);
+if (entrysize < 0) return entrysize;
+failrc = PCRE2_ERROR_UNAVAILABLE;
+for (entry = first; entry <= last; entry += entrysize)
+ {
+ uint32_t n = GET2(entry, 0);
+ if (n < match_data->oveccount)
+ {
+ if (match_data->ovector[n*2] != PCRE2_UNSET)
+ return pcre2_substring_length_bynumber(match_data, n, sizeptr);
+ failrc = PCRE2_ERROR_UNSET;
+ }
+ }
+return failrc;
+}
+
+
+
+/*************************************************
+* Get length of a numbered substring *
+*************************************************/
+
+/* This function returns the length of a captured substring. If the start is
+beyond the end (which can happen when \K is used in an assertion), it sets the
+length to zero.
+
+Arguments:
+ match_data pointer to match data
+ stringnumber the number of the required substring
+ sizeptr where to put the length, if not NULL
+
+Returns: if successful: 0
+ if not successful, a negative error code:
+ PCRE2_ERROR_NOSUBSTRING: no such substring
+ PCRE2_ERROR_UNAVAILABLE: ovector is too small
+ PCRE2_ERROR_UNSET: substring is not set
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_length_bynumber(pcre2_match_data *match_data,
+ uint32_t stringnumber, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SIZE left, right;
+int count = match_data->rc;
+if (count == PCRE2_ERROR_PARTIAL)
+ {
+ if (stringnumber > 0) return PCRE2_ERROR_PARTIAL;
+ count = 0;
+ }
+else if (count < 0) return count; /* Match failed */
+
+if (match_data->matchedby != PCRE2_MATCHEDBY_DFA_INTERPRETER)
+ {
+ if (stringnumber > match_data->code->top_bracket)
+ return PCRE2_ERROR_NOSUBSTRING;
+ if (stringnumber >= match_data->oveccount)
+ return PCRE2_ERROR_UNAVAILABLE;
+ if (match_data->ovector[stringnumber*2] == PCRE2_UNSET)
+ return PCRE2_ERROR_UNSET;
+ }
+else /* Matched using pcre2_dfa_match() */
+ {
+ if (stringnumber >= match_data->oveccount) return PCRE2_ERROR_UNAVAILABLE;
+ if (count != 0 && stringnumber >= (uint32_t)count) return PCRE2_ERROR_UNSET;
+ }
+
+left = match_data->ovector[stringnumber*2];
+right = match_data->ovector[stringnumber*2+1];
+if (sizeptr != NULL) *sizeptr = (left > right)? 0 : right - left;
+return 0;
+}
+
+
+
+/*************************************************
+* Extract all captured strings to new memory *
+*************************************************/
+
+/* This function gets one chunk of memory and builds a list of pointers and all
+the captured substrings in it. A NULL pointer is put on the end of the list.
+The substrings are zero-terminated, but also, if the final argument is
+non-NULL, a list of lengths is also returned. This allows binary data to be
+handled.
+
+Arguments:
+ match_data points to the match data
+ listptr set to point to the list of pointers
+ lengthsptr set to point to the list of lengths (may be NULL)
+
+Returns: if successful: 0
+ if not successful, a negative error code:
+ PCRE2_ERROR_NOMEMORY: failed to get memory,
+ or a match failure code
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_list_get(pcre2_match_data *match_data, PCRE2_UCHAR ***listptr,
+ PCRE2_SIZE **lengthsptr)
+{
+int i, count, count2;
+PCRE2_SIZE size;
+PCRE2_SIZE *lensp;
+pcre2_memctl *memp;
+PCRE2_UCHAR **listp;
+PCRE2_UCHAR *sp;
+PCRE2_SIZE *ovector;
+
+if ((count = match_data->rc) < 0) return count; /* Match failed */
+if (count == 0) count = match_data->oveccount; /* Ovector too small */
+
+count2 = 2*count;
+ovector = match_data->ovector;
+size = sizeof(pcre2_memctl) + sizeof(PCRE2_UCHAR *); /* For final NULL */
+if (lengthsptr != NULL) size += sizeof(PCRE2_SIZE) * count; /* For lengths */
+
+for (i = 0; i < count2; i += 2)
+ {
+ size += sizeof(PCRE2_UCHAR *) + CU2BYTES(1);
+ if (ovector[i+1] > ovector[i]) size += CU2BYTES(ovector[i+1] - ovector[i]);
+ }
+
+memp = PRIV(memctl_malloc)(size, (pcre2_memctl *)match_data);
+if (memp == NULL) return PCRE2_ERROR_NOMEMORY;
+
+*listptr = listp = (PCRE2_UCHAR **)((char *)memp + sizeof(pcre2_memctl));
+lensp = (PCRE2_SIZE *)((char *)listp + sizeof(PCRE2_UCHAR *) * (count + 1));
+
+if (lengthsptr == NULL)
+ {
+ sp = (PCRE2_UCHAR *)lensp;
+ lensp = NULL;
+ }
+else
+ {
+ *lengthsptr = lensp;
+ sp = (PCRE2_UCHAR *)((char *)lensp + sizeof(PCRE2_SIZE) * count);
+ }
+
+for (i = 0; i < count2; i += 2)
+ {
+ size = (ovector[i+1] > ovector[i])? (ovector[i+1] - ovector[i]) : 0;
+ memcpy(sp, match_data->subject + ovector[i], CU2BYTES(size));
+ *listp++ = sp;
+ if (lensp != NULL) *lensp++ = size;
+ sp += size;
+ *sp++ = 0;
+ }
+
+*listp = NULL;
+return 0;
+}
+
+
+
+/*************************************************
+* Free memory obtained by substring_list_get *
+*************************************************/
+
+/*
+Argument: the result of a previous pcre2_substring_list_get()
+Returns: nothing
+*/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_substring_list_free(PCRE2_SPTR *list)
+{
+if (list != NULL)
+ {
+ pcre2_memctl *memctl = (pcre2_memctl *)((char *)list - sizeof(pcre2_memctl));
+ memctl->free(memctl, memctl->memory_data);
+ }
+}
+
+
+
+/*************************************************
+* Find (multiple) entries for named string *
+*************************************************/
+
+/* This function scans the nametable for a given name, using binary chop. It
+returns either two pointers to the entries in the table, or, if no pointers are
+given, the number of a unique group with the given name. If duplicate names are
+permitted, and the name is not unique, an error is generated.
+
+Arguments:
+ code the compiled regex
+ stringname the name whose entries required
+ firstptr where to put the pointer to the first entry
+ lastptr where to put the pointer to the last entry
+
+Returns: PCRE2_ERROR_NOSUBSTRING if the name is not found
+ otherwise, if firstptr and lastptr are NULL:
+ a group number for a unique substring
+ else PCRE2_ERROR_NOUNIQUESUBSTRING
+ otherwise:
+ the length of each entry, having set firstptr and lastptr
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_nametable_scan(const pcre2_code *code, PCRE2_SPTR stringname,
+ PCRE2_SPTR *firstptr, PCRE2_SPTR *lastptr)
+{
+uint16_t bot = 0;
+uint16_t top = code->name_count;
+uint16_t entrysize = code->name_entry_size;
+PCRE2_SPTR nametable = (PCRE2_SPTR)((char *)code + sizeof(pcre2_real_code));
+
+while (top > bot)
+ {
+ uint16_t mid = (top + bot) / 2;
+ PCRE2_SPTR entry = nametable + entrysize*mid;
+ int c = PRIV(strcmp)(stringname, entry + IMM2_SIZE);
+ if (c == 0)
+ {
+ PCRE2_SPTR first;
+ PCRE2_SPTR last;
+ PCRE2_SPTR lastentry;
+ lastentry = nametable + entrysize * (code->name_count - 1);
+ first = last = entry;
+ while (first > nametable)
+ {
+ if (PRIV(strcmp)(stringname, (first - entrysize + IMM2_SIZE)) != 0) break;
+ first -= entrysize;
+ }
+ while (last < lastentry)
+ {
+ if (PRIV(strcmp)(stringname, (last + entrysize + IMM2_SIZE)) != 0) break;
+ last += entrysize;
+ }
+ if (firstptr == NULL) return (first == last)?
+ (int)GET2(entry, 0) : PCRE2_ERROR_NOUNIQUESUBSTRING;
+ *firstptr = first;
+ *lastptr = last;
+ return entrysize;
+ }
+ if (c > 0) bot = mid + 1; else top = mid;
+ }
+
+return PCRE2_ERROR_NOSUBSTRING;
+}
+
+
+/*************************************************
+* Find number for named string *
+*************************************************/
+
+/* This function is a convenience wrapper for pcre2_substring_nametable_scan()
+when it is known that names are unique. If there are duplicate names, it is not
+defined which number is returned.
+
+Arguments:
+ code the compiled regex
+ stringname the name whose number is required
+
+Returns: the number of the named parenthesis, or a negative number
+ PCRE2_ERROR_NOSUBSTRING if not found
+ PCRE2_ERROR_NOUNIQUESUBSTRING if not unique
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_number_from_name(const pcre2_code *code,
+ PCRE2_SPTR stringname)
+{
+return pcre2_substring_nametable_scan(code, stringname, NULL, NULL);
+}
+
+/* End of pcre2_substring.c */
diff --git a/src/3rdparty/pcre/pcre_tables.c b/src/3rdparty/pcre2/src/pcre2_tables.c
index 4960af57c4..b945ed7a7f 100644
--- a/src/3rdparty/pcre/pcre_tables.c
+++ b/src/3rdparty/pcre2/src/pcre2_tables.c
@@ -6,7 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -37,46 +38,64 @@ POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
-#ifndef PCRE_INCLUDED
-
/* This module contains some fixed tables that are used by more than one of the
-PCRE code modules. The tables are also #included by the pcretest program, which
-uses macros to change their names from _pcre_xxx to xxxx, thereby avoiding name
-clashes with the library. */
-
+PCRE code modules. The tables are also #included by the pcre2test program,
+which uses macros to change their names from _pcre2_xxx to xxxx, thereby
+avoiding name clashes with the library. In this case, PCRE2_PCRE2TEST is
+defined. */
+#ifndef PCRE2_PCRE2TEST /* We're compiling the library */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#include "pcre2_internal.h"
+#endif /* PCRE2_PCRE2TEST */
-#include "pcre_internal.h"
-
-#endif /* PCRE_INCLUDED */
/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
-the definition is next to the definition of the opcodes in pcre_internal.h. */
+the definition is next to the definition of the opcodes in pcre2_internal.h.
+This is mode-dependent, so is skipped when this file is included by pcre2test. */
-const pcre_uint8 PRIV(OP_lengths)[] = { OP_LENGTHS };
+#ifndef PCRE2_PCRE2TEST
+const uint8_t PRIV(OP_lengths)[] = { OP_LENGTHS };
+#endif
/* Tables of horizontal and vertical whitespace characters, suitable for
adding to classes. */
-const pcre_uint32 PRIV(hspace_list)[] = { HSPACE_LIST };
-const pcre_uint32 PRIV(vspace_list)[] = { VSPACE_LIST };
+const uint32_t PRIV(hspace_list)[] = { HSPACE_LIST };
+const uint32_t PRIV(vspace_list)[] = { VSPACE_LIST };
+
+/* These tables are the pairs of delimiters that are valid for callout string
+arguments. For each starting delimiter there must be a matching ending
+delimiter, which in fact is different only for bracket-like delimiters. */
+
+const uint32_t PRIV(callout_start_delims)[] = {
+ CHAR_GRAVE_ACCENT, CHAR_APOSTROPHE, CHAR_QUOTATION_MARK,
+ CHAR_CIRCUMFLEX_ACCENT, CHAR_PERCENT_SIGN, CHAR_NUMBER_SIGN,
+ CHAR_DOLLAR_SIGN, CHAR_LEFT_CURLY_BRACKET, 0 };
+const uint32_t PRIV(callout_end_delims[]) = {
+ CHAR_GRAVE_ACCENT, CHAR_APOSTROPHE, CHAR_QUOTATION_MARK,
+ CHAR_CIRCUMFLEX_ACCENT, CHAR_PERCENT_SIGN, CHAR_NUMBER_SIGN,
+ CHAR_DOLLAR_SIGN, CHAR_RIGHT_CURLY_BRACKET, 0 };
/*************************************************
* Tables for UTF-8 support *
*************************************************/
-/* These are the breakpoints for different numbers of bytes in a UTF-8
-character. */
+/* These tables are required by pcre2test in 16- or 32-bit mode, as well
+as for the library in 8-bit mode, because pcre2test uses UTF-8 internally for
+handling wide characters. */
-#if (defined SUPPORT_UTF && defined COMPILE_PCRE8) \
- || (defined PCRE_INCLUDED && (defined SUPPORT_PCRE16 || defined SUPPORT_PCRE32))
+#if defined PCRE2_PCRE2TEST || \
+ (defined SUPPORT_UNICODE && \
+ defined PCRE2_CODE_UNIT_WIDTH && \
+ PCRE2_CODE_UNIT_WIDTH == 8)
-/* These tables are also required by pcretest in 16- or 32-bit mode. */
+/* These are the breakpoints for different numbers of bytes in a UTF-8
+character. */
const int PRIV(utf8_table1)[] =
{ 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
@@ -92,19 +111,20 @@ const int PRIV(utf8_table3)[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
/* Table of the number of extra bytes, indexed by the first byte masked with
0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */
-const pcre_uint8 PRIV(utf8_table4)[] = {
+const uint8_t PRIV(utf8_table4)[] = {
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,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
-#endif /* (SUPPORT_UTF && COMPILE_PCRE8) || (PCRE_INCLUDED && SUPPORT_PCRE[16|32])*/
+#endif /* UTF-8 support needed */
+
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
/* Table to translate from particular type value to the general value. */
-const pcre_uint32 PRIV(ucp_gentype)[] = {
+const uint32_t PRIV(ucp_gentype)[] = {
ucp_C, ucp_C, ucp_C, ucp_C, ucp_C, /* Cc, Cf, Cn, Co, Cs */
ucp_L, ucp_L, ucp_L, ucp_L, ucp_L, /* Ll, Lu, Lm, Lo, Lt */
ucp_M, ucp_M, ucp_M, /* Mc, Me, Mn */
@@ -117,11 +137,11 @@ const pcre_uint32 PRIV(ucp_gentype)[] = {
/* This table encodes the rules for finding the end of an extended grapheme
cluster. Every code point has a grapheme break property which is one of the
-ucp_gbXX values defined in ucp.h. The 2-dimensional table is indexed by the
-properties of two adjacent code points. The left property selects a word from
-the table, and the right property selects a bit from that word like this:
+ucp_gbXX values defined in pcre2_ucp.h. The 2-dimensional table is indexed by
+the properties of two adjacent code points. The left property selects a word
+from the table, and the right property selects a bit from that word like this:
- ucp_gbtable[left-property] & (1 << right-property)
+ PRIV(ucp_gbtable)[left-property] & (1 << right-property)
The value is non-zero if a grapheme break is NOT permitted between the relevant
two code points. The breaking rules are as follows:
@@ -149,7 +169,7 @@ are implementing).
7. Otherwise, break everywhere.
*/
-const pcre_uint32 PRIV(ucp_gbtable[]) = {
+const uint32_t PRIV(ucp_gbtable)[] = {
(1<<ucp_gbLF), /* 0 CR */
0, /* 1 LF */
0, /* 2 Control */
@@ -190,7 +210,7 @@ const int PRIV(ucp_typerange)[] = {
};
#endif /* SUPPORT_JIT */
-/* The pcre_utt[] table below translates Unicode property names into type and
+/* The PRIV(utt)[] table below translates Unicode property names into type and
code values. It is searched by binary chop, so must be in collating sequence of
name. Originally, the table contained pointers to the name strings in the first
field of each entry. However, that leads to a large number of relocations when
@@ -207,6 +227,8 @@ version. Like all other character and string literals that are compared against
the regular expression pattern, we must use STR_ macros instead of literal
strings to make sure that UTF-8 support works on EBCDIC platforms. */
+#define STRING_Ahom0 STR_A STR_h STR_o STR_m "\0"
+#define STRING_Anatolian_Hieroglyphs0 STR_A STR_n STR_a STR_t STR_o STR_l STR_i STR_a STR_n STR_UNDERSCORE STR_H STR_i STR_e STR_r STR_o STR_g STR_l STR_y STR_p STR_h STR_s "\0"
#define STRING_Any0 STR_A STR_n STR_y "\0"
#define STRING_Arabic0 STR_A STR_r STR_a STR_b STR_i STR_c "\0"
#define STRING_Armenian0 STR_A STR_r STR_m STR_e STR_n STR_i STR_a STR_n "\0"
@@ -254,6 +276,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Han0 STR_H STR_a STR_n "\0"
#define STRING_Hangul0 STR_H STR_a STR_n STR_g STR_u STR_l "\0"
#define STRING_Hanunoo0 STR_H STR_a STR_n STR_u STR_n STR_o STR_o "\0"
+#define STRING_Hatran0 STR_H STR_a STR_t STR_r STR_a STR_n "\0"
#define STRING_Hebrew0 STR_H STR_e STR_b STR_r STR_e STR_w "\0"
#define STRING_Hiragana0 STR_H STR_i STR_r STR_a STR_g STR_a STR_n STR_a "\0"
#define STRING_Imperial_Aramaic0 STR_I STR_m STR_p STR_e STR_r STR_i STR_a STR_l STR_UNDERSCORE STR_A STR_r STR_a STR_m STR_a STR_i STR_c "\0"
@@ -301,6 +324,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Modi0 STR_M STR_o STR_d STR_i "\0"
#define STRING_Mongolian0 STR_M STR_o STR_n STR_g STR_o STR_l STR_i STR_a STR_n "\0"
#define STRING_Mro0 STR_M STR_r STR_o "\0"
+#define STRING_Multani0 STR_M STR_u STR_l STR_t STR_a STR_n STR_i "\0"
#define STRING_Myanmar0 STR_M STR_y STR_a STR_n STR_m STR_a STR_r "\0"
#define STRING_N0 STR_N "\0"
#define STRING_Nabataean0 STR_N STR_a STR_b STR_a STR_t STR_a STR_e STR_a STR_n "\0"
@@ -311,6 +335,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_No0 STR_N STR_o "\0"
#define STRING_Ogham0 STR_O STR_g STR_h STR_a STR_m "\0"
#define STRING_Ol_Chiki0 STR_O STR_l STR_UNDERSCORE STR_C STR_h STR_i STR_k STR_i "\0"
+#define STRING_Old_Hungarian0 STR_O STR_l STR_d STR_UNDERSCORE STR_H STR_u STR_n STR_g STR_a STR_r STR_i STR_a STR_n "\0"
#define STRING_Old_Italic0 STR_O STR_l STR_d STR_UNDERSCORE STR_I STR_t STR_a STR_l STR_i STR_c "\0"
#define STRING_Old_North_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_N STR_o STR_r STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0"
#define STRING_Old_Permic0 STR_O STR_l STR_d STR_UNDERSCORE STR_P STR_e STR_r STR_m STR_i STR_c "\0"
@@ -342,6 +367,7 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Sharada0 STR_S STR_h STR_a STR_r STR_a STR_d STR_a "\0"
#define STRING_Shavian0 STR_S STR_h STR_a STR_v STR_i STR_a STR_n "\0"
#define STRING_Siddham0 STR_S STR_i STR_d STR_d STR_h STR_a STR_m "\0"
+#define STRING_SignWriting0 STR_S STR_i STR_g STR_n STR_W STR_r STR_i STR_t STR_i STR_n STR_g "\0"
#define STRING_Sinhala0 STR_S STR_i STR_n STR_h STR_a STR_l STR_a "\0"
#define STRING_Sk0 STR_S STR_k "\0"
#define STRING_Sm0 STR_S STR_m "\0"
@@ -378,6 +404,8 @@ strings to make sure that UTF-8 support works on EBCDIC platforms. */
#define STRING_Zs0 STR_Z STR_s "\0"
const char PRIV(utt_names)[] =
+ STRING_Ahom0
+ STRING_Anatolian_Hieroglyphs0
STRING_Any0
STRING_Arabic0
STRING_Armenian0
@@ -425,6 +453,7 @@ const char PRIV(utt_names)[] =
STRING_Han0
STRING_Hangul0
STRING_Hanunoo0
+ STRING_Hatran0
STRING_Hebrew0
STRING_Hiragana0
STRING_Imperial_Aramaic0
@@ -472,6 +501,7 @@ const char PRIV(utt_names)[] =
STRING_Modi0
STRING_Mongolian0
STRING_Mro0
+ STRING_Multani0
STRING_Myanmar0
STRING_N0
STRING_Nabataean0
@@ -482,6 +512,7 @@ const char PRIV(utt_names)[] =
STRING_No0
STRING_Ogham0
STRING_Ol_Chiki0
+ STRING_Old_Hungarian0
STRING_Old_Italic0
STRING_Old_North_Arabian0
STRING_Old_Permic0
@@ -513,6 +544,7 @@ const char PRIV(utt_names)[] =
STRING_Sharada0
STRING_Shavian0
STRING_Siddham0
+ STRING_SignWriting0
STRING_Sinhala0
STRING_Sk0
STRING_Sm0
@@ -549,179 +581,185 @@ const char PRIV(utt_names)[] =
STRING_Zs0;
const ucp_type_table PRIV(utt)[] = {
- { 0, PT_ANY, 0 },
- { 4, PT_SC, ucp_Arabic },
- { 11, PT_SC, ucp_Armenian },
- { 20, PT_SC, ucp_Avestan },
- { 28, PT_SC, ucp_Balinese },
- { 37, PT_SC, ucp_Bamum },
- { 43, PT_SC, ucp_Bassa_Vah },
- { 53, PT_SC, ucp_Batak },
- { 59, PT_SC, ucp_Bengali },
- { 67, PT_SC, ucp_Bopomofo },
- { 76, PT_SC, ucp_Brahmi },
- { 83, PT_SC, ucp_Braille },
- { 91, PT_SC, ucp_Buginese },
- { 100, PT_SC, ucp_Buhid },
- { 106, PT_GC, ucp_C },
- { 108, PT_SC, ucp_Canadian_Aboriginal },
- { 128, PT_SC, ucp_Carian },
- { 135, PT_SC, ucp_Caucasian_Albanian },
- { 154, PT_PC, ucp_Cc },
- { 157, PT_PC, ucp_Cf },
- { 160, PT_SC, ucp_Chakma },
- { 167, PT_SC, ucp_Cham },
- { 172, PT_SC, ucp_Cherokee },
- { 181, PT_PC, ucp_Cn },
- { 184, PT_PC, ucp_Co },
- { 187, PT_SC, ucp_Common },
- { 194, PT_SC, ucp_Coptic },
- { 201, PT_PC, ucp_Cs },
- { 204, PT_SC, ucp_Cuneiform },
- { 214, PT_SC, ucp_Cypriot },
- { 222, PT_SC, ucp_Cyrillic },
- { 231, PT_SC, ucp_Deseret },
- { 239, PT_SC, ucp_Devanagari },
- { 250, PT_SC, ucp_Duployan },
- { 259, PT_SC, ucp_Egyptian_Hieroglyphs },
- { 280, PT_SC, ucp_Elbasan },
- { 288, PT_SC, ucp_Ethiopic },
- { 297, PT_SC, ucp_Georgian },
- { 306, PT_SC, ucp_Glagolitic },
- { 317, PT_SC, ucp_Gothic },
- { 324, PT_SC, ucp_Grantha },
- { 332, PT_SC, ucp_Greek },
- { 338, PT_SC, ucp_Gujarati },
- { 347, PT_SC, ucp_Gurmukhi },
- { 356, PT_SC, ucp_Han },
- { 360, PT_SC, ucp_Hangul },
- { 367, PT_SC, ucp_Hanunoo },
- { 375, PT_SC, ucp_Hebrew },
- { 382, PT_SC, ucp_Hiragana },
- { 391, PT_SC, ucp_Imperial_Aramaic },
- { 408, PT_SC, ucp_Inherited },
- { 418, PT_SC, ucp_Inscriptional_Pahlavi },
- { 440, PT_SC, ucp_Inscriptional_Parthian },
- { 463, PT_SC, ucp_Javanese },
- { 472, PT_SC, ucp_Kaithi },
- { 479, PT_SC, ucp_Kannada },
- { 487, PT_SC, ucp_Katakana },
- { 496, PT_SC, ucp_Kayah_Li },
- { 505, PT_SC, ucp_Kharoshthi },
- { 516, PT_SC, ucp_Khmer },
- { 522, PT_SC, ucp_Khojki },
- { 529, PT_SC, ucp_Khudawadi },
- { 539, PT_GC, ucp_L },
- { 541, PT_LAMP, 0 },
- { 544, PT_SC, ucp_Lao },
- { 548, PT_SC, ucp_Latin },
- { 554, PT_SC, ucp_Lepcha },
- { 561, PT_SC, ucp_Limbu },
- { 567, PT_SC, ucp_Linear_A },
- { 576, PT_SC, ucp_Linear_B },
- { 585, PT_SC, ucp_Lisu },
- { 590, PT_PC, ucp_Ll },
- { 593, PT_PC, ucp_Lm },
- { 596, PT_PC, ucp_Lo },
- { 599, PT_PC, ucp_Lt },
- { 602, PT_PC, ucp_Lu },
- { 605, PT_SC, ucp_Lycian },
- { 612, PT_SC, ucp_Lydian },
- { 619, PT_GC, ucp_M },
- { 621, PT_SC, ucp_Mahajani },
- { 630, PT_SC, ucp_Malayalam },
- { 640, PT_SC, ucp_Mandaic },
- { 648, PT_SC, ucp_Manichaean },
- { 659, PT_PC, ucp_Mc },
- { 662, PT_PC, ucp_Me },
- { 665, PT_SC, ucp_Meetei_Mayek },
- { 678, PT_SC, ucp_Mende_Kikakui },
- { 692, PT_SC, ucp_Meroitic_Cursive },
- { 709, PT_SC, ucp_Meroitic_Hieroglyphs },
- { 730, PT_SC, ucp_Miao },
- { 735, PT_PC, ucp_Mn },
- { 738, PT_SC, ucp_Modi },
- { 743, PT_SC, ucp_Mongolian },
- { 753, PT_SC, ucp_Mro },
- { 757, PT_SC, ucp_Myanmar },
- { 765, PT_GC, ucp_N },
- { 767, PT_SC, ucp_Nabataean },
- { 777, PT_PC, ucp_Nd },
- { 780, PT_SC, ucp_New_Tai_Lue },
- { 792, PT_SC, ucp_Nko },
- { 796, PT_PC, ucp_Nl },
- { 799, PT_PC, ucp_No },
- { 802, PT_SC, ucp_Ogham },
- { 808, PT_SC, ucp_Ol_Chiki },
- { 817, PT_SC, ucp_Old_Italic },
- { 828, PT_SC, ucp_Old_North_Arabian },
- { 846, PT_SC, ucp_Old_Permic },
- { 857, PT_SC, ucp_Old_Persian },
- { 869, PT_SC, ucp_Old_South_Arabian },
- { 887, PT_SC, ucp_Old_Turkic },
- { 898, PT_SC, ucp_Oriya },
- { 904, PT_SC, ucp_Osmanya },
- { 912, PT_GC, ucp_P },
- { 914, PT_SC, ucp_Pahawh_Hmong },
- { 927, PT_SC, ucp_Palmyrene },
- { 937, PT_SC, ucp_Pau_Cin_Hau },
- { 949, PT_PC, ucp_Pc },
- { 952, PT_PC, ucp_Pd },
- { 955, PT_PC, ucp_Pe },
- { 958, PT_PC, ucp_Pf },
- { 961, PT_SC, ucp_Phags_Pa },
- { 970, PT_SC, ucp_Phoenician },
- { 981, PT_PC, ucp_Pi },
- { 984, PT_PC, ucp_Po },
- { 987, PT_PC, ucp_Ps },
- { 990, PT_SC, ucp_Psalter_Pahlavi },
- { 1006, PT_SC, ucp_Rejang },
- { 1013, PT_SC, ucp_Runic },
- { 1019, PT_GC, ucp_S },
- { 1021, PT_SC, ucp_Samaritan },
- { 1031, PT_SC, ucp_Saurashtra },
- { 1042, PT_PC, ucp_Sc },
- { 1045, PT_SC, ucp_Sharada },
- { 1053, PT_SC, ucp_Shavian },
- { 1061, PT_SC, ucp_Siddham },
- { 1069, PT_SC, ucp_Sinhala },
- { 1077, PT_PC, ucp_Sk },
- { 1080, PT_PC, ucp_Sm },
- { 1083, PT_PC, ucp_So },
- { 1086, PT_SC, ucp_Sora_Sompeng },
- { 1099, PT_SC, ucp_Sundanese },
- { 1109, PT_SC, ucp_Syloti_Nagri },
- { 1122, PT_SC, ucp_Syriac },
- { 1129, PT_SC, ucp_Tagalog },
- { 1137, PT_SC, ucp_Tagbanwa },
- { 1146, PT_SC, ucp_Tai_Le },
- { 1153, PT_SC, ucp_Tai_Tham },
- { 1162, PT_SC, ucp_Tai_Viet },
- { 1171, PT_SC, ucp_Takri },
- { 1177, PT_SC, ucp_Tamil },
- { 1183, PT_SC, ucp_Telugu },
- { 1190, PT_SC, ucp_Thaana },
- { 1197, PT_SC, ucp_Thai },
- { 1202, PT_SC, ucp_Tibetan },
- { 1210, PT_SC, ucp_Tifinagh },
- { 1219, PT_SC, ucp_Tirhuta },
- { 1227, PT_SC, ucp_Ugaritic },
- { 1236, PT_SC, ucp_Vai },
- { 1240, PT_SC, ucp_Warang_Citi },
- { 1252, PT_ALNUM, 0 },
- { 1256, PT_PXSPACE, 0 },
- { 1260, PT_SPACE, 0 },
- { 1264, PT_UCNC, 0 },
- { 1268, PT_WORD, 0 },
- { 1272, PT_SC, ucp_Yi },
- { 1275, PT_GC, ucp_Z },
- { 1277, PT_PC, ucp_Zl },
- { 1280, PT_PC, ucp_Zp },
- { 1283, PT_PC, ucp_Zs }
+ { 0, PT_SC, ucp_Ahom },
+ { 5, PT_SC, ucp_Anatolian_Hieroglyphs },
+ { 27, PT_ANY, 0 },
+ { 31, PT_SC, ucp_Arabic },
+ { 38, PT_SC, ucp_Armenian },
+ { 47, PT_SC, ucp_Avestan },
+ { 55, PT_SC, ucp_Balinese },
+ { 64, PT_SC, ucp_Bamum },
+ { 70, PT_SC, ucp_Bassa_Vah },
+ { 80, PT_SC, ucp_Batak },
+ { 86, PT_SC, ucp_Bengali },
+ { 94, PT_SC, ucp_Bopomofo },
+ { 103, PT_SC, ucp_Brahmi },
+ { 110, PT_SC, ucp_Braille },
+ { 118, PT_SC, ucp_Buginese },
+ { 127, PT_SC, ucp_Buhid },
+ { 133, PT_GC, ucp_C },
+ { 135, PT_SC, ucp_Canadian_Aboriginal },
+ { 155, PT_SC, ucp_Carian },
+ { 162, PT_SC, ucp_Caucasian_Albanian },
+ { 181, PT_PC, ucp_Cc },
+ { 184, PT_PC, ucp_Cf },
+ { 187, PT_SC, ucp_Chakma },
+ { 194, PT_SC, ucp_Cham },
+ { 199, PT_SC, ucp_Cherokee },
+ { 208, PT_PC, ucp_Cn },
+ { 211, PT_PC, ucp_Co },
+ { 214, PT_SC, ucp_Common },
+ { 221, PT_SC, ucp_Coptic },
+ { 228, PT_PC, ucp_Cs },
+ { 231, PT_SC, ucp_Cuneiform },
+ { 241, PT_SC, ucp_Cypriot },
+ { 249, PT_SC, ucp_Cyrillic },
+ { 258, PT_SC, ucp_Deseret },
+ { 266, PT_SC, ucp_Devanagari },
+ { 277, PT_SC, ucp_Duployan },
+ { 286, PT_SC, ucp_Egyptian_Hieroglyphs },
+ { 307, PT_SC, ucp_Elbasan },
+ { 315, PT_SC, ucp_Ethiopic },
+ { 324, PT_SC, ucp_Georgian },
+ { 333, PT_SC, ucp_Glagolitic },
+ { 344, PT_SC, ucp_Gothic },
+ { 351, PT_SC, ucp_Grantha },
+ { 359, PT_SC, ucp_Greek },
+ { 365, PT_SC, ucp_Gujarati },
+ { 374, PT_SC, ucp_Gurmukhi },
+ { 383, PT_SC, ucp_Han },
+ { 387, PT_SC, ucp_Hangul },
+ { 394, PT_SC, ucp_Hanunoo },
+ { 402, PT_SC, ucp_Hatran },
+ { 409, PT_SC, ucp_Hebrew },
+ { 416, PT_SC, ucp_Hiragana },
+ { 425, PT_SC, ucp_Imperial_Aramaic },
+ { 442, PT_SC, ucp_Inherited },
+ { 452, PT_SC, ucp_Inscriptional_Pahlavi },
+ { 474, PT_SC, ucp_Inscriptional_Parthian },
+ { 497, PT_SC, ucp_Javanese },
+ { 506, PT_SC, ucp_Kaithi },
+ { 513, PT_SC, ucp_Kannada },
+ { 521, PT_SC, ucp_Katakana },
+ { 530, PT_SC, ucp_Kayah_Li },
+ { 539, PT_SC, ucp_Kharoshthi },
+ { 550, PT_SC, ucp_Khmer },
+ { 556, PT_SC, ucp_Khojki },
+ { 563, PT_SC, ucp_Khudawadi },
+ { 573, PT_GC, ucp_L },
+ { 575, PT_LAMP, 0 },
+ { 578, PT_SC, ucp_Lao },
+ { 582, PT_SC, ucp_Latin },
+ { 588, PT_SC, ucp_Lepcha },
+ { 595, PT_SC, ucp_Limbu },
+ { 601, PT_SC, ucp_Linear_A },
+ { 610, PT_SC, ucp_Linear_B },
+ { 619, PT_SC, ucp_Lisu },
+ { 624, PT_PC, ucp_Ll },
+ { 627, PT_PC, ucp_Lm },
+ { 630, PT_PC, ucp_Lo },
+ { 633, PT_PC, ucp_Lt },
+ { 636, PT_PC, ucp_Lu },
+ { 639, PT_SC, ucp_Lycian },
+ { 646, PT_SC, ucp_Lydian },
+ { 653, PT_GC, ucp_M },
+ { 655, PT_SC, ucp_Mahajani },
+ { 664, PT_SC, ucp_Malayalam },
+ { 674, PT_SC, ucp_Mandaic },
+ { 682, PT_SC, ucp_Manichaean },
+ { 693, PT_PC, ucp_Mc },
+ { 696, PT_PC, ucp_Me },
+ { 699, PT_SC, ucp_Meetei_Mayek },
+ { 712, PT_SC, ucp_Mende_Kikakui },
+ { 726, PT_SC, ucp_Meroitic_Cursive },
+ { 743, PT_SC, ucp_Meroitic_Hieroglyphs },
+ { 764, PT_SC, ucp_Miao },
+ { 769, PT_PC, ucp_Mn },
+ { 772, PT_SC, ucp_Modi },
+ { 777, PT_SC, ucp_Mongolian },
+ { 787, PT_SC, ucp_Mro },
+ { 791, PT_SC, ucp_Multani },
+ { 799, PT_SC, ucp_Myanmar },
+ { 807, PT_GC, ucp_N },
+ { 809, PT_SC, ucp_Nabataean },
+ { 819, PT_PC, ucp_Nd },
+ { 822, PT_SC, ucp_New_Tai_Lue },
+ { 834, PT_SC, ucp_Nko },
+ { 838, PT_PC, ucp_Nl },
+ { 841, PT_PC, ucp_No },
+ { 844, PT_SC, ucp_Ogham },
+ { 850, PT_SC, ucp_Ol_Chiki },
+ { 859, PT_SC, ucp_Old_Hungarian },
+ { 873, PT_SC, ucp_Old_Italic },
+ { 884, PT_SC, ucp_Old_North_Arabian },
+ { 902, PT_SC, ucp_Old_Permic },
+ { 913, PT_SC, ucp_Old_Persian },
+ { 925, PT_SC, ucp_Old_South_Arabian },
+ { 943, PT_SC, ucp_Old_Turkic },
+ { 954, PT_SC, ucp_Oriya },
+ { 960, PT_SC, ucp_Osmanya },
+ { 968, PT_GC, ucp_P },
+ { 970, PT_SC, ucp_Pahawh_Hmong },
+ { 983, PT_SC, ucp_Palmyrene },
+ { 993, PT_SC, ucp_Pau_Cin_Hau },
+ { 1005, PT_PC, ucp_Pc },
+ { 1008, PT_PC, ucp_Pd },
+ { 1011, PT_PC, ucp_Pe },
+ { 1014, PT_PC, ucp_Pf },
+ { 1017, PT_SC, ucp_Phags_Pa },
+ { 1026, PT_SC, ucp_Phoenician },
+ { 1037, PT_PC, ucp_Pi },
+ { 1040, PT_PC, ucp_Po },
+ { 1043, PT_PC, ucp_Ps },
+ { 1046, PT_SC, ucp_Psalter_Pahlavi },
+ { 1062, PT_SC, ucp_Rejang },
+ { 1069, PT_SC, ucp_Runic },
+ { 1075, PT_GC, ucp_S },
+ { 1077, PT_SC, ucp_Samaritan },
+ { 1087, PT_SC, ucp_Saurashtra },
+ { 1098, PT_PC, ucp_Sc },
+ { 1101, PT_SC, ucp_Sharada },
+ { 1109, PT_SC, ucp_Shavian },
+ { 1117, PT_SC, ucp_Siddham },
+ { 1125, PT_SC, ucp_SignWriting },
+ { 1137, PT_SC, ucp_Sinhala },
+ { 1145, PT_PC, ucp_Sk },
+ { 1148, PT_PC, ucp_Sm },
+ { 1151, PT_PC, ucp_So },
+ { 1154, PT_SC, ucp_Sora_Sompeng },
+ { 1167, PT_SC, ucp_Sundanese },
+ { 1177, PT_SC, ucp_Syloti_Nagri },
+ { 1190, PT_SC, ucp_Syriac },
+ { 1197, PT_SC, ucp_Tagalog },
+ { 1205, PT_SC, ucp_Tagbanwa },
+ { 1214, PT_SC, ucp_Tai_Le },
+ { 1221, PT_SC, ucp_Tai_Tham },
+ { 1230, PT_SC, ucp_Tai_Viet },
+ { 1239, PT_SC, ucp_Takri },
+ { 1245, PT_SC, ucp_Tamil },
+ { 1251, PT_SC, ucp_Telugu },
+ { 1258, PT_SC, ucp_Thaana },
+ { 1265, PT_SC, ucp_Thai },
+ { 1270, PT_SC, ucp_Tibetan },
+ { 1278, PT_SC, ucp_Tifinagh },
+ { 1287, PT_SC, ucp_Tirhuta },
+ { 1295, PT_SC, ucp_Ugaritic },
+ { 1304, PT_SC, ucp_Vai },
+ { 1308, PT_SC, ucp_Warang_Citi },
+ { 1320, PT_ALNUM, 0 },
+ { 1324, PT_PXSPACE, 0 },
+ { 1328, PT_SPACE, 0 },
+ { 1332, PT_UCNC, 0 },
+ { 1336, PT_WORD, 0 },
+ { 1340, PT_SC, ucp_Yi },
+ { 1343, PT_GC, ucp_Z },
+ { 1345, PT_PC, ucp_Zl },
+ { 1348, PT_PC, ucp_Zp },
+ { 1351, PT_PC, ucp_Zs }
};
-const int PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);
+const size_t PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);
-#endif /* SUPPORT_UTF */
+#endif /* SUPPORT_UNICODE */
-/* End of pcre_tables.c */
+/* End of pcre2_tables.c */
diff --git a/src/3rdparty/pcre/pcre_ucd.c b/src/3rdparty/pcre2/src/pcre2_ucd.c
index 69c4fd42c3..116f537b38 100644
--- a/src/3rdparty/pcre/pcre_ucd.c
+++ b/src/3rdparty/pcre2/src/pcre2_ucd.c
@@ -2,28 +2,29 @@
Do not modify it by hand. Instead modify the script and run it
to regenerate this code.
-As well as being part of the PCRE library, this module is #included
-by the pcretest program, which redefines the PRIV macro to change
-table names from _pcre_xxx to xxxx, thereby avoiding name clashes
+As well as being part of the PCRE2 library, this module is #included
+by the pcre2test program, which redefines the PRIV macro to change
+table names from _pcre2_xxx to xxxx, thereby avoiding name clashes
with the library. At present, just one of these tables is actually
needed. */
-#ifndef PCRE_INCLUDED
+#ifndef PCRE2_PCRE2TEST
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include "pcre_internal.h"
+#include "pcre2_internal.h"
-#endif /* PCRE_INCLUDED */
+#endif /* PCRE2_PCRE2TEST */
/* Unicode character database. */
/* This file was autogenerated by the MultiStage2.py script. */
-/* Total size: 72576 bytes, block size: 128. */
+/* Total size: 75072 bytes, block size: 128. */
-/* The tables herein are needed only when UCP support is built
-into PCRE. This module should not be referenced otherwise, so
+/* The tables herein are needed only when UCP support is built,
+and in PCRE2 that happens automatically with UTF support.
+This module should not be referenced otherwise, so
it should not matter whether it is compiled or not. However
a comment was received about space saving - maybe the guy linked
all the modules rather than using a library - so we include a
@@ -31,28 +32,30 @@ condition to cut out the tables when not needed. But don't leave
a totally empty module because some compilers barf at that.
Instead, just supply small dummy tables. */
-#ifndef SUPPORT_UCP
+#ifndef SUPPORT_UNICODE
const ucd_record PRIV(ucd_records)[] = {{0,0,0,0,0 }};
-const pcre_uint8 PRIV(ucd_stage1)[] = {0};
-const pcre_uint16 PRIV(ucd_stage2)[] = {0};
-const pcre_uint32 PRIV(ucd_caseless_sets)[] = {0};
+const uint8_t PRIV(ucd_stage1)[] = {0};
+const uint16_t PRIV(ucd_stage2)[] = {0};
+const uint32_t PRIV(ucd_caseless_sets)[] = {0};
#else
+const char *PRIV(unicode_version) = "8.0.0";
+
/* When recompiling tables with a new Unicode version, please check the
-types in this structure definition from pcre_internal.h (the actual
+types in this structure definition from pcre2_internal.h (the actual
field names will be different):
typedef struct {
-pcre_uint8 property_0;
-pcre_uint8 property_1;
-pcre_uint8 property_2;
-pcre_uint8 property_3;
+uint8_t property_0;
+uint8_t property_1;
+uint8_t property_2;
+uint8_t property_3;
pcre_int32 property_4;
} ucd_record;
*/
-const pcre_uint32 PRIV(ucd_caseless_sets)[] = {
+const uint32_t PRIV(ucd_caseless_sets)[] = {
NOTACHAR,
0x0053, 0x0073, 0x017f, NOTACHAR,
0x01c4, 0x01c5, 0x01c6, NOTACHAR,
@@ -75,11 +78,11 @@ const pcre_uint32 PRIV(ucd_caseless_sets)[] = {
0x00c5, 0x00e5, 0x212b, NOTACHAR,
};
-/* When #included in pcretest, we don't need this large table. */
+/* When #included in pcre2test, we don't need this large table. */
-#ifndef PCRE_INCLUDED
+#ifndef PCRE2_PCRE2TEST
-const ucd_record PRIV(ucd_records)[] = { /* 5760 bytes, record size 8 */
+const ucd_record PRIV(ucd_records)[] = { /* 5952 bytes, record size 8 */
{ 9, 0, 2, 0, 0, }, /* 0 */
{ 9, 0, 1, 0, 0, }, /* 1 */
{ 9, 0, 0, 0, 0, }, /* 2 */
@@ -185,624 +188,648 @@ const ucd_record PRIV(ucd_records)[] = { /* 5760 bytes, record size 8 */
{ 33, 5, 12, 0, -217, }, /* 102 */
{ 33, 5, 12, 0, -71, }, /* 103 */
{ 33, 5, 12, 0, -219, }, /* 104 */
- { 33, 5, 12, 0, 42258, }, /* 105 */
- { 33, 6, 12, 0, 0, }, /* 106 */
- { 9, 6, 12, 0, 0, }, /* 107 */
- { 3, 24, 12, 0, 0, }, /* 108 */
- { 27, 12, 3, 0, 0, }, /* 109 */
- { 27, 12, 3, 21, 116, }, /* 110 */
- { 19, 9, 12, 0, 1, }, /* 111 */
- { 19, 5, 12, 0, -1, }, /* 112 */
- { 19, 24, 12, 0, 0, }, /* 113 */
- { 9, 2, 12, 0, 0, }, /* 114 */
- { 19, 6, 12, 0, 0, }, /* 115 */
- { 19, 5, 12, 0, 130, }, /* 116 */
- { 19, 9, 12, 0, 116, }, /* 117 */
- { 19, 9, 12, 0, 38, }, /* 118 */
- { 19, 9, 12, 0, 37, }, /* 119 */
- { 19, 9, 12, 0, 64, }, /* 120 */
- { 19, 9, 12, 0, 63, }, /* 121 */
- { 19, 5, 12, 0, 0, }, /* 122 */
- { 19, 9, 12, 0, 32, }, /* 123 */
- { 19, 9, 12, 34, 32, }, /* 124 */
- { 19, 9, 12, 59, 32, }, /* 125 */
- { 19, 9, 12, 38, 32, }, /* 126 */
- { 19, 9, 12, 21, 32, }, /* 127 */
- { 19, 9, 12, 51, 32, }, /* 128 */
- { 19, 9, 12, 26, 32, }, /* 129 */
- { 19, 9, 12, 47, 32, }, /* 130 */
- { 19, 9, 12, 55, 32, }, /* 131 */
- { 19, 9, 12, 30, 32, }, /* 132 */
- { 19, 9, 12, 43, 32, }, /* 133 */
- { 19, 9, 12, 67, 32, }, /* 134 */
- { 19, 5, 12, 0, -38, }, /* 135 */
- { 19, 5, 12, 0, -37, }, /* 136 */
- { 19, 5, 12, 0, -32, }, /* 137 */
- { 19, 5, 12, 34, -32, }, /* 138 */
- { 19, 5, 12, 59, -32, }, /* 139 */
- { 19, 5, 12, 38, -32, }, /* 140 */
- { 19, 5, 12, 21, -116, }, /* 141 */
- { 19, 5, 12, 51, -32, }, /* 142 */
- { 19, 5, 12, 26, -775, }, /* 143 */
- { 19, 5, 12, 47, -32, }, /* 144 */
- { 19, 5, 12, 55, -32, }, /* 145 */
- { 19, 5, 12, 30, 1, }, /* 146 */
- { 19, 5, 12, 30, -32, }, /* 147 */
- { 19, 5, 12, 43, -32, }, /* 148 */
- { 19, 5, 12, 67, -32, }, /* 149 */
- { 19, 5, 12, 0, -64, }, /* 150 */
- { 19, 5, 12, 0, -63, }, /* 151 */
- { 19, 9, 12, 0, 8, }, /* 152 */
- { 19, 5, 12, 34, -30, }, /* 153 */
- { 19, 5, 12, 38, -25, }, /* 154 */
- { 19, 9, 12, 0, 0, }, /* 155 */
- { 19, 5, 12, 43, -15, }, /* 156 */
- { 19, 5, 12, 47, -22, }, /* 157 */
- { 19, 5, 12, 0, -8, }, /* 158 */
- { 10, 9, 12, 0, 1, }, /* 159 */
- { 10, 5, 12, 0, -1, }, /* 160 */
- { 19, 5, 12, 51, -54, }, /* 161 */
- { 19, 5, 12, 55, -48, }, /* 162 */
- { 19, 5, 12, 0, 7, }, /* 163 */
- { 19, 5, 12, 0, -116, }, /* 164 */
- { 19, 9, 12, 38, -60, }, /* 165 */
- { 19, 5, 12, 59, -64, }, /* 166 */
- { 19, 25, 12, 0, 0, }, /* 167 */
- { 19, 9, 12, 0, -7, }, /* 168 */
- { 19, 9, 12, 0, -130, }, /* 169 */
- { 12, 9, 12, 0, 80, }, /* 170 */
- { 12, 9, 12, 0, 32, }, /* 171 */
- { 12, 5, 12, 0, -32, }, /* 172 */
- { 12, 5, 12, 0, -80, }, /* 173 */
- { 12, 9, 12, 0, 1, }, /* 174 */
- { 12, 5, 12, 0, -1, }, /* 175 */
- { 12, 26, 12, 0, 0, }, /* 176 */
- { 12, 12, 3, 0, 0, }, /* 177 */
- { 12, 11, 3, 0, 0, }, /* 178 */
- { 12, 9, 12, 0, 15, }, /* 179 */
- { 12, 5, 12, 0, -15, }, /* 180 */
- { 1, 9, 12, 0, 48, }, /* 181 */
- { 1, 6, 12, 0, 0, }, /* 182 */
- { 1, 21, 12, 0, 0, }, /* 183 */
- { 1, 5, 12, 0, -48, }, /* 184 */
- { 1, 5, 12, 0, 0, }, /* 185 */
- { 1, 17, 12, 0, 0, }, /* 186 */
- { 1, 26, 12, 0, 0, }, /* 187 */
- { 1, 23, 12, 0, 0, }, /* 188 */
- { 25, 12, 3, 0, 0, }, /* 189 */
- { 25, 17, 12, 0, 0, }, /* 190 */
- { 25, 21, 12, 0, 0, }, /* 191 */
- { 25, 7, 12, 0, 0, }, /* 192 */
- { 0, 1, 2, 0, 0, }, /* 193 */
- { 0, 25, 12, 0, 0, }, /* 194 */
- { 0, 21, 12, 0, 0, }, /* 195 */
- { 0, 23, 12, 0, 0, }, /* 196 */
- { 0, 26, 12, 0, 0, }, /* 197 */
- { 0, 12, 3, 0, 0, }, /* 198 */
- { 0, 7, 12, 0, 0, }, /* 199 */
- { 0, 6, 12, 0, 0, }, /* 200 */
+ { 33, 5, 12, 0, 42261, }, /* 105 */
+ { 33, 5, 12, 0, 42258, }, /* 106 */
+ { 33, 6, 12, 0, 0, }, /* 107 */
+ { 9, 6, 12, 0, 0, }, /* 108 */
+ { 3, 24, 12, 0, 0, }, /* 109 */
+ { 27, 12, 3, 0, 0, }, /* 110 */
+ { 27, 12, 3, 21, 116, }, /* 111 */
+ { 19, 9, 12, 0, 1, }, /* 112 */
+ { 19, 5, 12, 0, -1, }, /* 113 */
+ { 19, 24, 12, 0, 0, }, /* 114 */
+ { 9, 2, 12, 0, 0, }, /* 115 */
+ { 19, 6, 12, 0, 0, }, /* 116 */
+ { 19, 5, 12, 0, 130, }, /* 117 */
+ { 19, 9, 12, 0, 116, }, /* 118 */
+ { 19, 9, 12, 0, 38, }, /* 119 */
+ { 19, 9, 12, 0, 37, }, /* 120 */
+ { 19, 9, 12, 0, 64, }, /* 121 */
+ { 19, 9, 12, 0, 63, }, /* 122 */
+ { 19, 5, 12, 0, 0, }, /* 123 */
+ { 19, 9, 12, 0, 32, }, /* 124 */
+ { 19, 9, 12, 34, 32, }, /* 125 */
+ { 19, 9, 12, 59, 32, }, /* 126 */
+ { 19, 9, 12, 38, 32, }, /* 127 */
+ { 19, 9, 12, 21, 32, }, /* 128 */
+ { 19, 9, 12, 51, 32, }, /* 129 */
+ { 19, 9, 12, 26, 32, }, /* 130 */
+ { 19, 9, 12, 47, 32, }, /* 131 */
+ { 19, 9, 12, 55, 32, }, /* 132 */
+ { 19, 9, 12, 30, 32, }, /* 133 */
+ { 19, 9, 12, 43, 32, }, /* 134 */
+ { 19, 9, 12, 67, 32, }, /* 135 */
+ { 19, 5, 12, 0, -38, }, /* 136 */
+ { 19, 5, 12, 0, -37, }, /* 137 */
+ { 19, 5, 12, 0, -32, }, /* 138 */
+ { 19, 5, 12, 34, -32, }, /* 139 */
+ { 19, 5, 12, 59, -32, }, /* 140 */
+ { 19, 5, 12, 38, -32, }, /* 141 */
+ { 19, 5, 12, 21, -116, }, /* 142 */
+ { 19, 5, 12, 51, -32, }, /* 143 */
+ { 19, 5, 12, 26, -775, }, /* 144 */
+ { 19, 5, 12, 47, -32, }, /* 145 */
+ { 19, 5, 12, 55, -32, }, /* 146 */
+ { 19, 5, 12, 30, 1, }, /* 147 */
+ { 19, 5, 12, 30, -32, }, /* 148 */
+ { 19, 5, 12, 43, -32, }, /* 149 */
+ { 19, 5, 12, 67, -32, }, /* 150 */
+ { 19, 5, 12, 0, -64, }, /* 151 */
+ { 19, 5, 12, 0, -63, }, /* 152 */
+ { 19, 9, 12, 0, 8, }, /* 153 */
+ { 19, 5, 12, 34, -30, }, /* 154 */
+ { 19, 5, 12, 38, -25, }, /* 155 */
+ { 19, 9, 12, 0, 0, }, /* 156 */
+ { 19, 5, 12, 43, -15, }, /* 157 */
+ { 19, 5, 12, 47, -22, }, /* 158 */
+ { 19, 5, 12, 0, -8, }, /* 159 */
+ { 10, 9, 12, 0, 1, }, /* 160 */
+ { 10, 5, 12, 0, -1, }, /* 161 */
+ { 19, 5, 12, 51, -54, }, /* 162 */
+ { 19, 5, 12, 55, -48, }, /* 163 */
+ { 19, 5, 12, 0, 7, }, /* 164 */
+ { 19, 5, 12, 0, -116, }, /* 165 */
+ { 19, 9, 12, 38, -60, }, /* 166 */
+ { 19, 5, 12, 59, -64, }, /* 167 */
+ { 19, 25, 12, 0, 0, }, /* 168 */
+ { 19, 9, 12, 0, -7, }, /* 169 */
+ { 19, 9, 12, 0, -130, }, /* 170 */
+ { 12, 9, 12, 0, 80, }, /* 171 */
+ { 12, 9, 12, 0, 32, }, /* 172 */
+ { 12, 5, 12, 0, -32, }, /* 173 */
+ { 12, 5, 12, 0, -80, }, /* 174 */
+ { 12, 9, 12, 0, 1, }, /* 175 */
+ { 12, 5, 12, 0, -1, }, /* 176 */
+ { 12, 26, 12, 0, 0, }, /* 177 */
+ { 12, 12, 3, 0, 0, }, /* 178 */
+ { 12, 11, 3, 0, 0, }, /* 179 */
+ { 12, 9, 12, 0, 15, }, /* 180 */
+ { 12, 5, 12, 0, -15, }, /* 181 */
+ { 1, 9, 12, 0, 48, }, /* 182 */
+ { 1, 6, 12, 0, 0, }, /* 183 */
+ { 1, 21, 12, 0, 0, }, /* 184 */
+ { 1, 5, 12, 0, -48, }, /* 185 */
+ { 1, 5, 12, 0, 0, }, /* 186 */
+ { 1, 17, 12, 0, 0, }, /* 187 */
+ { 1, 26, 12, 0, 0, }, /* 188 */
+ { 1, 23, 12, 0, 0, }, /* 189 */
+ { 25, 12, 3, 0, 0, }, /* 190 */
+ { 25, 17, 12, 0, 0, }, /* 191 */
+ { 25, 21, 12, 0, 0, }, /* 192 */
+ { 25, 7, 12, 0, 0, }, /* 193 */
+ { 0, 1, 2, 0, 0, }, /* 194 */
+ { 0, 25, 12, 0, 0, }, /* 195 */
+ { 0, 21, 12, 0, 0, }, /* 196 */
+ { 0, 23, 12, 0, 0, }, /* 197 */
+ { 0, 26, 12, 0, 0, }, /* 198 */
+ { 0, 12, 3, 0, 0, }, /* 199 */
+ { 0, 7, 12, 0, 0, }, /* 200 */
{ 0, 13, 12, 0, 0, }, /* 201 */
- { 49, 21, 12, 0, 0, }, /* 202 */
- { 49, 1, 2, 0, 0, }, /* 203 */
- { 49, 7, 12, 0, 0, }, /* 204 */
- { 49, 12, 3, 0, 0, }, /* 205 */
- { 55, 7, 12, 0, 0, }, /* 206 */
- { 55, 12, 3, 0, 0, }, /* 207 */
- { 63, 13, 12, 0, 0, }, /* 208 */
- { 63, 7, 12, 0, 0, }, /* 209 */
- { 63, 12, 3, 0, 0, }, /* 210 */
- { 63, 6, 12, 0, 0, }, /* 211 */
- { 63, 26, 12, 0, 0, }, /* 212 */
- { 63, 21, 12, 0, 0, }, /* 213 */
- { 89, 7, 12, 0, 0, }, /* 214 */
- { 89, 12, 3, 0, 0, }, /* 215 */
- { 89, 6, 12, 0, 0, }, /* 216 */
- { 89, 21, 12, 0, 0, }, /* 217 */
- { 94, 7, 12, 0, 0, }, /* 218 */
- { 94, 12, 3, 0, 0, }, /* 219 */
- { 94, 21, 12, 0, 0, }, /* 220 */
- { 14, 12, 3, 0, 0, }, /* 221 */
- { 14, 10, 5, 0, 0, }, /* 222 */
- { 14, 7, 12, 0, 0, }, /* 223 */
- { 14, 13, 12, 0, 0, }, /* 224 */
- { 14, 21, 12, 0, 0, }, /* 225 */
- { 14, 6, 12, 0, 0, }, /* 226 */
- { 2, 7, 12, 0, 0, }, /* 227 */
- { 2, 12, 3, 0, 0, }, /* 228 */
- { 2, 10, 5, 0, 0, }, /* 229 */
- { 2, 10, 3, 0, 0, }, /* 230 */
- { 2, 13, 12, 0, 0, }, /* 231 */
- { 2, 23, 12, 0, 0, }, /* 232 */
- { 2, 15, 12, 0, 0, }, /* 233 */
- { 2, 26, 12, 0, 0, }, /* 234 */
- { 21, 12, 3, 0, 0, }, /* 235 */
- { 21, 10, 5, 0, 0, }, /* 236 */
- { 21, 7, 12, 0, 0, }, /* 237 */
- { 21, 13, 12, 0, 0, }, /* 238 */
- { 20, 12, 3, 0, 0, }, /* 239 */
- { 20, 10, 5, 0, 0, }, /* 240 */
- { 20, 7, 12, 0, 0, }, /* 241 */
- { 20, 13, 12, 0, 0, }, /* 242 */
- { 20, 21, 12, 0, 0, }, /* 243 */
- { 20, 23, 12, 0, 0, }, /* 244 */
- { 43, 12, 3, 0, 0, }, /* 245 */
- { 43, 10, 5, 0, 0, }, /* 246 */
- { 43, 7, 12, 0, 0, }, /* 247 */
- { 43, 10, 3, 0, 0, }, /* 248 */
- { 43, 13, 12, 0, 0, }, /* 249 */
- { 43, 26, 12, 0, 0, }, /* 250 */
- { 43, 15, 12, 0, 0, }, /* 251 */
- { 53, 12, 3, 0, 0, }, /* 252 */
- { 53, 7, 12, 0, 0, }, /* 253 */
- { 53, 10, 3, 0, 0, }, /* 254 */
- { 53, 10, 5, 0, 0, }, /* 255 */
- { 53, 13, 12, 0, 0, }, /* 256 */
- { 53, 15, 12, 0, 0, }, /* 257 */
- { 53, 26, 12, 0, 0, }, /* 258 */
- { 53, 23, 12, 0, 0, }, /* 259 */
- { 54, 12, 3, 0, 0, }, /* 260 */
- { 54, 10, 5, 0, 0, }, /* 261 */
- { 54, 7, 12, 0, 0, }, /* 262 */
- { 54, 13, 12, 0, 0, }, /* 263 */
- { 54, 15, 12, 0, 0, }, /* 264 */
- { 54, 26, 12, 0, 0, }, /* 265 */
- { 28, 12, 3, 0, 0, }, /* 266 */
- { 28, 10, 5, 0, 0, }, /* 267 */
- { 28, 7, 12, 0, 0, }, /* 268 */
- { 28, 10, 3, 0, 0, }, /* 269 */
- { 28, 13, 12, 0, 0, }, /* 270 */
- { 36, 12, 3, 0, 0, }, /* 271 */
- { 36, 10, 5, 0, 0, }, /* 272 */
- { 36, 7, 12, 0, 0, }, /* 273 */
- { 36, 10, 3, 0, 0, }, /* 274 */
- { 36, 13, 12, 0, 0, }, /* 275 */
- { 36, 15, 12, 0, 0, }, /* 276 */
- { 36, 26, 12, 0, 0, }, /* 277 */
- { 47, 10, 5, 0, 0, }, /* 278 */
- { 47, 7, 12, 0, 0, }, /* 279 */
- { 47, 12, 3, 0, 0, }, /* 280 */
- { 47, 10, 3, 0, 0, }, /* 281 */
- { 47, 13, 12, 0, 0, }, /* 282 */
- { 47, 21, 12, 0, 0, }, /* 283 */
- { 56, 7, 12, 0, 0, }, /* 284 */
- { 56, 12, 3, 0, 0, }, /* 285 */
- { 56, 7, 5, 0, 0, }, /* 286 */
- { 56, 6, 12, 0, 0, }, /* 287 */
- { 56, 21, 12, 0, 0, }, /* 288 */
- { 56, 13, 12, 0, 0, }, /* 289 */
- { 32, 7, 12, 0, 0, }, /* 290 */
- { 32, 12, 3, 0, 0, }, /* 291 */
- { 32, 7, 5, 0, 0, }, /* 292 */
- { 32, 6, 12, 0, 0, }, /* 293 */
- { 32, 13, 12, 0, 0, }, /* 294 */
- { 57, 7, 12, 0, 0, }, /* 295 */
- { 57, 26, 12, 0, 0, }, /* 296 */
- { 57, 21, 12, 0, 0, }, /* 297 */
- { 57, 12, 3, 0, 0, }, /* 298 */
- { 57, 13, 12, 0, 0, }, /* 299 */
- { 57, 15, 12, 0, 0, }, /* 300 */
- { 57, 22, 12, 0, 0, }, /* 301 */
- { 57, 18, 12, 0, 0, }, /* 302 */
- { 57, 10, 5, 0, 0, }, /* 303 */
- { 38, 7, 12, 0, 0, }, /* 304 */
- { 38, 10, 12, 0, 0, }, /* 305 */
- { 38, 12, 3, 0, 0, }, /* 306 */
- { 38, 10, 5, 0, 0, }, /* 307 */
- { 38, 13, 12, 0, 0, }, /* 308 */
- { 38, 21, 12, 0, 0, }, /* 309 */
- { 38, 26, 12, 0, 0, }, /* 310 */
- { 16, 9, 12, 0, 7264, }, /* 311 */
- { 16, 7, 12, 0, 0, }, /* 312 */
- { 16, 6, 12, 0, 0, }, /* 313 */
- { 23, 7, 6, 0, 0, }, /* 314 */
- { 23, 7, 7, 0, 0, }, /* 315 */
- { 23, 7, 8, 0, 0, }, /* 316 */
- { 15, 7, 12, 0, 0, }, /* 317 */
- { 15, 12, 3, 0, 0, }, /* 318 */
- { 15, 21, 12, 0, 0, }, /* 319 */
- { 15, 15, 12, 0, 0, }, /* 320 */
- { 15, 26, 12, 0, 0, }, /* 321 */
- { 8, 7, 12, 0, 0, }, /* 322 */
- { 7, 17, 12, 0, 0, }, /* 323 */
- { 7, 7, 12, 0, 0, }, /* 324 */
- { 7, 21, 12, 0, 0, }, /* 325 */
- { 40, 29, 12, 0, 0, }, /* 326 */
- { 40, 7, 12, 0, 0, }, /* 327 */
- { 40, 22, 12, 0, 0, }, /* 328 */
- { 40, 18, 12, 0, 0, }, /* 329 */
- { 45, 7, 12, 0, 0, }, /* 330 */
- { 45, 14, 12, 0, 0, }, /* 331 */
- { 50, 7, 12, 0, 0, }, /* 332 */
- { 50, 12, 3, 0, 0, }, /* 333 */
- { 24, 7, 12, 0, 0, }, /* 334 */
- { 24, 12, 3, 0, 0, }, /* 335 */
- { 6, 7, 12, 0, 0, }, /* 336 */
- { 6, 12, 3, 0, 0, }, /* 337 */
- { 51, 7, 12, 0, 0, }, /* 338 */
- { 51, 12, 3, 0, 0, }, /* 339 */
- { 31, 7, 12, 0, 0, }, /* 340 */
- { 31, 12, 3, 0, 0, }, /* 341 */
- { 31, 10, 5, 0, 0, }, /* 342 */
- { 31, 21, 12, 0, 0, }, /* 343 */
- { 31, 6, 12, 0, 0, }, /* 344 */
- { 31, 23, 12, 0, 0, }, /* 345 */
- { 31, 13, 12, 0, 0, }, /* 346 */
- { 31, 15, 12, 0, 0, }, /* 347 */
- { 37, 21, 12, 0, 0, }, /* 348 */
- { 37, 17, 12, 0, 0, }, /* 349 */
- { 37, 12, 3, 0, 0, }, /* 350 */
- { 37, 1, 2, 0, 0, }, /* 351 */
- { 37, 13, 12, 0, 0, }, /* 352 */
- { 37, 7, 12, 0, 0, }, /* 353 */
- { 37, 6, 12, 0, 0, }, /* 354 */
- { 34, 7, 12, 0, 0, }, /* 355 */
- { 34, 12, 3, 0, 0, }, /* 356 */
- { 34, 10, 5, 0, 0, }, /* 357 */
- { 34, 26, 12, 0, 0, }, /* 358 */
- { 34, 21, 12, 0, 0, }, /* 359 */
- { 34, 13, 12, 0, 0, }, /* 360 */
- { 52, 7, 12, 0, 0, }, /* 361 */
- { 39, 7, 12, 0, 0, }, /* 362 */
- { 39, 10, 12, 0, 0, }, /* 363 */
- { 39, 10, 5, 0, 0, }, /* 364 */
- { 39, 13, 12, 0, 0, }, /* 365 */
- { 39, 15, 12, 0, 0, }, /* 366 */
- { 39, 26, 12, 0, 0, }, /* 367 */
- { 31, 26, 12, 0, 0, }, /* 368 */
- { 5, 7, 12, 0, 0, }, /* 369 */
- { 5, 12, 3, 0, 0, }, /* 370 */
- { 5, 10, 5, 0, 0, }, /* 371 */
- { 5, 21, 12, 0, 0, }, /* 372 */
- { 90, 7, 12, 0, 0, }, /* 373 */
- { 90, 10, 5, 0, 0, }, /* 374 */
- { 90, 12, 3, 0, 0, }, /* 375 */
- { 90, 10, 12, 0, 0, }, /* 376 */
- { 90, 13, 12, 0, 0, }, /* 377 */
- { 90, 21, 12, 0, 0, }, /* 378 */
- { 90, 6, 12, 0, 0, }, /* 379 */
- { 27, 11, 3, 0, 0, }, /* 380 */
- { 61, 12, 3, 0, 0, }, /* 381 */
- { 61, 10, 5, 0, 0, }, /* 382 */
- { 61, 7, 12, 0, 0, }, /* 383 */
- { 61, 13, 12, 0, 0, }, /* 384 */
- { 61, 21, 12, 0, 0, }, /* 385 */
- { 61, 26, 12, 0, 0, }, /* 386 */
- { 75, 12, 3, 0, 0, }, /* 387 */
- { 75, 10, 5, 0, 0, }, /* 388 */
- { 75, 7, 12, 0, 0, }, /* 389 */
- { 75, 13, 12, 0, 0, }, /* 390 */
- { 92, 7, 12, 0, 0, }, /* 391 */
- { 92, 12, 3, 0, 0, }, /* 392 */
- { 92, 10, 5, 0, 0, }, /* 393 */
- { 92, 21, 12, 0, 0, }, /* 394 */
- { 69, 7, 12, 0, 0, }, /* 395 */
- { 69, 10, 5, 0, 0, }, /* 396 */
- { 69, 12, 3, 0, 0, }, /* 397 */
- { 69, 21, 12, 0, 0, }, /* 398 */
- { 69, 13, 12, 0, 0, }, /* 399 */
- { 72, 13, 12, 0, 0, }, /* 400 */
- { 72, 7, 12, 0, 0, }, /* 401 */
- { 72, 6, 12, 0, 0, }, /* 402 */
- { 72, 21, 12, 0, 0, }, /* 403 */
- { 75, 21, 12, 0, 0, }, /* 404 */
- { 9, 10, 5, 0, 0, }, /* 405 */
- { 9, 7, 12, 0, 0, }, /* 406 */
- { 12, 5, 12, 0, 0, }, /* 407 */
- { 12, 6, 12, 0, 0, }, /* 408 */
- { 33, 5, 12, 0, 35332, }, /* 409 */
- { 33, 5, 12, 0, 3814, }, /* 410 */
- { 33, 9, 12, 63, 1, }, /* 411 */
- { 33, 5, 12, 63, -1, }, /* 412 */
- { 33, 5, 12, 63, -58, }, /* 413 */
- { 33, 9, 12, 0, -7615, }, /* 414 */
- { 19, 5, 12, 0, 8, }, /* 415 */
- { 19, 9, 12, 0, -8, }, /* 416 */
- { 19, 5, 12, 0, 74, }, /* 417 */
- { 19, 5, 12, 0, 86, }, /* 418 */
- { 19, 5, 12, 0, 100, }, /* 419 */
- { 19, 5, 12, 0, 128, }, /* 420 */
- { 19, 5, 12, 0, 112, }, /* 421 */
- { 19, 5, 12, 0, 126, }, /* 422 */
- { 19, 8, 12, 0, -8, }, /* 423 */
- { 19, 5, 12, 0, 9, }, /* 424 */
- { 19, 9, 12, 0, -74, }, /* 425 */
- { 19, 8, 12, 0, -9, }, /* 426 */
- { 19, 5, 12, 21, -7173, }, /* 427 */
- { 19, 9, 12, 0, -86, }, /* 428 */
- { 19, 9, 12, 0, -100, }, /* 429 */
- { 19, 9, 12, 0, -112, }, /* 430 */
- { 19, 9, 12, 0, -128, }, /* 431 */
- { 19, 9, 12, 0, -126, }, /* 432 */
- { 27, 1, 3, 0, 0, }, /* 433 */
- { 9, 27, 2, 0, 0, }, /* 434 */
- { 9, 28, 2, 0, 0, }, /* 435 */
- { 9, 2, 2, 0, 0, }, /* 436 */
- { 9, 9, 12, 0, 0, }, /* 437 */
- { 9, 5, 12, 0, 0, }, /* 438 */
- { 19, 9, 12, 67, -7517, }, /* 439 */
- { 33, 9, 12, 71, -8383, }, /* 440 */
- { 33, 9, 12, 75, -8262, }, /* 441 */
- { 33, 9, 12, 0, 28, }, /* 442 */
- { 33, 5, 12, 0, -28, }, /* 443 */
- { 33, 14, 12, 0, 16, }, /* 444 */
- { 33, 14, 12, 0, -16, }, /* 445 */
- { 33, 14, 12, 0, 0, }, /* 446 */
- { 9, 26, 12, 0, 26, }, /* 447 */
- { 9, 26, 12, 0, -26, }, /* 448 */
- { 4, 26, 12, 0, 0, }, /* 449 */
- { 17, 9, 12, 0, 48, }, /* 450 */
- { 17, 5, 12, 0, -48, }, /* 451 */
- { 33, 9, 12, 0, -10743, }, /* 452 */
- { 33, 9, 12, 0, -3814, }, /* 453 */
- { 33, 9, 12, 0, -10727, }, /* 454 */
- { 33, 5, 12, 0, -10795, }, /* 455 */
- { 33, 5, 12, 0, -10792, }, /* 456 */
- { 33, 9, 12, 0, -10780, }, /* 457 */
- { 33, 9, 12, 0, -10749, }, /* 458 */
- { 33, 9, 12, 0, -10783, }, /* 459 */
- { 33, 9, 12, 0, -10782, }, /* 460 */
- { 33, 9, 12, 0, -10815, }, /* 461 */
- { 10, 5, 12, 0, 0, }, /* 462 */
- { 10, 26, 12, 0, 0, }, /* 463 */
- { 10, 12, 3, 0, 0, }, /* 464 */
- { 10, 21, 12, 0, 0, }, /* 465 */
- { 10, 15, 12, 0, 0, }, /* 466 */
- { 16, 5, 12, 0, -7264, }, /* 467 */
- { 58, 7, 12, 0, 0, }, /* 468 */
- { 58, 6, 12, 0, 0, }, /* 469 */
- { 58, 21, 12, 0, 0, }, /* 470 */
- { 58, 12, 3, 0, 0, }, /* 471 */
- { 22, 26, 12, 0, 0, }, /* 472 */
- { 22, 6, 12, 0, 0, }, /* 473 */
- { 22, 14, 12, 0, 0, }, /* 474 */
- { 23, 10, 3, 0, 0, }, /* 475 */
- { 26, 7, 12, 0, 0, }, /* 476 */
- { 26, 6, 12, 0, 0, }, /* 477 */
- { 29, 7, 12, 0, 0, }, /* 478 */
- { 29, 6, 12, 0, 0, }, /* 479 */
- { 3, 7, 12, 0, 0, }, /* 480 */
- { 23, 7, 12, 0, 0, }, /* 481 */
- { 23, 26, 12, 0, 0, }, /* 482 */
- { 29, 26, 12, 0, 0, }, /* 483 */
- { 22, 7, 12, 0, 0, }, /* 484 */
- { 60, 7, 12, 0, 0, }, /* 485 */
- { 60, 6, 12, 0, 0, }, /* 486 */
- { 60, 26, 12, 0, 0, }, /* 487 */
- { 85, 7, 12, 0, 0, }, /* 488 */
- { 85, 6, 12, 0, 0, }, /* 489 */
- { 85, 21, 12, 0, 0, }, /* 490 */
- { 76, 7, 12, 0, 0, }, /* 491 */
- { 76, 6, 12, 0, 0, }, /* 492 */
- { 76, 21, 12, 0, 0, }, /* 493 */
- { 76, 13, 12, 0, 0, }, /* 494 */
- { 12, 7, 12, 0, 0, }, /* 495 */
- { 12, 21, 12, 0, 0, }, /* 496 */
- { 78, 7, 12, 0, 0, }, /* 497 */
- { 78, 14, 12, 0, 0, }, /* 498 */
- { 78, 12, 3, 0, 0, }, /* 499 */
- { 78, 21, 12, 0, 0, }, /* 500 */
- { 33, 9, 12, 0, -35332, }, /* 501 */
- { 33, 9, 12, 0, -42280, }, /* 502 */
- { 33, 9, 12, 0, -42308, }, /* 503 */
- { 33, 9, 12, 0, -42319, }, /* 504 */
- { 33, 9, 12, 0, -42315, }, /* 505 */
- { 33, 9, 12, 0, -42305, }, /* 506 */
- { 33, 9, 12, 0, -42258, }, /* 507 */
- { 33, 9, 12, 0, -42282, }, /* 508 */
- { 48, 7, 12, 0, 0, }, /* 509 */
- { 48, 12, 3, 0, 0, }, /* 510 */
- { 48, 10, 5, 0, 0, }, /* 511 */
- { 48, 26, 12, 0, 0, }, /* 512 */
- { 64, 7, 12, 0, 0, }, /* 513 */
- { 64, 21, 12, 0, 0, }, /* 514 */
- { 74, 10, 5, 0, 0, }, /* 515 */
- { 74, 7, 12, 0, 0, }, /* 516 */
- { 74, 12, 3, 0, 0, }, /* 517 */
- { 74, 21, 12, 0, 0, }, /* 518 */
- { 74, 13, 12, 0, 0, }, /* 519 */
- { 68, 13, 12, 0, 0, }, /* 520 */
- { 68, 7, 12, 0, 0, }, /* 521 */
- { 68, 12, 3, 0, 0, }, /* 522 */
- { 68, 21, 12, 0, 0, }, /* 523 */
- { 73, 7, 12, 0, 0, }, /* 524 */
- { 73, 12, 3, 0, 0, }, /* 525 */
- { 73, 10, 5, 0, 0, }, /* 526 */
- { 73, 21, 12, 0, 0, }, /* 527 */
- { 83, 12, 3, 0, 0, }, /* 528 */
- { 83, 10, 5, 0, 0, }, /* 529 */
- { 83, 7, 12, 0, 0, }, /* 530 */
- { 83, 21, 12, 0, 0, }, /* 531 */
- { 83, 13, 12, 0, 0, }, /* 532 */
- { 38, 6, 12, 0, 0, }, /* 533 */
- { 67, 7, 12, 0, 0, }, /* 534 */
- { 67, 12, 3, 0, 0, }, /* 535 */
- { 67, 10, 5, 0, 0, }, /* 536 */
- { 67, 13, 12, 0, 0, }, /* 537 */
- { 67, 21, 12, 0, 0, }, /* 538 */
- { 91, 7, 12, 0, 0, }, /* 539 */
- { 91, 12, 3, 0, 0, }, /* 540 */
- { 91, 6, 12, 0, 0, }, /* 541 */
- { 91, 21, 12, 0, 0, }, /* 542 */
- { 86, 7, 12, 0, 0, }, /* 543 */
- { 86, 10, 5, 0, 0, }, /* 544 */
- { 86, 12, 3, 0, 0, }, /* 545 */
- { 86, 21, 12, 0, 0, }, /* 546 */
- { 86, 6, 12, 0, 0, }, /* 547 */
- { 86, 13, 12, 0, 0, }, /* 548 */
- { 23, 7, 9, 0, 0, }, /* 549 */
- { 23, 7, 10, 0, 0, }, /* 550 */
- { 9, 4, 2, 0, 0, }, /* 551 */
- { 9, 3, 12, 0, 0, }, /* 552 */
- { 25, 25, 12, 0, 0, }, /* 553 */
- { 0, 24, 12, 0, 0, }, /* 554 */
- { 9, 6, 3, 0, 0, }, /* 555 */
- { 35, 7, 12, 0, 0, }, /* 556 */
- { 19, 14, 12, 0, 0, }, /* 557 */
- { 19, 15, 12, 0, 0, }, /* 558 */
- { 19, 26, 12, 0, 0, }, /* 559 */
- { 70, 7, 12, 0, 0, }, /* 560 */
- { 66, 7, 12, 0, 0, }, /* 561 */
- { 41, 7, 12, 0, 0, }, /* 562 */
- { 41, 15, 12, 0, 0, }, /* 563 */
- { 18, 7, 12, 0, 0, }, /* 564 */
- { 18, 14, 12, 0, 0, }, /* 565 */
- { 117, 7, 12, 0, 0, }, /* 566 */
- { 117, 12, 3, 0, 0, }, /* 567 */
- { 59, 7, 12, 0, 0, }, /* 568 */
- { 59, 21, 12, 0, 0, }, /* 569 */
- { 42, 7, 12, 0, 0, }, /* 570 */
- { 42, 21, 12, 0, 0, }, /* 571 */
- { 42, 14, 12, 0, 0, }, /* 572 */
- { 13, 9, 12, 0, 40, }, /* 573 */
- { 13, 5, 12, 0, -40, }, /* 574 */
- { 46, 7, 12, 0, 0, }, /* 575 */
- { 44, 7, 12, 0, 0, }, /* 576 */
- { 44, 13, 12, 0, 0, }, /* 577 */
- { 105, 7, 12, 0, 0, }, /* 578 */
- { 103, 7, 12, 0, 0, }, /* 579 */
- { 103, 21, 12, 0, 0, }, /* 580 */
- { 109, 7, 12, 0, 0, }, /* 581 */
- { 11, 7, 12, 0, 0, }, /* 582 */
- { 80, 7, 12, 0, 0, }, /* 583 */
- { 80, 21, 12, 0, 0, }, /* 584 */
- { 80, 15, 12, 0, 0, }, /* 585 */
- { 119, 7, 12, 0, 0, }, /* 586 */
- { 119, 26, 12, 0, 0, }, /* 587 */
- { 119, 15, 12, 0, 0, }, /* 588 */
- { 115, 7, 12, 0, 0, }, /* 589 */
- { 115, 15, 12, 0, 0, }, /* 590 */
- { 65, 7, 12, 0, 0, }, /* 591 */
- { 65, 15, 12, 0, 0, }, /* 592 */
- { 65, 21, 12, 0, 0, }, /* 593 */
- { 71, 7, 12, 0, 0, }, /* 594 */
- { 71, 21, 12, 0, 0, }, /* 595 */
- { 97, 7, 12, 0, 0, }, /* 596 */
- { 96, 7, 12, 0, 0, }, /* 597 */
- { 30, 7, 12, 0, 0, }, /* 598 */
- { 30, 12, 3, 0, 0, }, /* 599 */
- { 30, 15, 12, 0, 0, }, /* 600 */
- { 30, 21, 12, 0, 0, }, /* 601 */
- { 87, 7, 12, 0, 0, }, /* 602 */
- { 87, 15, 12, 0, 0, }, /* 603 */
- { 87, 21, 12, 0, 0, }, /* 604 */
- { 116, 7, 12, 0, 0, }, /* 605 */
- { 116, 15, 12, 0, 0, }, /* 606 */
- { 111, 7, 12, 0, 0, }, /* 607 */
- { 111, 26, 12, 0, 0, }, /* 608 */
- { 111, 12, 3, 0, 0, }, /* 609 */
- { 111, 15, 12, 0, 0, }, /* 610 */
- { 111, 21, 12, 0, 0, }, /* 611 */
- { 77, 7, 12, 0, 0, }, /* 612 */
- { 77, 21, 12, 0, 0, }, /* 613 */
- { 82, 7, 12, 0, 0, }, /* 614 */
- { 82, 15, 12, 0, 0, }, /* 615 */
- { 81, 7, 12, 0, 0, }, /* 616 */
- { 81, 15, 12, 0, 0, }, /* 617 */
- { 120, 7, 12, 0, 0, }, /* 618 */
- { 120, 21, 12, 0, 0, }, /* 619 */
- { 120, 15, 12, 0, 0, }, /* 620 */
- { 88, 7, 12, 0, 0, }, /* 621 */
- { 0, 15, 12, 0, 0, }, /* 622 */
- { 93, 10, 5, 0, 0, }, /* 623 */
- { 93, 12, 3, 0, 0, }, /* 624 */
- { 93, 7, 12, 0, 0, }, /* 625 */
- { 93, 21, 12, 0, 0, }, /* 626 */
- { 93, 15, 12, 0, 0, }, /* 627 */
- { 93, 13, 12, 0, 0, }, /* 628 */
- { 84, 12, 3, 0, 0, }, /* 629 */
- { 84, 10, 5, 0, 0, }, /* 630 */
- { 84, 7, 12, 0, 0, }, /* 631 */
- { 84, 21, 12, 0, 0, }, /* 632 */
- { 84, 1, 2, 0, 0, }, /* 633 */
- { 100, 7, 12, 0, 0, }, /* 634 */
- { 100, 13, 12, 0, 0, }, /* 635 */
- { 95, 12, 3, 0, 0, }, /* 636 */
- { 95, 7, 12, 0, 0, }, /* 637 */
- { 95, 10, 5, 0, 0, }, /* 638 */
- { 95, 13, 12, 0, 0, }, /* 639 */
- { 95, 21, 12, 0, 0, }, /* 640 */
- { 110, 7, 12, 0, 0, }, /* 641 */
- { 110, 12, 3, 0, 0, }, /* 642 */
- { 110, 21, 12, 0, 0, }, /* 643 */
- { 99, 12, 3, 0, 0, }, /* 644 */
- { 99, 10, 5, 0, 0, }, /* 645 */
- { 99, 7, 12, 0, 0, }, /* 646 */
- { 99, 21, 12, 0, 0, }, /* 647 */
- { 99, 13, 12, 0, 0, }, /* 648 */
- { 47, 15, 12, 0, 0, }, /* 649 */
- { 107, 7, 12, 0, 0, }, /* 650 */
- { 107, 10, 5, 0, 0, }, /* 651 */
- { 107, 12, 3, 0, 0, }, /* 652 */
- { 107, 21, 12, 0, 0, }, /* 653 */
- { 108, 7, 12, 0, 0, }, /* 654 */
- { 108, 12, 3, 0, 0, }, /* 655 */
- { 108, 10, 5, 0, 0, }, /* 656 */
- { 108, 13, 12, 0, 0, }, /* 657 */
- { 106, 12, 3, 0, 0, }, /* 658 */
- { 106, 10, 5, 0, 0, }, /* 659 */
- { 106, 7, 12, 0, 0, }, /* 660 */
- { 106, 10, 3, 0, 0, }, /* 661 */
- { 123, 7, 12, 0, 0, }, /* 662 */
- { 123, 10, 3, 0, 0, }, /* 663 */
- { 123, 10, 5, 0, 0, }, /* 664 */
- { 123, 12, 3, 0, 0, }, /* 665 */
- { 123, 21, 12, 0, 0, }, /* 666 */
- { 123, 13, 12, 0, 0, }, /* 667 */
- { 122, 7, 12, 0, 0, }, /* 668 */
- { 122, 10, 3, 0, 0, }, /* 669 */
- { 122, 10, 5, 0, 0, }, /* 670 */
- { 122, 12, 3, 0, 0, }, /* 671 */
- { 122, 21, 12, 0, 0, }, /* 672 */
- { 113, 7, 12, 0, 0, }, /* 673 */
- { 113, 10, 5, 0, 0, }, /* 674 */
- { 113, 12, 3, 0, 0, }, /* 675 */
- { 113, 21, 12, 0, 0, }, /* 676 */
- { 113, 13, 12, 0, 0, }, /* 677 */
- { 101, 7, 12, 0, 0, }, /* 678 */
- { 101, 12, 3, 0, 0, }, /* 679 */
- { 101, 10, 5, 0, 0, }, /* 680 */
- { 101, 13, 12, 0, 0, }, /* 681 */
- { 124, 9, 12, 0, 32, }, /* 682 */
- { 124, 5, 12, 0, -32, }, /* 683 */
- { 124, 13, 12, 0, 0, }, /* 684 */
- { 124, 15, 12, 0, 0, }, /* 685 */
- { 124, 7, 12, 0, 0, }, /* 686 */
- { 121, 7, 12, 0, 0, }, /* 687 */
- { 62, 7, 12, 0, 0, }, /* 688 */
- { 62, 14, 12, 0, 0, }, /* 689 */
- { 62, 21, 12, 0, 0, }, /* 690 */
- { 79, 7, 12, 0, 0, }, /* 691 */
- { 114, 7, 12, 0, 0, }, /* 692 */
- { 114, 13, 12, 0, 0, }, /* 693 */
- { 114, 21, 12, 0, 0, }, /* 694 */
- { 102, 7, 12, 0, 0, }, /* 695 */
- { 102, 12, 3, 0, 0, }, /* 696 */
- { 102, 21, 12, 0, 0, }, /* 697 */
- { 118, 7, 12, 0, 0, }, /* 698 */
- { 118, 12, 3, 0, 0, }, /* 699 */
- { 118, 21, 12, 0, 0, }, /* 700 */
- { 118, 26, 12, 0, 0, }, /* 701 */
- { 118, 6, 12, 0, 0, }, /* 702 */
- { 118, 13, 12, 0, 0, }, /* 703 */
- { 118, 15, 12, 0, 0, }, /* 704 */
- { 98, 7, 12, 0, 0, }, /* 705 */
- { 98, 10, 5, 0, 0, }, /* 706 */
- { 98, 12, 3, 0, 0, }, /* 707 */
- { 98, 6, 12, 0, 0, }, /* 708 */
- { 104, 7, 12, 0, 0, }, /* 709 */
- { 104, 26, 12, 0, 0, }, /* 710 */
- { 104, 12, 3, 0, 0, }, /* 711 */
- { 104, 21, 12, 0, 0, }, /* 712 */
- { 9, 10, 3, 0, 0, }, /* 713 */
- { 19, 12, 3, 0, 0, }, /* 714 */
- { 112, 7, 12, 0, 0, }, /* 715 */
- { 112, 15, 12, 0, 0, }, /* 716 */
- { 112, 12, 3, 0, 0, }, /* 717 */
- { 9, 26, 11, 0, 0, }, /* 718 */
- { 26, 26, 12, 0, 0, }, /* 719 */
+ { 0, 6, 12, 0, 0, }, /* 202 */
+ { 49, 21, 12, 0, 0, }, /* 203 */
+ { 49, 1, 2, 0, 0, }, /* 204 */
+ { 49, 7, 12, 0, 0, }, /* 205 */
+ { 49, 12, 3, 0, 0, }, /* 206 */
+ { 55, 7, 12, 0, 0, }, /* 207 */
+ { 55, 12, 3, 0, 0, }, /* 208 */
+ { 63, 13, 12, 0, 0, }, /* 209 */
+ { 63, 7, 12, 0, 0, }, /* 210 */
+ { 63, 12, 3, 0, 0, }, /* 211 */
+ { 63, 6, 12, 0, 0, }, /* 212 */
+ { 63, 26, 12, 0, 0, }, /* 213 */
+ { 63, 21, 12, 0, 0, }, /* 214 */
+ { 89, 7, 12, 0, 0, }, /* 215 */
+ { 89, 12, 3, 0, 0, }, /* 216 */
+ { 89, 6, 12, 0, 0, }, /* 217 */
+ { 89, 21, 12, 0, 0, }, /* 218 */
+ { 94, 7, 12, 0, 0, }, /* 219 */
+ { 94, 12, 3, 0, 0, }, /* 220 */
+ { 94, 21, 12, 0, 0, }, /* 221 */
+ { 14, 12, 3, 0, 0, }, /* 222 */
+ { 14, 10, 5, 0, 0, }, /* 223 */
+ { 14, 7, 12, 0, 0, }, /* 224 */
+ { 14, 13, 12, 0, 0, }, /* 225 */
+ { 14, 21, 12, 0, 0, }, /* 226 */
+ { 14, 6, 12, 0, 0, }, /* 227 */
+ { 2, 7, 12, 0, 0, }, /* 228 */
+ { 2, 12, 3, 0, 0, }, /* 229 */
+ { 2, 10, 5, 0, 0, }, /* 230 */
+ { 2, 10, 3, 0, 0, }, /* 231 */
+ { 2, 13, 12, 0, 0, }, /* 232 */
+ { 2, 23, 12, 0, 0, }, /* 233 */
+ { 2, 15, 12, 0, 0, }, /* 234 */
+ { 2, 26, 12, 0, 0, }, /* 235 */
+ { 21, 12, 3, 0, 0, }, /* 236 */
+ { 21, 10, 5, 0, 0, }, /* 237 */
+ { 21, 7, 12, 0, 0, }, /* 238 */
+ { 21, 13, 12, 0, 0, }, /* 239 */
+ { 20, 12, 3, 0, 0, }, /* 240 */
+ { 20, 10, 5, 0, 0, }, /* 241 */
+ { 20, 7, 12, 0, 0, }, /* 242 */
+ { 20, 13, 12, 0, 0, }, /* 243 */
+ { 20, 21, 12, 0, 0, }, /* 244 */
+ { 20, 23, 12, 0, 0, }, /* 245 */
+ { 43, 12, 3, 0, 0, }, /* 246 */
+ { 43, 10, 5, 0, 0, }, /* 247 */
+ { 43, 7, 12, 0, 0, }, /* 248 */
+ { 43, 10, 3, 0, 0, }, /* 249 */
+ { 43, 13, 12, 0, 0, }, /* 250 */
+ { 43, 26, 12, 0, 0, }, /* 251 */
+ { 43, 15, 12, 0, 0, }, /* 252 */
+ { 53, 12, 3, 0, 0, }, /* 253 */
+ { 53, 7, 12, 0, 0, }, /* 254 */
+ { 53, 10, 3, 0, 0, }, /* 255 */
+ { 53, 10, 5, 0, 0, }, /* 256 */
+ { 53, 13, 12, 0, 0, }, /* 257 */
+ { 53, 15, 12, 0, 0, }, /* 258 */
+ { 53, 26, 12, 0, 0, }, /* 259 */
+ { 53, 23, 12, 0, 0, }, /* 260 */
+ { 54, 12, 3, 0, 0, }, /* 261 */
+ { 54, 10, 5, 0, 0, }, /* 262 */
+ { 54, 7, 12, 0, 0, }, /* 263 */
+ { 54, 13, 12, 0, 0, }, /* 264 */
+ { 54, 15, 12, 0, 0, }, /* 265 */
+ { 54, 26, 12, 0, 0, }, /* 266 */
+ { 28, 12, 3, 0, 0, }, /* 267 */
+ { 28, 10, 5, 0, 0, }, /* 268 */
+ { 28, 7, 12, 0, 0, }, /* 269 */
+ { 28, 10, 3, 0, 0, }, /* 270 */
+ { 28, 13, 12, 0, 0, }, /* 271 */
+ { 36, 12, 3, 0, 0, }, /* 272 */
+ { 36, 10, 5, 0, 0, }, /* 273 */
+ { 36, 7, 12, 0, 0, }, /* 274 */
+ { 36, 10, 3, 0, 0, }, /* 275 */
+ { 36, 13, 12, 0, 0, }, /* 276 */
+ { 36, 15, 12, 0, 0, }, /* 277 */
+ { 36, 26, 12, 0, 0, }, /* 278 */
+ { 47, 10, 5, 0, 0, }, /* 279 */
+ { 47, 7, 12, 0, 0, }, /* 280 */
+ { 47, 12, 3, 0, 0, }, /* 281 */
+ { 47, 10, 3, 0, 0, }, /* 282 */
+ { 47, 13, 12, 0, 0, }, /* 283 */
+ { 47, 21, 12, 0, 0, }, /* 284 */
+ { 56, 7, 12, 0, 0, }, /* 285 */
+ { 56, 12, 3, 0, 0, }, /* 286 */
+ { 56, 7, 5, 0, 0, }, /* 287 */
+ { 56, 6, 12, 0, 0, }, /* 288 */
+ { 56, 21, 12, 0, 0, }, /* 289 */
+ { 56, 13, 12, 0, 0, }, /* 290 */
+ { 32, 7, 12, 0, 0, }, /* 291 */
+ { 32, 12, 3, 0, 0, }, /* 292 */
+ { 32, 7, 5, 0, 0, }, /* 293 */
+ { 32, 6, 12, 0, 0, }, /* 294 */
+ { 32, 13, 12, 0, 0, }, /* 295 */
+ { 57, 7, 12, 0, 0, }, /* 296 */
+ { 57, 26, 12, 0, 0, }, /* 297 */
+ { 57, 21, 12, 0, 0, }, /* 298 */
+ { 57, 12, 3, 0, 0, }, /* 299 */
+ { 57, 13, 12, 0, 0, }, /* 300 */
+ { 57, 15, 12, 0, 0, }, /* 301 */
+ { 57, 22, 12, 0, 0, }, /* 302 */
+ { 57, 18, 12, 0, 0, }, /* 303 */
+ { 57, 10, 5, 0, 0, }, /* 304 */
+ { 38, 7, 12, 0, 0, }, /* 305 */
+ { 38, 10, 12, 0, 0, }, /* 306 */
+ { 38, 12, 3, 0, 0, }, /* 307 */
+ { 38, 10, 5, 0, 0, }, /* 308 */
+ { 38, 13, 12, 0, 0, }, /* 309 */
+ { 38, 21, 12, 0, 0, }, /* 310 */
+ { 38, 26, 12, 0, 0, }, /* 311 */
+ { 16, 9, 12, 0, 7264, }, /* 312 */
+ { 16, 7, 12, 0, 0, }, /* 313 */
+ { 16, 6, 12, 0, 0, }, /* 314 */
+ { 23, 7, 6, 0, 0, }, /* 315 */
+ { 23, 7, 7, 0, 0, }, /* 316 */
+ { 23, 7, 8, 0, 0, }, /* 317 */
+ { 15, 7, 12, 0, 0, }, /* 318 */
+ { 15, 12, 3, 0, 0, }, /* 319 */
+ { 15, 21, 12, 0, 0, }, /* 320 */
+ { 15, 15, 12, 0, 0, }, /* 321 */
+ { 15, 26, 12, 0, 0, }, /* 322 */
+ { 8, 9, 12, 0, 38864, }, /* 323 */
+ { 8, 9, 12, 0, 8, }, /* 324 */
+ { 8, 5, 12, 0, -8, }, /* 325 */
+ { 7, 17, 12, 0, 0, }, /* 326 */
+ { 7, 7, 12, 0, 0, }, /* 327 */
+ { 7, 21, 12, 0, 0, }, /* 328 */
+ { 40, 29, 12, 0, 0, }, /* 329 */
+ { 40, 7, 12, 0, 0, }, /* 330 */
+ { 40, 22, 12, 0, 0, }, /* 331 */
+ { 40, 18, 12, 0, 0, }, /* 332 */
+ { 45, 7, 12, 0, 0, }, /* 333 */
+ { 45, 14, 12, 0, 0, }, /* 334 */
+ { 50, 7, 12, 0, 0, }, /* 335 */
+ { 50, 12, 3, 0, 0, }, /* 336 */
+ { 24, 7, 12, 0, 0, }, /* 337 */
+ { 24, 12, 3, 0, 0, }, /* 338 */
+ { 6, 7, 12, 0, 0, }, /* 339 */
+ { 6, 12, 3, 0, 0, }, /* 340 */
+ { 51, 7, 12, 0, 0, }, /* 341 */
+ { 51, 12, 3, 0, 0, }, /* 342 */
+ { 31, 7, 12, 0, 0, }, /* 343 */
+ { 31, 12, 3, 0, 0, }, /* 344 */
+ { 31, 10, 5, 0, 0, }, /* 345 */
+ { 31, 21, 12, 0, 0, }, /* 346 */
+ { 31, 6, 12, 0, 0, }, /* 347 */
+ { 31, 23, 12, 0, 0, }, /* 348 */
+ { 31, 13, 12, 0, 0, }, /* 349 */
+ { 31, 15, 12, 0, 0, }, /* 350 */
+ { 37, 21, 12, 0, 0, }, /* 351 */
+ { 37, 17, 12, 0, 0, }, /* 352 */
+ { 37, 12, 3, 0, 0, }, /* 353 */
+ { 37, 1, 2, 0, 0, }, /* 354 */
+ { 37, 13, 12, 0, 0, }, /* 355 */
+ { 37, 7, 12, 0, 0, }, /* 356 */
+ { 37, 6, 12, 0, 0, }, /* 357 */
+ { 34, 7, 12, 0, 0, }, /* 358 */
+ { 34, 12, 3, 0, 0, }, /* 359 */
+ { 34, 10, 5, 0, 0, }, /* 360 */
+ { 34, 26, 12, 0, 0, }, /* 361 */
+ { 34, 21, 12, 0, 0, }, /* 362 */
+ { 34, 13, 12, 0, 0, }, /* 363 */
+ { 52, 7, 12, 0, 0, }, /* 364 */
+ { 39, 7, 12, 0, 0, }, /* 365 */
+ { 39, 13, 12, 0, 0, }, /* 366 */
+ { 39, 15, 12, 0, 0, }, /* 367 */
+ { 39, 26, 12, 0, 0, }, /* 368 */
+ { 31, 26, 12, 0, 0, }, /* 369 */
+ { 5, 7, 12, 0, 0, }, /* 370 */
+ { 5, 12, 3, 0, 0, }, /* 371 */
+ { 5, 10, 5, 0, 0, }, /* 372 */
+ { 5, 21, 12, 0, 0, }, /* 373 */
+ { 90, 7, 12, 0, 0, }, /* 374 */
+ { 90, 10, 5, 0, 0, }, /* 375 */
+ { 90, 12, 3, 0, 0, }, /* 376 */
+ { 90, 10, 12, 0, 0, }, /* 377 */
+ { 90, 13, 12, 0, 0, }, /* 378 */
+ { 90, 21, 12, 0, 0, }, /* 379 */
+ { 90, 6, 12, 0, 0, }, /* 380 */
+ { 27, 11, 3, 0, 0, }, /* 381 */
+ { 61, 12, 3, 0, 0, }, /* 382 */
+ { 61, 10, 5, 0, 0, }, /* 383 */
+ { 61, 7, 12, 0, 0, }, /* 384 */
+ { 61, 13, 12, 0, 0, }, /* 385 */
+ { 61, 21, 12, 0, 0, }, /* 386 */
+ { 61, 26, 12, 0, 0, }, /* 387 */
+ { 75, 12, 3, 0, 0, }, /* 388 */
+ { 75, 10, 5, 0, 0, }, /* 389 */
+ { 75, 7, 12, 0, 0, }, /* 390 */
+ { 75, 13, 12, 0, 0, }, /* 391 */
+ { 92, 7, 12, 0, 0, }, /* 392 */
+ { 92, 12, 3, 0, 0, }, /* 393 */
+ { 92, 10, 5, 0, 0, }, /* 394 */
+ { 92, 21, 12, 0, 0, }, /* 395 */
+ { 69, 7, 12, 0, 0, }, /* 396 */
+ { 69, 10, 5, 0, 0, }, /* 397 */
+ { 69, 12, 3, 0, 0, }, /* 398 */
+ { 69, 21, 12, 0, 0, }, /* 399 */
+ { 69, 13, 12, 0, 0, }, /* 400 */
+ { 72, 13, 12, 0, 0, }, /* 401 */
+ { 72, 7, 12, 0, 0, }, /* 402 */
+ { 72, 6, 12, 0, 0, }, /* 403 */
+ { 72, 21, 12, 0, 0, }, /* 404 */
+ { 75, 21, 12, 0, 0, }, /* 405 */
+ { 9, 10, 5, 0, 0, }, /* 406 */
+ { 9, 7, 12, 0, 0, }, /* 407 */
+ { 12, 5, 12, 0, 0, }, /* 408 */
+ { 12, 6, 12, 0, 0, }, /* 409 */
+ { 33, 5, 12, 0, 35332, }, /* 410 */
+ { 33, 5, 12, 0, 3814, }, /* 411 */
+ { 33, 9, 12, 63, 1, }, /* 412 */
+ { 33, 5, 12, 63, -1, }, /* 413 */
+ { 33, 5, 12, 63, -58, }, /* 414 */
+ { 33, 9, 12, 0, -7615, }, /* 415 */
+ { 19, 5, 12, 0, 8, }, /* 416 */
+ { 19, 9, 12, 0, -8, }, /* 417 */
+ { 19, 5, 12, 0, 74, }, /* 418 */
+ { 19, 5, 12, 0, 86, }, /* 419 */
+ { 19, 5, 12, 0, 100, }, /* 420 */
+ { 19, 5, 12, 0, 128, }, /* 421 */
+ { 19, 5, 12, 0, 112, }, /* 422 */
+ { 19, 5, 12, 0, 126, }, /* 423 */
+ { 19, 8, 12, 0, -8, }, /* 424 */
+ { 19, 5, 12, 0, 9, }, /* 425 */
+ { 19, 9, 12, 0, -74, }, /* 426 */
+ { 19, 8, 12, 0, -9, }, /* 427 */
+ { 19, 5, 12, 21, -7173, }, /* 428 */
+ { 19, 9, 12, 0, -86, }, /* 429 */
+ { 19, 9, 12, 0, -100, }, /* 430 */
+ { 19, 9, 12, 0, -112, }, /* 431 */
+ { 19, 9, 12, 0, -128, }, /* 432 */
+ { 19, 9, 12, 0, -126, }, /* 433 */
+ { 27, 1, 3, 0, 0, }, /* 434 */
+ { 9, 27, 2, 0, 0, }, /* 435 */
+ { 9, 28, 2, 0, 0, }, /* 436 */
+ { 9, 2, 2, 0, 0, }, /* 437 */
+ { 9, 9, 12, 0, 0, }, /* 438 */
+ { 9, 5, 12, 0, 0, }, /* 439 */
+ { 19, 9, 12, 67, -7517, }, /* 440 */
+ { 33, 9, 12, 71, -8383, }, /* 441 */
+ { 33, 9, 12, 75, -8262, }, /* 442 */
+ { 33, 9, 12, 0, 28, }, /* 443 */
+ { 33, 5, 12, 0, -28, }, /* 444 */
+ { 33, 14, 12, 0, 16, }, /* 445 */
+ { 33, 14, 12, 0, -16, }, /* 446 */
+ { 33, 14, 12, 0, 0, }, /* 447 */
+ { 9, 26, 12, 0, 26, }, /* 448 */
+ { 9, 26, 12, 0, -26, }, /* 449 */
+ { 4, 26, 12, 0, 0, }, /* 450 */
+ { 17, 9, 12, 0, 48, }, /* 451 */
+ { 17, 5, 12, 0, -48, }, /* 452 */
+ { 33, 9, 12, 0, -10743, }, /* 453 */
+ { 33, 9, 12, 0, -3814, }, /* 454 */
+ { 33, 9, 12, 0, -10727, }, /* 455 */
+ { 33, 5, 12, 0, -10795, }, /* 456 */
+ { 33, 5, 12, 0, -10792, }, /* 457 */
+ { 33, 9, 12, 0, -10780, }, /* 458 */
+ { 33, 9, 12, 0, -10749, }, /* 459 */
+ { 33, 9, 12, 0, -10783, }, /* 460 */
+ { 33, 9, 12, 0, -10782, }, /* 461 */
+ { 33, 9, 12, 0, -10815, }, /* 462 */
+ { 10, 5, 12, 0, 0, }, /* 463 */
+ { 10, 26, 12, 0, 0, }, /* 464 */
+ { 10, 12, 3, 0, 0, }, /* 465 */
+ { 10, 21, 12, 0, 0, }, /* 466 */
+ { 10, 15, 12, 0, 0, }, /* 467 */
+ { 16, 5, 12, 0, -7264, }, /* 468 */
+ { 58, 7, 12, 0, 0, }, /* 469 */
+ { 58, 6, 12, 0, 0, }, /* 470 */
+ { 58, 21, 12, 0, 0, }, /* 471 */
+ { 58, 12, 3, 0, 0, }, /* 472 */
+ { 22, 26, 12, 0, 0, }, /* 473 */
+ { 22, 6, 12, 0, 0, }, /* 474 */
+ { 22, 14, 12, 0, 0, }, /* 475 */
+ { 23, 10, 3, 0, 0, }, /* 476 */
+ { 26, 7, 12, 0, 0, }, /* 477 */
+ { 26, 6, 12, 0, 0, }, /* 478 */
+ { 29, 7, 12, 0, 0, }, /* 479 */
+ { 29, 6, 12, 0, 0, }, /* 480 */
+ { 3, 7, 12, 0, 0, }, /* 481 */
+ { 23, 7, 12, 0, 0, }, /* 482 */
+ { 23, 26, 12, 0, 0, }, /* 483 */
+ { 29, 26, 12, 0, 0, }, /* 484 */
+ { 22, 7, 12, 0, 0, }, /* 485 */
+ { 60, 7, 12, 0, 0, }, /* 486 */
+ { 60, 6, 12, 0, 0, }, /* 487 */
+ { 60, 26, 12, 0, 0, }, /* 488 */
+ { 85, 7, 12, 0, 0, }, /* 489 */
+ { 85, 6, 12, 0, 0, }, /* 490 */
+ { 85, 21, 12, 0, 0, }, /* 491 */
+ { 76, 7, 12, 0, 0, }, /* 492 */
+ { 76, 6, 12, 0, 0, }, /* 493 */
+ { 76, 21, 12, 0, 0, }, /* 494 */
+ { 76, 13, 12, 0, 0, }, /* 495 */
+ { 12, 7, 12, 0, 0, }, /* 496 */
+ { 12, 21, 12, 0, 0, }, /* 497 */
+ { 78, 7, 12, 0, 0, }, /* 498 */
+ { 78, 14, 12, 0, 0, }, /* 499 */
+ { 78, 12, 3, 0, 0, }, /* 500 */
+ { 78, 21, 12, 0, 0, }, /* 501 */
+ { 33, 9, 12, 0, -35332, }, /* 502 */
+ { 33, 9, 12, 0, -42280, }, /* 503 */
+ { 33, 9, 12, 0, -42308, }, /* 504 */
+ { 33, 9, 12, 0, -42319, }, /* 505 */
+ { 33, 9, 12, 0, -42315, }, /* 506 */
+ { 33, 9, 12, 0, -42305, }, /* 507 */
+ { 33, 9, 12, 0, -42258, }, /* 508 */
+ { 33, 9, 12, 0, -42282, }, /* 509 */
+ { 33, 9, 12, 0, -42261, }, /* 510 */
+ { 33, 9, 12, 0, 928, }, /* 511 */
+ { 48, 7, 12, 0, 0, }, /* 512 */
+ { 48, 12, 3, 0, 0, }, /* 513 */
+ { 48, 10, 5, 0, 0, }, /* 514 */
+ { 48, 26, 12, 0, 0, }, /* 515 */
+ { 64, 7, 12, 0, 0, }, /* 516 */
+ { 64, 21, 12, 0, 0, }, /* 517 */
+ { 74, 10, 5, 0, 0, }, /* 518 */
+ { 74, 7, 12, 0, 0, }, /* 519 */
+ { 74, 12, 3, 0, 0, }, /* 520 */
+ { 74, 21, 12, 0, 0, }, /* 521 */
+ { 74, 13, 12, 0, 0, }, /* 522 */
+ { 68, 13, 12, 0, 0, }, /* 523 */
+ { 68, 7, 12, 0, 0, }, /* 524 */
+ { 68, 12, 3, 0, 0, }, /* 525 */
+ { 68, 21, 12, 0, 0, }, /* 526 */
+ { 73, 7, 12, 0, 0, }, /* 527 */
+ { 73, 12, 3, 0, 0, }, /* 528 */
+ { 73, 10, 5, 0, 0, }, /* 529 */
+ { 73, 21, 12, 0, 0, }, /* 530 */
+ { 83, 12, 3, 0, 0, }, /* 531 */
+ { 83, 10, 5, 0, 0, }, /* 532 */
+ { 83, 7, 12, 0, 0, }, /* 533 */
+ { 83, 21, 12, 0, 0, }, /* 534 */
+ { 83, 13, 12, 0, 0, }, /* 535 */
+ { 38, 6, 12, 0, 0, }, /* 536 */
+ { 67, 7, 12, 0, 0, }, /* 537 */
+ { 67, 12, 3, 0, 0, }, /* 538 */
+ { 67, 10, 5, 0, 0, }, /* 539 */
+ { 67, 13, 12, 0, 0, }, /* 540 */
+ { 67, 21, 12, 0, 0, }, /* 541 */
+ { 91, 7, 12, 0, 0, }, /* 542 */
+ { 91, 12, 3, 0, 0, }, /* 543 */
+ { 91, 6, 12, 0, 0, }, /* 544 */
+ { 91, 21, 12, 0, 0, }, /* 545 */
+ { 86, 7, 12, 0, 0, }, /* 546 */
+ { 86, 10, 5, 0, 0, }, /* 547 */
+ { 86, 12, 3, 0, 0, }, /* 548 */
+ { 86, 21, 12, 0, 0, }, /* 549 */
+ { 86, 6, 12, 0, 0, }, /* 550 */
+ { 33, 5, 12, 0, -928, }, /* 551 */
+ { 8, 5, 12, 0, -38864, }, /* 552 */
+ { 86, 13, 12, 0, 0, }, /* 553 */
+ { 23, 7, 9, 0, 0, }, /* 554 */
+ { 23, 7, 10, 0, 0, }, /* 555 */
+ { 9, 4, 2, 0, 0, }, /* 556 */
+ { 9, 3, 12, 0, 0, }, /* 557 */
+ { 25, 25, 12, 0, 0, }, /* 558 */
+ { 0, 24, 12, 0, 0, }, /* 559 */
+ { 9, 6, 3, 0, 0, }, /* 560 */
+ { 35, 7, 12, 0, 0, }, /* 561 */
+ { 19, 14, 12, 0, 0, }, /* 562 */
+ { 19, 15, 12, 0, 0, }, /* 563 */
+ { 19, 26, 12, 0, 0, }, /* 564 */
+ { 70, 7, 12, 0, 0, }, /* 565 */
+ { 66, 7, 12, 0, 0, }, /* 566 */
+ { 41, 7, 12, 0, 0, }, /* 567 */
+ { 41, 15, 12, 0, 0, }, /* 568 */
+ { 18, 7, 12, 0, 0, }, /* 569 */
+ { 18, 14, 12, 0, 0, }, /* 570 */
+ { 117, 7, 12, 0, 0, }, /* 571 */
+ { 117, 12, 3, 0, 0, }, /* 572 */
+ { 59, 7, 12, 0, 0, }, /* 573 */
+ { 59, 21, 12, 0, 0, }, /* 574 */
+ { 42, 7, 12, 0, 0, }, /* 575 */
+ { 42, 21, 12, 0, 0, }, /* 576 */
+ { 42, 14, 12, 0, 0, }, /* 577 */
+ { 13, 9, 12, 0, 40, }, /* 578 */
+ { 13, 5, 12, 0, -40, }, /* 579 */
+ { 46, 7, 12, 0, 0, }, /* 580 */
+ { 44, 7, 12, 0, 0, }, /* 581 */
+ { 44, 13, 12, 0, 0, }, /* 582 */
+ { 105, 7, 12, 0, 0, }, /* 583 */
+ { 103, 7, 12, 0, 0, }, /* 584 */
+ { 103, 21, 12, 0, 0, }, /* 585 */
+ { 109, 7, 12, 0, 0, }, /* 586 */
+ { 11, 7, 12, 0, 0, }, /* 587 */
+ { 80, 7, 12, 0, 0, }, /* 588 */
+ { 80, 21, 12, 0, 0, }, /* 589 */
+ { 80, 15, 12, 0, 0, }, /* 590 */
+ { 119, 7, 12, 0, 0, }, /* 591 */
+ { 119, 26, 12, 0, 0, }, /* 592 */
+ { 119, 15, 12, 0, 0, }, /* 593 */
+ { 115, 7, 12, 0, 0, }, /* 594 */
+ { 115, 15, 12, 0, 0, }, /* 595 */
+ { 127, 7, 12, 0, 0, }, /* 596 */
+ { 127, 15, 12, 0, 0, }, /* 597 */
+ { 65, 7, 12, 0, 0, }, /* 598 */
+ { 65, 15, 12, 0, 0, }, /* 599 */
+ { 65, 21, 12, 0, 0, }, /* 600 */
+ { 71, 7, 12, 0, 0, }, /* 601 */
+ { 71, 21, 12, 0, 0, }, /* 602 */
+ { 97, 7, 12, 0, 0, }, /* 603 */
+ { 96, 7, 12, 0, 0, }, /* 604 */
+ { 96, 15, 12, 0, 0, }, /* 605 */
+ { 30, 7, 12, 0, 0, }, /* 606 */
+ { 30, 12, 3, 0, 0, }, /* 607 */
+ { 30, 15, 12, 0, 0, }, /* 608 */
+ { 30, 21, 12, 0, 0, }, /* 609 */
+ { 87, 7, 12, 0, 0, }, /* 610 */
+ { 87, 15, 12, 0, 0, }, /* 611 */
+ { 87, 21, 12, 0, 0, }, /* 612 */
+ { 116, 7, 12, 0, 0, }, /* 613 */
+ { 116, 15, 12, 0, 0, }, /* 614 */
+ { 111, 7, 12, 0, 0, }, /* 615 */
+ { 111, 26, 12, 0, 0, }, /* 616 */
+ { 111, 12, 3, 0, 0, }, /* 617 */
+ { 111, 15, 12, 0, 0, }, /* 618 */
+ { 111, 21, 12, 0, 0, }, /* 619 */
+ { 77, 7, 12, 0, 0, }, /* 620 */
+ { 77, 21, 12, 0, 0, }, /* 621 */
+ { 82, 7, 12, 0, 0, }, /* 622 */
+ { 82, 15, 12, 0, 0, }, /* 623 */
+ { 81, 7, 12, 0, 0, }, /* 624 */
+ { 81, 15, 12, 0, 0, }, /* 625 */
+ { 120, 7, 12, 0, 0, }, /* 626 */
+ { 120, 21, 12, 0, 0, }, /* 627 */
+ { 120, 15, 12, 0, 0, }, /* 628 */
+ { 88, 7, 12, 0, 0, }, /* 629 */
+ { 129, 9, 12, 0, 64, }, /* 630 */
+ { 129, 5, 12, 0, -64, }, /* 631 */
+ { 129, 15, 12, 0, 0, }, /* 632 */
+ { 0, 15, 12, 0, 0, }, /* 633 */
+ { 93, 10, 5, 0, 0, }, /* 634 */
+ { 93, 12, 3, 0, 0, }, /* 635 */
+ { 93, 7, 12, 0, 0, }, /* 636 */
+ { 93, 21, 12, 0, 0, }, /* 637 */
+ { 93, 15, 12, 0, 0, }, /* 638 */
+ { 93, 13, 12, 0, 0, }, /* 639 */
+ { 84, 12, 3, 0, 0, }, /* 640 */
+ { 84, 10, 5, 0, 0, }, /* 641 */
+ { 84, 7, 12, 0, 0, }, /* 642 */
+ { 84, 21, 12, 0, 0, }, /* 643 */
+ { 84, 1, 2, 0, 0, }, /* 644 */
+ { 100, 7, 12, 0, 0, }, /* 645 */
+ { 100, 13, 12, 0, 0, }, /* 646 */
+ { 95, 12, 3, 0, 0, }, /* 647 */
+ { 95, 7, 12, 0, 0, }, /* 648 */
+ { 95, 10, 5, 0, 0, }, /* 649 */
+ { 95, 13, 12, 0, 0, }, /* 650 */
+ { 95, 21, 12, 0, 0, }, /* 651 */
+ { 110, 7, 12, 0, 0, }, /* 652 */
+ { 110, 12, 3, 0, 0, }, /* 653 */
+ { 110, 21, 12, 0, 0, }, /* 654 */
+ { 99, 12, 3, 0, 0, }, /* 655 */
+ { 99, 10, 5, 0, 0, }, /* 656 */
+ { 99, 7, 12, 0, 0, }, /* 657 */
+ { 99, 21, 12, 0, 0, }, /* 658 */
+ { 99, 13, 12, 0, 0, }, /* 659 */
+ { 47, 15, 12, 0, 0, }, /* 660 */
+ { 107, 7, 12, 0, 0, }, /* 661 */
+ { 107, 10, 5, 0, 0, }, /* 662 */
+ { 107, 12, 3, 0, 0, }, /* 663 */
+ { 107, 21, 12, 0, 0, }, /* 664 */
+ { 128, 7, 12, 0, 0, }, /* 665 */
+ { 128, 21, 12, 0, 0, }, /* 666 */
+ { 108, 7, 12, 0, 0, }, /* 667 */
+ { 108, 12, 3, 0, 0, }, /* 668 */
+ { 108, 10, 5, 0, 0, }, /* 669 */
+ { 108, 13, 12, 0, 0, }, /* 670 */
+ { 106, 12, 3, 0, 0, }, /* 671 */
+ { 106, 10, 5, 0, 0, }, /* 672 */
+ { 106, 7, 12, 0, 0, }, /* 673 */
+ { 106, 10, 3, 0, 0, }, /* 674 */
+ { 123, 7, 12, 0, 0, }, /* 675 */
+ { 123, 10, 3, 0, 0, }, /* 676 */
+ { 123, 10, 5, 0, 0, }, /* 677 */
+ { 123, 12, 3, 0, 0, }, /* 678 */
+ { 123, 21, 12, 0, 0, }, /* 679 */
+ { 123, 13, 12, 0, 0, }, /* 680 */
+ { 122, 7, 12, 0, 0, }, /* 681 */
+ { 122, 10, 3, 0, 0, }, /* 682 */
+ { 122, 10, 5, 0, 0, }, /* 683 */
+ { 122, 12, 3, 0, 0, }, /* 684 */
+ { 122, 21, 12, 0, 0, }, /* 685 */
+ { 113, 7, 12, 0, 0, }, /* 686 */
+ { 113, 10, 5, 0, 0, }, /* 687 */
+ { 113, 12, 3, 0, 0, }, /* 688 */
+ { 113, 21, 12, 0, 0, }, /* 689 */
+ { 113, 13, 12, 0, 0, }, /* 690 */
+ { 101, 7, 12, 0, 0, }, /* 691 */
+ { 101, 12, 3, 0, 0, }, /* 692 */
+ { 101, 10, 5, 0, 0, }, /* 693 */
+ { 101, 13, 12, 0, 0, }, /* 694 */
+ { 125, 7, 12, 0, 0, }, /* 695 */
+ { 125, 12, 3, 0, 0, }, /* 696 */
+ { 125, 10, 5, 0, 0, }, /* 697 */
+ { 125, 13, 12, 0, 0, }, /* 698 */
+ { 125, 15, 12, 0, 0, }, /* 699 */
+ { 125, 21, 12, 0, 0, }, /* 700 */
+ { 125, 26, 12, 0, 0, }, /* 701 */
+ { 124, 9, 12, 0, 32, }, /* 702 */
+ { 124, 5, 12, 0, -32, }, /* 703 */
+ { 124, 13, 12, 0, 0, }, /* 704 */
+ { 124, 15, 12, 0, 0, }, /* 705 */
+ { 124, 7, 12, 0, 0, }, /* 706 */
+ { 121, 7, 12, 0, 0, }, /* 707 */
+ { 62, 7, 12, 0, 0, }, /* 708 */
+ { 62, 14, 12, 0, 0, }, /* 709 */
+ { 62, 21, 12, 0, 0, }, /* 710 */
+ { 79, 7, 12, 0, 0, }, /* 711 */
+ { 126, 7, 12, 0, 0, }, /* 712 */
+ { 114, 7, 12, 0, 0, }, /* 713 */
+ { 114, 13, 12, 0, 0, }, /* 714 */
+ { 114, 21, 12, 0, 0, }, /* 715 */
+ { 102, 7, 12, 0, 0, }, /* 716 */
+ { 102, 12, 3, 0, 0, }, /* 717 */
+ { 102, 21, 12, 0, 0, }, /* 718 */
+ { 118, 7, 12, 0, 0, }, /* 719 */
+ { 118, 12, 3, 0, 0, }, /* 720 */
+ { 118, 21, 12, 0, 0, }, /* 721 */
+ { 118, 26, 12, 0, 0, }, /* 722 */
+ { 118, 6, 12, 0, 0, }, /* 723 */
+ { 118, 13, 12, 0, 0, }, /* 724 */
+ { 118, 15, 12, 0, 0, }, /* 725 */
+ { 98, 7, 12, 0, 0, }, /* 726 */
+ { 98, 10, 5, 0, 0, }, /* 727 */
+ { 98, 12, 3, 0, 0, }, /* 728 */
+ { 98, 6, 12, 0, 0, }, /* 729 */
+ { 104, 7, 12, 0, 0, }, /* 730 */
+ { 104, 26, 12, 0, 0, }, /* 731 */
+ { 104, 12, 3, 0, 0, }, /* 732 */
+ { 104, 21, 12, 0, 0, }, /* 733 */
+ { 9, 10, 3, 0, 0, }, /* 734 */
+ { 19, 12, 3, 0, 0, }, /* 735 */
+ { 130, 26, 12, 0, 0, }, /* 736 */
+ { 130, 12, 3, 0, 0, }, /* 737 */
+ { 130, 21, 12, 0, 0, }, /* 738 */
+ { 112, 7, 12, 0, 0, }, /* 739 */
+ { 112, 15, 12, 0, 0, }, /* 740 */
+ { 112, 12, 3, 0, 0, }, /* 741 */
+ { 9, 26, 11, 0, 0, }, /* 742 */
+ { 26, 26, 12, 0, 0, }, /* 743 */
};
-const pcre_uint8 PRIV(ucd_stage1)[] = { /* 8704 bytes */
+const uint8_t PRIV(ucd_stage1)[] = { /* 8704 bytes */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* U+0000 */
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* U+0800 */
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 41, 41, 42, 43, 44, 45, /* U+1000 */
@@ -836,19 +863,19 @@ const pcre_uint8 PRIV(ucd_stage1)[] = { /* 8704 bytes */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+F000 */
123,123, 95, 95,124,125,126,127,128,128,129,130,131,132,133,134, /* U+F800 */
135,136,137,138,139,140,141,142,143,144,145,139,146,146,147,139, /* U+10000 */
-148,149,150,151,152,153,154,155,156,139,139,139,157,139,139,139, /* U+10800 */
-158,159,160,161,162,163,164,139,139,165,139,166,167,168,139,139, /* U+11000 */
-139,169,139,139,139,170,139,139,139,139,139,139,139,139,139,139, /* U+11800 */
-171,171,171,171,171,171,171,172,173,139,139,139,139,139,139,139, /* U+12000 */
+148,149,150,151,152,153,154,155,156,157,139,139,158,139,139,139, /* U+10800 */
+159,160,161,162,163,164,165,139,139,166,139,167,168,169,170,139, /* U+11000 */
+139,171,139,139,139,172,139,139,139,139,139,139,139,139,139,139, /* U+11800 */
+173,173,173,173,173,173,173,174,175,173,176,139,139,139,139,139, /* U+12000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+12800 */
-174,174,174,174,174,174,174,174,175,139,139,139,139,139,139,139, /* U+13000 */
+177,177,177,177,177,177,177,177,178,139,139,139,139,139,139,139, /* U+13000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+13800 */
-139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+14000 */
+139,139,139,139,139,139,139,139,179,179,179,179,180,139,139,139, /* U+14000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+14800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+15000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+15800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+16000 */
-176,176,176,176,177,178,179,180,139,139,139,139,139,139,181,182, /* U+16800 */
+181,181,181,181,182,183,184,185,139,139,139,139,139,139,186,187, /* U+16800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+17000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+17800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+18000 */
@@ -857,16 +884,16 @@ const pcre_uint8 PRIV(ucd_stage1)[] = { /* 8704 bytes */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+19800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1A000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1A800 */
-183,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1B000 */
-139,139,139,139,139,139,139,139,184,185,139,139,139,139,139,139, /* U+1B800 */
+188,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1B000 */
+139,139,139,139,139,139,139,139,189,190,139,139,139,139,139,139, /* U+1B800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1C000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1C800 */
- 71,186,187,188,189,139,190,139,191,192,193,194,195,196,197,198, /* U+1D000 */
-139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1D800 */
+ 71,191,192,193,194,139,195,139,196,197,198,199,200,201,202,203, /* U+1D000 */
+204,204,204,204,205,206,139,139,139,139,139,139,139,139,139,139, /* U+1D800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1E000 */
-199,200,139,139,139,139,139,139,139,139,139,139,201,202,139,139, /* U+1E800 */
-203,204,205,206,207,139,208,209, 71,210,211,212,213,214,215,216, /* U+1F000 */
-217,218,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1F800 */
+207,208,139,139,139,139,139,139,139,139,139,139,209,210,139,139, /* U+1E800 */
+211,212,213,214,215,139, 71,216, 71, 71,217,218, 71,219,220,221, /* U+1F000 */
+222,223,224,225,139,139,139,139,139,139,139,139,139,139,139,139, /* U+1F800 */
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+20000 */
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+20800 */
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+21000 */
@@ -887,18 +914,18 @@ const pcre_uint8 PRIV(ucd_stage1)[] = { /* 8704 bytes */
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+28800 */
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+29000 */
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+29800 */
- 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,219, 95, 95, /* U+2A000 */
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,226, 95, 95, /* U+2A000 */
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+2A800 */
- 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,220, 95, /* U+2B000 */
-221,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2B800 */
-139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2C000 */
-139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2C800 */
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,227, 95, /* U+2B000 */
+228, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+2B800 */
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, /* U+2C000 */
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,229,139,139, /* U+2C800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2D000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2D800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2E000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2E800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+2F000 */
- 95, 95, 95, 95,221,139,139,139,139,139,139,139,139,139,139,139, /* U+2F800 */
+ 95, 95, 95, 95,230,139,139,139,139,139,139,139,139,139,139,139, /* U+2F800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+30000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+30800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+31000 */
@@ -1251,8 +1278,8 @@ const pcre_uint8 PRIV(ucd_stage1)[] = { /* 8704 bytes */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DE800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DF000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+DF800 */
-222,223,224,225,223,223,223,223,223,223,223,223,223,223,223,223, /* U+E0000 */
-223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, /* U+E0800 */
+231,232,233,234,232,232,232,232,232,232,232,232,232,232,232,232, /* U+E0000 */
+232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, /* U+E0800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E1000 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E1800 */
139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, /* U+E2000 */
@@ -1314,7 +1341,7 @@ const pcre_uint8 PRIV(ucd_stage1)[] = { /* 8704 bytes */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FE000 */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FE800 */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+FF000 */
-123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,226, /* U+FF800 */
+123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,235, /* U+FF800 */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+100000 */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+100800 */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+101000 */
@@ -1346,10 +1373,10 @@ const pcre_uint8 PRIV(ucd_stage1)[] = { /* 8704 bytes */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10E000 */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10E800 */
123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, /* U+10F000 */
-123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,226, /* U+10F800 */
+123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,235, /* U+10F800 */
};
-const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
+const uint16_t PRIV(ucd_stage2)[] = { /* 60416 bytes, block = 128 */
/* block 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1402,533 +1429,533 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
/* block 5 */
99, 33, 33, 99, 33, 33, 33,100, 99,101,102,102,103, 33, 33, 33,
- 33, 33,104, 33, 20, 33, 33, 33, 33, 33, 33, 33, 33, 33,105, 33,
+ 33, 33,104, 33, 20, 33, 33, 33, 33, 33, 33, 33, 33,105,106, 33,
33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
-106,106,106,106,106,106,106,106,106,107,107,107,107,107,107,107,
-107,107, 14, 14, 14, 14,107,107,107,107,107,107,107,107,107,107,
-107,107, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
-106,106,106,106,106, 14, 14, 14, 14, 14,108,108,107, 14,107, 14,
+107,107,107,107,107,107,107,107,107,108,108,108,108,108,108,108,
+108,108, 14, 14, 14, 14,108,108,108,108,108,108,108,108,108,108,
+108,108, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+107,107,107,107,107, 14, 14, 14, 14, 14,109,109,108, 14,108, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
/* block 6 */
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,110,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-111,112,111,112,107,113,111,112,114,114,115,116,116,116, 4,117,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,111,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+112,113,112,113,108,114,112,113,115,115,116,117,117,117, 4,118,
/* block 7 */
-114,114,114,114,113, 14,118, 4,119,119,119,114,120,114,121,121,
-122,123,124,123,123,125,123,123,126,127,128,123,129,123,123,123,
-130,131,114,132,123,123,133,123,123,134,123,123,135,136,136,136,
-122,137,138,137,137,139,137,137,140,141,142,137,143,137,137,137,
-144,145,146,147,137,137,148,137,137,149,137,137,150,151,151,152,
-153,154,155,155,155,156,157,158,111,112,111,112,111,112,111,112,
-111,112,159,160,159,160,159,160,159,160,159,160,159,160,159,160,
-161,162,163,164,165,166,167,111,112,168,111,112,122,169,169,169,
+115,115,115,115,114, 14,119, 4,120,120,120,115,121,115,122,122,
+123,124,125,124,124,126,124,124,127,128,129,124,130,124,124,124,
+131,132,115,133,124,124,134,124,124,135,124,124,136,137,137,137,
+123,138,139,138,138,140,138,138,141,142,143,138,144,138,138,138,
+145,146,147,148,138,138,149,138,138,150,138,138,151,152,152,153,
+154,155,156,156,156,157,158,159,112,113,112,113,112,113,112,113,
+112,113,160,161,160,161,160,161,160,161,160,161,160,161,160,161,
+162,163,164,165,166,167,168,112,113,169,112,113,123,170,170,170,
/* block 8 */
-170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
-171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
+173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
+174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
/* block 9 */
-174,175,176,177,177,109,109,177,178,178,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-179,174,175,174,175,174,175,174,175,174,175,174,175,174,175,180,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
+175,176,177,178,178,110,110,178,179,179,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+180,175,176,175,176,175,176,175,176,175,176,175,176,175,176,181,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
/* block 10 */
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-114,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
-181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
-181,181,181,181,181,181,181,114,114,182,183,183,183,183,183,183,
-114,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
-184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+115,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+182,182,182,182,182,182,182,115,115,183,184,184,184,184,184,184,
+115,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
+185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
/* block 11 */
-184,184,184,184,184,184,184,185,114, 4,186,114,114,187,187,188,
-114,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
-189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
-189,189,189,189,189,189,189,189,189,189,189,189,189,189,190,189,
-191,189,189,191,189,189,191,189,114,114,114,114,114,114,114,114,
-192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,
-192,192,192,192,192,192,192,192,192,192,192,114,114,114,114,114,
-192,192,192,191,191,114,114,114,114,114,114,114,114,114,114,114,
+185,185,185,185,185,185,185,186,115, 4,187,115,115,188,188,189,
+115,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,
+190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,
+190,190,190,190,190,190,190,190,190,190,190,190,190,190,191,190,
+192,190,190,192,190,190,192,190,115,115,115,115,115,115,115,115,
+193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
+193,193,193,193,193,193,193,193,193,193,193,115,115,115,115,115,
+193,193,193,192,192,115,115,115,115,115,115,115,115,115,115,115,
/* block 12 */
-193,193,193,193,193, 22,194,194,194,195,195,196, 4,195,197,197,
-198,198,198,198,198,198,198,198,198,198,198, 4, 22,114,195, 4,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-107,199,199,199,199,199,199,199,199,199,199,109,109,109,109,109,
-109,109,109,109,109,109,198,198,198,198,198,198,198,198,198,198,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,195,195,195,195,199,199,
-109,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
+194,194,194,194,194, 22,195,195,195,196,196,197, 4,196,198,198,
+199,199,199,199,199,199,199,199,199,199,199, 4, 22,115,196, 4,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+108,200,200,200,200,200,200,200,200,200,200,110,110,110,110,110,
+110,110,110,110,110,110,199,199,199,199,199,199,199,199,199,199,
+201,201,201,201,201,201,201,201,201,201,196,196,196,196,200,200,
+110,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
/* block 13 */
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,195,199,198,198,198,198,198,198,198, 22,197,198,
-198,198,198,198,198,200,200,198,198,197,198,198,198,198,199,199,
-201,201,201,201,201,201,201,201,201,201,199,199,199,197,197,199,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,196,200,199,199,199,199,199,199,199, 22,198,199,
+199,199,199,199,199,202,202,199,199,198,199,199,199,199,200,200,
+201,201,201,201,201,201,201,201,201,201,200,200,200,198,198,200,
/* block 14 */
-202,202,202,202,202,202,202,202,202,202,202,202,202,202,114,203,
-204,205,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
-204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,
+203,203,203,203,203,203,203,203,203,203,203,203,203,203,115,204,
+205,206,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
-205,205,205,205,205,205,205,205,205,205,205,114,114,204,204,204,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
+206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,
+206,206,206,206,206,206,206,206,206,206,206,115,115,205,205,205,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
/* block 15 */
-206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,
-206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,
-206,206,206,206,206,206,207,207,207,207,207,207,207,207,207,207,
-207,206,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-208,208,208,208,208,208,208,208,208,208,209,209,209,209,209,209,
-209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,
-209,209,209,209,209,209,209,209,209,209,209,210,210,210,210,210,
-210,210,210,210,211,211,212,213,213,213,211,114,114,114,114,114,
+207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,
+207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,
+207,207,207,207,207,207,208,208,208,208,208,208,208,208,208,208,
+208,207,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+209,209,209,209,209,209,209,209,209,209,210,210,210,210,210,210,
+210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,
+210,210,210,210,210,210,210,210,210,210,210,211,211,211,211,211,
+211,211,211,211,212,212,213,214,214,214,212,115,115,115,115,115,
/* block 16 */
-214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,
-214,214,214,214,214,214,215,215,215,215,216,215,215,215,215,215,
-215,215,215,215,216,215,215,215,216,215,215,215,215,215,114,114,
-217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,114,
-218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,
-218,218,218,218,218,218,218,218,218,219,219,219,114,114,220,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,
+215,215,215,215,215,215,216,216,216,216,217,216,216,216,216,216,
+216,216,216,216,217,216,216,216,217,216,216,216,216,216,115,115,
+218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,115,
+219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,
+219,219,219,219,219,219,219,219,219,220,220,220,115,115,221,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 17 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,199,199,199,199,199,199,199,199,199,199,199,199,199,
199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,198,198,198,198,198,198,198,198,198,198,198,198,
-198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,
/* block 18 */
-221,221,221,222,223,223,223,223,223,223,223,223,223,223,223,223,
-223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
-223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
-223,223,223,223,223,223,223,223,223,223,221,222,221,223,222,222,
-222,221,221,221,221,221,221,221,221,222,222,222,222,221,222,222,
-223,109,109,221,221,221,221,221,223,223,223,223,223,223,223,223,
-223,223,221,221, 4, 4,224,224,224,224,224,224,224,224,224,224,
-225,226,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
+222,222,222,223,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,222,223,222,224,223,223,
+223,222,222,222,222,222,222,222,222,223,223,223,223,222,223,223,
+224,110,110,222,222,222,222,222,224,224,224,224,224,224,224,224,
+224,224,222,222, 4, 4,225,225,225,225,225,225,225,225,225,225,
+226,227,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
/* block 19 */
-227,228,229,229,114,227,227,227,227,227,227,227,227,114,114,227,
-227,114,114,227,227,227,227,227,227,227,227,227,227,227,227,227,
-227,227,227,227,227,227,227,227,227,114,227,227,227,227,227,227,
-227,114,227,114,114,114,227,227,227,227,114,114,228,227,230,229,
-229,228,228,228,228,114,114,229,229,114,114,229,229,228,227,114,
-114,114,114,114,114,114,114,230,114,114,114,114,227,227,114,227,
-227,227,228,228,114,114,231,231,231,231,231,231,231,231,231,231,
-227,227,232,232,233,233,233,233,233,233,234,232,114,114,114,114,
+228,229,230,230,115,228,228,228,228,228,228,228,228,115,115,228,
+228,115,115,228,228,228,228,228,228,228,228,228,228,228,228,228,
+228,228,228,228,228,228,228,228,228,115,228,228,228,228,228,228,
+228,115,228,115,115,115,228,228,228,228,115,115,229,228,231,230,
+230,229,229,229,229,115,115,230,230,115,115,230,230,229,228,115,
+115,115,115,115,115,115,115,231,115,115,115,115,228,228,115,228,
+228,228,229,229,115,115,232,232,232,232,232,232,232,232,232,232,
+228,228,233,233,234,234,234,234,234,234,235,233,115,115,115,115,
/* block 20 */
-114,235,235,236,114,237,237,237,237,237,237,114,114,114,114,237,
-237,114,114,237,237,237,237,237,237,237,237,237,237,237,237,237,
-237,237,237,237,237,237,237,237,237,114,237,237,237,237,237,237,
-237,114,237,237,114,237,237,114,237,237,114,114,235,114,236,236,
-236,235,235,114,114,114,114,235,235,114,114,235,235,235,114,114,
-114,235,114,114,114,114,114,114,114,237,237,237,237,114,237,114,
-114,114,114,114,114,114,238,238,238,238,238,238,238,238,238,238,
-235,235,237,237,237,235,114,114,114,114,114,114,114,114,114,114,
+115,236,236,237,115,238,238,238,238,238,238,115,115,115,115,238,
+238,115,115,238,238,238,238,238,238,238,238,238,238,238,238,238,
+238,238,238,238,238,238,238,238,238,115,238,238,238,238,238,238,
+238,115,238,238,115,238,238,115,238,238,115,115,236,115,237,237,
+237,236,236,115,115,115,115,236,236,115,115,236,236,236,115,115,
+115,236,115,115,115,115,115,115,115,238,238,238,238,115,238,115,
+115,115,115,115,115,115,239,239,239,239,239,239,239,239,239,239,
+236,236,238,238,238,236,115,115,115,115,115,115,115,115,115,115,
/* block 21 */
-114,239,239,240,114,241,241,241,241,241,241,241,241,241,114,241,
-241,241,114,241,241,241,241,241,241,241,241,241,241,241,241,241,
-241,241,241,241,241,241,241,241,241,114,241,241,241,241,241,241,
-241,114,241,241,114,241,241,241,241,241,114,114,239,241,240,240,
-240,239,239,239,239,239,114,239,239,240,114,240,240,239,114,114,
-241,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-241,241,239,239,114,114,242,242,242,242,242,242,242,242,242,242,
-243,244,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+115,240,240,241,115,242,242,242,242,242,242,242,242,242,115,242,
+242,242,115,242,242,242,242,242,242,242,242,242,242,242,242,242,
+242,242,242,242,242,242,242,242,242,115,242,242,242,242,242,242,
+242,115,242,242,115,242,242,242,242,242,115,115,240,242,241,241,
+241,240,240,240,240,240,115,240,240,241,115,241,241,240,115,115,
+242,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+242,242,240,240,115,115,243,243,243,243,243,243,243,243,243,243,
+244,245,115,115,115,115,115,115,115,242,115,115,115,115,115,115,
/* block 22 */
-114,245,246,246,114,247,247,247,247,247,247,247,247,114,114,247,
-247,114,114,247,247,247,247,247,247,247,247,247,247,247,247,247,
-247,247,247,247,247,247,247,247,247,114,247,247,247,247,247,247,
-247,114,247,247,114,247,247,247,247,247,114,114,245,247,248,245,
-246,245,245,245,245,114,114,246,246,114,114,246,246,245,114,114,
-114,114,114,114,114,114,245,248,114,114,114,114,247,247,114,247,
-247,247,245,245,114,114,249,249,249,249,249,249,249,249,249,249,
-250,247,251,251,251,251,251,251,114,114,114,114,114,114,114,114,
+115,246,247,247,115,248,248,248,248,248,248,248,248,115,115,248,
+248,115,115,248,248,248,248,248,248,248,248,248,248,248,248,248,
+248,248,248,248,248,248,248,248,248,115,248,248,248,248,248,248,
+248,115,248,248,115,248,248,248,248,248,115,115,246,248,249,246,
+247,246,246,246,246,115,115,247,247,115,115,247,247,246,115,115,
+115,115,115,115,115,115,246,249,115,115,115,115,248,248,115,248,
+248,248,246,246,115,115,250,250,250,250,250,250,250,250,250,250,
+251,248,252,252,252,252,252,252,115,115,115,115,115,115,115,115,
/* block 23 */
-114,114,252,253,114,253,253,253,253,253,253,114,114,114,253,253,
-253,114,253,253,253,253,114,114,114,253,253,114,253,114,253,253,
-114,114,114,253,253,114,114,114,253,253,253,114,114,114,253,253,
-253,253,253,253,253,253,253,253,253,253,114,114,114,114,254,255,
-252,255,255,114,114,114,255,255,255,114,255,255,255,252,114,114,
-253,114,114,114,114,114,114,254,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,256,256,256,256,256,256,256,256,256,256,
-257,257,257,258,258,258,258,258,258,259,258,114,114,114,114,114,
+115,115,253,254,115,254,254,254,254,254,254,115,115,115,254,254,
+254,115,254,254,254,254,115,115,115,254,254,115,254,115,254,254,
+115,115,115,254,254,115,115,115,254,254,254,115,115,115,254,254,
+254,254,254,254,254,254,254,254,254,254,115,115,115,115,255,256,
+253,256,256,115,115,115,256,256,256,115,256,256,256,253,115,115,
+254,115,115,115,115,115,115,255,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,257,257,257,257,257,257,257,257,257,257,
+258,258,258,259,259,259,259,259,259,260,259,115,115,115,115,115,
/* block 24 */
-260,261,261,261,114,262,262,262,262,262,262,262,262,114,262,262,
-262,114,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-262,262,262,262,262,262,262,262,262,114,262,262,262,262,262,262,
-262,262,262,262,262,262,262,262,262,262,114,114,114,262,260,260,
-260,261,261,261,261,114,260,260,260,114,260,260,260,260,114,114,
-114,114,114,114,114,260,260,114,262,262,114,114,114,114,114,114,
-262,262,260,260,114,114,263,263,263,263,263,263,263,263,263,263,
-114,114,114,114,114,114,114,114,264,264,264,264,264,264,264,265,
+261,262,262,262,115,263,263,263,263,263,263,263,263,115,263,263,
+263,115,263,263,263,263,263,263,263,263,263,263,263,263,263,263,
+263,263,263,263,263,263,263,263,263,115,263,263,263,263,263,263,
+263,263,263,263,263,263,263,263,263,263,115,115,115,263,261,261,
+261,262,262,262,262,115,261,261,261,115,261,261,261,261,115,115,
+115,115,115,115,115,261,261,115,263,263,263,115,115,115,115,115,
+263,263,261,261,115,115,264,264,264,264,264,264,264,264,264,264,
+115,115,115,115,115,115,115,115,265,265,265,265,265,265,265,266,
/* block 25 */
-114,266,267,267,114,268,268,268,268,268,268,268,268,114,268,268,
-268,114,268,268,268,268,268,268,268,268,268,268,268,268,268,268,
-268,268,268,268,268,268,268,268,268,114,268,268,268,268,268,268,
-268,268,268,268,114,268,268,268,268,268,114,114,266,268,267,266,
-267,267,269,267,267,114,266,267,267,114,267,267,266,266,114,114,
-114,114,114,114,114,269,269,114,114,114,114,114,114,114,268,114,
-268,268,266,266,114,114,270,270,270,270,270,270,270,270,270,270,
-114,268,268,114,114,114,114,114,114,114,114,114,114,114,114,114,
+115,267,268,268,115,269,269,269,269,269,269,269,269,115,269,269,
+269,115,269,269,269,269,269,269,269,269,269,269,269,269,269,269,
+269,269,269,269,269,269,269,269,269,115,269,269,269,269,269,269,
+269,269,269,269,115,269,269,269,269,269,115,115,267,269,268,267,
+268,268,270,268,268,115,267,268,268,115,268,268,267,267,115,115,
+115,115,115,115,115,270,270,115,115,115,115,115,115,115,269,115,
+269,269,267,267,115,115,271,271,271,271,271,271,271,271,271,271,
+115,269,269,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 26 */
-114,271,272,272,114,273,273,273,273,273,273,273,273,114,273,273,
-273,114,273,273,273,273,273,273,273,273,273,273,273,273,273,273,
-273,273,273,273,273,273,273,273,273,273,273,273,273,273,273,273,
-273,273,273,273,273,273,273,273,273,273,273,114,114,273,274,272,
-272,271,271,271,271,114,272,272,272,114,272,272,272,271,273,114,
-114,114,114,114,114,114,114,274,114,114,114,114,114,114,114,114,
-273,273,271,271,114,114,275,275,275,275,275,275,275,275,275,275,
-276,276,276,276,276,276,114,114,114,277,273,273,273,273,273,273,
+115,272,273,273,115,274,274,274,274,274,274,274,274,115,274,274,
+274,115,274,274,274,274,274,274,274,274,274,274,274,274,274,274,
+274,274,274,274,274,274,274,274,274,274,274,274,274,274,274,274,
+274,274,274,274,274,274,274,274,274,274,274,115,115,274,275,273,
+273,272,272,272,272,115,273,273,273,115,273,273,273,272,274,115,
+115,115,115,115,115,115,115,275,115,115,115,115,115,115,115,274,
+274,274,272,272,115,115,276,276,276,276,276,276,276,276,276,276,
+277,277,277,277,277,277,115,115,115,278,274,274,274,274,274,274,
/* block 27 */
-114,114,278,278,114,279,279,279,279,279,279,279,279,279,279,279,
-279,279,279,279,279,279,279,114,114,114,279,279,279,279,279,279,
-279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,
-279,279,114,279,279,279,279,279,279,279,279,279,114,279,114,114,
-279,279,279,279,279,279,279,114,114,114,280,114,114,114,114,281,
-278,278,280,280,280,114,280,114,278,278,278,278,278,278,278,281,
-114,114,114,114,114,114,282,282,282,282,282,282,282,282,282,282,
-114,114,278,278,283,114,114,114,114,114,114,114,114,114,114,114,
+115,115,279,279,115,280,280,280,280,280,280,280,280,280,280,280,
+280,280,280,280,280,280,280,115,115,115,280,280,280,280,280,280,
+280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,
+280,280,115,280,280,280,280,280,280,280,280,280,115,280,115,115,
+280,280,280,280,280,280,280,115,115,115,281,115,115,115,115,282,
+279,279,281,281,281,115,281,115,279,279,279,279,279,279,279,282,
+115,115,115,115,115,115,283,283,283,283,283,283,283,283,283,283,
+115,115,279,279,284,115,115,115,115,115,115,115,115,115,115,115,
/* block 28 */
-114,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,
-284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,
-284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,
-284,285,284,286,285,285,285,285,285,285,285,114,114,114,114, 5,
-284,284,284,284,284,284,287,285,285,285,285,285,285,285,285,288,
-289,289,289,289,289,289,289,289,289,289,288,288,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+115,285,285,285,285,285,285,285,285,285,285,285,285,285,285,285,
+285,285,285,285,285,285,285,285,285,285,285,285,285,285,285,285,
+285,285,285,285,285,285,285,285,285,285,285,285,285,285,285,285,
+285,286,285,287,286,286,286,286,286,286,286,115,115,115,115, 5,
+285,285,285,285,285,285,288,286,286,286,286,286,286,286,286,289,
+290,290,290,290,290,290,290,290,290,290,289,289,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 29 */
-114,290,290,114,290,114,114,290,290,114,290,114,114,290,114,114,
-114,114,114,114,290,290,290,290,114,290,290,290,290,290,290,290,
-114,290,290,290,114,290,114,290,114,114,290,290,114,290,290,290,
-290,291,290,292,291,291,291,291,291,291,114,291,291,290,114,114,
-290,290,290,290,290,114,293,114,291,291,291,291,291,291,114,114,
-294,294,294,294,294,294,294,294,294,294,114,114,290,290,290,290,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+115,291,291,115,291,115,115,291,291,115,291,115,115,291,115,115,
+115,115,115,115,291,291,291,291,115,291,291,291,291,291,291,291,
+115,291,291,291,115,291,115,291,115,115,291,291,115,291,291,291,
+291,292,291,293,292,292,292,292,292,292,115,292,292,291,115,115,
+291,291,291,291,291,115,294,115,292,292,292,292,292,292,115,115,
+295,295,295,295,295,295,295,295,295,295,115,115,291,291,291,291,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 30 */
-295,296,296,296,297,297,297,297,297,297,297,297,297,297,297,297,
-297,297,297,296,297,296,296,296,298,298,296,296,296,296,296,296,
-299,299,299,299,299,299,299,299,299,299,300,300,300,300,300,300,
-300,300,300,300,296,298,296,298,296,298,301,302,301,302,303,303,
-295,295,295,295,295,295,295,295,114,295,295,295,295,295,295,295,
-295,295,295,295,295,295,295,295,295,295,295,295,295,295,295,295,
-295,295,295,295,295,295,295,295,295,295,295,295,295,114,114,114,
-114,298,298,298,298,298,298,298,298,298,298,298,298,298,298,303,
+296,297,297,297,298,298,298,298,298,298,298,298,298,298,298,298,
+298,298,298,297,298,297,297,297,299,299,297,297,297,297,297,297,
+300,300,300,300,300,300,300,300,300,300,301,301,301,301,301,301,
+301,301,301,301,297,299,297,299,297,299,302,303,302,303,304,304,
+296,296,296,296,296,296,296,296,115,296,296,296,296,296,296,296,
+296,296,296,296,296,296,296,296,296,296,296,296,296,296,296,296,
+296,296,296,296,296,296,296,296,296,296,296,296,296,115,115,115,
+115,299,299,299,299,299,299,299,299,299,299,299,299,299,299,304,
/* block 31 */
-298,298,298,298,298,297,298,298,295,295,295,295,295,298,298,298,
-298,298,298,298,298,298,298,298,114,298,298,298,298,298,298,298,
-298,298,298,298,298,298,298,298,298,298,298,298,298,298,298,298,
-298,298,298,298,298,298,298,298,298,298,298,298,298,114,296,296,
-296,296,296,296,296,296,298,296,296,296,296,296,296,114,296,296,
-297,297,297,297,297, 19, 19, 19, 19,297,297,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+299,299,299,299,299,298,299,299,296,296,296,296,296,299,299,299,
+299,299,299,299,299,299,299,299,115,299,299,299,299,299,299,299,
+299,299,299,299,299,299,299,299,299,299,299,299,299,299,299,299,
+299,299,299,299,299,299,299,299,299,299,299,299,299,115,297,297,
+297,297,297,297,297,297,299,297,297,297,297,297,297,115,297,297,
+298,298,298,298,298, 19, 19, 19, 19,298,298,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 32 */
-304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,
-304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,
-304,304,304,304,304,304,304,304,304,304,304,305,305,306,306,306,
-306,307,306,306,306,306,306,306,305,306,306,307,307,306,306,304,
-308,308,308,308,308,308,308,308,308,308,309,309,309,309,309,309,
-304,304,304,304,304,304,307,307,306,306,304,304,304,304,306,306,
-306,304,305,305,305,304,304,305,305,305,305,305,305,305,304,304,
-304,306,306,306,306,304,304,304,304,304,304,304,304,304,304,304,
+305,305,305,305,305,305,305,305,305,305,305,305,305,305,305,305,
+305,305,305,305,305,305,305,305,305,305,305,305,305,305,305,305,
+305,305,305,305,305,305,305,305,305,305,305,306,306,307,307,307,
+307,308,307,307,307,307,307,307,306,307,307,308,308,307,307,305,
+309,309,309,309,309,309,309,309,309,309,310,310,310,310,310,310,
+305,305,305,305,305,305,308,308,307,307,305,305,305,305,307,307,
+307,305,306,306,306,305,305,306,306,306,306,306,306,306,305,305,
+305,307,307,307,307,305,305,305,305,305,305,305,305,305,305,305,
/* block 33 */
-304,304,306,305,307,306,306,305,305,305,305,305,305,306,304,305,
-308,308,308,308,308,308,308,308,308,308,305,305,305,306,310,310,
-311,311,311,311,311,311,311,311,311,311,311,311,311,311,311,311,
-311,311,311,311,311,311,311,311,311,311,311,311,311,311,311,311,
-311,311,311,311,311,311,114,311,114,114,114,114,114,311,114,114,
+305,305,307,306,308,307,307,306,306,306,306,306,306,307,305,306,
+309,309,309,309,309,309,309,309,309,309,306,306,306,307,311,311,
312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,
312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,312,
-312,312,312,312,312,312,312,312,312,312,312, 4,313,312,312,312,
+312,312,312,312,312,312,115,312,115,115,115,115,115,312,115,115,
+313,313,313,313,313,313,313,313,313,313,313,313,313,313,313,313,
+313,313,313,313,313,313,313,313,313,313,313,313,313,313,313,313,
+313,313,313,313,313,313,313,313,313,313,313, 4,314,313,313,313,
/* block 34 */
-314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
-314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
-314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
-314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
-314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
-314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,
315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,
-
-/* block 35 */
315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,
315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,
-315,315,315,315,315,315,315,315,316,316,316,316,316,316,316,316,
-316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,
+315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,
+315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,
316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,
316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,
+
+/* block 35 */
316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,
316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,
-
-/* block 36 */
+316,316,316,316,316,316,316,316,317,317,317,317,317,317,317,317,
317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,317,317,114,317,317,317,317,114,114,
-317,317,317,317,317,317,317,114,317,114,317,317,317,317,114,114,
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
+/* block 36 */
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,115,318,318,318,318,115,115,
+318,318,318,318,318,318,318,115,318,115,318,318,318,318,115,115,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+
/* block 37 */
-317,317,317,317,317,317,317,317,317,114,317,317,317,317,114,114,
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-317,114,317,317,317,317,114,114,317,317,317,317,317,317,317,114,
-317,114,317,317,317,317,114,114,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
+318,318,318,318,318,318,318,318,318,115,318,318,318,318,115,115,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,115,318,318,318,318,115,115,318,318,318,318,318,318,318,115,
+318,115,318,318,318,318,115,115,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,115,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
/* block 38 */
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-317,114,317,317,317,317,114,114,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,317,317,317,317,114,114,318,318,318,
-319,319,319,319,319,319,319,319,319,320,320,320,320,320,320,320,
-320,320,320,320,320,320,320,320,320,320,320,320,320,114,114,114,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,115,318,318,318,318,115,115,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,115,115,319,319,319,
+320,320,320,320,320,320,320,320,320,321,321,321,321,321,321,321,
+321,321,321,321,321,321,321,321,321,321,321,321,321,115,115,115,
/* block 39 */
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-321,321,321,321,321,321,321,321,321,321,114,114,114,114,114,114,
-322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,
-322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,
-322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,
-322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,
-322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,322,
-322,322,322,322,322,114,114,114,114,114,114,114,114,114,114,114,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+322,322,322,322,322,322,322,322,322,322,115,115,115,115,115,115,
+323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,
+323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,
+323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,
+323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,
+323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,323,
+324,324,324,324,324,324,115,115,325,325,325,325,325,325,115,115,
/* block 40 */
-323,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
+326,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
/* block 41 */
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
/* block 42 */
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,325,325,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,328,328,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
/* block 43 */
-326,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
-327,327,327,327,327,327,327,327,327,327,327,328,329,114,114,114,
-330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,
-330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,
-330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,
-330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,
-330,330,330,330,330,330,330,330,330,330,330, 4, 4, 4,331,331,
-331,330,330,330,330,330,330,330,330,114,114,114,114,114,114,114,
+329,330,330,330,330,330,330,330,330,330,330,330,330,330,330,330,
+330,330,330,330,330,330,330,330,330,330,330,331,332,115,115,115,
+333,333,333,333,333,333,333,333,333,333,333,333,333,333,333,333,
+333,333,333,333,333,333,333,333,333,333,333,333,333,333,333,333,
+333,333,333,333,333,333,333,333,333,333,333,333,333,333,333,333,
+333,333,333,333,333,333,333,333,333,333,333,333,333,333,333,333,
+333,333,333,333,333,333,333,333,333,333,333, 4, 4, 4,334,334,
+334,333,333,333,333,333,333,333,333,115,115,115,115,115,115,115,
/* block 44 */
-332,332,332,332,332,332,332,332,332,332,332,332,332,114,332,332,
-332,332,333,333,333,114,114,114,114,114,114,114,114,114,114,114,
-334,334,334,334,334,334,334,334,334,334,334,334,334,334,334,334,
-334,334,335,335,335, 4, 4,114,114,114,114,114,114,114,114,114,
-336,336,336,336,336,336,336,336,336,336,336,336,336,336,336,336,
-336,336,337,337,114,114,114,114,114,114,114,114,114,114,114,114,
-338,338,338,338,338,338,338,338,338,338,338,338,338,114,338,338,
-338,114,339,339,114,114,114,114,114,114,114,114,114,114,114,114,
+335,335,335,335,335,335,335,335,335,335,335,335,335,115,335,335,
+335,335,336,336,336,115,115,115,115,115,115,115,115,115,115,115,
+337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,
+337,337,338,338,338, 4, 4,115,115,115,115,115,115,115,115,115,
+339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,
+339,339,340,340,115,115,115,115,115,115,115,115,115,115,115,115,
+341,341,341,341,341,341,341,341,341,341,341,341,341,115,341,341,
+341,115,342,342,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 45 */
-340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
-340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
-340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
-340,340,340,340,341,341,342,341,341,341,341,341,341,341,342,342,
-342,342,342,342,342,342,341,342,342,341,341,341,341,341,341,341,
-341,341,341,341,343,343,343,344,343,343,343,345,340,341,114,114,
-346,346,346,346,346,346,346,346,346,346,114,114,114,114,114,114,
-347,347,347,347,347,347,347,347,347,347,114,114,114,114,114,114,
+343,343,343,343,343,343,343,343,343,343,343,343,343,343,343,343,
+343,343,343,343,343,343,343,343,343,343,343,343,343,343,343,343,
+343,343,343,343,343,343,343,343,343,343,343,343,343,343,343,343,
+343,343,343,343,344,344,345,344,344,344,344,344,344,344,345,345,
+345,345,345,345,345,345,344,345,345,344,344,344,344,344,344,344,
+344,344,344,344,346,346,346,347,346,346,346,348,343,344,115,115,
+349,349,349,349,349,349,349,349,349,349,115,115,115,115,115,115,
+350,350,350,350,350,350,350,350,350,350,115,115,115,115,115,115,
/* block 46 */
-348,348, 4, 4,348, 4,349,348,348,348,348,350,350,350,351,114,
-352,352,352,352,352,352,352,352,352,352,114,114,114,114,114,114,
-353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
-353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
-353,353,353,354,353,353,353,353,353,353,353,353,353,353,353,353,
-353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
-353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
-353,353,353,353,353,353,353,353,114,114,114,114,114,114,114,114,
+351,351, 4, 4,351, 4,352,351,351,351,351,353,353,353,354,115,
+355,355,355,355,355,355,355,355,355,355,115,115,115,115,115,115,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,357,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,115,115,115,115,115,115,115,115,
/* block 47 */
-353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
-353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,353,
-353,353,353,353,353,353,353,353,353,350,353,114,114,114,114,114,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,324,
-324,324,324,324,324,324,114,114,114,114,114,114,114,114,114,114,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,356,
+356,356,356,356,356,356,356,356,356,353,356,115,115,115,115,115,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,115,115,115,115,115,115,115,115,115,115,
/* block 48 */
-355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,
-355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,114,
-356,356,356,357,357,357,357,356,356,357,357,357,114,114,114,114,
-357,357,356,357,357,357,357,357,357,356,356,356,114,114,114,114,
-358,114,114,114,359,359,360,360,360,360,360,360,360,360,360,360,
-361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
-361,361,361,361,361,361,361,361,361,361,361,361,361,361,114,114,
-361,361,361,361,361,114,114,114,114,114,114,114,114,114,114,114,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,
+358,358,358,358,358,358,358,358,358,358,358,358,358,358,358,115,
+359,359,359,360,360,360,360,359,359,360,360,360,115,115,115,115,
+360,360,359,360,360,360,360,360,360,359,359,359,115,115,115,115,
+361,115,115,115,362,362,363,363,363,363,363,363,363,363,363,363,
+364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,364,
+364,364,364,364,364,364,364,364,364,364,364,364,364,364,115,115,
+364,364,364,364,364,115,115,115,115,115,115,115,115,115,115,115,
/* block 49 */
-362,362,362,362,362,362,362,362,362,362,362,362,362,362,362,362,
-362,362,362,362,362,362,362,362,362,362,362,362,362,362,362,362,
-362,362,362,362,362,362,362,362,362,362,362,362,114,114,114,114,
-363,363,363,363,363,364,364,364,363,363,364,363,363,363,363,363,
-363,362,362,362,362,362,362,362,363,363,114,114,114,114,114,114,
-365,365,365,365,365,365,365,365,365,365,366,114,114,114,367,367,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
-368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,368,
+365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,
+365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,
+365,365,365,365,365,365,365,365,365,365,365,365,115,115,115,115,
+365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,
+365,365,365,365,365,365,365,365,365,365,115,115,115,115,115,115,
+366,366,366,366,366,366,366,366,366,366,367,115,115,115,368,368,
+369,369,369,369,369,369,369,369,369,369,369,369,369,369,369,369,
+369,369,369,369,369,369,369,369,369,369,369,369,369,369,369,369,
/* block 50 */
-369,369,369,369,369,369,369,369,369,369,369,369,369,369,369,369,
-369,369,369,369,369,369,369,370,370,371,371,370,114,114,372,372,
-373,373,373,373,373,373,373,373,373,373,373,373,373,373,373,373,
-373,373,373,373,373,373,373,373,373,373,373,373,373,373,373,373,
-373,373,373,373,373,373,373,373,373,373,373,373,373,373,373,373,
-373,373,373,373,373,374,375,374,375,375,375,375,375,375,375,114,
-375,376,375,376,376,375,375,375,375,375,375,375,375,374,374,374,
-374,374,374,375,375,375,375,375,375,375,375,375,375,114,114,375,
+370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,370,
+370,370,370,370,370,370,370,371,371,372,372,371,115,115,373,373,
+374,374,374,374,374,374,374,374,374,374,374,374,374,374,374,374,
+374,374,374,374,374,374,374,374,374,374,374,374,374,374,374,374,
+374,374,374,374,374,374,374,374,374,374,374,374,374,374,374,374,
+374,374,374,374,374,375,376,375,376,376,376,376,376,376,376,115,
+376,377,376,377,377,376,376,376,376,376,376,376,376,375,375,375,
+375,375,375,376,376,376,376,376,376,376,376,376,376,115,115,376,
/* block 51 */
-377,377,377,377,377,377,377,377,377,377,114,114,114,114,114,114,
-377,377,377,377,377,377,377,377,377,377,114,114,114,114,114,114,
-378,378,378,378,378,378,378,379,378,378,378,378,378,378,114,114,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,380,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+378,378,378,378,378,378,378,378,378,378,115,115,115,115,115,115,
+378,378,378,378,378,378,378,378,378,378,115,115,115,115,115,115,
+379,379,379,379,379,379,379,380,379,379,379,379,379,379,115,115,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,381,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 52 */
-381,381,381,381,382,383,383,383,383,383,383,383,383,383,383,383,
-383,383,383,383,383,383,383,383,383,383,383,383,383,383,383,383,
-383,383,383,383,383,383,383,383,383,383,383,383,383,383,383,383,
-383,383,383,383,381,382,381,381,381,381,381,382,381,382,382,382,
-382,382,381,382,382,383,383,383,383,383,383,383,114,114,114,114,
-384,384,384,384,384,384,384,384,384,384,385,385,385,385,385,385,
-385,386,386,386,386,386,386,386,386,386,386,381,381,381,381,381,
-381,381,381,381,386,386,386,386,386,386,386,386,386,114,114,114,
+382,382,382,382,383,384,384,384,384,384,384,384,384,384,384,384,
+384,384,384,384,384,384,384,384,384,384,384,384,384,384,384,384,
+384,384,384,384,384,384,384,384,384,384,384,384,384,384,384,384,
+384,384,384,384,382,383,382,382,382,382,382,383,382,383,383,383,
+383,383,382,383,383,384,384,384,384,384,384,384,115,115,115,115,
+385,385,385,385,385,385,385,385,385,385,386,386,386,386,386,386,
+386,387,387,387,387,387,387,387,387,387,387,382,382,382,382,382,
+382,382,382,382,387,387,387,387,387,387,387,387,387,115,115,115,
/* block 53 */
-387,387,388,389,389,389,389,389,389,389,389,389,389,389,389,389,
-389,389,389,389,389,389,389,389,389,389,389,389,389,389,389,389,
-389,388,387,387,387,387,388,388,387,387,388,387,387,387,389,389,
-390,390,390,390,390,390,390,390,390,390,389,389,389,389,389,389,
-391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,
-391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,
-391,391,391,391,391,391,392,393,392,392,393,393,393,392,393,392,
-392,392,393,393,114,114,114,114,114,114,114,114,394,394,394,394,
+388,388,389,390,390,390,390,390,390,390,390,390,390,390,390,390,
+390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,
+390,389,388,388,388,388,389,389,388,388,389,388,388,388,390,390,
+391,391,391,391,391,391,391,391,391,391,390,390,390,390,390,390,
+392,392,392,392,392,392,392,392,392,392,392,392,392,392,392,392,
+392,392,392,392,392,392,392,392,392,392,392,392,392,392,392,392,
+392,392,392,392,392,392,393,394,393,393,394,394,394,393,394,393,
+393,393,394,394,115,115,115,115,115,115,115,115,395,395,395,395,
/* block 54 */
-395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,
-395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,
-395,395,395,395,396,396,396,396,396,396,396,396,397,397,397,397,
-397,397,397,397,396,396,397,397,114,114,114,398,398,398,398,398,
-399,399,399,399,399,399,399,399,399,399,114,114,114,395,395,395,
-400,400,400,400,400,400,400,400,400,400,401,401,401,401,401,401,
-401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,
-401,401,401,401,401,401,401,401,402,402,402,402,402,402,403,403,
+396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,
+396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,
+396,396,396,396,397,397,397,397,397,397,397,397,398,398,398,398,
+398,398,398,398,397,397,398,398,115,115,115,399,399,399,399,399,
+400,400,400,400,400,400,400,400,400,400,115,115,115,396,396,396,
+401,401,401,401,401,401,401,401,401,401,402,402,402,402,402,402,
+402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,402,
+402,402,402,402,402,402,402,402,403,403,403,403,403,403,404,404,
/* block 55 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-404,404,404,404,404,404,404,404,114,114,114,114,114,114,114,114,
-109,109,109, 4,109,109,109,109,109,109,109,109,109,109,109,109,
-109,405,109,109,109,109,109,109,109,406,406,406,406,109,406,406,
-406,406,405,405,109,406,406,114,109,109,114,114,114,114,114,114,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+405,405,405,405,405,405,405,405,115,115,115,115,115,115,115,115,
+110,110,110, 4,110,110,110,110,110,110,110,110,110,110,110,110,
+110,406,110,110,110,110,110,110,110,407,407,407,407,110,407,407,
+407,407,406,406,110,407,407,115,110,110,115,115,115,115,115,115,
/* block 56 */
33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33,122,122,122,122,122,407,106,106,106,106,
-106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
-106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
-106,106,106,106,106,106,106,106,106,106,106,106,106,115,115,115,
-115,115,106,106,106,106,115,115,115,115,115, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,408,409, 33, 33, 33,410, 33, 33,
+ 33, 33, 33, 33, 33, 33,123,123,123,123,123,408,107,107,107,107,
+107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
+107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
+107,107,107,107,107,107,107,107,107,107,107,107,107,116,116,116,
+116,116,107,107,107,107,116,116,116,116,116, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,409,410, 33, 33, 33,411, 33, 33,
/* block 57 */
33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,106,106,106,106,106,
-106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
-106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,115,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,114,114,114,114,114,114,109,109,109,109,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,107,107,107,107,107,
+107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
+107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,116,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,115,115,115,115,115,115,110,110,110,110,
/* block 58 */
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
@@ -1937,12 +1964,12 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
-411,412, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
+412,413, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
/* block 59 */
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
- 30, 31, 30, 31, 30, 31, 33, 33, 33, 33, 33,413, 33, 33,414, 33,
+ 30, 31, 30, 31, 30, 31, 33, 33, 33, 33, 33,414, 33, 33,415, 33,
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
@@ -1951,57 +1978,57 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
/* block 60 */
-415,415,415,415,415,415,415,415,416,416,416,416,416,416,416,416,
-415,415,415,415,415,415,114,114,416,416,416,416,416,416,114,114,
-415,415,415,415,415,415,415,415,416,416,416,416,416,416,416,416,
-415,415,415,415,415,415,415,415,416,416,416,416,416,416,416,416,
-415,415,415,415,415,415,114,114,416,416,416,416,416,416,114,114,
-122,415,122,415,122,415,122,415,114,416,114,416,114,416,114,416,
-415,415,415,415,415,415,415,415,416,416,416,416,416,416,416,416,
-417,417,418,418,418,418,419,419,420,420,421,421,422,422,114,114,
+416,416,416,416,416,416,416,416,417,417,417,417,417,417,417,417,
+416,416,416,416,416,416,115,115,417,417,417,417,417,417,115,115,
+416,416,416,416,416,416,416,416,417,417,417,417,417,417,417,417,
+416,416,416,416,416,416,416,416,417,417,417,417,417,417,417,417,
+416,416,416,416,416,416,115,115,417,417,417,417,417,417,115,115,
+123,416,123,416,123,416,123,416,115,417,115,417,115,417,115,417,
+416,416,416,416,416,416,416,416,417,417,417,417,417,417,417,417,
+418,418,419,419,419,419,420,420,421,421,422,422,423,423,115,115,
/* block 61 */
-415,415,415,415,415,415,415,415,423,423,423,423,423,423,423,423,
-415,415,415,415,415,415,415,415,423,423,423,423,423,423,423,423,
-415,415,415,415,415,415,415,415,423,423,423,423,423,423,423,423,
-415,415,122,424,122,114,122,122,416,416,425,425,426,113,427,113,
-113,113,122,424,122,114,122,122,428,428,428,428,426,113,113,113,
-415,415,122,122,114,114,122,122,416,416,429,429,114,113,113,113,
-415,415,122,122,122,163,122,122,416,416,430,430,168,113,113,113,
-114,114,122,424,122,114,122,122,431,431,432,432,426,113,113,114,
+416,416,416,416,416,416,416,416,424,424,424,424,424,424,424,424,
+416,416,416,416,416,416,416,416,424,424,424,424,424,424,424,424,
+416,416,416,416,416,416,416,416,424,424,424,424,424,424,424,424,
+416,416,123,425,123,115,123,123,417,417,426,426,427,114,428,114,
+114,114,123,425,123,115,123,123,429,429,429,429,427,114,114,114,
+416,416,123,123,115,115,123,123,417,417,430,430,115,114,114,114,
+416,416,123,123,123,164,123,123,417,417,431,431,169,114,114,114,
+115,115,123,425,123,115,123,123,432,432,433,433,427,114,114,115,
/* block 62 */
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 22,433,433, 22, 22,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 22,434,434, 22, 22,
9, 9, 9, 9, 9, 9, 4, 4, 21, 25, 6, 21, 21, 25, 6, 21,
- 4, 4, 4, 4, 4, 4, 4, 4,434,435, 22, 22, 22, 22, 22, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4,435,436, 22, 22, 22, 22, 22, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 21, 25, 4, 4, 4, 4, 15,
15, 4, 4, 4, 8, 6, 7, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 8, 4, 15, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3,
- 22, 22, 22, 22, 22,436, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 23,106,114,114, 23, 23, 23, 23, 23, 23, 8, 8, 8, 6, 7,106,
+ 22, 22, 22, 22, 22,437, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 23,107,115,115, 23, 23, 23, 23, 23, 23, 8, 8, 8, 6, 7,107,
/* block 63 */
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 8, 8, 8, 6, 7,114,
-106,106,106,106,106,106,106,106,106,106,106,106,106,114,114,114,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 8, 8, 8, 6, 7,115,
+107,107,107,107,107,107,107,107,107,107,107,107,107,115,115,115,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-109,109,109,109,109,109,109,109,109,109,109,109,109,380,380,380,
-380,109,380,380,380,109,109,109,109,109,109,109,109,109,109,109,
-109,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+110,110,110,110,110,110,110,110,110,110,110,110,110,381,381,381,
+381,110,381,381,381,110,110,110,110,110,110,110,110,110,110,110,
+110,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 64 */
- 19, 19,437, 19, 19, 19, 19,437, 19, 19,438,437,437,437,438,438,
-437,437,437,438, 19,437, 19, 19, 8,437,437,437,437,437, 19, 19,
- 19, 19, 19, 19,437, 19,439, 19,437, 19,440,441,437,437, 19,438,
-437,437,442,437,438,406,406,406,406,438, 19, 19,438,438,437,437,
- 8, 8, 8, 8, 8,437,438,438,438,438, 19, 8, 19, 19,443, 19,
+ 19, 19,438, 19, 19, 19, 19,438, 19, 19,439,438,438,438,439,439,
+438,438,438,439, 19,438, 19, 19, 8,438,438,438,438,438, 19, 19,
+ 19, 19, 19, 19,438, 19,440, 19,438, 19,441,442,438,438, 19,439,
+438,438,443,438,439,407,407,407,407,439, 19, 19,439,439,438,438,
+ 8, 8, 8, 8, 8,438,439,439,439,439, 19, 8, 19, 19,444, 19,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-444,444,444,444,444,444,444,444,444,444,444,444,444,444,444,444,
445,445,445,445,445,445,445,445,445,445,445,445,445,445,445,445,
+446,446,446,446,446,446,446,446,446,446,446,446,446,446,446,446,
/* block 65 */
-446,446,446, 30, 31,446,446,446,446, 23,114,114,114,114,114,114,
+447,447,447, 30, 31,447,447,447,447, 23, 19, 19,115,115,115,115,
8, 8, 8, 8, 8, 19, 19, 19, 19, 19, 8, 8, 19, 19, 19, 19,
8, 19, 19, 8, 19, 19, 8, 19, 19, 19, 19, 19, 19, 19, 8, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
@@ -2038,15 +2065,15 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8, 8,
8, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,
/* block 69 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
@@ -2054,10 +2081,10 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19,447,447,447,447,447,447,447,447,447,447,
-447,447,447,447,447,447,447,447,447,447,447,447,447,447,447,447,
+ 19, 19, 19, 19, 19, 19,448,448,448,448,448,448,448,448,448,448,
448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
-448,448,448,448,448,448,448,448,448,448, 23, 23, 23, 23, 23, 23,
+449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,
+449,449,449,449,449,449,449,449,449,449, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
/* block 71 */
@@ -2111,14 +2138,14 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
/* block 76 */
-449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,
-449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,
-449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,
-449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,
-449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,
-449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,
-449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,
-449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,449,
+450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
+450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
+450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
+450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
+450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
+450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
+450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
+450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
/* block 77 */
8, 8, 8, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6,
@@ -2138,147 +2165,147 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
8, 8, 8, 8, 8, 19, 19, 8, 8, 8, 8, 8, 8, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19,115,115, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
/* block 79 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19,114,114, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19,115,115, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19,114, 19, 19, 19, 19, 19, 19,
- 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19,115, 19, 19, 19, 19, 19, 19,
+ 19, 19,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115, 19, 19, 19, 19,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 80 */
-450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
-450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,
-450,450,450,450,450,450,450,450,450,450,450,450,450,450,450,114,
451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,
451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,
-451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,114,
- 30, 31,452,453,454,455,456, 30, 31, 30, 31, 30, 31,457,458,459,
-460, 33, 30, 31, 33, 30, 31, 33, 33, 33, 33, 33,106,106,461,461,
+451,451,451,451,451,451,451,451,451,451,451,451,451,451,451,115,
+452,452,452,452,452,452,452,452,452,452,452,452,452,452,452,452,
+452,452,452,452,452,452,452,452,452,452,452,452,452,452,452,452,
+452,452,452,452,452,452,452,452,452,452,452,452,452,452,452,115,
+ 30, 31,453,454,455,456,457, 30, 31, 30, 31, 30, 31,458,459,460,
+461, 33, 30, 31, 33, 30, 31, 33, 33, 33, 33, 33,107,107,462,462,
/* block 81 */
-159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160,
-159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160,
-159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160,
-159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160,
-159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160,
-159,160,159,160,159,160,159,160,159,160,159,160,159,160,159,160,
-159,160,159,160,462,463,463,463,463,463,463,159,160,159,160,464,
-464,464,159,160,114,114,114,114,114,465,465,465,465,466,465,465,
+160,161,160,161,160,161,160,161,160,161,160,161,160,161,160,161,
+160,161,160,161,160,161,160,161,160,161,160,161,160,161,160,161,
+160,161,160,161,160,161,160,161,160,161,160,161,160,161,160,161,
+160,161,160,161,160,161,160,161,160,161,160,161,160,161,160,161,
+160,161,160,161,160,161,160,161,160,161,160,161,160,161,160,161,
+160,161,160,161,160,161,160,161,160,161,160,161,160,161,160,161,
+160,161,160,161,463,464,464,464,464,464,464,160,161,160,161,465,
+465,465,160,161,115,115,115,115,115,466,466,466,466,467,466,466,
/* block 82 */
-467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,
-467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,
-467,467,467,467,467,467,114,467,114,114,114,114,114,467,114,114,
-468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,
468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,
468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,
-468,468,468,468,468,468,468,468,114,114,114,114,114,114,114,469,
-470,114,114,114,114,114,114,114,114,114,114,114,114,114,114,471,
+468,468,468,468,468,468,115,468,115,115,115,115,115,468,115,115,
+469,469,469,469,469,469,469,469,469,469,469,469,469,469,469,469,
+469,469,469,469,469,469,469,469,469,469,469,469,469,469,469,469,
+469,469,469,469,469,469,469,469,469,469,469,469,469,469,469,469,
+469,469,469,469,469,469,469,469,115,115,115,115,115,115,115,470,
+471,115,115,115,115,115,115,115,115,115,115,115,115,115,115,472,
/* block 83 */
-317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
-317,317,317,317,317,317,317,114,114,114,114,114,114,114,114,114,
-317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114,
-317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114,
-317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114,
-317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114,
-177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
-177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,115,115,115,115,115,115,115,115,115,
+318,318,318,318,318,318,318,115,318,318,318,318,318,318,318,115,
+318,318,318,318,318,318,318,115,318,318,318,318,318,318,318,115,
+318,318,318,318,318,318,318,115,318,318,318,318,318,318,318,115,
+318,318,318,318,318,318,318,115,318,318,318,318,318,318,318,115,
+178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
+178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
/* block 84 */
4, 4, 21, 25, 21, 25, 4, 4, 4, 21, 25, 4, 21, 25, 4, 4,
4, 4, 4, 4, 4, 4, 4, 9, 4, 4, 9, 4, 21, 25, 4, 4,
- 21, 25, 6, 7, 6, 7, 6, 7, 6, 7, 4, 4, 4, 4, 4,107,
+ 21, 25, 6, 7, 6, 7, 6, 7, 6, 7, 4, 4, 4, 4, 4,108,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 9, 9, 4, 4, 4, 4,
- 9, 4, 6,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+ 9, 4, 6,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 85 */
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,114,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,114,114,114,114,114,114,114,114,114,114,114,114,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,115,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 86 */
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
/* block 87 */
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
-472,472,472,472,472,472,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,
/* block 88 */
- 3, 4, 4, 4, 19,473,406,474, 6, 7, 6, 7, 6, 7, 6, 7,
+ 3, 4, 4, 4, 19,474,407,475, 6, 7, 6, 7, 6, 7, 6, 7,
6, 7, 19, 19, 6, 7, 6, 7, 6, 7, 6, 7, 9, 6, 7, 7,
- 19,474,474,474,474,474,474,474,474,474,109,109,109,109,475,475,
- 9,107,107,107,107,107, 19, 19,474,474,474,473,406, 4, 19, 19,
-114,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,
-476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,
-476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,
-476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,
+ 19,475,475,475,475,475,475,475,475,475,110,110,110,110,476,476,
+ 9,108,108,108,108,108, 19, 19,475,475,475,474,407, 4, 19, 19,
+115,477,477,477,477,477,477,477,477,477,477,477,477,477,477,477,
+477,477,477,477,477,477,477,477,477,477,477,477,477,477,477,477,
+477,477,477,477,477,477,477,477,477,477,477,477,477,477,477,477,
+477,477,477,477,477,477,477,477,477,477,477,477,477,477,477,477,
/* block 89 */
-476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,476,
-476,476,476,476,476,476,476,114,114,109,109, 14, 14,477,477,476,
- 9,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,
-478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,
-478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,
-478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,
-478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,
-478,478,478,478,478,478,478,478,478,478,478, 4,107,479,479,478,
+477,477,477,477,477,477,477,477,477,477,477,477,477,477,477,477,
+477,477,477,477,477,477,477,115,115,110,110, 14, 14,478,478,477,
+ 9,479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,
+479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,
+479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,
+479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,
+479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,
+479,479,479,479,479,479,479,479,479,479,479, 4,108,480,480,479,
/* block 90 */
-114,114,114,114,114,480,480,480,480,480,480,480,480,480,480,480,
-480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,
-480,480,480,480,480,480,480,480,480,480,480,480,480,480,114,114,
-114,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,
-481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,
-481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,
-481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,
+115,115,115,115,115,481,481,481,481,481,481,481,481,481,481,481,
481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,
+481,481,481,481,481,481,481,481,481,481,481,481,481,481,115,115,
+115,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,
+482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,
+482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,
+482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,
+482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,
/* block 91 */
-481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,114,
+482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,115,
19, 19, 23, 23, 23, 23, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,
-480,480,480,480,480,480,480,480,480,480,480,114,114,114,114,114,
+481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,
+481,481,481,481,481,481,481,481,481,481,481,115,115,115,115,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,
-478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,
+ 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,115,115,115,
+479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,
/* block 92 */
-482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,
-482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,114,
+483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
+483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,115,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 23, 23, 23, 23, 23, 23, 23, 23,
19, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,
-482,482,482,482,482,482,482,482,482,482,482,482,482,482,482, 19,
+483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
+483,483,483,483,483,483,483,483,483,483,483,483,483,483,483, 19,
/* block 93 */
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 19, 19, 19, 19, 19, 19,
@@ -2286,53 +2313,23 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,114,
-
-/* block 94 */
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-483,483,483,483,483,483,483,483, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-
-/* block 95 */
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,115,
+
+/* block 94 */
484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-
-/* block 96 */
484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,114,114,114,114,114,114,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+484,484,484,484,484,484,484,484, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-
-/* block 97 */
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-/* block 98 */
+/* block 95 */
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
-485,485,485,485,485,486,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
@@ -2340,877 +2337,957 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
-/* block 99 */
+/* block 96 */
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,115,115,115,115,115,115,115,115,115,115,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+/* block 97 */
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 98 */
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,487,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+
+/* block 99 */
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
/* block 100 */
-485,485,485,485,485,485,485,485,485,485,485,485,485,114,114,114,
-487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
-487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
-487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
-487,487,487,487,487,487,487,114,114,114,114,114,114,114,114,114,
+486,486,486,486,486,486,486,486,486,486,486,486,486,115,115,115,
+488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,
488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,
488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,
-488,488,488,488,488,488,488,488,489,489,489,489,489,489,490,490,
+488,488,488,488,488,488,488,115,115,115,115,115,115,115,115,115,
+489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,
+489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,
+489,489,489,489,489,489,489,489,490,490,490,490,490,490,491,491,
/* block 101 */
-491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,
-491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,
-491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,
-491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,
-491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,
-491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,
-491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,
-491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,
+492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,
+492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,
+492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,
+492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,
+492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,
+492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,
+492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,
+492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,
/* block 102 */
-491,491,491,491,491,491,491,491,491,491,491,491,492,493,493,493,
-491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,
-494,494,494,494,494,494,494,494,494,494,491,491,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,495,177,
-178,178,178,496,177,177,177,177,177,177,177,177,177,177,496,408,
+492,492,492,492,492,492,492,492,492,492,492,492,493,494,494,494,
+492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,492,
+495,495,495,495,495,495,495,495,495,495,492,492,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,496,178,
+179,179,179,497,178,178,178,178,178,178,178,178,178,178,497,409,
/* block 103 */
-174,175,174,175,174,175,174,175,174,175,174,175,174,175,174,175,
-174,175,174,175,174,175,174,175,174,175,174,175,408,408,114,177,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,498,498,498,498,498,498,498,498,498,498,
-499,499,500,500,500,500,500,500,114,114,114,114,114,114,114,114,
+175,176,175,176,175,176,175,176,175,176,175,176,175,176,175,176,
+175,176,175,176,175,176,175,176,175,176,175,176,409,409,178,178,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,499,499,499,499,499,499,499,499,499,499,
+500,500,501,501,501,501,501,501,115,115,115,115,115,115,115,115,
/* block 104 */
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14,107,107,107,107,107,107,107,107,107,
+ 14, 14, 14, 14, 14, 14, 14,108,108,108,108,108,108,108,108,108,
14, 14, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
33, 33, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
-106, 33, 33, 33, 33, 33, 33, 33, 33, 30, 31, 30, 31,501, 30, 31,
+107, 33, 33, 33, 33, 33, 33, 33, 33, 30, 31, 30, 31,502, 30, 31,
/* block 105 */
- 30, 31, 30, 31, 30, 31, 30, 31,107, 14, 14, 30, 31,502, 33,114,
+ 30, 31, 30, 31, 30, 31, 30, 31,108, 14, 14, 30, 31,503, 33, 20,
30, 31, 30, 31, 33, 33, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,
- 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,503,504,505,506,114,114,
-507,508,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114, 20,106,106, 33, 20, 20, 20, 20, 20,
+ 30, 31, 30, 31, 30, 31, 30, 31, 30, 31,504,505,506,507,115,115,
+508,509,510,511, 30, 31, 30, 31,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115, 20,107,107, 33, 20, 20, 20, 20, 20,
/* block 106 */
-509,509,510,509,509,509,510,509,509,509,509,510,509,509,509,509,
-509,509,509,509,509,509,509,509,509,509,509,509,509,509,509,509,
-509,509,509,511,511,510,510,511,512,512,512,512,114,114,114,114,
- 23, 23, 23, 23, 23, 23, 19, 19, 5, 19,114,114,114,114,114,114,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,513,513,514,514,514,514,114,114,114,114,114,114,114,114,
-
-/* block 107 */
-515,515,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+512,512,513,512,512,512,513,512,512,512,512,513,512,512,512,512,
+512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,
+512,512,512,514,514,513,513,514,515,515,515,515,115,115,115,115,
+ 23, 23, 23, 23, 23, 23, 19, 19, 5, 19,115,115,115,115,115,115,
516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
-516,516,516,516,515,515,515,515,515,515,515,515,515,515,515,515,
-515,515,515,515,517,114,114,114,114,114,114,114,114,114,518,518,
-519,519,519,519,519,519,519,519,519,519,114,114,114,114,114,114,
-221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,
-221,221,223,223,223,223,223,223,225,225,225,223,114,114,114,114,
+516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,516,
+516,516,516,516,517,517,517,517,115,115,115,115,115,115,115,115,
+
+/* block 107 */
+518,518,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,518,518,518,518,518,518,518,518,518,518,518,518,
+518,518,518,518,520,115,115,115,115,115,115,115,115,115,521,521,
+522,522,522,522,522,522,522,522,522,522,115,115,115,115,115,115,
+222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
+222,222,224,224,224,224,224,224,226,226,226,224,226,224,115,115,
/* block 108 */
-520,520,520,520,520,520,520,520,520,520,521,521,521,521,521,521,
-521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,
-521,521,521,521,521,521,522,522,522,522,522,522,522,522, 4,523,
+523,523,523,523,523,523,523,523,523,523,524,524,524,524,524,524,
524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
-524,524,524,524,524,524,524,525,525,525,525,525,525,525,525,525,
-525,525,526,526,114,114,114,114,114,114,114,114,114,114,114,527,
-314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
-314,314,314,314,314,314,314,314,314,314,314,314,314,114,114,114,
+524,524,524,524,524,524,525,525,525,525,525,525,525,525, 4,526,
+527,527,527,527,527,527,527,527,527,527,527,527,527,527,527,527,
+527,527,527,527,527,527,527,528,528,528,528,528,528,528,528,528,
+528,528,529,529,115,115,115,115,115,115,115,115,115,115,115,530,
+315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,
+315,315,315,315,315,315,315,315,315,315,315,315,315,115,115,115,
/* block 109 */
-528,528,528,529,530,530,530,530,530,530,530,530,530,530,530,530,
-530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
-530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
-530,530,530,528,529,529,528,528,528,528,529,529,528,529,529,529,
-529,531,531,531,531,531,531,531,531,531,531,531,531,531,114,107,
-532,532,532,532,532,532,532,532,532,532,114,114,114,114,531,531,
-304,304,304,304,304,306,533,304,304,304,304,304,304,304,304,304,
-308,308,308,308,308,308,308,308,308,308,304,304,304,304,304,114,
+531,531,531,532,533,533,533,533,533,533,533,533,533,533,533,533,
+533,533,533,533,533,533,533,533,533,533,533,533,533,533,533,533,
+533,533,533,533,533,533,533,533,533,533,533,533,533,533,533,533,
+533,533,533,531,532,532,531,531,531,531,532,532,531,532,532,532,
+532,534,534,534,534,534,534,534,534,534,534,534,534,534,115,108,
+535,535,535,535,535,535,535,535,535,535,115,115,115,115,534,534,
+305,305,305,305,305,307,536,305,305,305,305,305,305,305,305,305,
+309,309,309,309,309,309,309,309,309,309,305,305,305,305,305,115,
/* block 110 */
-534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
-534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,534,
-534,534,534,534,534,534,534,534,534,535,535,535,535,535,535,536,
-536,535,535,536,536,535,535,114,114,114,114,114,114,114,114,114,
-534,534,534,535,534,534,534,534,534,534,534,534,535,536,114,114,
-537,537,537,537,537,537,537,537,537,537,114,114,538,538,538,538,
-304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,
-533,304,304,304,304,304,304,310,310,310,304,305,306,305,304,304,
+537,537,537,537,537,537,537,537,537,537,537,537,537,537,537,537,
+537,537,537,537,537,537,537,537,537,537,537,537,537,537,537,537,
+537,537,537,537,537,537,537,537,537,538,538,538,538,538,538,539,
+539,538,538,539,539,538,538,115,115,115,115,115,115,115,115,115,
+537,537,537,538,537,537,537,537,537,537,537,537,538,539,115,115,
+540,540,540,540,540,540,540,540,540,540,115,115,541,541,541,541,
+305,305,305,305,305,305,305,305,305,305,305,305,305,305,305,305,
+536,305,305,305,305,305,305,311,311,311,305,306,307,306,305,305,
/* block 111 */
-539,539,539,539,539,539,539,539,539,539,539,539,539,539,539,539,
-539,539,539,539,539,539,539,539,539,539,539,539,539,539,539,539,
-539,539,539,539,539,539,539,539,539,539,539,539,539,539,539,539,
-540,539,540,540,540,539,539,540,540,539,539,539,539,539,540,540,
-539,540,539,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,539,539,541,542,542,
-543,543,543,543,543,543,543,543,543,543,543,544,545,545,544,544,
-546,546,543,547,547,544,545,114,114,114,114,114,114,114,114,114,
+542,542,542,542,542,542,542,542,542,542,542,542,542,542,542,542,
+542,542,542,542,542,542,542,542,542,542,542,542,542,542,542,542,
+542,542,542,542,542,542,542,542,542,542,542,542,542,542,542,542,
+543,542,543,543,543,542,542,543,543,542,542,542,542,542,543,543,
+542,543,542,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,542,542,544,545,545,
+546,546,546,546,546,546,546,546,546,546,546,547,548,548,547,547,
+549,549,546,550,550,547,548,115,115,115,115,115,115,115,115,115,
/* block 112 */
-114,317,317,317,317,317,317,114,114,317,317,317,317,317,317,114,
-114,317,317,317,317,317,317,114,114,114,114,114,114,114,114,114,
-317,317,317,317,317,317,317,114,317,317,317,317,317,317,317,114,
+115,318,318,318,318,318,318,115,115,318,318,318,318,318,318,115,
+115,318,318,318,318,318,318,115,115,115,115,115,115,115,115,115,
+318,318,318,318,318,318,318,115,318,318,318,318,318,318,318,115,
33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 14,106,106,106,106,
-114,114,114,114, 33,122,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+ 33, 33, 33,551, 33, 33, 33, 33, 33, 33, 33, 14,107,107,107,107,
+ 33, 33, 33, 33, 33,123,115,115,115,115,115,115,115,115,115,115,
+552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
/* block 113 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-543,543,543,543,543,543,543,543,543,543,543,543,543,543,543,543,
-543,543,543,543,543,543,543,543,543,543,543,543,543,543,543,543,
-543,543,543,544,544,545,544,544,545,544,544,546,544,545,114,114,
-548,548,548,548,548,548,548,548,548,548,114,114,114,114,114,114,
+552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
+552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
+552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
+552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
+546,546,546,546,546,546,546,546,546,546,546,546,546,546,546,546,
+546,546,546,546,546,546,546,546,546,546,546,546,546,546,546,546,
+546,546,546,547,547,548,547,547,548,547,547,549,547,548,115,115,
+553,553,553,553,553,553,553,553,553,553,115,115,115,115,115,115,
/* block 114 */
-549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
+554,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,554,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,554,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,554,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+554,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
/* block 115 */
-550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550,
+555,555,555,555,555,555,555,555,555,555,555,555,554,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,554,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,554,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+554,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,554,555,555,555,
/* block 116 */
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,554,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,554,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+554,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,554,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
/* block 117 */
-550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550,
+555,555,555,555,555,555,555,555,554,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,554,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+554,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,554,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,554,555,555,555,555,555,555,555,
/* block 118 */
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,554,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+554,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,554,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,554,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
/* block 119 */
-550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550,
+555,555,555,555,554,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+554,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,554,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,554,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,554,555,555,555,555,555,555,555,555,555,555,555,
/* block 120 */
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-549,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,549,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,549,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+554,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,554,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,554,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,554,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
/* block 121 */
-550,550,550,550,550,550,550,550,549,550,550,550,550,550,550,550,
-550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,550,
-550,550,550,550,114,114,114,114,114,114,114,114,114,114,114,114,
-315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,315,
-315,315,315,315,315,315,315,114,114,114,114,316,316,316,316,316,
+555,555,555,555,555,555,555,555,554,555,555,555,555,555,555,555,
+555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,555,
+555,555,555,555,115,115,115,115,115,115,115,115,115,115,115,115,
316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,
-316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,316,
-316,316,316,316,316,316,316,316,316,316,316,316,114,114,114,114,
+316,316,316,316,316,316,316,115,115,115,115,317,317,317,317,317,
+317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
+317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,317,
+317,317,317,317,317,317,317,317,317,317,317,317,115,115,115,115,
/* block 122 */
-551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,
-551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,
-551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,
-551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,
-551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,
-551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,
-551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,
-551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,551,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
/* block 123 */
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
/* block 124 */
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,114,114,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,115,115,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
/* block 125 */
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 126 */
- 33, 33, 33, 33, 33, 33, 33,114,114,114,114,114,114,114,114,114,
-114,114,114,185,185,185,185,185,114,114,114,114,114,192,189,192,
-192,192,192,192,192,192,192,192,192,553,192,192,192,192,192,192,
-192,192,192,192,192,192,192,114,192,192,192,192,192,114,192,114,
-192,192,114,192,192,114,192,192,192,192,192,192,192,192,192,192,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
+ 33, 33, 33, 33, 33, 33, 33,115,115,115,115,115,115,115,115,115,
+115,115,115,186,186,186,186,186,115,115,115,115,115,193,190,193,
+193,193,193,193,193,193,193,193,193,558,193,193,193,193,193,193,
+193,193,193,193,193,193,193,115,193,193,193,193,193,115,193,115,
+193,193,115,193,193,115,193,193,193,193,193,193,193,193,193,193,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
/* block 127 */
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,554,554,554,554,554,554,554,554,554,554,554,554,554,554,
-554,554,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
/* block 128 */
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
/* block 129 */
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199, 7, 6,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200, 7, 6,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
/* block 130 */
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-114,114,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-199,199,199,199,199,199,199,199,199,199,199,199,196,197,114,114,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+115,115,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+200,200,200,200,200,200,200,200,200,200,200,200,197,198,115,115,
/* block 131 */
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
- 4, 4, 4, 4, 4, 4, 4, 6, 7, 4,114,114,114,114,114,114,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,114,114,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+ 4, 4, 4, 4, 4, 4, 4, 6, 7, 4,115,115,115,115,115,115,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,178,178,
4, 9, 9, 15, 15, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6,
7, 6, 7, 6, 7, 4, 4, 6, 7, 4, 4, 4, 4, 15, 15, 15,
- 4, 4, 4,114, 4, 4, 4, 4, 9, 6, 7, 6, 7, 6, 7, 4,
- 4, 4, 8, 9, 8, 8, 8,114, 4, 5, 4, 4,114,114,114,114,
-199,199,199,199,199,114,199,199,199,199,199,199,199,199,199,199,
+ 4, 4, 4,115, 4, 4, 4, 4, 9, 6, 7, 6, 7, 6, 7, 4,
+ 4, 4, 8, 9, 8, 8, 8,115, 4, 5, 4, 4,115,115,115,115,
+200,200,200,200,200,115,200,200,200,200,200,200,200,200,200,200,
/* block 132 */
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,114,114, 22,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,115,115, 22,
/* block 133 */
-114, 4, 4, 4, 5, 4, 4, 4, 6, 7, 4, 8, 4, 9, 4, 4,
+115, 4, 4, 4, 5, 4, 4, 4, 6, 7, 4, 8, 4, 9, 4, 4,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 4, 8, 8, 8, 4,
4, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6, 4, 7, 14, 15,
14, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 6, 8, 7, 8, 6,
- 7, 4, 6, 7, 4, 4,478,478,478,478,478,478,478,478,478,478,
-107,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,
+ 7, 4, 6, 7, 4, 4,479,479,479,479,479,479,479,479,479,479,
+108,479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,
/* block 134 */
-478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,478,
-478,478,478,478,478,478,478,478,478,478,478,478,478,478,555,555,
-481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,
-481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,114,
-114,114,481,481,481,481,481,481,114,114,481,481,481,481,481,481,
-114,114,481,481,481,481,481,481,114,114,481,481,481,114,114,114,
- 5, 5, 8, 14, 19, 5, 5,114, 19, 8, 8, 8, 8, 19, 19,114,
-436,436,436,436,436,436,436,436,436, 22, 22, 22, 19, 19,114,114,
+479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,479,
+479,479,479,479,479,479,479,479,479,479,479,479,479,479,560,560,
+482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,
+482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,115,
+115,115,482,482,482,482,482,482,115,115,482,482,482,482,482,482,
+115,115,482,482,482,482,482,482,115,115,482,482,482,115,115,115,
+ 5, 5, 8, 14, 19, 5, 5,115, 19, 8, 8, 8, 8, 19, 19,115,
+437,437,437,437,437,437,437,437,437, 22, 22, 22, 19, 19,115,115,
/* block 135 */
-556,556,556,556,556,556,556,556,556,556,556,556,114,556,556,556,
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
-556,556,556,556,556,556,556,114,556,556,556,556,556,556,556,556,
-556,556,556,556,556,556,556,556,556,556,556,114,556,556,114,556,
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,114,114,
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+561,561,561,561,561,561,561,561,561,561,561,561,115,561,561,561,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
+561,561,561,561,561,561,561,115,561,561,561,561,561,561,561,561,
+561,561,561,561,561,561,561,561,561,561,561,115,561,561,115,561,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,115,115,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 136 */
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
-556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
-556,556,556,556,556,556,556,556,556,556,556,114,114,114,114,114,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
+561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
+561,561,561,561,561,561,561,561,561,561,561,115,115,115,115,115,
/* block 137 */
- 4, 4, 4,114,114,114,114, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 4, 4, 4,115,115,115,115, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
-557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
-557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
-557,557,557,557,557,558,558,558,558,559,559,559,559,559,559,559,
+ 23, 23, 23, 23,115,115,115, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,
+562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,
+562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,
+562,562,562,562,562,563,563,563,563,564,564,564,564,564,564,564,
/* block 138 */
-559,559,559,559,559,559,559,559,559,559,558,558,559,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,
-559,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+564,564,564,564,564,564,564,564,564,564,563,563,564,115,115,115,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,
+564,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,109,114,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,110,115,115,
/* block 139 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 140 */
-560,560,560,560,560,560,560,560,560,560,560,560,560,560,560,560,
-560,560,560,560,560,560,560,560,560,560,560,560,560,114,114,114,
-561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
-561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
-561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,561,
-561,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-109, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,114,114,114,114,
-
-/* block 141 */
-562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,
-562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,562,
-563,563,563,563,114,114,114,114,114,114,114,114,114,114,114,114,
-564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,
-564,565,564,564,564,564,564,564,564,564,565,114,114,114,114,114,
+565,565,565,565,565,565,565,565,565,565,565,565,565,565,565,565,
+565,565,565,565,565,565,565,565,565,565,565,565,565,115,115,115,
+566,566,566,566,566,566,566,566,566,566,566,566,566,566,566,566,
566,566,566,566,566,566,566,566,566,566,566,566,566,566,566,566,
566,566,566,566,566,566,566,566,566,566,566,566,566,566,566,566,
-566,566,566,566,566,566,567,567,567,567,567,114,114,114,114,114,
+566,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+110, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,115,115,115,115,
-/* block 142 */
-568,568,568,568,568,568,568,568,568,568,568,568,568,568,568,568,
-568,568,568,568,568,568,568,568,568,568,568,568,568,568,114,569,
-570,570,570,570,570,570,570,570,570,570,570,570,570,570,570,570,
-570,570,570,570,570,570,570,570,570,570,570,570,570,570,570,570,
-570,570,570,570,114,114,114,114,570,570,570,570,570,570,570,570,
-571,572,572,572,572,572,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+/* block 141 */
+567,567,567,567,567,567,567,567,567,567,567,567,567,567,567,567,
+567,567,567,567,567,567,567,567,567,567,567,567,567,567,567,567,
+568,568,568,568,115,115,115,115,115,115,115,115,115,115,115,115,
+569,569,569,569,569,569,569,569,569,569,569,569,569,569,569,569,
+569,570,569,569,569,569,569,569,569,569,570,115,115,115,115,115,
+571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,
+571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,571,
+571,571,571,571,571,571,572,572,572,572,572,115,115,115,115,115,
-/* block 143 */
-573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+/* block 142 */
573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,573,573,573,574,574,574,574,574,574,574,574,
-574,574,574,574,574,574,574,574,574,574,574,574,574,574,574,574,
-574,574,574,574,574,574,574,574,574,574,574,574,574,574,574,574,
-575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,115,574,
575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,
575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,
+575,575,575,575,115,115,115,115,575,575,575,575,575,575,575,575,
+576,577,577,577,577,577,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 144 */
-576,576,576,576,576,576,576,576,576,576,576,576,576,576,576,576,
-576,576,576,576,576,576,576,576,576,576,576,576,576,576,114,114,
-577,577,577,577,577,577,577,577,577,577,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-
-/* block 145 */
+/* block 143 */
578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,578,
-578,578,578,578,578,578,578,578,114,114,114,114,114,114,114,114,
+578,578,578,578,578,578,578,578,579,579,579,579,579,579,579,579,
579,579,579,579,579,579,579,579,579,579,579,579,579,579,579,579,
579,579,579,579,579,579,579,579,579,579,579,579,579,579,579,579,
-579,579,579,579,579,579,579,579,579,579,579,579,579,579,579,579,
-579,579,579,579,114,114,114,114,114,114,114,114,114,114,114,580,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
+580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
+580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,580,
-/* block 146 */
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
+/* block 144 */
581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
+581,581,581,581,581,581,581,581,581,581,581,581,581,581,115,115,
+582,582,582,582,582,582,582,582,582,582,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 145 */
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
+583,583,583,583,583,583,583,583,115,115,115,115,115,115,115,115,
+584,584,584,584,584,584,584,584,584,584,584,584,584,584,584,584,
+584,584,584,584,584,584,584,584,584,584,584,584,584,584,584,584,
+584,584,584,584,584,584,584,584,584,584,584,584,584,584,584,584,
+584,584,584,584,115,115,115,115,115,115,115,115,115,115,115,585,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 146 */
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
/* block 147 */
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,581,114,114,114,114,114,114,114,114,114,
-581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,581,
-581,581,581,581,581,581,114,114,114,114,114,114,114,114,114,114,
-581,581,581,581,581,581,581,581,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,115,115,115,115,115,115,115,115,115,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,115,115,115,115,115,115,115,115,115,115,
+586,586,586,586,586,586,586,586,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 148 */
-582,582,582,582,582,582,114,114,582,114,582,582,582,582,582,582,
-582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,
-582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,
-582,582,582,582,582,582,114,582,582,114,114,114,582,114,114,582,
-583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,583,
-583,583,583,583,583,583,114,584,585,585,585,585,585,585,585,585,
-586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
-586,586,586,586,586,586,586,587,587,588,588,588,588,588,588,588,
+587,587,587,587,587,587,115,115,587,115,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,
+587,587,587,587,587,587,115,587,587,115,115,115,587,115,115,587,
+588,588,588,588,588,588,588,588,588,588,588,588,588,588,588,588,
+588,588,588,588,588,588,115,589,590,590,590,590,590,590,590,590,
+591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,
+591,591,591,591,591,591,591,592,592,593,593,593,593,593,593,593,
/* block 149 */
-589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,
-589,589,589,589,589,589,589,589,589,589,589,589,589,589,589,114,
-114,114,114,114,114,114,114,590,590,590,590,590,590,590,590,590,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,
+594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,115,
+115,115,115,115,115,115,115,595,595,595,595,595,595,595,595,595,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
+596,596,596,115,596,596,115,115,115,115,115,597,597,597,597,597,
/* block 150 */
-591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,
-591,591,591,591,591,591,592,592,592,592,592,592,114,114,114,593,
-594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,594,
-594,594,594,594,594,594,594,594,594,594,114,114,114,114,114,595,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+598,598,598,598,598,598,598,598,598,598,598,598,598,598,598,598,
+598,598,598,598,598,598,599,599,599,599,599,599,115,115,115,600,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,115,115,115,115,115,602,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 151 */
-596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
-596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
-597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
-597,597,597,597,597,597,597,597,114,114,114,114,114,114,597,597,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+603,603,603,603,603,603,603,603,603,603,603,603,603,603,603,603,
+603,603,603,603,603,603,603,603,603,603,603,603,603,603,603,603,
+604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,
+604,604,604,604,604,604,604,604,115,115,115,115,605,605,604,604,
+605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,
+115,115,605,605,605,605,605,605,605,605,605,605,605,605,605,605,
+605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,
+605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,
/* block 152 */
-598,599,599,599,114,599,599,114,114,114,114,114,599,599,599,599,
-598,598,598,598,114,598,598,598,114,598,598,598,598,598,598,598,
-598,598,598,598,598,598,598,598,598,598,598,598,598,598,598,598,
-598,598,598,598,114,114,114,114,599,599,599,114,114,114,114,599,
-600,600,600,600,600,600,600,600,114,114,114,114,114,114,114,114,
-601,601,601,601,601,601,601,601,601,114,114,114,114,114,114,114,
-602,602,602,602,602,602,602,602,602,602,602,602,602,602,602,602,
-602,602,602,602,602,602,602,602,602,602,602,602,602,603,603,604,
+606,607,607,607,115,607,607,115,115,115,115,115,607,607,607,607,
+606,606,606,606,115,606,606,606,115,606,606,606,606,606,606,606,
+606,606,606,606,606,606,606,606,606,606,606,606,606,606,606,606,
+606,606,606,606,115,115,115,115,607,607,607,115,115,115,115,607,
+608,608,608,608,608,608,608,608,115,115,115,115,115,115,115,115,
+609,609,609,609,609,609,609,609,609,115,115,115,115,115,115,115,
+610,610,610,610,610,610,610,610,610,610,610,610,610,610,610,610,
+610,610,610,610,610,610,610,610,610,610,610,610,610,611,611,612,
/* block 153 */
-605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,
-605,605,605,605,605,605,605,605,605,605,605,605,605,606,606,606,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-607,607,607,607,607,607,607,607,608,607,607,607,607,607,607,607,
-607,607,607,607,607,607,607,607,607,607,607,607,607,607,607,607,
-607,607,607,607,607,609,609,114,114,114,114,610,610,610,610,610,
-611,611,611,611,611,611,611,114,114,114,114,114,114,114,114,114,
+613,613,613,613,613,613,613,613,613,613,613,613,613,613,613,613,
+613,613,613,613,613,613,613,613,613,613,613,613,613,614,614,614,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+615,615,615,615,615,615,615,615,616,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,617,617,115,115,115,115,618,618,618,618,618,
+619,619,619,619,619,619,619,115,115,115,115,115,115,115,115,115,
/* block 154 */
-612,612,612,612,612,612,612,612,612,612,612,612,612,612,612,612,
-612,612,612,612,612,612,612,612,612,612,612,612,612,612,612,612,
-612,612,612,612,612,612,612,612,612,612,612,612,612,612,612,612,
-612,612,612,612,612,612,114,114,114,613,613,613,613,613,613,613,
-614,614,614,614,614,614,614,614,614,614,614,614,614,614,614,614,
-614,614,614,614,614,614,114,114,615,615,615,615,615,615,615,615,
-616,616,616,616,616,616,616,616,616,616,616,616,616,616,616,616,
-616,616,616,114,114,114,114,114,617,617,617,617,617,617,617,617,
+620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,
+620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,
+620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,
+620,620,620,620,620,620,115,115,115,621,621,621,621,621,621,621,
+622,622,622,622,622,622,622,622,622,622,622,622,622,622,622,622,
+622,622,622,622,622,622,115,115,623,623,623,623,623,623,623,623,
+624,624,624,624,624,624,624,624,624,624,624,624,624,624,624,624,
+624,624,624,115,115,115,115,115,625,625,625,625,625,625,625,625,
/* block 155 */
-618,618,618,618,618,618,618,618,618,618,618,618,618,618,618,618,
-618,618,114,114,114,114,114,114,114,619,619,619,619,114,114,114,
-114,114,114,114,114,114,114,114,114,620,620,620,620,620,620,620,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+626,626,626,626,626,626,626,626,626,626,626,626,626,626,626,626,
+626,626,115,115,115,115,115,115,115,627,627,627,627,115,115,115,
+115,115,115,115,115,115,115,115,115,628,628,628,628,628,628,628,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 156 */
-621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,
-621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,
-621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,
-621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,
-621,621,621,621,621,621,621,621,621,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,
+629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,
+629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,
+629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,
+629,629,629,629,629,629,629,629,629,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 157 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-622,622,622,622,622,622,622,622,622,622,622,622,622,622,622,622,
-622,622,622,622,622,622,622,622,622,622,622,622,622,622,622,114,
+630,630,630,630,630,630,630,630,630,630,630,630,630,630,630,630,
+630,630,630,630,630,630,630,630,630,630,630,630,630,630,630,630,
+630,630,630,630,630,630,630,630,630,630,630,630,630,630,630,630,
+630,630,630,115,115,115,115,115,115,115,115,115,115,115,115,115,
+631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
+631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
+631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
+631,631,631,115,115,115,115,115,115,115,632,632,632,632,632,632,
/* block 158 */
-623,624,623,625,625,625,625,625,625,625,625,625,625,625,625,625,
-625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,
-625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,
-625,625,625,625,625,625,625,625,624,624,624,624,624,624,624,624,
-624,624,624,624,624,624,624,626,626,626,626,626,626,626,114,114,
-114,114,627,627,627,627,627,627,627,627,627,627,627,627,627,627,
-627,627,627,627,627,627,628,628,628,628,628,628,628,628,628,628,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,624,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+633,633,633,633,633,633,633,633,633,633,633,633,633,633,633,633,
+633,633,633,633,633,633,633,633,633,633,633,633,633,633,633,115,
/* block 159 */
-629,629,630,631,631,631,631,631,631,631,631,631,631,631,631,631,
-631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
-631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,631,
-630,630,630,629,629,629,629,630,630,629,629,632,632,633,632,632,
-632,632,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-634,634,634,634,634,634,634,634,634,634,634,634,634,634,634,634,
-634,634,634,634,634,634,634,634,634,114,114,114,114,114,114,114,
-635,635,635,635,635,635,635,635,635,635,114,114,114,114,114,114,
+634,635,634,636,636,636,636,636,636,636,636,636,636,636,636,636,
+636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,
+636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,
+636,636,636,636,636,636,636,636,635,635,635,635,635,635,635,635,
+635,635,635,635,635,635,635,637,637,637,637,637,637,637,115,115,
+115,115,638,638,638,638,638,638,638,638,638,638,638,638,638,638,
+638,638,638,638,638,638,639,639,639,639,639,639,639,639,639,639,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,635,
/* block 160 */
-636,636,636,637,637,637,637,637,637,637,637,637,637,637,637,637,
-637,637,637,637,637,637,637,637,637,637,637,637,637,637,637,637,
-637,637,637,637,637,637,637,636,636,636,636,636,638,636,636,636,
-636,636,636,636,636,114,639,639,639,639,639,639,639,639,639,639,
-640,640,640,640,114,114,114,114,114,114,114,114,114,114,114,114,
-641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,
-641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,641,
-641,641,641,642,643,643,641,114,114,114,114,114,114,114,114,114,
+640,640,641,642,642,642,642,642,642,642,642,642,642,642,642,642,
+642,642,642,642,642,642,642,642,642,642,642,642,642,642,642,642,
+642,642,642,642,642,642,642,642,642,642,642,642,642,642,642,642,
+641,641,641,640,640,640,640,641,641,640,640,643,643,644,643,643,
+643,643,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+645,645,645,645,645,645,645,645,645,645,645,645,645,645,645,645,
+645,645,645,645,645,645,645,645,645,115,115,115,115,115,115,115,
+646,646,646,646,646,646,646,646,646,646,115,115,115,115,115,115,
/* block 161 */
-644,644,645,646,646,646,646,646,646,646,646,646,646,646,646,646,
-646,646,646,646,646,646,646,646,646,646,646,646,646,646,646,646,
-646,646,646,646,646,646,646,646,646,646,646,646,646,646,646,646,
-646,646,646,645,645,645,644,644,644,644,644,644,644,644,644,645,
-645,646,646,646,646,647,647,647,647,114,114,114,114,647,114,114,
-648,648,648,648,648,648,648,648,648,648,646,114,114,114,114,114,
-114,649,649,649,649,649,649,649,649,649,649,649,649,649,649,649,
-649,649,649,649,649,114,114,114,114,114,114,114,114,114,114,114,
+647,647,647,648,648,648,648,648,648,648,648,648,648,648,648,648,
+648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,
+648,648,648,648,648,648,648,647,647,647,647,647,649,647,647,647,
+647,647,647,647,647,115,650,650,650,650,650,650,650,650,650,650,
+651,651,651,651,115,115,115,115,115,115,115,115,115,115,115,115,
+652,652,652,652,652,652,652,652,652,652,652,652,652,652,652,652,
+652,652,652,652,652,652,652,652,652,652,652,652,652,652,652,652,
+652,652,652,653,654,654,652,115,115,115,115,115,115,115,115,115,
/* block 162 */
-650,650,650,650,650,650,650,650,650,650,650,650,650,650,650,650,
-650,650,114,650,650,650,650,650,650,650,650,650,650,650,650,650,
-650,650,650,650,650,650,650,650,650,650,650,650,651,651,651,652,
-652,652,651,651,652,651,652,652,653,653,653,653,653,653,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+655,655,656,657,657,657,657,657,657,657,657,657,657,657,657,657,
+657,657,657,657,657,657,657,657,657,657,657,657,657,657,657,657,
+657,657,657,657,657,657,657,657,657,657,657,657,657,657,657,657,
+657,657,657,656,656,656,655,655,655,655,655,655,655,655,655,656,
+656,657,657,657,657,658,658,658,658,658,655,655,655,658,115,115,
+659,659,659,659,659,659,659,659,659,659,657,658,657,658,658,658,
+115,660,660,660,660,660,660,660,660,660,660,660,660,660,660,660,
+660,660,660,660,660,115,115,115,115,115,115,115,115,115,115,115,
/* block 163 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-654,654,654,654,654,654,654,654,654,654,654,654,654,654,654,654,
-654,654,654,654,654,654,654,654,654,654,654,654,654,654,654,654,
-654,654,654,654,654,654,654,654,654,654,654,654,654,654,654,655,
-656,656,656,655,655,655,655,655,655,655,655,114,114,114,114,114,
-657,657,657,657,657,657,657,657,657,657,114,114,114,114,114,114,
+661,661,661,661,661,661,661,661,661,661,661,661,661,661,661,661,
+661,661,115,661,661,661,661,661,661,661,661,661,661,661,661,661,
+661,661,661,661,661,661,661,661,661,661,661,661,662,662,662,663,
+663,663,662,662,663,662,663,663,664,664,664,664,664,664,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 164 */
-114,658,659,659,114,660,660,660,660,660,660,660,660,114,114,660,
-660,114,114,660,660,660,660,660,660,660,660,660,660,660,660,660,
-660,660,660,660,660,660,660,660,660,114,660,660,660,660,660,660,
-660,114,660,660,114,660,660,660,660,660,114,114,658,660,661,659,
-658,659,659,659,659,114,114,659,659,114,114,659,659,659,114,114,
-114,114,114,114,114,114,114,661,114,114,114,114,114,660,660,660,
-660,660,659,659,114,114,658,658,658,658,658,658,658,114,114,114,
-658,658,658,658,658,114,114,114,114,114,114,114,114,114,114,114,
+665,665,665,665,665,665,665,115,665,115,665,665,665,665,115,665,
+665,665,665,665,665,665,665,665,665,665,665,665,665,665,115,665,
+665,665,665,665,665,665,665,665,665,666,115,115,115,115,115,115,
+667,667,667,667,667,667,667,667,667,667,667,667,667,667,667,667,
+667,667,667,667,667,667,667,667,667,667,667,667,667,667,667,667,
+667,667,667,667,667,667,667,667,667,667,667,667,667,667,667,668,
+669,669,669,668,668,668,668,668,668,668,668,115,115,115,115,115,
+670,670,670,670,670,670,670,670,670,670,115,115,115,115,115,115,
/* block 165 */
-662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
-662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
-662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
-663,664,664,665,665,665,665,665,665,664,665,664,664,663,664,665,
-665,664,665,665,662,662,666,662,114,114,114,114,114,114,114,114,
-667,667,667,667,667,667,667,667,667,667,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+671,671,672,672,115,673,673,673,673,673,673,673,673,115,115,673,
+673,115,115,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,115,673,673,673,673,673,673,
+673,115,673,673,115,673,673,673,673,673,115,115,671,673,674,672,
+671,672,672,672,672,115,115,672,672,115,115,672,672,672,115,115,
+673,115,115,115,115,115,115,674,115,115,115,115,115,673,673,673,
+673,673,672,672,115,115,671,671,671,671,671,671,671,115,115,115,
+671,671,671,671,671,115,115,115,115,115,115,115,115,115,115,115,
/* block 166 */
-668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
-668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
-668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,669,
-670,670,671,671,671,671,114,114,670,670,670,670,671,671,670,671,
-671,672,672,672,672,672,672,672,672,672,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,
+675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,
+675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,
+676,677,677,678,678,678,678,678,678,677,678,677,677,676,677,678,
+678,677,678,678,675,675,679,675,115,115,115,115,115,115,115,115,
+680,680,680,680,680,680,680,680,680,680,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 167 */
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
-674,674,674,675,675,675,675,675,675,675,675,674,674,675,674,675,
-675,676,676,676,673,114,114,114,114,114,114,114,114,114,114,114,
-677,677,677,677,677,677,677,677,677,677,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,
+681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,
+681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,682,
+683,683,684,684,684,684,115,115,683,683,683,683,684,684,683,684,
+684,685,685,685,685,685,685,685,685,685,685,685,685,685,685,685,
+685,685,685,685,685,685,685,685,681,681,681,681,684,684,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 168 */
-678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
-678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
-678,678,678,678,678,678,678,678,678,678,678,679,680,679,680,680,
-679,679,679,679,679,679,680,679,114,114,114,114,114,114,114,114,
-681,681,681,681,681,681,681,681,681,681,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,
+686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,
+686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,686,
+687,687,687,688,688,688,688,688,688,688,688,687,687,688,687,688,
+688,689,689,689,686,115,115,115,115,115,115,115,115,115,115,115,
+690,690,690,690,690,690,690,690,690,690,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 169 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-682,682,682,682,682,682,682,682,682,682,682,682,682,682,682,682,
-682,682,682,682,682,682,682,682,682,682,682,682,682,682,682,682,
-683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,
-683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,683,
-684,684,684,684,684,684,684,684,684,684,685,685,685,685,685,685,
-685,685,685,114,114,114,114,114,114,114,114,114,114,114,114,686,
+691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
+691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
+691,691,691,691,691,691,691,691,691,691,691,692,693,692,693,693,
+692,692,692,692,692,692,693,692,115,115,115,115,115,115,115,115,
+694,694,694,694,694,694,694,694,694,694,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 170 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
-687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
-687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
-687,687,687,687,687,687,687,687,687,114,114,114,114,114,114,114,
+695,695,695,695,695,695,695,695,695,695,695,695,695,695,695,695,
+695,695,695,695,695,695,695,695,695,695,115,115,115,696,696,696,
+697,697,696,696,696,696,697,696,696,696,696,696,115,115,115,115,
+698,698,698,698,698,698,698,698,698,698,699,699,700,700,700,701,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 171 */
-688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
-688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
-688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
-688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
-688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
-688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
-688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
-688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,
+702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,702,
+703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
+703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
+704,704,704,704,704,704,704,704,704,704,705,705,705,705,705,705,
+705,705,705,115,115,115,115,115,115,115,115,115,115,115,115,706,
/* block 172 */
-688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,688,
-688,688,688,688,688,688,688,688,688,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,
+707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,
+707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,
+707,707,707,707,707,707,707,707,707,115,115,115,115,115,115,115,
/* block 173 */
-689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,
-689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,
-689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,
-689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,
-689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,
-689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,
-689,689,689,689,689,689,689,689,689,689,689,689,689,689,689,114,
-690,690,690,690,690,114,114,114,114,114,114,114,114,114,114,114,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
/* block 174 */
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 175 */
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,
-691,691,691,691,691,691,691,691,691,691,691,691,691,691,691,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
+709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,115,
+710,710,710,710,710,115,115,115,115,115,115,115,115,115,115,115,
/* block 176 */
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 177 */
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,497,
-497,497,497,497,497,497,497,497,497,114,114,114,114,114,114,114,
-692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,
-692,692,692,692,692,692,692,692,692,692,692,692,692,692,692,114,
-693,693,693,693,693,693,693,693,693,693,114,114,114,114,694,694,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
/* block 178 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-695,695,695,695,695,695,695,695,695,695,695,695,695,695,695,695,
-695,695,695,695,695,695,695,695,695,695,695,695,695,695,114,114,
-696,696,696,696,696,697,114,114,114,114,114,114,114,114,114,114,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,
+711,711,711,711,711,711,711,711,711,711,711,711,711,711,711,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 179 */
-698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,
-698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,
-698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,
-699,699,699,699,699,699,699,700,700,700,700,700,701,701,701,701,
-702,702,702,702,700,701,114,114,114,114,114,114,114,114,114,114,
-703,703,703,703,703,703,703,703,703,703,114,704,704,704,704,704,
-704,704,114,698,698,698,698,698,698,698,698,698,698,698,698,698,
-698,698,698,698,698,698,698,698,114,114,114,114,114,698,698,698,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
/* block 180 */
-698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,698,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,712,712,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 181 */
-705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,
-705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,
-705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,
-705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,705,
-705,705,705,705,705,114,114,114,114,114,114,114,114,114,114,114,
-705,706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,
-706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,
-706,706,706,706,706,706,706,706,706,706,706,706,706,706,706,114,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
/* block 182 */
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,707,
-707,707,707,708,708,708,708,708,708,708,708,708,708,708,708,708,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,498,
+498,498,498,498,498,498,498,498,498,115,115,115,115,115,115,115,
+713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,
+713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,115,
+714,714,714,714,714,714,714,714,714,714,115,115,115,115,715,715,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 183 */
-478,476,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,716,
+716,716,716,716,716,716,716,716,716,716,716,716,716,716,115,115,
+717,717,717,717,717,718,115,115,115,115,115,115,115,115,115,115,
/* block 184 */
-709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
-709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
-709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
-709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
-709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
-709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,709,
-709,709,709,709,709,709,709,709,709,709,709,114,114,114,114,114,
-709,709,709,709,709,709,709,709,709,709,709,709,709,114,114,114,
+719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,
+719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,
+719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,
+720,720,720,720,720,720,720,721,721,721,721,721,722,722,722,722,
+723,723,723,723,721,722,115,115,115,115,115,115,115,115,115,115,
+724,724,724,724,724,724,724,724,724,724,115,725,725,725,725,725,
+725,725,115,719,719,719,719,719,719,719,719,719,719,719,719,719,
+719,719,719,719,719,719,719,719,115,115,115,115,115,719,719,719,
/* block 185 */
-709,709,709,709,709,709,709,709,709,114,114,114,114,114,114,114,
-709,709,709,709,709,709,709,709,709,709,114,114,710,711,711,712,
- 22, 22, 22, 22,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
/* block 186 */
+726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
+726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
+726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
+726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
+726,726,726,726,726,115,115,115,115,115,115,115,115,115,115,115,
+726,727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,
+727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,
+727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,115,
+
+/* block 187 */
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,728,
+728,728,728,729,729,729,729,729,729,729,729,729,729,729,729,729,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 188 */
+479,477,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 189 */
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,730,
+730,730,730,730,730,730,730,730,730,730,730,115,115,115,115,115,
+730,730,730,730,730,730,730,730,730,730,730,730,730,115,115,115,
+
+/* block 190 */
+730,730,730,730,730,730,730,730,730,115,115,115,115,115,115,115,
+730,730,730,730,730,730,730,730,730,730,115,115,731,732,732,733,
+ 22, 22, 22, 22,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 191 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
@@ -3218,239 +3295,259 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,115,
-/* block 187 */
+/* block 192 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19,114,114, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19,115,115, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19,713,405,109,109,109, 19, 19, 19,405,713,713,
-713,713,713, 22, 22, 22, 22, 22, 22, 22, 22,109,109,109,109,109,
+ 19, 19, 19, 19, 19,734,406,110,110,110, 19, 19, 19,406,734,734,
+734,734,734, 22, 22, 22, 22, 22, 22, 22, 22,110,110,110,110,110,
-/* block 188 */
-109,109,109, 19, 19,109,109,109,109,109,109,109, 19, 19, 19, 19,
+/* block 193 */
+110,110,110, 19, 19,110,110,110,110,110,110,110, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,110,110,110,110, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,109,109,109,109, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 189 */
-559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
-559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
-559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
-559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
-559,559,714,714,714,559,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+/* block 194 */
+564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,
+564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,
+564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,
+564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,
+564,564,735,735,735,564,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 190 */
+/* block 195 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+ 23, 23,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 191 */
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,438,438,438,438,438,438,
+/* block 196 */
+438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
+438,438,438,438,438,438,438,438,438,438,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,438,438,438,438,438,438,438,438,438,438,438,438,
+438,438,438,438,438,438,438,438,438,438,438,438,438,438,439,439,
+439,439,439,439,439,115,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,438,438,438,438,438,438,438,438,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,438,438,
-438,438,438,438,438,114,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,438,438,438,438,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-/* block 192 */
-437,437,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,438,438,438,438,438,438,438,438,437,114,437,437,
-114,114,437,114,114,437,437,114,114,437,437,437,437,114,437,437,
-437,437,437,437,437,437,438,438,438,438,114,438,114,438,438,438,
-438,438,438,438,114,438,438,438,438,438,438,438,438,438,438,438,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,438,438,438,438,438,438,
+/* block 197 */
+438,438,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,438,115,438,438,
+115,115,438,115,115,438,438,115,115,438,438,438,438,115,438,438,
+438,438,438,438,438,438,439,439,439,439,115,439,115,439,439,439,
+439,439,439,439,115,439,439,439,439,439,439,439,439,439,439,439,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
+438,438,438,438,438,438,438,438,438,438,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
-/* block 193 */
-438,438,438,438,437,437,114,437,437,437,437,114,114,437,437,437,
-437,437,437,437,437,114,437,437,437,437,437,437,437,114,438,438,
+/* block 198 */
+439,439,439,439,438,438,115,438,438,438,438,115,115,438,438,438,
+438,438,438,438,438,115,438,438,438,438,438,438,438,115,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,438,438,115,438,438,438,438,115,
+438,438,438,438,438,115,438,115,115,115,438,438,438,438,438,438,
+438,115,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,438,438,438,438,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,438,438,438,438,437,437,114,437,437,437,437,114,
-437,437,437,437,437,114,437,114,114,114,437,437,437,437,437,437,
-437,114,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,438,438,438,438,438,438,438,438,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-/* block 194 */
-437,437,437,437,437,437,438,438,438,438,438,438,438,438,438,438,
+/* block 199 */
+438,438,438,438,438,438,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,438,438,438,438,438,438,
+438,438,438,438,438,438,438,438,438,438,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,438,438,438,438,438,438,438,438,438,438,438,438,
+438,438,438,438,438,438,438,438,438,438,438,438,438,438,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+
+/* block 200 */
+439,439,439,439,439,439,439,439,438,438,438,438,438,438,438,438,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,438,438,
+438,438,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,438,438,438,438,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-
-/* block 195 */
-438,438,438,438,438,438,438,438,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,438,438,438,438,438,438,438,438,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,438,438,438,438,438,438,438,438,438,438,
+438,438,438,438,438,438,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-/* block 196 */
-437,437,437,437,437,437,437,437,437,437,438,438,438,438,438,438,
+/* block 201 */
+438,438,438,438,438,438,438,438,438,438,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,115,115,438,438,438,438,438,438,438,438,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,438,438,114,114,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-437, 8,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,438,438,438,438,438,438,438, 8,438,438,438,438,
-438,438,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437, 8,438,438,438,438,
+438, 8,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439, 8,439,439,439,439,
+439,439,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
+438,438,438,438,438,438,438,438,438,438,438, 8,439,439,439,439,
-/* block 197 */
+/* block 202 */
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439, 8,439,439,439,439,439,439,438,438,438,438,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,438, 8,438,438,438,438,438,438,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437, 8,438,438,438,438,438,438,438,438,438,438,
+438,438,438,438,438, 8,439,439,439,439,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439, 8,
+439,439,439,439,439,439,438,438,438,438,438,438,438,438,438,438,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438, 8,
-438,438,438,438,438,438,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437, 8,
-438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
-/* block 198 */
-438,438,438,438,438,438,438,438,438, 8,438,438,438,438,438,438,
-437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-437,437,437,437,437,437,437,437,437, 8,438,438,438,438,438,438,
+/* block 203 */
+439,439,439,439,439,439,439,439,439, 8,439,439,439,439,439,439,
438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438, 8,438,438,438,438,438,438,437,438,114,114, 10, 10,
+438,438,438,438,438,438,438,438,438, 8,439,439,439,439,439,439,
+439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,439,
+439,439,439, 8,439,439,439,439,439,439,438,439,115,115, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
-/* block 199 */
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
+/* block 204 */
+736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,
+736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,
+736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,
+736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,
+736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,
+736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,
+736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,
+736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,736,
-/* block 200 */
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,715,
-715,715,715,715,715,114,114,716,716,716,716,716,716,716,716,716,
-717,717,717,717,717,717,717,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+/* block 205 */
+737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,
+737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,
+737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,
+737,737,737,737,737,737,737,736,736,736,736,737,737,737,737,737,
+737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,
+737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,
+737,737,737,737,737,737,737,737,737,737,737,737,737,736,736,736,
+736,736,736,736,736,737,736,736,736,736,736,736,736,736,736,736,
-/* block 201 */
-199,199,199,199,114,199,199,199,199,199,199,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,
-114,199,199,114,199,114,114,199,114,199,199,199,199,199,199,199,
-199,199,199,114,199,199,199,199,114,199,114,199,114,114,114,114,
-114,114,199,114,114,114,114,199,114,199,114,199,114,199,199,199,
-114,199,199,114,199,114,114,199,114,199,114,199,114,199,114,199,
-114,199,199,114,199,114,114,199,199,199,199,114,199,199,199,199,
-199,199,199,114,199,199,199,199,114,199,199,199,199,114,199,114,
+/* block 206 */
+736,736,736,736,737,736,736,738,738,738,738,738,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,737,737,737,737,737,
+115,737,737,737,737,737,737,737,737,737,737,737,737,737,737,737,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 202 */
-199,199,199,199,199,199,199,199,199,199,114,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,114,114,114,114,
-114,199,199,199,114,199,199,199,199,199,114,199,199,199,199,199,
-199,199,199,199,199,199,199,199,199,199,199,199,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-194,194,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+/* block 207 */
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
-/* block 203 */
+/* block 208 */
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+739,739,739,739,739,115,115,740,740,740,740,740,740,740,740,740,
+741,741,741,741,741,741,741,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 209 */
+200,200,200,200,115,200,200,200,200,200,200,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,
+115,200,200,115,200,115,115,200,115,200,200,200,200,200,200,200,
+200,200,200,115,200,200,200,200,115,200,115,200,115,115,115,115,
+115,115,200,115,115,115,115,200,115,200,115,200,115,200,200,200,
+115,200,200,115,200,115,115,200,115,200,115,200,115,200,115,200,
+115,200,200,115,200,115,115,200,200,200,200,115,200,200,200,200,
+200,200,200,115,200,200,200,200,115,200,200,200,200,115,200,115,
+
+/* block 210 */
+200,200,200,200,200,200,200,200,200,200,115,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,115,115,115,115,
+115,200,200,200,115,200,200,200,200,200,115,200,200,200,200,200,
+200,200,200,200,200,200,200,200,200,200,200,200,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+195,195,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 211 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-/* block 204 */
+/* block 212 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,
-114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,115,115,115,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,
+115, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+115, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+115, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,115,
-/* block 205 */
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,114,114,114,
+/* block 213 */
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,115,115,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-/* block 206 */
+/* block 214 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,718,718,718,718,718,718,718,718,718,718,
-718,718,718,718,718,718,718,718,718,718,718,718,718,718,718,718,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,742,742,742,742,742,742,742,742,742,742,
+742,742,742,742,742,742,742,742,742,742,742,742,742,742,742,742,
-/* block 207 */
-719, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,114,
+/* block 215 */
+743, 19, 19,115,115,115,115,115,115,115,115,115,115,115,115,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,
- 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,115,
+ 19, 19,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 208 */
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+/* block 216 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,
-
-/* block 209 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,
-114,114,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 14, 14, 14, 14, 14,
-/* block 210 */
+/* block 217 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
@@ -3458,121 +3555,141 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115, 19, 19, 19, 19, 19,
-/* block 211 */
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+/* block 218 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19,115, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114, 19, 19, 19, 19, 19,
-
-/* block 212 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+/* block 219 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,
+ 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 213 */
+/* block 220 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19,114,114, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 214 */
+/* block 221 */
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,
- 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 215 */
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+/* block 222 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,115,115,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,114,
-/* block 216 */
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+/* block 223 */
+ 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,115,115,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 217 */
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+/* block 224 */
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 218 */
- 19, 19, 19, 19, 19, 19, 19, 19,114,114,114,114,114,114,114,114,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+/* block 225 */
+ 19, 19, 19, 19, 19,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+ 19,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 219 */
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+/* block 226 */
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
-/* block 220 */
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,114,114,114,114,114,114,114,114,114,114,114,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+/* block 227 */
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,115,115,115,115,115,115,115,115,115,115,115,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
-/* block 221 */
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
-484,484,484,484,484,484,484,484,484,484,484,484,484,484,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
-114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,
+/* block 228 */
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,115,115,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
-/* block 222 */
-436, 22,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
+/* block 229 */
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 230 */
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,485,
+485,485,485,485,485,485,485,485,485,485,485,485,485,485,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
+
+/* block 231 */
+437, 22,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
@@ -3580,51 +3697,51 @@ const pcre_uint16 PRIV(ucd_stage2)[] = { /* 58112 bytes, block = 128 */
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
-/* block 223 */
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
-
-/* block 224 */
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
+/* block 232 */
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-/* block 225 */
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
-436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
+/* block 233 */
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+
+/* block 234 */
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
-/* block 226 */
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,552,552,552,552,114,114,
+/* block 235 */
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,557,
+557,557,557,557,557,557,557,557,557,557,557,557,557,557,115,115,
};
#if UCD_BLOCK_SIZE != 128
-#error Please correct UCD_BLOCK_SIZE in pcre_internal.h
+#error Please correct UCD_BLOCK_SIZE in pcre2_internal.h
#endif
-#endif /* SUPPORT_UCP */
+#endif /* SUPPORT_UNICODE */
-#endif /* PCRE_INCLUDED */
+#endif /* PCRE2_PCRE2TEST */
diff --git a/src/3rdparty/pcre/ucp.h b/src/3rdparty/pcre2/src/pcre2_ucp.h
index 2fa00296e4..0b7553e5e0 100644
--- a/src/3rdparty/pcre/ucp.h
+++ b/src/3rdparty/pcre2/src/pcre2_ucp.h
@@ -1,9 +1,46 @@
/*************************************************
-* Unicode Property Table handler *
+* Perl-Compatible Regular Expressions *
*************************************************/
-#ifndef _UCP_H
-#define _UCP_H
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifndef _PCRE2_UCP_H
+#define _PCRE2_UCP_H
/* This file contains definitions of the property values that are returned by
the UCD access macros. New values that are added for new releases of Unicode
@@ -14,7 +51,7 @@ the same as the values that are generated by the maint/MultiStage2.py script,
where the equivalent property descriptive names are listed in vectors.
ALSO: The specific values of the first two enums are assumed for the table
-called catposstab in pcre_compile.c. */
+called catposstab in pcre2_compile.c. */
/* These are the general character categories. */
@@ -216,9 +253,16 @@ enum {
ucp_Pau_Cin_Hau,
ucp_Siddham,
ucp_Tirhuta,
- ucp_Warang_Citi
+ ucp_Warang_Citi,
+ /* New for Unicode 8.0.0: */
+ ucp_Ahom,
+ ucp_Anatolian_Hieroglyphs,
+ ucp_Hatran,
+ ucp_Multani,
+ ucp_Old_Hungarian,
+ ucp_SignWriting
};
#endif
-/* End of ucp.h */
+/* End of pcre2_ucp.h */
diff --git a/src/3rdparty/pcre/pcre_valid_utf8.c b/src/3rdparty/pcre2/src/pcre2_valid_utf.c
index 3b0f6464a3..2dfd8df34d 100644
--- a/src/3rdparty/pcre/pcre_valid_utf8.c
+++ b/src/3rdparty/pcre2/src/pcre2_valid_utf.c
@@ -6,7 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2013 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -38,107 +39,131 @@ POSSIBILITY OF SUCH DAMAGE.
*/
-/* This module contains an internal function for validating UTF-8 character
-strings. */
-
+/* This module contains an internal function for validating UTF character
+strings. This file is also #included by the pcre2test program, which uses
+macros to change names from _pcre2_xxx to xxxx, thereby avoiding name clashes
+with the library. In this case, PCRE2_PCRE2TEST is defined. */
+#ifndef PCRE2_PCRE2TEST /* We're compiling the library */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#include "pcre2_internal.h"
+#endif /* PCRE2_PCRE2TEST */
+
+
+#ifndef SUPPORT_UNICODE
+/*************************************************
+* Dummy function when Unicode is not supported *
+*************************************************/
+
+/* This function should never be called when Unicode is not supported. */
+
+int
+PRIV(valid_utf)(PCRE2_SPTR string, PCRE2_SIZE length, PCRE2_SIZE *erroroffset)
+{
+(void)string;
+(void)length;
+(void)erroroffset;
+return 0;
+}
+#else /* UTF is supported */
-#include "pcre_internal.h"
/*************************************************
-* Validate a UTF-8 string *
+* Validate a UTF string *
*************************************************/
/* This function is called (optionally) at the start of compile or match, to
-check that a supposed UTF-8 string is actually valid. The early check means
+check that a supposed UTF string is actually valid. The early check means
that subsequent code can assume it is dealing with a valid string. The check
can be turned off for maximum performance, but the consequences of supplying an
invalid string are then undefined.
-Originally, this function checked according to RFC 2279, allowing for values in
-the range 0 to 0x7fffffff, up to 6 bytes long, but ensuring that they were in
-the canonical format. Once somebody had pointed out RFC 3629 to me (it
-obsoletes 2279), additional restrictions were applied. The values are now
-limited to be between 0 and 0x0010ffff, no more than 4 bytes long, and the
-subrange 0xd000 to 0xdfff is excluded. However, the format of 5-byte and 6-byte
-characters is still checked.
-
-From release 8.13 more information about the details of the error are passed
-back in the returned value:
-
-PCRE_UTF8_ERR0 No error
-PCRE_UTF8_ERR1 Missing 1 byte at the end of the string
-PCRE_UTF8_ERR2 Missing 2 bytes at the end of the string
-PCRE_UTF8_ERR3 Missing 3 bytes at the end of the string
-PCRE_UTF8_ERR4 Missing 4 bytes at the end of the string
-PCRE_UTF8_ERR5 Missing 5 bytes at the end of the string
-PCRE_UTF8_ERR6 2nd-byte's two top bits are not 0x80
-PCRE_UTF8_ERR7 3rd-byte's two top bits are not 0x80
-PCRE_UTF8_ERR8 4th-byte's two top bits are not 0x80
-PCRE_UTF8_ERR9 5th-byte's two top bits are not 0x80
-PCRE_UTF8_ERR10 6th-byte's two top bits are not 0x80
-PCRE_UTF8_ERR11 5-byte character is not permitted by RFC 3629
-PCRE_UTF8_ERR12 6-byte character is not permitted by RFC 3629
-PCRE_UTF8_ERR13 4-byte character with value > 0x10ffff is not permitted
-PCRE_UTF8_ERR14 3-byte character with value 0xd000-0xdfff is not permitted
-PCRE_UTF8_ERR15 Overlong 2-byte sequence
-PCRE_UTF8_ERR16 Overlong 3-byte sequence
-PCRE_UTF8_ERR17 Overlong 4-byte sequence
-PCRE_UTF8_ERR18 Overlong 5-byte sequence (won't ever occur)
-PCRE_UTF8_ERR19 Overlong 6-byte sequence (won't ever occur)
-PCRE_UTF8_ERR20 Isolated 0x80 byte (not within UTF-8 character)
-PCRE_UTF8_ERR21 Byte with the illegal value 0xfe or 0xff
-PCRE_UTF8_ERR22 Unused (was non-character)
-
Arguments:
string points to the string
- length length of string, or -1 if the string is zero-terminated
+ length length of string
errp pointer to an error position offset variable
-Returns: = 0 if the string is a valid UTF-8 string
- > 0 otherwise, setting the offset of the bad character
+Returns: == 0 if the string is a valid UTF string
+ != 0 otherwise, setting the offset of the bad character
*/
int
-PRIV(valid_utf)(PCRE_PUCHAR string, int length, int *erroroffset)
+PRIV(valid_utf)(PCRE2_SPTR string, PCRE2_SIZE length, PCRE2_SIZE *erroroffset)
{
-#ifdef SUPPORT_UTF
-register PCRE_PUCHAR p;
+register PCRE2_SPTR p;
+register uint32_t c;
-if (length < 0)
- {
- for (p = string; *p != 0; p++);
- length = (int)(p - string);
- }
+/* ----------------- Check a UTF-8 string ----------------- */
-for (p = string; length-- > 0; p++)
+#if PCRE2_CODE_UNIT_WIDTH == 8
+
+/* Originally, this function checked according to RFC 2279, allowing for values
+in the range 0 to 0x7fffffff, up to 6 bytes long, but ensuring that they were
+in the canonical format. Once somebody had pointed out RFC 3629 to me (it
+obsoletes 2279), additional restrictions were applied. The values are now
+limited to be between 0 and 0x0010ffff, no more than 4 bytes long, and the
+subrange 0xd000 to 0xdfff is excluded. However, the format of 5-byte and 6-byte
+characters is still checked. Error returns are as follows:
+
+PCRE2_ERROR_UTF8_ERR1 Missing 1 byte at the end of the string
+PCRE2_ERROR_UTF8_ERR2 Missing 2 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR3 Missing 3 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR4 Missing 4 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR5 Missing 5 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR6 2nd-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR7 3rd-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR8 4th-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR9 5th-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR10 6th-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR11 5-byte character is not permitted by RFC 3629
+PCRE2_ERROR_UTF8_ERR12 6-byte character is not permitted by RFC 3629
+PCRE2_ERROR_UTF8_ERR13 4-byte character with value > 0x10ffff is not permitted
+PCRE2_ERROR_UTF8_ERR14 3-byte character with value 0xd800-0xdfff is not permitted
+PCRE2_ERROR_UTF8_ERR15 Overlong 2-byte sequence
+PCRE2_ERROR_UTF8_ERR16 Overlong 3-byte sequence
+PCRE2_ERROR_UTF8_ERR17 Overlong 4-byte sequence
+PCRE2_ERROR_UTF8_ERR18 Overlong 5-byte sequence (won't ever occur)
+PCRE2_ERROR_UTF8_ERR19 Overlong 6-byte sequence (won't ever occur)
+PCRE2_ERROR_UTF8_ERR20 Isolated 0x80 byte (not within UTF-8 character)
+PCRE2_ERROR_UTF8_ERR21 Byte with the illegal value 0xfe or 0xff
+*/
+
+for (p = string; length > 0; p++)
{
- register pcre_uchar ab, c, d;
+ register uint32_t ab, d;
c = *p;
+ length--;
+
if (c < 128) continue; /* ASCII character */
if (c < 0xc0) /* Isolated 10xx xxxx byte */
{
*erroroffset = (int)(p - string);
- return PCRE_UTF8_ERR20;
+ return PCRE2_ERROR_UTF8_ERR20;
}
if (c >= 0xfe) /* Invalid 0xfe or 0xff bytes */
{
*erroroffset = (int)(p - string);
- return PCRE_UTF8_ERR21;
+ return PCRE2_ERROR_UTF8_ERR21;
}
- ab = PRIV(utf8_table4)[c & 0x3f]; /* Number of additional bytes */
- if (length < ab)
+ ab = PRIV(utf8_table4)[c & 0x3f]; /* Number of additional bytes (1-5) */
+ if (length < ab) /* Missing bytes */
{
- *erroroffset = (int)(p - string); /* Missing bytes */
- return ab - length; /* Codes ERR1 to ERR5 */
+ *erroroffset = (int)(p - string);
+ switch(ab - length)
+ {
+ case 1: return PCRE2_ERROR_UTF8_ERR1;
+ case 2: return PCRE2_ERROR_UTF8_ERR2;
+ case 3: return PCRE2_ERROR_UTF8_ERR3;
+ case 4: return PCRE2_ERROR_UTF8_ERR4;
+ case 5: return PCRE2_ERROR_UTF8_ERR5;
+ }
}
length -= ab; /* Length remaining */
@@ -147,7 +172,7 @@ for (p = string; length-- > 0; p++)
if (((d = *(++p)) & 0xc0) != 0x80)
{
*erroroffset = (int)(p - string) - 1;
- return PCRE_UTF8_ERR6;
+ return PCRE2_ERROR_UTF8_ERR6;
}
/* For each length, check that the remaining bytes start with the 0x80 bit
@@ -162,7 +187,7 @@ for (p = string; length-- > 0; p++)
case 1: if ((c & 0x3e) == 0)
{
*erroroffset = (int)(p - string) - 1;
- return PCRE_UTF8_ERR15;
+ return PCRE2_ERROR_UTF8_ERR15;
}
break;
@@ -174,17 +199,17 @@ for (p = string; length-- > 0; p++)
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
{
*erroroffset = (int)(p - string) - 2;
- return PCRE_UTF8_ERR7;
+ return PCRE2_ERROR_UTF8_ERR7;
}
if (c == 0xe0 && (d & 0x20) == 0)
{
*erroroffset = (int)(p - string) - 2;
- return PCRE_UTF8_ERR16;
+ return PCRE2_ERROR_UTF8_ERR16;
}
if (c == 0xed && d >= 0xa0)
{
*erroroffset = (int)(p - string) - 2;
- return PCRE_UTF8_ERR14;
+ return PCRE2_ERROR_UTF8_ERR14;
}
break;
@@ -196,22 +221,22 @@ for (p = string; length-- > 0; p++)
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
{
*erroroffset = (int)(p - string) - 2;
- return PCRE_UTF8_ERR7;
+ return PCRE2_ERROR_UTF8_ERR7;
}
if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
{
*erroroffset = (int)(p - string) - 3;
- return PCRE_UTF8_ERR8;
+ return PCRE2_ERROR_UTF8_ERR8;
}
if (c == 0xf0 && (d & 0x30) == 0)
{
*erroroffset = (int)(p - string) - 3;
- return PCRE_UTF8_ERR17;
+ return PCRE2_ERROR_UTF8_ERR17;
}
if (c > 0xf4 || (c == 0xf4 && d > 0x8f))
{
*erroroffset = (int)(p - string) - 3;
- return PCRE_UTF8_ERR13;
+ return PCRE2_ERROR_UTF8_ERR13;
}
break;
@@ -227,22 +252,22 @@ for (p = string; length-- > 0; p++)
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
{
*erroroffset = (int)(p - string) - 2;
- return PCRE_UTF8_ERR7;
+ return PCRE2_ERROR_UTF8_ERR7;
}
if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
{
*erroroffset = (int)(p - string) - 3;
- return PCRE_UTF8_ERR8;
+ return PCRE2_ERROR_UTF8_ERR8;
}
if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */
{
*erroroffset = (int)(p - string) - 4;
- return PCRE_UTF8_ERR9;
+ return PCRE2_ERROR_UTF8_ERR9;
}
if (c == 0xf8 && (d & 0x38) == 0)
{
*erroroffset = (int)(p - string) - 4;
- return PCRE_UTF8_ERR18;
+ return PCRE2_ERROR_UTF8_ERR18;
}
break;
@@ -253,27 +278,27 @@ for (p = string; length-- > 0; p++)
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
{
*erroroffset = (int)(p - string) - 2;
- return PCRE_UTF8_ERR7;
+ return PCRE2_ERROR_UTF8_ERR7;
}
if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
{
*erroroffset = (int)(p - string) - 3;
- return PCRE_UTF8_ERR8;
+ return PCRE2_ERROR_UTF8_ERR8;
}
if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */
{
*erroroffset = (int)(p - string) - 4;
- return PCRE_UTF8_ERR9;
+ return PCRE2_ERROR_UTF8_ERR9;
}
if ((*(++p) & 0xc0) != 0x80) /* Sixth byte */
{
*erroroffset = (int)(p - string) - 5;
- return PCRE_UTF8_ERR10;
+ return PCRE2_ERROR_UTF8_ERR10;
}
if (c == 0xfc && (d & 0x3c) == 0)
{
*erroroffset = (int)(p - string) - 5;
- return PCRE_UTF8_ERR19;
+ return PCRE2_ERROR_UTF8_ERR19;
}
break;
}
@@ -285,17 +310,89 @@ for (p = string; length-- > 0; p++)
if (ab > 3)
{
*erroroffset = (int)(p - string) - ab;
- return (ab == 4)? PCRE_UTF8_ERR11 : PCRE_UTF8_ERR12;
+ return (ab == 4)? PCRE2_ERROR_UTF8_ERR11 : PCRE2_ERROR_UTF8_ERR12;
}
}
+return 0;
-#else /* Not SUPPORT_UTF */
-(void)(string); /* Keep picky compilers happy */
-(void)(length);
-(void)(erroroffset);
-#endif
-return PCRE_UTF8_ERR0; /* This indicates success */
+/* ----------------- Check a UTF-16 string ----------------- */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+
+/* There's not so much work, nor so many errors, for UTF-16.
+PCRE2_ERROR_UTF16_ERR1 Missing low surrogate at the end of the string
+PCRE2_ERROR_UTF16_ERR2 Invalid low surrogate
+PCRE2_ERROR_UTF16_ERR3 Isolated low surrogate
+*/
+
+for (p = string; length > 0; p++)
+ {
+ c = *p;
+ length--;
+
+ if ((c & 0xf800) != 0xd800)
+ {
+ /* Normal UTF-16 code point. Neither high nor low surrogate. */
+ }
+ else if ((c & 0x0400) == 0)
+ {
+ /* High surrogate. Must be a followed by a low surrogate. */
+ if (length == 0)
+ {
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF16_ERR1;
+ }
+ p++;
+ length--;
+ if ((*p & 0xfc00) != 0xdc00)
+ {
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF16_ERR2;
+ }
+ }
+ else
+ {
+ /* Isolated low surrogate. Always an error. */
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF16_ERR3;
+ }
+ }
+return 0;
+
+
+
+/* ----------------- Check a UTF-32 string ----------------- */
+
+#else
+
+/* There is very little to do for a UTF-32 string.
+PCRE2_ERROR_UTF32_ERR1 Surrogate character
+PCRE2_ERROR_UTF32_ERR2 Character > 0x10ffff
+*/
+
+for (p = string; length > 0; length--, p++)
+ {
+ c = *p;
+ if ((c & 0xfffff800u) != 0xd800u)
+ {
+ /* Normal UTF-32 code point. Neither high nor low surrogate. */
+ if (c > 0x10ffffu)
+ {
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF32_ERR2;
+ }
+ }
+ else
+ {
+ /* A surrogate */
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF32_ERR1;
+ }
+ }
+return 0;
+#endif /* CODE_UNIT_WIDTH */
}
+#endif /* SUPPORT_UNICODE */
-/* End of pcre_valid_utf8.c */
+/* End of pcre2_valid_utf.c */
diff --git a/src/3rdparty/pcre/pcre_xclass.c b/src/3rdparty/pcre2/src/pcre2_xclass.c
index ef759a589a..407d3f5b87 100644
--- a/src/3rdparty/pcre/pcre_xclass.c
+++ b/src/3rdparty/pcre2/src/pcre2_xclass.c
@@ -6,7 +6,8 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2013 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -37,46 +38,46 @@ POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
*/
-
/* This module contains an internal function that is used to match an extended
-class. It is used by both pcre_exec() and pcre_def_exec(). */
+class. It is used by pcre2_auto_possessify() and by both pcre2_match() and
+pcre2_def_match(). */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include "pcre_internal.h"
+#include "pcre2_internal.h"
/*************************************************
* Match character against an XCLASS *
*************************************************/
/* This function is called to match a character against an extended class that
-might contain values > 255 and/or Unicode properties.
+might contain codepoints above 255 and/or Unicode properties.
Arguments:
c the character
- data points to the flag byte of the XCLASS data
+ data points to the flag code unit of the XCLASS data
+ utf TRUE if in UTF mode
Returns: TRUE if character matches, else FALSE
*/
BOOL
-PRIV(xclass)(pcre_uint32 c, const pcre_uchar *data, BOOL utf)
+PRIV(xclass)(uint32_t c, PCRE2_SPTR data, BOOL utf)
{
-pcre_uchar t;
+PCRE2_UCHAR t;
BOOL negated = (*data & XCL_NOT) != 0;
-(void)utf;
-#ifdef COMPILE_PCRE8
+#if PCRE2_CODE_UNIT_WIDTH == 8
/* In 8 bit mode, this must always be TRUE. Help the compiler to know that. */
utf = TRUE;
#endif
-/* Character values < 256 are matched against a bitmap, if one is present. If
-not, we still carry on, because there may be ranges that start below 256 in the
+/* Code points < 256 are matched against a bitmap, if one is present. If not,
+we still carry on, because there may be ranges that start below 256 in the
additional data. */
if (c < 256)
@@ -84,37 +85,37 @@ if (c < 256)
if ((*data & XCL_HASPROP) == 0)
{
if ((*data & XCL_MAP) == 0) return negated;
- return (((pcre_uint8 *)(data + 1))[c/8] & (1 << (c&7))) != 0;
+ return (((uint8_t *)(data + 1))[c/8] & (1 << (c&7))) != 0;
}
if ((*data & XCL_MAP) != 0 &&
- (((pcre_uint8 *)(data + 1))[c/8] & (1 << (c&7))) != 0)
+ (((uint8_t *)(data + 1))[c/8] & (1 << (c&7))) != 0)
return !negated; /* char found */
}
/* First skip the bit map if present. Then match against the list of Unicode
properties or large chars or ranges that end with a large char. We won't ever
-encounter XCL_PROP or XCL_NOTPROP when UCP support is not compiled. */
+encounter XCL_PROP or XCL_NOTPROP when UTF support is not compiled. */
-if ((*data++ & XCL_MAP) != 0) data += 32 / sizeof(pcre_uchar);
+if ((*data++ & XCL_MAP) != 0) data += 32 / sizeof(PCRE2_UCHAR);
while ((t = *data++) != XCL_END)
{
- pcre_uint32 x, y;
+ uint32_t x, y;
if (t == XCL_SINGLE)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
GETCHARINC(x, data); /* macro generates multiple statements */
}
else
#endif
- x = *data++;
+ x = *data++;
if (c == x) return !negated;
}
else if (t == XCL_RANGE)
{
-#ifdef SUPPORT_UTF
+#ifdef SUPPORT_UNICODE
if (utf)
{
GETCHARINC(x, data); /* macro generates multiple statements */
@@ -129,7 +130,7 @@ while ((t = *data++) != XCL_END)
if (c >= x && c <= y) return !negated;
}
-#ifdef SUPPORT_UCP
+#ifdef SUPPORT_UNICODE
else /* XCL_PROP & XCL_NOTPROP */
{
const ucd_record *prop = GET_UCD(c);
@@ -259,10 +260,12 @@ while ((t = *data++) != XCL_END)
data += 2;
}
-#endif /* SUPPORT_UCP */
+#else
+ (void)utf; /* Avoid compiler warning */
+#endif /* SUPPORT_UNICODE */
}
return negated; /* char did not match */
}
-/* End of pcre_xclass.c */
+/* End of pcre2_xclass.c */
diff --git a/src/3rdparty/pcre/sljit/sljitConfig.h b/src/3rdparty/pcre2/src/sljit/sljitConfig.h
index 1c8a521aa8..a548c37ab6 100644
--- a/src/3rdparty/pcre/sljit/sljitConfig.h
+++ b/src/3rdparty/pcre2/src/sljit/sljitConfig.h
@@ -82,7 +82,7 @@
/* --------------------------------------------------------------------- */
/* If SLJIT_STD_MACROS_DEFINED is not defined, the application should
- define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMMOVE, and NULL. */
+ define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMCPY, and NULL. */
#ifndef SLJIT_STD_MACROS_DEFINED
/* Disabled by default. */
#define SLJIT_STD_MACROS_DEFINED 0
diff --git a/src/3rdparty/pcre/sljit/sljitConfigInternal.h b/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h
index 9275b14992..566c368063 100644
--- a/src/3rdparty/pcre/sljit/sljitConfigInternal.h
+++ b/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h
@@ -210,8 +210,8 @@
#define SLJIT_FREE(ptr, allocator_data) free(ptr)
#endif
-#ifndef SLJIT_MEMMOVE
-#define SLJIT_MEMMOVE(dest, src, len) memmove(dest, src, len)
+#ifndef SLJIT_MEMCPY
+#define SLJIT_MEMCPY(dest, src, len) memcpy(dest, src, len)
#endif
#ifndef SLJIT_ZEROMEM
diff --git a/src/3rdparty/pcre/sljit/sljitExecAllocator.c b/src/3rdparty/pcre2/src/sljit/sljitExecAllocator.c
index 54f05f5dd7..54f05f5dd7 100644
--- a/src/3rdparty/pcre/sljit/sljitExecAllocator.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitExecAllocator.c
diff --git a/src/3rdparty/pcre/sljit/sljitLir.c b/src/3rdparty/pcre2/src/sljit/sljitLir.c
index ec1781e4c7..ec1781e4c7 100644
--- a/src/3rdparty/pcre/sljit/sljitLir.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitLir.c
diff --git a/src/3rdparty/pcre/sljit/sljitLir.h b/src/3rdparty/pcre2/src/sljit/sljitLir.h
index df69b8656f..df69b8656f 100644
--- a/src/3rdparty/pcre/sljit/sljitLir.h
+++ b/src/3rdparty/pcre2/src/sljit/sljitLir.h
diff --git a/src/3rdparty/pcre/sljit/sljitNativeARM_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c
index b92808f526..b92808f526 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeARM_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeARM_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c
index d9958512c8..d9958512c8 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeARM_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeARM_T2_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
index 1ed44a8130..1ed44a8130 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeARM_T2_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeMIPS_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
index 5096e4f55e..5096e4f55e 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeMIPS_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeMIPS_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
index c7ee8c9c2e..c7ee8c9c2e 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeMIPS_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeMIPS_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
index c2c251b1ff..c2c251b1ff 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeMIPS_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativePPC_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_32.c
index 0f23cf86dd..0f23cf86dd 100644
--- a/src/3rdparty/pcre/sljit/sljitNativePPC_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_32.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativePPC_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_64.c
index 8e3223f725..8e3223f725 100644
--- a/src/3rdparty/pcre/sljit/sljitNativePPC_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_64.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativePPC_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c
index a3647327bf..a3647327bf 100644
--- a/src/3rdparty/pcre/sljit/sljitNativePPC_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeSPARC_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_32.c
index 7e589a17c2..7e589a17c2 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeSPARC_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_32.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeSPARC_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_common.c
index f3a33a1097..f3a33a1097 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeSPARC_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeSPARC_common.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeTILEGX-encoder.c b/src/3rdparty/pcre2/src/sljit/sljitNativeTILEGX-encoder.c
index 719632908c..719632908c 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeTILEGX-encoder.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeTILEGX-encoder.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeTILEGX_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeTILEGX_64.c
index 462a8b9cd9..462a8b9cd9 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeTILEGX_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeTILEGX_64.c
diff --git a/src/3rdparty/pcre/sljit/sljitNativeX86_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c
index cd3c656c66..78f3dcb06f 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeX86_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c
@@ -34,7 +34,7 @@ static sljit_s32 emit_do_imm(struct sljit_compiler *compiler, sljit_u8 opcode, s
FAIL_IF(!inst);
INC_SIZE(1 + sizeof(sljit_sw));
*inst++ = opcode;
- *(sljit_sw*)inst = imm;
+ sljit_unaligned_store_sw(inst, imm);
return SLJIT_SUCCESS;
}
@@ -57,7 +57,7 @@ static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_
if (jump->flags & JUMP_LABEL)
jump->flags |= PATCH_MW;
else
- *(sljit_sw*)code_ptr = jump->u.target - (jump->addr + 4);
+ sljit_unaligned_store_sw(code_ptr, jump->u.target - (jump->addr + 4));
code_ptr += 4;
return code_ptr;
@@ -151,12 +151,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
inst[1] = MOD_REG | (reg_map[TMP_REG1] << 3) | reg_map[SLJIT_SP];
inst[2] = GROUP_F7;
inst[3] = MOD_REG | (0 << 3) | reg_map[SLJIT_SP];
- *(sljit_sw*)(inst + 4) = 0x4;
+ sljit_unaligned_store_sw(inst + 4, 0x4);
inst[8] = JNE_i8;
inst[9] = 6;
inst[10] = GROUP_BINARY_81;
inst[11] = MOD_REG | (5 << 3) | reg_map[SLJIT_SP];
- *(sljit_sw*)(inst + 12) = 0x4;
+ sljit_unaligned_store_sw(inst + 12, 0x4);
inst[16] = PUSH_r + reg_map[TMP_REG1];
}
else
@@ -406,7 +406,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32
if (immb <= 127 && immb >= -128)
*buf_ptr++ = immb; /* 8 bit displacement. */
else {
- *(sljit_sw*)buf_ptr = immb; /* 32 bit displacement. */
+ sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
buf_ptr += sizeof(sljit_sw);
}
}
@@ -418,7 +418,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32
}
else {
*buf_ptr++ |= 0x05;
- *(sljit_sw*)buf_ptr = immb; /* 32 bit displacement. */
+ sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
buf_ptr += sizeof(sljit_sw);
}
@@ -426,9 +426,9 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32
if (flags & EX86_BYTE_ARG)
*buf_ptr = imma;
else if (flags & EX86_HALF_ARG)
- *(short*)buf_ptr = imma;
+ sljit_unaligned_store_s16(buf_ptr, imma);
else if (!(flags & EX86_SHIFT_INS))
- *(sljit_sw*)buf_ptr = imma;
+ sljit_unaligned_store_sw(buf_ptr, imma);
}
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
@@ -541,7 +541,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler
INC_SIZE(5 + 1);
*inst++ = PUSH_i32;
- *(sljit_sw*)inst = srcw;
+ sljit_unaligned_store_sw(inst, srcw);
inst += sizeof(sljit_sw);
}
diff --git a/src/3rdparty/pcre/sljit/sljitNativeX86_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c
index 6ea27e5513..e88ddedcd1 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeX86_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c
@@ -35,7 +35,7 @@ static sljit_s32 emit_load_imm64(struct sljit_compiler *compiler, sljit_s32 reg,
INC_SIZE(2 + sizeof(sljit_sw));
*inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
*inst++ = MOV_r_i32 + (reg_map[reg] & 0x7);
- *(sljit_sw*)inst = imm;
+ sljit_unaligned_store_sw(inst, imm);
return SLJIT_SUCCESS;
}
@@ -55,7 +55,7 @@ static sljit_u8* generate_far_jump_code(struct sljit_jump *jump, sljit_u8 *code_
if (jump->flags & JUMP_LABEL)
jump->flags |= PATCH_MD;
else
- *(sljit_sw*)code_ptr = jump->u.target;
+ sljit_unaligned_store_sw(code_ptr, jump->u.target);
code_ptr += sizeof(sljit_sw);
*code_ptr++ = REX_B;
@@ -71,13 +71,13 @@ static sljit_u8* generate_fixed_jump(sljit_u8 *code_ptr, sljit_sw addr, sljit_s3
if (delta <= HALFWORD_MAX && delta >= HALFWORD_MIN) {
*code_ptr++ = (type == 2) ? CALL_i32 : JMP_i32;
- *(sljit_sw*)code_ptr = delta;
+ sljit_unaligned_store_sw(code_ptr, delta);
}
else {
SLJIT_COMPILE_ASSERT(reg_map[TMP_REG3] == 9, tmp3_is_9_second);
*code_ptr++ = REX_W | REX_B;
*code_ptr++ = MOV_r_i32 + 1;
- *(sljit_sw*)code_ptr = addr;
+ sljit_unaligned_store_sw(code_ptr, addr);
code_ptr += sizeof(sljit_sw);
*code_ptr++ = REX_B;
*code_ptr++ = GROUP_FF;
@@ -193,7 +193,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
*inst++ = REX_W;
*inst++ = MOV_rm_i32;
*inst++ = MOD_REG | reg_lmap[SLJIT_R0];
- *(sljit_s32*)inst = local_size;
+ sljit_unaligned_store_s32(inst, local_size);
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
compiler->skip_checks = 1;
@@ -219,7 +219,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
*inst++ = REX_W;
*inst++ = GROUP_BINARY_81;
*inst++ = MOD_REG | SUB | 4;
- *(sljit_s32*)inst = local_size;
+ sljit_unaligned_store_s32(inst, local_size);
inst += sizeof(sljit_s32);
}
@@ -230,7 +230,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
FAIL_IF(!inst);
INC_SIZE(5);
*inst++ = GROUP_0F;
- *(sljit_s32*)inst = 0x20247429;
+ sljit_unaligned_store_s32(inst, 0x20247429);
}
#endif
@@ -271,7 +271,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
FAIL_IF(!inst);
INC_SIZE(5);
*inst++ = GROUP_0F;
- *(sljit_s32*)inst = 0x20247428;
+ sljit_unaligned_store_s32(inst, 0x20247428);
}
#endif
@@ -292,7 +292,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
*inst++ = REX_W;
*inst++ = GROUP_BINARY_81;
*inst++ = MOD_REG | ADD | 4;
- *(sljit_s32*)inst = compiler->local_size;
+ sljit_unaligned_store_s32(inst, compiler->local_size);
}
tmp = compiler->scratches;
@@ -339,7 +339,7 @@ static sljit_s32 emit_do_imm32(struct sljit_compiler *compiler, sljit_u8 rex, sl
if (rex)
*inst++ = rex;
*inst++ = opcode;
- *(sljit_s32*)inst = imm;
+ sljit_unaligned_store_s32(inst, imm);
return SLJIT_SUCCESS;
}
@@ -516,7 +516,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32
if (immb <= 127 && immb >= -128)
*buf_ptr++ = immb; /* 8 bit displacement. */
else {
- *(sljit_s32*)buf_ptr = immb; /* 32 bit displacement. */
+ sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
buf_ptr += sizeof(sljit_s32);
}
}
@@ -533,7 +533,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32
else {
*buf_ptr++ |= 0x04;
*buf_ptr++ = 0x25;
- *(sljit_s32*)buf_ptr = immb; /* 32 bit displacement. */
+ sljit_unaligned_store_s32(buf_ptr, immb); /* 32 bit displacement. */
buf_ptr += sizeof(sljit_s32);
}
@@ -541,9 +541,9 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_s32
if (flags & EX86_BYTE_ARG)
*buf_ptr = imma;
else if (flags & EX86_HALF_ARG)
- *(short*)buf_ptr = imma;
+ sljit_unaligned_store_s16(buf_ptr, imma);
else if (!(flags & EX86_SHIFT_INS))
- *(sljit_s32*)buf_ptr = imma;
+ sljit_unaligned_store_s32(buf_ptr, imma);
}
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
@@ -676,7 +676,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_return(struct sljit_compiler
INC_SIZE(5 + 1);
*inst++ = PUSH_i32;
- *(sljit_s32*)inst = srcw;
+ sljit_unaligned_store_s32(inst, srcw);
inst += sizeof(sljit_s32);
}
diff --git a/src/3rdparty/pcre/sljit/sljitNativeX86_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c
index 4aa5020623..aa5ba089d2 100644
--- a/src/3rdparty/pcre/sljit/sljitNativeX86_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c
@@ -279,6 +279,29 @@ static sljit_s32 cpu_has_cmov = -1;
#include <intrin.h>
#endif
+/******************************************************/
+/* Unaligned-store functions */
+/******************************************************/
+
+static SLJIT_INLINE void sljit_unaligned_store_s16(void *addr, sljit_s16 value)
+{
+ SLJIT_MEMCPY(addr, &value, sizeof(value));
+}
+
+static SLJIT_INLINE void sljit_unaligned_store_s32(void *addr, sljit_s32 value)
+{
+ SLJIT_MEMCPY(addr, &value, sizeof(value));
+}
+
+static SLJIT_INLINE void sljit_unaligned_store_sw(void *addr, sljit_sw value)
+{
+ SLJIT_MEMCPY(addr, &value, sizeof(value));
+}
+
+/******************************************************/
+/* Utility functions */
+/******************************************************/
+
static void get_cpu_features(void)
{
sljit_u32 features;
@@ -289,7 +312,7 @@ static void get_cpu_features(void)
__cpuid(CPUInfo, 1);
features = (sljit_u32)CPUInfo[3];
-#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C) || defined(__ghs)
+#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C)
/* AT&T syntax. */
__asm__ (
@@ -478,7 +501,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
len = *buf_ptr++;
if (len > 0) {
/* The code is already generated. */
- SLJIT_MEMMOVE(code_ptr, buf_ptr, len);
+ SLJIT_MEMCPY(code_ptr, buf_ptr, len);
code_ptr += len;
buf_ptr += len;
}
@@ -504,7 +527,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
*code_ptr++ = (*buf_ptr == 2) ? CALL_i32 : JMP_i32;
buf_ptr++;
- *(sljit_sw*)code_ptr = *(sljit_sw*)buf_ptr - ((sljit_sw)code_ptr + sizeof(sljit_sw));
+ sljit_unaligned_store_sw(code_ptr, *(sljit_sw*)buf_ptr - ((sljit_sw)code_ptr + sizeof(sljit_sw)));
code_ptr += sizeof(sljit_sw);
buf_ptr += sizeof(sljit_sw) - 1;
#else
@@ -531,24 +554,24 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
} else if (jump->flags & PATCH_MW) {
if (jump->flags & JUMP_LABEL) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- *(sljit_sw*)jump->addr = (sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_sw)));
+ sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_sw))));
#else
SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_s32))) >= HALFWORD_MIN && (sljit_sw)(jump->u.label->addr - (jump->addr + sizeof(sljit_s32))) <= HALFWORD_MAX);
- *(sljit_s32*)jump->addr = (sljit_s32)(jump->u.label->addr - (jump->addr + sizeof(sljit_s32)));
+ sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)(jump->u.label->addr - (jump->addr + sizeof(sljit_s32))));
#endif
}
else {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- *(sljit_sw*)jump->addr = (sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_sw)));
+ sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_sw))));
#else
SLJIT_ASSERT((sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_s32))) >= HALFWORD_MIN && (sljit_sw)(jump->u.target - (jump->addr + sizeof(sljit_s32))) <= HALFWORD_MAX);
- *(sljit_s32*)jump->addr = (sljit_s32)(jump->u.target - (jump->addr + sizeof(sljit_s32)));
+ sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)(jump->u.target - (jump->addr + sizeof(sljit_s32))));
#endif
}
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
else if (jump->flags & PATCH_MD)
- *(sljit_sw*)jump->addr = jump->u.label->addr;
+ sljit_unaligned_store_sw((void*)jump->addr, jump->u.label->addr);
#endif
jump = jump->next;
@@ -1699,7 +1722,7 @@ static sljit_s32 emit_mul(struct sljit_compiler *compiler,
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
- *(sljit_sw*)inst = src1w;
+ sljit_unaligned_store_sw(inst, src1w);
}
#else
else if (IS_HALFWORD(src1w)) {
@@ -1709,7 +1732,7 @@ static sljit_s32 emit_mul(struct sljit_compiler *compiler,
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
- *(sljit_s32*)inst = (sljit_s32)src1w;
+ sljit_unaligned_store_s32(inst, (sljit_s32)src1w);
}
else {
EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, src1w);
@@ -1742,7 +1765,7 @@ static sljit_s32 emit_mul(struct sljit_compiler *compiler,
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
- *(sljit_sw*)inst = src2w;
+ sljit_unaligned_store_sw(inst, src2w);
}
#else
else if (IS_HALFWORD(src2w)) {
@@ -1752,7 +1775,7 @@ static sljit_s32 emit_mul(struct sljit_compiler *compiler,
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
- *(sljit_s32*)inst = (sljit_s32)src2w;
+ sljit_unaligned_store_s32(inst, (sljit_s32)src2w);
}
else {
EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, src2w);
@@ -2248,7 +2271,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
- SLJIT_MEMMOVE(inst, instruction, size);
+ SLJIT_MEMCPY(inst, instruction, size);
return SLJIT_SUCCESS;
}
@@ -2926,15 +2949,15 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
{
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- *(sljit_sw*)addr = new_addr - (addr + 4);
+ sljit_unaligned_store_sw((void*)addr, new_addr - (addr + 4));
#else
- *(sljit_uw*)addr = new_addr;
+ sljit_unaligned_store_sw((void*)addr, (sljit_sw) new_addr);
#endif
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
- *(sljit_sw*)addr = new_constant;
+ sljit_unaligned_store_sw((void*)addr, new_constant);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_x86_is_sse2_available(void)
diff --git a/src/3rdparty/pcre/sljit/sljitUtils.c b/src/3rdparty/pcre2/src/sljit/sljitUtils.c
index ec5c321194..ec5c321194 100644
--- a/src/3rdparty/pcre/sljit/sljitUtils.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitUtils.c
diff --git a/src/3rdparty/sqlite.pri b/src/3rdparty/sqlite.pri
index 87c356870b..79179daaf4 100644
--- a/src/3rdparty/sqlite.pri
+++ b/src/3rdparty/sqlite.pri
@@ -1,9 +1,8 @@
CONFIG(release, debug|release):DEFINES *= NDEBUG
-DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_RTREE
+DEFINES += SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_COMPLETE SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_FTS5 SQLITE_ENABLE_RTREE
!contains(CONFIG, largefile):DEFINES += SQLITE_DISABLE_LFS
qtConfig(posix_fallocate): DEFINES += HAVE_POSIX_FALLOCATE=1
winrt: DEFINES += SQLITE_OS_WINRT
-winphone: DEFINES += SQLITE_WIN32_FILEMAPPING_API=1
qnx: DEFINES += _QNX_SOURCE
integrity: QMAKE_CFLAGS += -include qplatformdefs.h
INCLUDEPATH += $$PWD/sqlite
diff --git a/src/3rdparty/sqlite/qt_attribution.json b/src/3rdparty/sqlite/qt_attribution.json
index a4ea0cdbd2..02686c2147 100644
--- a/src/3rdparty/sqlite/qt_attribution.json
+++ b/src/3rdparty/sqlite/qt_attribution.json
@@ -6,7 +6,7 @@
"Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.",
"Homepage": "http://www.sqlite.org/",
- "Version": "3.11.1.0",
+ "Version": "3.16.1",
"License": "Public Domain",
"Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed."
}
diff --git a/src/3rdparty/sqlite/sqlite3.c b/src/3rdparty/sqlite/sqlite3.c
index 123c65e396..905176cf9d 100644
--- a/src/3rdparty/sqlite/sqlite3.c
+++ b/src/3rdparty/sqlite/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.11.1. By combining all the individual C code files into this
+** version 3.16.1. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -9,7 +9,7 @@
**
** This file is all you need to compile SQLite. To use SQLite in other
** programs, you need this file and the "sqlite3.h" header file that defines
-** the programming interface to the SQLite library. (If you do not have
+** the programming interface to the SQLite library. (If you do not have
** the "sqlite3.h" header file at hand, you will find a copy embedded within
** the text of this file. Search for "Begin file sqlite3.h" to find the start
** of the embedded sqlite3.h header file.) Additional code files may be needed
@@ -37,8 +37,51 @@
** Internal interface definitions for SQLite.
**
*/
-#ifndef _SQLITEINT_H_
-#define _SQLITEINT_H_
+#ifndef SQLITEINT_H
+#define SQLITEINT_H
+
+/* Special Comments:
+**
+** Some comments have special meaning to the tools that measure test
+** coverage:
+**
+** NO_TEST - The branches on this line are not
+** measured by branch coverage. This is
+** used on lines of code that actually
+** implement parts of coverage testing.
+**
+** OPTIMIZATION-IF-TRUE - This branch is allowed to alway be false
+** and the correct answer is still obtained,
+** though perhaps more slowly.
+**
+** OPTIMIZATION-IF-FALSE - This branch is allowed to alway be true
+** and the correct answer is still obtained,
+** though perhaps more slowly.
+**
+** PREVENTS-HARMLESS-OVERREAD - This branch prevents a buffer overread
+** that would be harmless and undetectable
+** if it did occur.
+**
+** In all cases, the special comment must be enclosed in the usual
+** slash-asterisk...asterisk-slash comment marks, with no spaces between the
+** asterisks and the comment text.
+*/
+
+/*
+** Make sure the Tcl calling convention macro is defined. This macro is
+** only used by test code and Tcl integration code.
+*/
+#ifndef SQLITE_TCLAPI
+# define SQLITE_TCLAPI
+#endif
+
+/*
+** Make sure that rand_s() is available on Windows systems with MSVC 2005
+** or higher.
+*/
+#if defined(_MSC_VER) && _MSC_VER>=1400
+# define _CRT_RAND_S
+#endif
/*
** Include the header file used to customize the compiler options for MSVC.
@@ -62,8 +105,8 @@
**
** This file contains code that is specific to MSVC.
*/
-#ifndef _MSVC_H_
-#define _MSVC_H_
+#ifndef SQLITE_MSVC_H
+#define SQLITE_MSVC_H
#if defined(_MSC_VER)
#pragma warning(disable : 4054)
@@ -83,7 +126,7 @@
#pragma warning(disable : 4706)
#endif /* defined(_MSC_VER) */
-#endif /* _MSVC_H_ */
+#endif /* SQLITE_MSVC_H */
/************** End of msvc.h ************************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -247,8 +290,8 @@
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
*/
-#ifndef _SQLITE3_H_
-#define _SQLITE3_H_
+#ifndef SQLITE3_H
+#define SQLITE3_H
#include <stdarg.h> /* Needed for the definition of va_list */
/*
@@ -271,8 +314,17 @@ extern "C" {
#ifndef SQLITE_CDECL
# define SQLITE_CDECL
#endif
+#ifndef SQLITE_APICALL
+# define SQLITE_APICALL
+#endif
#ifndef SQLITE_STDCALL
-# define SQLITE_STDCALL
+# define SQLITE_STDCALL SQLITE_APICALL
+#endif
+#ifndef SQLITE_CALLBACK
+# define SQLITE_CALLBACK
+#endif
+#ifndef SQLITE_SYSAPI
+# define SQLITE_SYSAPI
#endif
/*
@@ -316,7 +368,8 @@ extern "C" {
** be held constant and Z will be incremented or else Y will be incremented
** and Z will be reset to zero.
**
-** Since version 3.6.18, SQLite source code has been stored in the
+** Since [version 3.6.18] ([dateof:3.6.18]),
+** SQLite source code has been stored in the
** <a href="http://www.fossil-scm.org/">Fossil configuration management
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
** a string which identifies a particular check-in of SQLite
@@ -328,13 +381,13 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.11.1"
-#define SQLITE_VERSION_NUMBER 3011001
-#define SQLITE_SOURCE_ID "2016-03-03 16:17:53 f047920ce16971e573bc6ec9a48b118c9de2b3a7"
+#define SQLITE_VERSION "3.16.1"
+#define SQLITE_VERSION_NUMBER 3016001
+#define SQLITE_SOURCE_ID "2017-01-03 18:27:03 979f04392853b8053817a3eea2fc679947b437fd"
/*
** CAPI3REF: Run-Time Library Version Numbers
-** KEYWORDS: sqlite3_version, sqlite3_sourceid
+** KEYWORDS: sqlite3_version sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
@@ -363,9 +416,9 @@ extern "C" {
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
-SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
-SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
+SQLITE_API const char *sqlite3_libversion(void);
+SQLITE_API const char *sqlite3_sourceid(void);
+SQLITE_API int sqlite3_libversion_number(void);
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
@@ -390,8 +443,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
** [sqlite_compileoption_get()] and the [compile_options pragma].
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
+SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
+SQLITE_API const char *sqlite3_compileoption_get(int N);
#endif
/*
@@ -430,7 +483,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
**
** See the [threading mode] documentation for additional information.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
+SQLITE_API int sqlite3_threadsafe(void);
/*
** CAPI3REF: Database Connection Handle
@@ -527,8 +580,8 @@ typedef sqlite_uint64 sqlite3_uint64;
** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
** argument is a harmless no-op.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
-SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
+SQLITE_API int sqlite3_close(sqlite3*);
+SQLITE_API int sqlite3_close_v2(sqlite3*);
/*
** The type for a callback function.
@@ -599,7 +652,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
** </ul>
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_exec(
+SQLITE_API int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
@@ -660,7 +713,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
** [result codes]. However, experience has shown that many of
** these result codes are too coarse-grained. They do not provide as
** much information about problems as programmers might like. In an effort to
-** address this, newer versions of SQLite (version 3.3.8 and later) include
+** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
+** and later) include
** support for additional result codes that provide more detailed information
** about errors. These [extended result codes] are enabled or disabled
** on a per database connection basis using the
@@ -723,6 +777,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
+#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -1183,6 +1238,12 @@ struct sqlite3_io_methods {
** on whether or not the file has been renamed, moved, or deleted since it
** was first opened.
**
+** <li>[[SQLITE_FCNTL_WIN32_GET_HANDLE]]
+** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the
+** underlying native file handle associated with a file handle. This file
+** control interprets its argument as a pointer to a native file handle and
+** writes the resulting value there.
+**
** <li>[[SQLITE_FCNTL_WIN32_SET_HANDLE]]
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
** opcode causes the xFileControl method to swap the file handle with the one
@@ -1233,6 +1294,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_RBU 26
#define SQLITE_FCNTL_VFS_POINTER 27
#define SQLITE_FCNTL_JOURNAL_POINTER 28
+#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
+#define SQLITE_FCNTL_PDB 30
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1253,6 +1316,16 @@ struct sqlite3_io_methods {
typedef struct sqlite3_mutex sqlite3_mutex;
/*
+** CAPI3REF: Loadable Extension Thunk
+**
+** A pointer to the opaque sqlite3_api_routines structure is passed as
+** the third parameter to entry points of [loadable extensions]. This
+** structure must be typedefed in order to work around compiler warnings
+** on some platforms.
+*/
+typedef struct sqlite3_api_routines sqlite3_api_routines;
+
+/*
** CAPI3REF: OS Interface Object
**
** An instance of the sqlite3_vfs object defines the interface between
@@ -1445,7 +1518,7 @@ struct sqlite3_vfs {
const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
/*
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
- ** New fields may be appended in figure versions. The iVersion
+ ** New fields may be appended in future versions. The iVersion
** value will increment whenever this happens.
*/
};
@@ -1587,10 +1660,10 @@ struct sqlite3_vfs {
** must return [SQLITE_OK] on success and some other [error code] upon
** failure.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
-SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
+SQLITE_API int sqlite3_initialize(void);
+SQLITE_API int sqlite3_shutdown(void);
+SQLITE_API int sqlite3_os_init(void);
+SQLITE_API int sqlite3_os_end(void);
/*
** CAPI3REF: Configuring The SQLite Library
@@ -1623,7 +1696,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
+SQLITE_API int sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
@@ -1642,7 +1715,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
@@ -2037,6 +2110,20 @@ struct sqlite3_mem_methods {
** is enabled (using the [PRAGMA threads] command) and the amount of content
** to be sorted exceeds the page size times the minimum of the
** [PRAGMA cache_size] setting and this value.
+**
+** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
+** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
+** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
+** becomes the [statement journal] spill-to-disk threshold.
+** [Statement journals] are held in memory until their size (in bytes)
+** exceeds this threshold, at which point they are written to disk.
+** Or if the threshold is -1, statement journals are always held
+** exclusively in memory.
+** Since many statement journals never become large, setting the spill
+** threshold to a value such as 64KiB can greatly reduce the amount of
+** I/O required to support statement rollback.
+** The default value for this setting is controlled by the
+** [SQLITE_STMTJRNL_SPILL] compile-time option.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -2064,6 +2151,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
+#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2121,11 +2209,66 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
+** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
+** <dd> ^This option is used to enable or disable the two-argument
+** version of the [fts3_tokenizer()] function which is part of the
+** [FTS3] full-text search engine extension.
+** There should be two additional arguments.
+** The first argument is an integer which is 0 to disable fts3_tokenizer() or
+** positive to enable fts3_tokenizer() or negative to leave the setting
+** unchanged.
+** The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
+** following this call. The second parameter may be a NULL pointer, in
+** which case the new setting is not reported back. </dd>
+**
+** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
+** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
+** interface independently of the [load_extension()] SQL function.
+** The [sqlite3_enable_load_extension()] API enables or disables both the
+** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
+** There should be two additional arguments.
+** When the first argument to this interface is 1, then only the C-API is
+** enabled and the SQL function remains disabled. If the first argument to
+** this interface is 0, then both the C-API and the SQL function are disabled.
+** If the first argument is -1, then no changes are made to state of either the
+** C-API or the SQL function.
+** The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
+** is disabled or enabled following this call. The second parameter may
+** be a NULL pointer, in which case the new setting is not reported back.
+** </dd>
+**
+** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
+** <dd> ^This option is used to change the name of the "main" database
+** schema. ^The sole argument is a pointer to a constant UTF8 string
+** which will become the new schema name in place of "main". ^SQLite
+** does not make a copy of the new main schema name string, so the application
+** must ensure that the argument passed into this DBCONFIG option is unchanged
+** until after the database connection closes.
+** </dd>
+**
+** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
+** <dd> Usually, when a database in wal mode is closed or detached from a
+** database handle, SQLite checks if this will mean that there are now no
+** connections at all to the database. If so, it performs a checkpoint
+** operation before closing the connection. This option may be used to
+** override this behaviour. The first parameter passed to this operation
+** is an integer - non-zero to disable checkpoints-on-close, or zero (the
+** default) to enable them. The second parameter is a pointer to an integer
+** into which is written 0 or 1 to indicate whether checkpoints-on-close
+** have been disabled - 0 if they are not disabled, 1 if they are.
+** </dd>
+**
** </dl>
*/
-#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
-#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
-#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
+#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
+#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
+#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
+#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
/*
@@ -2136,7 +2279,7 @@ struct sqlite3_mem_methods {
** [extended result codes] feature of SQLite. ^The extended result
** codes are disabled by default for historical compatibility.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
+SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
/*
** CAPI3REF: Last Insert Rowid
@@ -2188,7 +2331,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
** unpredictable and might not equal either the old or the new
** last insert [rowid].
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
+SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
/*
** CAPI3REF: Count The Number Of Rows Modified
@@ -2241,7 +2384,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
** while [sqlite3_changes()] is running then the value returned
** is unpredictable and not meaningful.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
+SQLITE_API int sqlite3_changes(sqlite3*);
/*
** CAPI3REF: Total Number Of Rows Modified
@@ -2265,7 +2408,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
** while [sqlite3_total_changes()] is running then the value
** returned is unpredictable and not meaningful.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
+SQLITE_API int sqlite3_total_changes(sqlite3*);
/*
** CAPI3REF: Interrupt A Long-Running Query
@@ -2305,7 +2448,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
** If the database connection closes while [sqlite3_interrupt()]
** is running then bad things will likely happen.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
+SQLITE_API void sqlite3_interrupt(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -2340,8 +2483,8 @@ SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
** The input to [sqlite3_complete16()] must be a zero-terminated
** UTF-16 string in native byte order.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
-SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
+SQLITE_API int sqlite3_complete(const char *sql);
+SQLITE_API int sqlite3_complete16(const void *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
@@ -2402,7 +2545,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
+SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
/*
** CAPI3REF: Set A Busy Timeout
@@ -2425,7 +2568,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int),
**
** See also: [PRAGMA busy_timeout]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
+SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
/*
** CAPI3REF: Convenience Routines For Running Queries
@@ -2500,7 +2643,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
** reflected in subsequent calls to [sqlite3_errcode()] or
** [sqlite3_errmsg()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
+SQLITE_API int sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
@@ -2508,7 +2651,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
-SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
+SQLITE_API void sqlite3_free_table(char **result);
/*
** CAPI3REF: Formatted String Printing Functions
@@ -2614,10 +2757,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
** addition that after the string has been read and copied into
** the result, [sqlite3_free()] is called on the input string.)^
*/
-SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
-SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
-SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
-SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
+SQLITE_API char *sqlite3_mprintf(const char*,...);
+SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
+SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
+SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
/*
** CAPI3REF: Memory Allocation Subsystem
@@ -2707,12 +2850,12 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list
** a block of memory after it has been released using
** [sqlite3_free()] or [sqlite3_realloc()].
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
-SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
-SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
+SQLITE_API void *sqlite3_malloc(int);
+SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
+SQLITE_API void *sqlite3_realloc(void*, int);
+SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
+SQLITE_API void sqlite3_free(void*);
+SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
/*
** CAPI3REF: Memory Allocator Statistics
@@ -2737,8 +2880,8 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
** by [sqlite3_memory_highwater(1)] is the high-water mark
** prior to the reset.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
+SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
+SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
/*
** CAPI3REF: Pseudo-Random Number Generator
@@ -2761,7 +2904,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
** internally and without recourse to the [sqlite3_vfs] xRandomness
** method.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
+SQLITE_API void sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
@@ -2844,7 +2987,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
** as stated in the previous paragraph, sqlite3_step() invokes
** sqlite3_prepare_v2() to reprepare a statement after a schema change.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
+SQLITE_API int sqlite3_set_authorizer(
sqlite3*,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pUserData
@@ -2924,6 +3067,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
** CAPI3REF: Tracing And Profiling Functions
** METHOD: sqlite3
**
+** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
+** instead of the routines described here.
+**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
**
@@ -2949,11 +3095,105 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
** sqlite3_profile() function is considered experimental and is
** subject to change in future versions of SQLite.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
+SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
+ void(*xTrace)(void*,const char*), void*);
+SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
+** CAPI3REF: SQL Trace Event Codes
+** KEYWORDS: SQLITE_TRACE
+**
+** These constants identify classes of events that can be monitored
+** using the [sqlite3_trace_v2()] tracing logic. The third argument
+** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of
+** the following constants. ^The first argument to the trace callback
+** is one of the following constants.
+**
+** New tracing constants may be added in future releases.
+**
+** ^A trace callback has four arguments: xCallback(T,C,P,X).
+** ^The T argument is one of the integer type codes above.
+** ^The C argument is a copy of the context pointer passed in as the
+** fourth argument to [sqlite3_trace_v2()].
+** The P and X arguments are pointers whose meanings depend on T.
+**
+** <dl>
+** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt>
+** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement
+** first begins running and possibly at other times during the
+** execution of the prepared statement, such as at the start of each
+** trigger subprogram. ^The P argument is a pointer to the
+** [prepared statement]. ^The X argument is a pointer to a string which
+** is the unexpanded SQL text of the prepared statement or an SQL comment
+** that indicates the invocation of a trigger. ^The callback can compute
+** the same text that would have been returned by the legacy [sqlite3_trace()]
+** interface by using the X argument when X begins with "--" and invoking
+** [sqlite3_expanded_sql(P)] otherwise.
+**
+** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt>
+** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
+** information as is provided by the [sqlite3_profile()] callback.
+** ^The P argument is a pointer to the [prepared statement] and the
+** X argument points to a 64-bit integer which is the estimated of
+** the number of nanosecond that the prepared statement took to run.
+** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
+**
+** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
+** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
+** statement generates a single row of result.
+** ^The P argument is a pointer to the [prepared statement] and the
+** X argument is unused.
+**
+** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt>
+** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database
+** connection closes.
+** ^The P argument is a pointer to the [database connection] object
+** and the X argument is unused.
+** </dl>
+*/
+#define SQLITE_TRACE_STMT 0x01
+#define SQLITE_TRACE_PROFILE 0x02
+#define SQLITE_TRACE_ROW 0x04
+#define SQLITE_TRACE_CLOSE 0x08
+
+/*
+** CAPI3REF: SQL Trace Hook
+** METHOD: sqlite3
+**
+** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback
+** function X against [database connection] D, using property mask M
+** and context pointer P. ^If the X callback is
+** NULL or if the M mask is zero, then tracing is disabled. The
+** M argument should be the bitwise OR-ed combination of
+** zero or more [SQLITE_TRACE] constants.
+**
+** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
+** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
+**
+** ^The X callback is invoked whenever any of the events identified by
+** mask M occur. ^The integer return value from the callback is currently
+** ignored, though this may change in future releases. Callback
+** implementations should return zero to ensure future compatibility.
+**
+** ^A trace callback is invoked with four arguments: callback(T,C,P,X).
+** ^The T argument is one of the [SQLITE_TRACE]
+** constants to indicate why the callback was invoked.
+** ^The C argument is a copy of the context pointer.
+** The P and X arguments are pointers whose meanings depend on T.
+**
+** The sqlite3_trace_v2() interface is intended to replace the legacy
+** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which
+** are deprecated.
+*/
+SQLITE_API int sqlite3_trace_v2(
+ sqlite3*,
+ unsigned uMask,
+ int(*xCallback)(unsigned,void*,void*,void*),
+ void *pCtx
+);
+
+/*
** CAPI3REF: Query Progress Callbacks
** METHOD: sqlite3
**
@@ -2985,7 +3225,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
** database connections for the meaning of "modify" in this paragraph.
**
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
+SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
/*
** CAPI3REF: Opening A New Database Connection
@@ -3214,15 +3454,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
**
** See also: [sqlite3_temp_directory]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_open(
+SQLITE_API int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_open16(
+SQLITE_API int sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
+SQLITE_API int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
@@ -3268,9 +3508,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
** VFS method, then the behavior of this routine is undefined and probably
** undesirable.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
+SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
/*
@@ -3314,11 +3554,11 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const cha
** was invoked incorrectly by the application. In that case, the
** error code and message may or may not be set.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
-SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
+SQLITE_API int sqlite3_errcode(sqlite3 *db);
+SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
+SQLITE_API const char *sqlite3_errmsg(sqlite3*);
+SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
+SQLITE_API const char *sqlite3_errstr(int);
/*
** CAPI3REF: Prepared Statement Object
@@ -3386,7 +3626,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
**
** New run-time limit categories may be added in future releases.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
+SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
/*
** CAPI3REF: Run-Time Limit Categories
@@ -3538,28 +3778,28 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
** </ol>
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
+SQLITE_API int sqlite3_prepare(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
+SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
+SQLITE_API int sqlite3_prepare16(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
+SQLITE_API int sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
@@ -3571,11 +3811,35 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
** CAPI3REF: Retrieving Statement SQL
** METHOD: sqlite3_stmt
**
-** ^This interface can be used to retrieve a saved copy of the original
-** SQL text used to create a [prepared statement] if that statement was
-** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
+** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
+** SQL text used to create [prepared statement] P if P was
+** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
+** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
+** string containing the SQL text of prepared statement P with
+** [bound parameters] expanded.
+**
+** ^(For example, if a prepared statement is created using the SQL
+** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
+** and parameter :xyz is unbound, then sqlite3_sql() will return
+** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql()
+** will return "SELECT 2345,NULL".)^
+**
+** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
+** is available to hold the result, or if the result would exceed the
+** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
+**
+** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
+** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time
+** option causes sqlite3_expanded_sql() to always return NULL.
+**
+** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
+** automatically freed when the prepared statement is finalized.
+** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
+** is obtained from [sqlite3_malloc()] and must be free by the application
+** by passing it to [sqlite3_free()].
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
+SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
+SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
@@ -3606,8 +3870,12 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
** sqlite3_stmt_readonly() to return true since, while those statements
** change the configuration of a database connection, they do not make
** changes to the content of the database files on disk.
+** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
+** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
+** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
+** sqlite3_stmt_readonly() returns false for those commands.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
@@ -3628,7 +3896,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
** for example, in diagnostic routines to search for prepared
** statements that are holding a transaction open.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
+SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
/*
** CAPI3REF: Dynamically Typed Value Object
@@ -3792,20 +4060,20 @@ typedef struct sqlite3_context sqlite3_context;
** See also: [sqlite3_bind_parameter_count()],
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
+SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
+SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
void(*)(void*));
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
+SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
+SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
+SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
+SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
+SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
+SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
+SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
void(*)(void*), unsigned char encoding);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
+SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
+SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
+SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
/*
** CAPI3REF: Number Of SQL Parameters
@@ -3826,7 +4094,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite
** [sqlite3_bind_parameter_name()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
+SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
/*
** CAPI3REF: Name Of A Host Parameter
@@ -3854,7 +4122,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
+SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
/*
** CAPI3REF: Index Of A Parameter With A Given Name
@@ -3871,7 +4139,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_name()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
+SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
/*
** CAPI3REF: Reset All Bindings On A Prepared Statement
@@ -3881,7 +4149,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const
** the [sqlite3_bind_blob | bindings] on a [prepared statement].
** ^Use this routine to reset all host parameters to NULL.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
+SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
/*
** CAPI3REF: Number Of Columns In A Result Set
@@ -3893,7 +4161,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
**
** See also: [sqlite3_data_count()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Column Names In A Result Set
@@ -3922,8 +4190,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
** then the name of the column is unspecified and may change from
** one release of SQLite to the next.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
+SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
+SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
/*
** CAPI3REF: Source Of Data In A Query Result
@@ -3971,12 +4239,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
+SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
+SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
+SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
+SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
+SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
+SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
/*
** CAPI3REF: Declared Datatype Of A Query Result
@@ -4008,8 +4276,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*
** is associated with individual values, not with the containers
** used to hold those values.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
+SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
+SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
/*
** CAPI3REF: Evaluate An SQL Statement
@@ -4070,7 +4338,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
** other than [SQLITE_ROW] before any subsequent invocation of
** sqlite3_step(). Failure to reset the prepared statement using
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
-** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began
+** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
+** sqlite3_step() began
** calling [sqlite3_reset()] automatically in this circumstance rather
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
** break because any application that ever receives an SQLITE_MISUSE error
@@ -4089,7 +4358,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
** then the more specific [error codes] are returned directly
** by sqlite3_step(). The use of the "v2" interface is recommended.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
+SQLITE_API int sqlite3_step(sqlite3_stmt*);
/*
** CAPI3REF: Number of columns in a result set
@@ -4110,7 +4379,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
**
** See also: [sqlite3_column_count()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Fundamental Datatypes
@@ -4300,16 +4569,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** pointer. Subsequent calls to [sqlite3_errcode()] will return
** [SQLITE_NOMEM].)^
*/
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
-SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
-SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
+SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
+SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
+SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
/*
** CAPI3REF: Destroy A Prepared Statement Object
@@ -4337,7 +4606,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int
** statement after it has been finalized can result in undefined and
** undesirable behavior such as segfaults and heap corruption.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Reset A Prepared Statement Object
@@ -4364,7 +4633,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
@@ -4464,7 +4733,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
** close the database connection nor finalize or reset the prepared
** statement in which the function is running.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
+SQLITE_API int sqlite3_create_function(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4474,7 +4743,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
+SQLITE_API int sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
@@ -4484,7 +4753,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
+SQLITE_API int sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4530,12 +4799,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
** these functions, we will not explain what they do.
*/
#ifndef SQLITE_OMIT_DEPRECATED
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
+SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
+SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
void*,sqlite3_int64);
#endif
@@ -4585,18 +4854,18 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
** These routines must be called from the same thread as
** the SQL function that supplied the [sqlite3_value*] parameters.
*/
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
-SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
+SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
+SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
+SQLITE_API double sqlite3_value_double(sqlite3_value*);
+SQLITE_API int sqlite3_value_int(sqlite3_value*);
+SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
+SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
+SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
+SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
+SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
+SQLITE_API int sqlite3_value_type(sqlite3_value*);
+SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
/*
** CAPI3REF: Finding The Subtype Of SQL Values
@@ -4612,7 +4881,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
** from the result of one [application-defined SQL function] into the
** input of another.
*/
-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
+SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
/*
** CAPI3REF: Copy And Free SQL Values
@@ -4628,8 +4897,8 @@ SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer
** then sqlite3_value_free(V) is a harmless no-op.
*/
-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
-SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
+SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*);
+SQLITE_API void sqlite3_value_free(sqlite3_value*);
/*
** CAPI3REF: Obtain Aggregate Function Context
@@ -4674,7 +4943,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
** This routine must be called from the same thread in which
** the aggregate SQL function is running.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
+SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
/*
** CAPI3REF: User Data For Functions
@@ -4689,7 +4958,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int
** This routine must be called from the same thread in which
** the application-defined function is running.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
+SQLITE_API void *sqlite3_user_data(sqlite3_context*);
/*
** CAPI3REF: Database Connection For Functions
@@ -4701,7 +4970,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
** and [sqlite3_create_function16()] routines that originally
** registered the application defined function.
*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
+SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
/*
** CAPI3REF: Function Auxiliary Data
@@ -4733,12 +5002,13 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
** SQLite will invoke the destructor function X with parameter P exactly
** once, when the metadata is discarded.
** SQLite is free to discard the metadata at any time, including: <ul>
-** <li> when the corresponding function parameter changes, or
-** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
-** SQL statement, or
-** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or
-** <li> during the original sqlite3_set_auxdata() call when a memory
-** allocation error occurs. </ul>)^
+** <li> ^(when the corresponding function parameter changes)^, or
+** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
+** SQL statement)^, or
+** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
+** parameter)^, or
+** <li> ^(during the original sqlite3_set_auxdata() call when a memory
+** allocation error occurs.)^ </ul>
**
** Note the last bullet in particular. The destructor X in
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
@@ -4754,8 +5024,8 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
** These routines must be called from the same thread in which
** the SQL function is running.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
-SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
+SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
/*
@@ -4891,27 +5161,27 @@ typedef void (*sqlite3_destructor_type)(void*);
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
+SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,
sqlite3_uint64,void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
+SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
+SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
+SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
+SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
+SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
+SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
+SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
+SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
+SQLITE_API void sqlite3_result_null(sqlite3_context*);
+SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
+SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
void(*)(void*), unsigned char encoding);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
+SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
+SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
+SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
/*
@@ -4926,7 +5196,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
+SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
/*
** CAPI3REF: Define New Collating Sequences
@@ -5008,14 +5278,14 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned
**
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
+SQLITE_API int sqlite3_create_collation(
sqlite3*,
const char *zName,
int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
+SQLITE_API int sqlite3_create_collation_v2(
sqlite3*,
const char *zName,
int eTextRep,
@@ -5023,7 +5293,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
+SQLITE_API int sqlite3_create_collation16(
sqlite3*,
const void *zName,
int eTextRep,
@@ -5058,12 +5328,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
** [sqlite3_create_collation_v2()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
+SQLITE_API int sqlite3_collation_needed(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const char*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
+SQLITE_API int sqlite3_collation_needed16(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const void*)
@@ -5077,11 +5347,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_key(
+SQLITE_API int sqlite3_key(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The key */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
+SQLITE_API int sqlite3_key_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The key */
@@ -5095,11 +5365,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
+SQLITE_API int sqlite3_rekey(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
+SQLITE_API int sqlite3_rekey_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The new key */
@@ -5109,7 +5379,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
** Specify the activation key for a SEE database. Unless
** activated, none of the SEE routines will work.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
+SQLITE_API void sqlite3_activate_see(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -5119,7 +5389,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
** Specify the activation key for a CEROD database. Unless
** activated, none of the CEROD routines will work.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
+SQLITE_API void sqlite3_activate_cerod(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -5141,7 +5411,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
+SQLITE_API int sqlite3_sleep(int);
/*
** CAPI3REF: Name Of The Folder Holding Temporary Files
@@ -5260,7 +5530,7 @@ SQLITE_API char *sqlite3_data_directory;
** connection while this routine is running, then the return value
** is undefined.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
+SQLITE_API int sqlite3_get_autocommit(sqlite3*);
/*
** CAPI3REF: Find The Database Handle Of A Prepared Statement
@@ -5273,7 +5543,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
** create the statement in the first place.
*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
+SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
/*
** CAPI3REF: Return The Filename For A Database Connection
@@ -5290,7 +5560,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -5300,7 +5570,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
** the name of a database on connection D.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
+SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Find the next prepared statement
@@ -5316,7 +5586,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
** [sqlite3_next_stmt(D,S)] must refer to an open database
** connection and in particular must not be a NULL pointer.
*/
-SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
+SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
/*
** CAPI3REF: Commit And Rollback Notification Callbacks
@@ -5365,8 +5635,8 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_
**
** See also the [sqlite3_update_hook()] interface.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
+SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
/*
** CAPI3REF: Data Change Notification Callbacks
@@ -5375,7 +5645,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
** ^The sqlite3_update_hook() interface registers a callback function
** with the [database connection] identified by the first argument
** to be invoked whenever a row is updated, inserted or deleted in
-** a rowid table.
+** a [rowid table].
** ^Any callback set by a previous call to this function
** for the same database connection is overridden.
**
@@ -5414,10 +5684,10 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
** on the same [database connection] D, or NULL for
** the first call on D.
**
-** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
-** interfaces.
+** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()],
+** and [sqlite3_preupdate_hook()] interfaces.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
+SQLITE_API void *sqlite3_update_hook(
sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
@@ -5432,7 +5702,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
** and disabled if the argument is false.)^
**
** ^Cache sharing is enabled and disabled for an entire process.
-** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
+** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
+** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
@@ -5457,7 +5728,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
**
** See Also: [SQLite Shared-Cache Mode]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
+SQLITE_API int sqlite3_enable_shared_cache(int);
/*
** CAPI3REF: Attempt To Free Heap Memory
@@ -5473,7 +5744,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
**
** See also: [sqlite3_db_release_memory()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
+SQLITE_API int sqlite3_release_memory(int);
/*
** CAPI3REF: Free Memory Used By A Database Connection
@@ -5487,7 +5758,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
**
** See also: [sqlite3_release_memory()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
+SQLITE_API int sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
@@ -5526,7 +5797,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
** from the heap.
** </ul>)^
**
-** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
+** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]),
+** the soft heap limit is enforced
** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
** the soft heap limit is enforced on every memory allocation. Without
@@ -5539,7 +5811,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
** The circumstances under which SQLite will enforce the soft heap limit may
** changes in future releases of SQLite.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
+SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
@@ -5550,7 +5822,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64
** only. All new applications should use the
** [sqlite3_soft_heap_limit64()] interface rather than this one.
*/
-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
+SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
/*
@@ -5565,7 +5837,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
** column exists. ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR and if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
-** NULL pointer, then this routine simply checks for the existance of the
+** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
** does not.
**
@@ -5620,7 +5892,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
** parsed, if that has not already been done, and returns an error if
** any errors are encountered while loading the schema.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
+SQLITE_API int sqlite3_table_column_metadata(
sqlite3 *db, /* Connection handle */
const char *zDbName, /* Database name or NULL */
const char *zTableName, /* Table name */
@@ -5662,12 +5934,21 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
** should free this memory by calling [sqlite3_free()].
**
** ^Extension loading must be enabled using
-** [sqlite3_enable_load_extension()] prior to calling this API,
+** [sqlite3_enable_load_extension()] or
+** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL)
+** prior to calling this API,
** otherwise an error will be returned.
**
+** <b>Security warning:</b> It is recommended that the
+** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
+** interface. The use of the [sqlite3_enable_load_extension()] interface
+** should be avoided. This will keep the SQL function [load_extension()]
+** disabled and prevent SQL injections from giving attackers
+** access to extension loading capabilities.
+**
** See also the [load_extension() SQL function].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
+SQLITE_API int sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Derived from zFile if 0 */
@@ -5687,8 +5968,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
** ^Call the sqlite3_enable_load_extension() routine with onoff==1
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
+**
+** ^This interface enables or disables both the C-API
+** [sqlite3_load_extension()] and the SQL function [load_extension()].
+** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
+** to enable or disable only the C-API.)^
+**
+** <b>Security warning:</b> It is recommended that extension loading
+** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
+** rather than this interface, so the [load_extension()] SQL function
+** remains disabled. This will prevent SQL injections from giving attackers
+** access to extension loading capabilities.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
+SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
** CAPI3REF: Automatically Load Statically Linked Extensions
@@ -5700,7 +5992,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
**
** ^(Even though the function prototype shows that xEntryPoint() takes
** no arguments and returns void, SQLite invokes xEntryPoint() with three
-** arguments and expects and integer result as if the signature of the
+** arguments and expects an integer result as if the signature of the
** entry point where as follows:
**
** <blockquote><pre>
@@ -5726,7 +6018,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
** See also: [sqlite3_reset_auto_extension()]
** and [sqlite3_cancel_auto_extension()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
/*
** CAPI3REF: Cancel Automatic Extension Loading
@@ -5738,7 +6030,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
** unregistered and it returns 0 if X was not on the list of initialization
** routines.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
/*
** CAPI3REF: Reset Automatic Extension Loading
@@ -5746,7 +6038,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(
** ^This interface disables all automatic extensions previously
** registered using [sqlite3_auto_extension()].
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
+SQLITE_API void sqlite3_reset_auto_extension(void);
/*
** The interface to the virtual-table mechanism is currently considered
@@ -5900,13 +6192,15 @@ struct sqlite3_module {
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
-** structure for SQLite version 3.8.2. If a virtual table extension is
+** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
+** If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
-** was added for version 3.9.0. It may therefore only be used if
+** was added for [version 3.9.0] ([dateof:3.9.0]).
+** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
*/
@@ -5991,13 +6285,13 @@ struct sqlite3_index_info {
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
+SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
+SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -6060,7 +6354,7 @@ struct sqlite3_vtab_cursor {
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
@@ -6079,7 +6373,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -6178,7 +6472,7 @@ typedef struct sqlite3_blob sqlite3_blob;
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
+SQLITE_API int sqlite3_blob_open(
sqlite3*,
const char *zDb,
const char *zTable,
@@ -6211,7 +6505,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
**
** ^This function sets the database handle error code and message.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
/*
** CAPI3REF: Close A BLOB Handle
@@ -6234,7 +6528,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64)
** is passed a valid open blob handle, the values returned by the
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
+SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
/*
** CAPI3REF: Return The Size Of An Open BLOB
@@ -6250,7 +6544,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
+SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
/*
** CAPI3REF: Read Data From A BLOB Incrementally
@@ -6279,7 +6573,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
**
** See also: [sqlite3_blob_write()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
+SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
/*
** CAPI3REF: Write Data Into A BLOB Incrementally
@@ -6321,7 +6615,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N,
**
** See also: [sqlite3_blob_read()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
+SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
/*
** CAPI3REF: Virtual File System Objects
@@ -6352,9 +6646,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z,
** ^(If the default VFS is unregistered, another VFS is chosen as
** the default. The choice for the new VFS is arbitrary.)^
*/
-SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
+SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
+SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
+SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
/*
** CAPI3REF: Mutexes
@@ -6470,11 +6764,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
+SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
+SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
+SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
+SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
+SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
/*
** CAPI3REF: Mutex Methods Object
@@ -6584,8 +6878,8 @@ struct sqlite3_mutex_methods {
** interface should also return 1 when given a NULL pointer.
*/
#ifndef NDEBUG
-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
+SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
+SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
#endif
/*
@@ -6604,7 +6898,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
-#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
+#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
@@ -6625,7 +6919,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
** ^If the [threading mode] is Single-thread or Multi-thread then this
** routine returns a NULL pointer.
*/
-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
+SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
/*
** CAPI3REF: Low-Level Control Of Database Files
@@ -6660,7 +6954,7 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
**
** See also: [SQLITE_FCNTL_LOCKSTATE]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
+SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
/*
** CAPI3REF: Testing Interface
@@ -6679,7 +6973,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName
** Unlike most of the SQLite API, this function is not guaranteed to
** operate consistently from one release to the next.
*/
-SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
+SQLITE_API int sqlite3_test_control(int op, ...);
/*
** CAPI3REF: Testing Interface Operation Codes
@@ -6708,6 +7002,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
+#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
@@ -6742,8 +7037,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int sqlite3_status64(
int op,
sqlite3_int64 *pCurrent,
sqlite3_int64 *pHighwater,
@@ -6868,7 +7163,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
@@ -6914,6 +7209,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
**
+** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
+** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
+** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
+** pager cache is shared between two or more connections the bytes of heap
+** memory used by that pager cache is divided evenly between the attached
+** connections.)^ In other words, if none of the pager caches associated
+** with the database connection are shared, this request returns the same
+** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
+** shared, the value returned by this call will be smaller than that returned
+** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
+** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
+**
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
** memory used to store the schema for all databases associated
@@ -6971,7 +7278,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
#define SQLITE_DBSTATUS_CACHE_MISS 8
#define SQLITE_DBSTATUS_CACHE_WRITE 9
#define SQLITE_DBSTATUS_DEFERRED_FKS 10
-#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */
+#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11
+#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */
/*
@@ -6998,7 +7306,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
@@ -7325,7 +7633,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
-** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
+** ^A call to sqlite3_backup_init() will fail, returning NULL, if
** there is already a read or read-write transaction open on the
** destination database.
**
@@ -7467,16 +7775,16 @@ typedef struct sqlite3_backup sqlite3_backup;
** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values.
*/
-SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
+SQLITE_API sqlite3_backup *sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */
const char *zDestName, /* Destination database name */
sqlite3 *pSource, /* Source database handle */
const char *zSourceName /* Source database name */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
+SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
+SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
+SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
+SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
/*
** CAPI3REF: Unlock Notification
@@ -7593,7 +7901,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
** the special "DROP TABLE/INDEX" case, the extended error code is just
** SQLITE_LOCKED.)^
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
+SQLITE_API int sqlite3_unlock_notify(
sqlite3 *pBlocked, /* Waiting connection */
void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */
void *pNotifyArg /* Argument to pass to xNotify */
@@ -7608,8 +7916,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
** strings in a case-independent fashion, using the same definition of "case
** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
-SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
+SQLITE_API int sqlite3_stricmp(const char *, const char *);
+SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
@@ -7626,7 +7934,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
**
** See also: [sqlite3_strlike()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
+SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
/*
** CAPI3REF: String LIKE Matching
@@ -7649,7 +7957,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zSt
**
** See also: [sqlite3_strglob()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
+SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
/*
** CAPI3REF: Error Logging Interface
@@ -7672,7 +7980,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zSt
** a few hundred characters, it will be truncated to the length of the
** buffer.
*/
-SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
+SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
** CAPI3REF: Write-Ahead Log Commit Hook
@@ -7706,9 +8014,9 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...)
** previously registered write-ahead log callback. ^Note that the
** [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
-** those overwrite any prior [sqlite3_wal_hook()] settings.
+** overwrite any prior [sqlite3_wal_hook()] settings.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
+SQLITE_API void *sqlite3_wal_hook(
sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
@@ -7743,7 +8051,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
** is only necessary if the default setting is found to be suboptimal
** for a particular application.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
/*
** CAPI3REF: Checkpoint a database
@@ -7765,7 +8073,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
** start a callback but which do not need the full power (and corresponding
** complication) of [sqlite3_wal_checkpoint_v2()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
/*
** CAPI3REF: Checkpoint a database
@@ -7859,7 +8167,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD
** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
** from SQL.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
+SQLITE_API int sqlite3_wal_checkpoint_v2(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of attached database (or NULL) */
int eMode, /* SQLITE_CHECKPOINT_* value */
@@ -7895,7 +8203,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options
** may be added in the future.
*/
-SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
+SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Virtual Table Configuration Options
@@ -7948,7 +8256,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
+SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
@@ -8053,7 +8361,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
**
** See also: [sqlite3_stmt_scanstatus_reset()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+SQLITE_API int sqlite3_stmt_scanstatus(
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
int idx, /* Index of loop to report on */
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
@@ -8069,7 +8377,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
** This API is only available if the library is built with pre-processor
** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
+SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
/*
** CAPI3REF: Flush caches to disk mid-transaction
@@ -8101,11 +8409,121 @@ SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
** ^This function does not set the database handle error code or message
** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*);
+SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
+
+/*
+** CAPI3REF: The pre-update hook.
+**
+** ^These interfaces are only available if SQLite is compiled using the
+** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
+**
+** ^The [sqlite3_preupdate_hook()] interface registers a callback function
+** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
+** on a [rowid table].
+** ^At most one preupdate hook may be registered at a time on a single
+** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
+** the previous setting.
+** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
+** with a NULL pointer as the second parameter.
+** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
+** the first parameter to callbacks.
+**
+** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate
+** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID]
+** tables.
+**
+** ^The second parameter to the preupdate callback is a pointer to
+** the [database connection] that registered the preupdate hook.
+** ^The third parameter to the preupdate callback is one of the constants
+** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the
+** kind of update operation that is about to occur.
+** ^(The fourth parameter to the preupdate callback is the name of the
+** database within the database connection that is being modified. This
+** will be "main" for the main database or "temp" for TEMP tables or
+** the name given after the AS keyword in the [ATTACH] statement for attached
+** databases.)^
+** ^The fifth parameter to the preupdate callback is the name of the
+** table that is being modified.
+** ^The sixth parameter to the preupdate callback is the initial [rowid] of the
+** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is
+** undefined for SQLITE_INSERT changes.
+** ^The seventh parameter to the preupdate callback is the final [rowid] of
+** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is
+** undefined for SQLITE_DELETE changes.
+**
+** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
+** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
+** provide additional information about a preupdate event. These routines
+** may only be called from within a preupdate callback. Invoking any of
+** these routines from outside of a preupdate callback or with a
+** [database connection] pointer that is different from the one supplied
+** to the preupdate callback results in undefined and probably undesirable
+** behavior.
+**
+** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
+** in the row that is being inserted, updated, or deleted.
+**
+** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
+** a [protected sqlite3_value] that contains the value of the Nth column of
+** the table row before it is updated. The N parameter must be between 0
+** and one less than the number of columns or the behavior will be
+** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
+** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
+** behavior is undefined. The [sqlite3_value] that P points to
+** will be destroyed when the preupdate callback returns.
+**
+** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
+** a [protected sqlite3_value] that contains the value of the Nth column of
+** the table row after it is updated. The N parameter must be between 0
+** and one less than the number of columns or the behavior will be
+** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
+** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
+** behavior is undefined. The [sqlite3_value] that P points to
+** will be destroyed when the preupdate callback returns.
+**
+** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
+** callback was invoked as a result of a direct insert, update, or delete
+** operation; or 1 for inserts, updates, or deletes invoked by top-level
+** triggers; or 2 for changes resulting from triggers called by top-level
+** triggers; and so forth.
+**
+** See also: [sqlite3_update_hook()]
+*/
+#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+SQLITE_API void *sqlite3_preupdate_hook(
+ sqlite3 *db,
+ void(*xPreUpdate)(
+ void *pCtx, /* Copy of third arg to preupdate_hook() */
+ sqlite3 *db, /* Database handle */
+ int op, /* SQLITE_UPDATE, DELETE or INSERT */
+ char const *zDb, /* Database name */
+ char const *zName, /* Table name */
+ sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */
+ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */
+ ),
+ void*
+);
+SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
+SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
+SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
+SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
+#endif
+
+/*
+** CAPI3REF: Low-level system error code
+**
+** ^Attempt to return the underlying operating system error code or error
+** number that caused the most recent I/O error or failure to open a file.
+** The return value is OS-dependent. For example, on unix systems, after
+** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
+** called to get back the underlying "errno" that caused the problem, such
+** as ENOSPC, EAUTH, EISDIR, and so forth.
+*/
+SQLITE_API int sqlite3_system_errno(sqlite3*);
/*
** CAPI3REF: Database Snapshot
-** KEYWORDS: {snapshot}
+** KEYWORDS: {snapshot} {sqlite3_snapshot}
** EXPERIMENTAL
**
** An instance of the snapshot object records the state of a [WAL mode]
@@ -8129,7 +8547,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*);
** to an historical snapshot (if possible). The destructor for
** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
*/
-typedef struct sqlite3_snapshot sqlite3_snapshot;
+typedef struct sqlite3_snapshot {
+ unsigned char hidden[48];
+} sqlite3_snapshot;
/*
** CAPI3REF: Record A Database Snapshot
@@ -8140,9 +8560,32 @@ typedef struct sqlite3_snapshot sqlite3_snapshot;
** schema S in database connection D. ^On success, the
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
-** ^If schema S of [database connection] D is not a [WAL mode] database
-** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)]
-** leaves the *P value unchanged and returns an appropriate [error code].
+** If there is not already a read-transaction open on schema S when
+** this function is called, one is opened automatically.
+**
+** The following must be true for this function to succeed. If any of
+** the following statements are false when sqlite3_snapshot_get() is
+** called, SQLITE_ERROR is returned. The final value of *P is undefined
+** in this case.
+**
+** <ul>
+** <li> The database handle must be in [autocommit mode].
+**
+** <li> Schema S of [database connection] D must be a [WAL mode] database.
+**
+** <li> There must not be a write transaction open on schema S of database
+** connection D.
+**
+** <li> One or more transactions must have been written to the current wal
+** file since it was created on disk (by any connection). This means
+** that a snapshot cannot be taken on a wal mode database with no wal
+** file immediately after it is first opened. At least one transaction
+** must be written to it first.
+** </ul>
+**
+** This function may also return SQLITE_NOMEM. If it is called with the
+** database handle in autocommit mode but fails for some other reason,
+** whether or not a read transaction is opened on schema S is undefined.
**
** The [sqlite3_snapshot] object returned from a successful call to
** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
@@ -8151,7 +8594,7 @@ typedef struct sqlite3_snapshot sqlite3_snapshot;
** The [sqlite3_snapshot_get()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get(
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
sqlite3 *db,
const char *zSchema,
sqlite3_snapshot **ppSnapshot
@@ -8161,22 +8604,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get(
** CAPI3REF: Start a read transaction on an historical snapshot
** EXPERIMENTAL
**
-** ^The [sqlite3_snapshot_open(D,S,P)] interface attempts to move the
-** read transaction that is currently open on schema S of
-** [database connection] D so that it refers to historical [snapshot] P.
+** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
+** read transaction for schema S of
+** [database connection] D such that the read transaction
+** refers to historical [snapshot] P, rather than the most
+** recent change to the database.
** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
** or an appropriate [error code] if it fails.
**
** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
-** the first operation, apart from other sqlite3_snapshot_open() calls,
-** following the [BEGIN] that starts a new read transaction.
-** ^A [snapshot] will fail to open if it has been overwritten by a
-** [checkpoint].
+** the first operation following the [BEGIN] that takes the schema S
+** out of [autocommit mode].
+** ^In other words, schema S must not currently be in
+** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
+** database connection D must be out of [autocommit mode].
+** ^A [snapshot] will fail to open if it has been overwritten by a
+** [checkpoint].
+** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
+** database connection D does not know that the database file for
+** schema S is in [WAL mode]. A database connection might not know
+** that the database file is in [WAL mode] if there has been no prior
+** I/O on that database connection, or if the database entered [WAL mode]
+** after the most recent I/O on the database connection.)^
+** (Hint: Run "[PRAGMA application_id]" against a newly opened
+** database connection in order to make it ready to use snapshots.)
**
** The [sqlite3_snapshot_open()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open(
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
sqlite3 *db,
const char *zSchema,
sqlite3_snapshot *pSnapshot
@@ -8193,7 +8649,56 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open(
** The [sqlite3_snapshot_free()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
-SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot*);
+SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
+
+/*
+** CAPI3REF: Compare the ages of two snapshot handles.
+** EXPERIMENTAL
+**
+** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
+** of two valid snapshot handles.
+**
+** If the two snapshot handles are not associated with the same database
+** file, the result of the comparison is undefined.
+**
+** Additionally, the result of the comparison is only valid if both of the
+** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
+** last time the wal file was deleted. The wal file is deleted when the
+** database is changed back to rollback mode or when the number of database
+** clients drops to zero. If either snapshot handle was obtained before the
+** wal file was last deleted, the value returned by this function
+** is undefined.
+**
+** Otherwise, this API returns a negative value if P1 refers to an older
+** snapshot than P2, zero if the two handles refer to the same database
+** snapshot, and a positive value if P1 is a newer snapshot than P2.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
+ sqlite3_snapshot *p1,
+ sqlite3_snapshot *p2
+);
+
+/*
+** CAPI3REF: Recover snapshots from a wal file
+** EXPERIMENTAL
+**
+** If all connections disconnect from a database file but do not perform
+** a checkpoint, the existing wal file is opened along with the database
+** file the next time the database is opened. At this point it is only
+** possible to successfully call sqlite3_snapshot_open() to open the most
+** recent snapshot of the database (the one at the head of the wal file),
+** even though the wal file may contain other valid snapshots for which
+** clients have sqlite3_snapshot handles.
+**
+** This function attempts to scan the wal file associated with database zDb
+** of database handle db and make all valid snapshots available to
+** sqlite3_snapshot_open(). It is an error if there is already a read
+** transaction open on the database, or if the database is not a wal mode
+** database.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
/*
** Undo the hack that converts floating point types to integer for
@@ -8206,8 +8711,9 @@ SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3
#if 0
} /* End of the 'extern "C"' block */
#endif
-#endif /* _SQLITE3_H_ */
+#endif /* SQLITE3_H */
+/******** Begin file sqlite3rtree.h *********/
/*
** 2010 August 30
**
@@ -8247,7 +8753,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
+SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
@@ -8273,7 +8779,7 @@ struct sqlite3_rtree_geometry {
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
+SQLITE_API int sqlite3_rtree_query_callback(
sqlite3 *db,
const char *zQueryFunc,
int (*xQueryFunc)(sqlite3_rtree_query_info*),
@@ -8325,6 +8831,1291 @@ struct sqlite3_rtree_query_info {
#endif /* ifndef _SQLITE3RTREE_H_ */
+/******** End of sqlite3rtree.h *********/
+/******** Begin file sqlite3session.h *********/
+
+#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION)
+#define __SQLITESESSION_H_ 1
+
+/*
+** Make sure we can call this stuff from C++.
+*/
+#if 0
+extern "C" {
+#endif
+
+
+/*
+** CAPI3REF: Session Object Handle
+*/
+typedef struct sqlite3_session sqlite3_session;
+
+/*
+** CAPI3REF: Changeset Iterator Handle
+*/
+typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
+
+/*
+** CAPI3REF: Create A New Session Object
+**
+** Create a new session object attached to database handle db. If successful,
+** a pointer to the new object is written to *ppSession and SQLITE_OK is
+** returned. If an error occurs, *ppSession is set to NULL and an SQLite
+** error code (e.g. SQLITE_NOMEM) is returned.
+**
+** It is possible to create multiple session objects attached to a single
+** database handle.
+**
+** Session objects created using this function should be deleted using the
+** [sqlite3session_delete()] function before the database handle that they
+** are attached to is itself closed. If the database handle is closed before
+** the session object is deleted, then the results of calling any session
+** module function, including [sqlite3session_delete()] on the session object
+** are undefined.
+**
+** Because the session module uses the [sqlite3_preupdate_hook()] API, it
+** is not possible for an application to register a pre-update hook on a
+** database handle that has one or more session objects attached. Nor is
+** it possible to create a session object attached to a database handle for
+** which a pre-update hook is already defined. The results of attempting
+** either of these things are undefined.
+**
+** The session object will be used to create changesets for tables in
+** database zDb, where zDb is either "main", or "temp", or the name of an
+** attached database. It is not an error if database zDb is not attached
+** to the database when the session object is created.
+*/
+int sqlite3session_create(
+ sqlite3 *db, /* Database handle */
+ const char *zDb, /* Name of db (e.g. "main") */
+ sqlite3_session **ppSession /* OUT: New session object */
+);
+
+/*
+** CAPI3REF: Delete A Session Object
+**
+** Delete a session object previously allocated using
+** [sqlite3session_create()]. Once a session object has been deleted, the
+** results of attempting to use pSession with any other session module
+** function are undefined.
+**
+** Session objects must be deleted before the database handle to which they
+** are attached is closed. Refer to the documentation for
+** [sqlite3session_create()] for details.
+*/
+void sqlite3session_delete(sqlite3_session *pSession);
+
+
+/*
+** CAPI3REF: Enable Or Disable A Session Object
+**
+** Enable or disable the recording of changes by a session object. When
+** enabled, a session object records changes made to the database. When
+** disabled - it does not. A newly created session object is enabled.
+** Refer to the documentation for [sqlite3session_changeset()] for further
+** details regarding how enabling and disabling a session object affects
+** the eventual changesets.
+**
+** Passing zero to this function disables the session. Passing a value
+** greater than zero enables it. Passing a value less than zero is a
+** no-op, and may be used to query the current state of the session.
+**
+** The return value indicates the final state of the session object: 0 if
+** the session is disabled, or 1 if it is enabled.
+*/
+int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
+
+/*
+** CAPI3REF: Set Or Clear the Indirect Change Flag
+**
+** Each change recorded by a session object is marked as either direct or
+** indirect. A change is marked as indirect if either:
+**
+** <ul>
+** <li> The session object "indirect" flag is set when the change is
+** made, or
+** <li> The change is made by an SQL trigger or foreign key action
+** instead of directly as a result of a users SQL statement.
+** </ul>
+**
+** If a single row is affected by more than one operation within a session,
+** then the change is considered indirect if all operations meet the criteria
+** for an indirect change above, or direct otherwise.
+**
+** This function is used to set, clear or query the session object indirect
+** flag. If the second argument passed to this function is zero, then the
+** indirect flag is cleared. If it is greater than zero, the indirect flag
+** is set. Passing a value less than zero does not modify the current value
+** of the indirect flag, and may be used to query the current state of the
+** indirect flag for the specified session object.
+**
+** The return value indicates the final state of the indirect flag: 0 if
+** it is clear, or 1 if it is set.
+*/
+int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
+
+/*
+** CAPI3REF: Attach A Table To A Session Object
+**
+** If argument zTab is not NULL, then it is the name of a table to attach
+** to the session object passed as the first argument. All subsequent changes
+** made to the table while the session object is enabled will be recorded. See
+** documentation for [sqlite3session_changeset()] for further details.
+**
+** Or, if argument zTab is NULL, then changes are recorded for all tables
+** in the database. If additional tables are added to the database (by
+** executing "CREATE TABLE" statements) after this call is made, changes for
+** the new tables are also recorded.
+**
+** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
+** defined as part of their CREATE TABLE statement. It does not matter if the
+** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
+** KEY may consist of a single column, or may be a composite key.
+**
+** It is not an error if the named table does not exist in the database. Nor
+** is it an error if the named table does not have a PRIMARY KEY. However,
+** no changes will be recorded in either of these scenarios.
+**
+** Changes are not recorded for individual rows that have NULL values stored
+** in one or more of their PRIMARY KEY columns.
+**
+** SQLITE_OK is returned if the call completes without error. Or, if an error
+** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
+*/
+int sqlite3session_attach(
+ sqlite3_session *pSession, /* Session object */
+ const char *zTab /* Table name */
+);
+
+/*
+** CAPI3REF: Set a table filter on a Session Object.
+**
+** The second argument (xFilter) is the "filter callback". For changes to rows
+** in tables that are not attached to the Session object, the filter is called
+** to determine whether changes to the table's rows should be tracked or not.
+** If xFilter returns 0, changes is not tracked. Note that once a table is
+** attached, xFilter will not be called again.
+*/
+void sqlite3session_table_filter(
+ sqlite3_session *pSession, /* Session object */
+ int(*xFilter)(
+ void *pCtx, /* Copy of third arg to _filter_table() */
+ const char *zTab /* Table name */
+ ),
+ void *pCtx /* First argument passed to xFilter */
+);
+
+/*
+** CAPI3REF: Generate A Changeset From A Session Object
+**
+** Obtain a changeset containing changes to the tables attached to the
+** session object passed as the first argument. If successful,
+** set *ppChangeset to point to a buffer containing the changeset
+** and *pnChangeset to the size of the changeset in bytes before returning
+** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
+** zero and return an SQLite error code.
+**
+** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes,
+** each representing a change to a single row of an attached table. An INSERT
+** change contains the values of each field of a new database row. A DELETE
+** contains the original values of each field of a deleted database row. An
+** UPDATE change contains the original values of each field of an updated
+** database row along with the updated values for each updated non-primary-key
+** column. It is not possible for an UPDATE change to represent a change that
+** modifies the values of primary key columns. If such a change is made, it
+** is represented in a changeset as a DELETE followed by an INSERT.
+**
+** Changes are not recorded for rows that have NULL values stored in one or
+** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
+** no corresponding change is present in the changesets returned by this
+** function. If an existing row with one or more NULL values stored in
+** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL,
+** only an INSERT is appears in the changeset. Similarly, if an existing row
+** with non-NULL PRIMARY KEY values is updated so that one or more of its
+** PRIMARY KEY columns are set to NULL, the resulting changeset contains a
+** DELETE change only.
+**
+** The contents of a changeset may be traversed using an iterator created
+** using the [sqlite3changeset_start()] API. A changeset may be applied to
+** a database with a compatible schema using the [sqlite3changeset_apply()]
+** API.
+**
+** Within a changeset generated by this function, all changes related to a
+** single table are grouped together. In other words, when iterating through
+** a changeset or when applying a changeset to a database, all changes related
+** to a single table are processed before moving on to the next table. Tables
+** are sorted in the same order in which they were attached (or auto-attached)
+** to the sqlite3_session object. The order in which the changes related to
+** a single table are stored is undefined.
+**
+** Following a successful call to this function, it is the responsibility of
+** the caller to eventually free the buffer that *ppChangeset points to using
+** [sqlite3_free()].
+**
+** <h3>Changeset Generation</h3>
+**
+** Once a table has been attached to a session object, the session object
+** records the primary key values of all new rows inserted into the table.
+** It also records the original primary key and other column values of any
+** deleted or updated rows. For each unique primary key value, data is only
+** recorded once - the first time a row with said primary key is inserted,
+** updated or deleted in the lifetime of the session.
+**
+** There is one exception to the previous paragraph: when a row is inserted,
+** updated or deleted, if one or more of its primary key columns contain a
+** NULL value, no record of the change is made.
+**
+** The session object therefore accumulates two types of records - those
+** that consist of primary key values only (created when the user inserts
+** a new record) and those that consist of the primary key values and the
+** original values of other table columns (created when the users deletes
+** or updates a record).
+**
+** When this function is called, the requested changeset is created using
+** both the accumulated records and the current contents of the database
+** file. Specifically:
+**
+** <ul>
+** <li> For each record generated by an insert, the database is queried
+** for a row with a matching primary key. If one is found, an INSERT
+** change is added to the changeset. If no such row is found, no change
+** is added to the changeset.
+**
+** <li> For each record generated by an update or delete, the database is
+** queried for a row with a matching primary key. If such a row is
+** found and one or more of the non-primary key fields have been
+** modified from their original values, an UPDATE change is added to
+** the changeset. Or, if no such row is found in the table, a DELETE
+** change is added to the changeset. If there is a row with a matching
+** primary key in the database, but all fields contain their original
+** values, no change is added to the changeset.
+** </ul>
+**
+** This means, amongst other things, that if a row is inserted and then later
+** deleted while a session object is active, neither the insert nor the delete
+** will be present in the changeset. Or if a row is deleted and then later a
+** row with the same primary key values inserted while a session object is
+** active, the resulting changeset will contain an UPDATE change instead of
+** a DELETE and an INSERT.
+**
+** When a session object is disabled (see the [sqlite3session_enable()] API),
+** it does not accumulate records when rows are inserted, updated or deleted.
+** This may appear to have some counter-intuitive effects if a single row
+** is written to more than once during a session. For example, if a row
+** is inserted while a session object is enabled, then later deleted while
+** the same session object is disabled, no INSERT record will appear in the
+** changeset, even though the delete took place while the session was disabled.
+** Or, if one field of a row is updated while a session is disabled, and
+** another field of the same row is updated while the session is enabled, the
+** resulting changeset will contain an UPDATE change that updates both fields.
+*/
+int sqlite3session_changeset(
+ sqlite3_session *pSession, /* Session object */
+ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
+ void **ppChangeset /* OUT: Buffer containing changeset */
+);
+
+/*
+** CAPI3REF: Load The Difference Between Tables Into A Session
+**
+** If it is not already attached to the session object passed as the first
+** argument, this function attaches table zTbl in the same manner as the
+** [sqlite3session_attach()] function. If zTbl does not exist, or if it
+** does not have a primary key, this function is a no-op (but does not return
+** an error).
+**
+** Argument zFromDb must be the name of a database ("main", "temp" etc.)
+** attached to the same database handle as the session object that contains
+** a table compatible with the table attached to the session by this function.
+** A table is considered compatible if it:
+**
+** <ul>
+** <li> Has the same name,
+** <li> Has the same set of columns declared in the same order, and
+** <li> Has the same PRIMARY KEY definition.
+** </ul>
+**
+** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables
+** are compatible but do not have any PRIMARY KEY columns, it is not an error
+** but no changes are added to the session object. As with other session
+** APIs, tables without PRIMARY KEYs are simply ignored.
+**
+** This function adds a set of changes to the session object that could be
+** used to update the table in database zFrom (call this the "from-table")
+** so that its content is the same as the table attached to the session
+** object (call this the "to-table"). Specifically:
+**
+** <ul>
+** <li> For each row (primary key) that exists in the to-table but not in
+** the from-table, an INSERT record is added to the session object.
+**
+** <li> For each row (primary key) that exists in the to-table but not in
+** the from-table, a DELETE record is added to the session object.
+**
+** <li> For each row (primary key) that exists in both tables, but features
+** different in each, an UPDATE record is added to the session.
+** </ul>
+**
+** To clarify, if this function is called and then a changeset constructed
+** using [sqlite3session_changeset()], then after applying that changeset to
+** database zFrom the contents of the two compatible tables would be
+** identical.
+**
+** It an error if database zFrom does not exist or does not contain the
+** required compatible table.
+**
+** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
+** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
+** may be set to point to a buffer containing an English language error
+** message. It is the responsibility of the caller to free this buffer using
+** sqlite3_free().
+*/
+int sqlite3session_diff(
+ sqlite3_session *pSession,
+ const char *zFromDb,
+ const char *zTbl,
+ char **pzErrMsg
+);
+
+
+/*
+** CAPI3REF: Generate A Patchset From A Session Object
+**
+** The differences between a patchset and a changeset are that:
+**
+** <ul>
+** <li> DELETE records consist of the primary key fields only. The
+** original values of other fields are omitted.
+** <li> The original values of any modified fields are omitted from
+** UPDATE records.
+** </ul>
+**
+** A patchset blob may be used with up to date versions of all
+** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
+** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
+** attempting to use a patchset blob with old versions of the
+** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
+**
+** Because the non-primary key "old.*" fields are omitted, no
+** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
+** is passed to the sqlite3changeset_apply() API. Other conflict types work
+** in the same way as for changesets.
+**
+** Changes within a patchset are ordered in the same way as for changesets
+** generated by the sqlite3session_changeset() function (i.e. all changes for
+** a single table are grouped together, tables appear in the order in which
+** they were attached to the session object).
+*/
+int sqlite3session_patchset(
+ sqlite3_session *pSession, /* Session object */
+ int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
+ void **ppPatchset /* OUT: Buffer containing changeset */
+);
+
+/*
+** CAPI3REF: Test if a changeset has recorded any changes.
+**
+** Return non-zero if no changes to attached tables have been recorded by
+** the session object passed as the first argument. Otherwise, if one or
+** more changes have been recorded, return zero.
+**
+** Even if this function returns zero, it is possible that calling
+** [sqlite3session_changeset()] on the session handle may still return a
+** changeset that contains no changes. This can happen when a row in
+** an attached table is modified and then later on the original values
+** are restored. However, if this function returns non-zero, then it is
+** guaranteed that a call to sqlite3session_changeset() will return a
+** changeset containing zero changes.
+*/
+int sqlite3session_isempty(sqlite3_session *pSession);
+
+/*
+** CAPI3REF: Create An Iterator To Traverse A Changeset
+**
+** Create an iterator used to iterate through the contents of a changeset.
+** If successful, *pp is set to point to the iterator handle and SQLITE_OK
+** is returned. Otherwise, if an error occurs, *pp is set to zero and an
+** SQLite error code is returned.
+**
+** The following functions can be used to advance and query a changeset
+** iterator created by this function:
+**
+** <ul>
+** <li> [sqlite3changeset_next()]
+** <li> [sqlite3changeset_op()]
+** <li> [sqlite3changeset_new()]
+** <li> [sqlite3changeset_old()]
+** </ul>
+**
+** It is the responsibility of the caller to eventually destroy the iterator
+** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
+** changeset (pChangeset) must remain valid until after the iterator is
+** destroyed.
+**
+** Assuming the changeset blob was created by one of the
+** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
+** [sqlite3changeset_invert()] functions, all changes within the changeset
+** that apply to a single table are grouped together. This means that when
+** an application iterates through a changeset using an iterator created by
+** this function, all changes that relate to a single table are visited
+** consecutively. There is no chance that the iterator will visit a change
+** the applies to table X, then one for table Y, and then later on visit
+** another change for table X.
+*/
+int sqlite3changeset_start(
+ sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
+ int nChangeset, /* Size of changeset blob in bytes */
+ void *pChangeset /* Pointer to blob containing changeset */
+);
+
+
+/*
+** CAPI3REF: Advance A Changeset Iterator
+**
+** This function may only be used with iterators created by function
+** [sqlite3changeset_start()]. If it is called on an iterator passed to
+** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
+** is returned and the call has no effect.
+**
+** Immediately after an iterator is created by sqlite3changeset_start(), it
+** does not point to any change in the changeset. Assuming the changeset
+** is not empty, the first call to this function advances the iterator to
+** point to the first change in the changeset. Each subsequent call advances
+** the iterator to point to the next change in the changeset (if any). If
+** no error occurs and the iterator points to a valid change after a call
+** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
+** Otherwise, if all changes in the changeset have already been visited,
+** SQLITE_DONE is returned.
+**
+** If an error occurs, an SQLite error code is returned. Possible error
+** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
+** SQLITE_NOMEM.
+*/
+int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
+
+/*
+** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
+**
+** The pIter argument passed to this function may either be an iterator
+** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
+** created by [sqlite3changeset_start()]. In the latter case, the most recent
+** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
+** is not the case, this function returns [SQLITE_MISUSE].
+**
+** If argument pzTab is not NULL, then *pzTab is set to point to a
+** nul-terminated utf-8 encoded string containing the name of the table
+** affected by the current change. The buffer remains valid until either
+** sqlite3changeset_next() is called on the iterator or until the
+** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
+** set to the number of columns in the table affected by the change. If
+** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
+** is an indirect change, or false (0) otherwise. See the documentation for
+** [sqlite3session_indirect()] for a description of direct and indirect
+** changes. Finally, if pOp is not NULL, then *pOp is set to one of
+** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
+** type of change that the iterator currently points to.
+**
+** If no error occurs, SQLITE_OK is returned. If an error does occur, an
+** SQLite error code is returned. The values of the output variables may not
+** be trusted in this case.
+*/
+int sqlite3changeset_op(
+ sqlite3_changeset_iter *pIter, /* Iterator object */
+ const char **pzTab, /* OUT: Pointer to table name */
+ int *pnCol, /* OUT: Number of columns in table */
+ int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */
+ int *pbIndirect /* OUT: True for an 'indirect' change */
+);
+
+/*
+** CAPI3REF: Obtain The Primary Key Definition Of A Table
+**
+** For each modified table, a changeset includes the following:
+**
+** <ul>
+** <li> The number of columns in the table, and
+** <li> Which of those columns make up the tables PRIMARY KEY.
+** </ul>
+**
+** This function is used to find which columns comprise the PRIMARY KEY of
+** the table modified by the change that iterator pIter currently points to.
+** If successful, *pabPK is set to point to an array of nCol entries, where
+** nCol is the number of columns in the table. Elements of *pabPK are set to
+** 0x01 if the corresponding column is part of the tables primary key, or
+** 0x00 if it is not.
+**
+** If argument pnCol is not NULL, then *pnCol is set to the number of columns
+** in the table.
+**
+** If this function is called when the iterator does not point to a valid
+** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise,
+** SQLITE_OK is returned and the output variables populated as described
+** above.
+*/
+int sqlite3changeset_pk(
+ sqlite3_changeset_iter *pIter, /* Iterator object */
+ unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */
+ int *pnCol /* OUT: Number of entries in output array */
+);
+
+/*
+** CAPI3REF: Obtain old.* Values From A Changeset Iterator
+**
+** The pIter argument passed to this function may either be an iterator
+** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
+** created by [sqlite3changeset_start()]. In the latter case, the most recent
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
+** Furthermore, it may only be called if the type of change that the iterator
+** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
+** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
+**
+** Argument iVal must be greater than or equal to 0, and less than the number
+** of columns in the table affected by the current change. Otherwise,
+** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
+**
+** If successful, this function sets *ppValue to point to a protected
+** sqlite3_value object containing the iVal'th value from the vector of
+** original row values stored as part of the UPDATE or DELETE change and
+** returns SQLITE_OK. The name of the function comes from the fact that this
+** is similar to the "old.*" columns available to update or delete triggers.
+**
+** If some other error occurs (e.g. an OOM condition), an SQLite error code
+** is returned and *ppValue is set to NULL.
+*/
+int sqlite3changeset_old(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int iVal, /* Column number */
+ sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */
+);
+
+/*
+** CAPI3REF: Obtain new.* Values From A Changeset Iterator
+**
+** The pIter argument passed to this function may either be an iterator
+** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
+** created by [sqlite3changeset_start()]. In the latter case, the most recent
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
+** Furthermore, it may only be called if the type of change that the iterator
+** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
+** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
+**
+** Argument iVal must be greater than or equal to 0, and less than the number
+** of columns in the table affected by the current change. Otherwise,
+** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
+**
+** If successful, this function sets *ppValue to point to a protected
+** sqlite3_value object containing the iVal'th value from the vector of
+** new row values stored as part of the UPDATE or INSERT change and
+** returns SQLITE_OK. If the change is an UPDATE and does not include
+** a new value for the requested column, *ppValue is set to NULL and
+** SQLITE_OK returned. The name of the function comes from the fact that
+** this is similar to the "new.*" columns available to update or delete
+** triggers.
+**
+** If some other error occurs (e.g. an OOM condition), an SQLite error code
+** is returned and *ppValue is set to NULL.
+*/
+int sqlite3changeset_new(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int iVal, /* Column number */
+ sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */
+);
+
+/*
+** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
+**
+** This function should only be used with iterator objects passed to a
+** conflict-handler callback by [sqlite3changeset_apply()] with either
+** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function
+** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue
+** is set to NULL.
+**
+** Argument iVal must be greater than or equal to 0, and less than the number
+** of columns in the table affected by the current change. Otherwise,
+** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
+**
+** If successful, this function sets *ppValue to point to a protected
+** sqlite3_value object containing the iVal'th value from the
+** "conflicting row" associated with the current conflict-handler callback
+** and returns SQLITE_OK.
+**
+** If some other error occurs (e.g. an OOM condition), an SQLite error code
+** is returned and *ppValue is set to NULL.
+*/
+int sqlite3changeset_conflict(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int iVal, /* Column number */
+ sqlite3_value **ppValue /* OUT: Value from conflicting row */
+);
+
+/*
+** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
+**
+** This function may only be called with an iterator passed to an
+** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
+** it sets the output variable to the total number of known foreign key
+** violations in the destination database and returns SQLITE_OK.
+**
+** In all other cases this function returns SQLITE_MISUSE.
+*/
+int sqlite3changeset_fk_conflicts(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int *pnOut /* OUT: Number of FK violations */
+);
+
+
+/*
+** CAPI3REF: Finalize A Changeset Iterator
+**
+** This function is used to finalize an iterator allocated with
+** [sqlite3changeset_start()].
+**
+** This function should only be called on iterators created using the
+** [sqlite3changeset_start()] function. If an application calls this
+** function with an iterator passed to a conflict-handler by
+** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the
+** call has no effect.
+**
+** If an error was encountered within a call to an sqlite3changeset_xxx()
+** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
+** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
+** to that error is returned by this function. Otherwise, SQLITE_OK is
+** returned. This is to allow the following pattern (pseudo-code):
+**
+** sqlite3changeset_start();
+** while( SQLITE_ROW==sqlite3changeset_next() ){
+** // Do something with change.
+** }
+** rc = sqlite3changeset_finalize();
+** if( rc!=SQLITE_OK ){
+** // An error has occurred
+** }
+*/
+int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
+
+/*
+** CAPI3REF: Invert A Changeset
+**
+** This function is used to "invert" a changeset object. Applying an inverted
+** changeset to a database reverses the effects of applying the uninverted
+** changeset. Specifically:
+**
+** <ul>
+** <li> Each DELETE change is changed to an INSERT, and
+** <li> Each INSERT change is changed to a DELETE, and
+** <li> For each UPDATE change, the old.* and new.* values are exchanged.
+** </ul>
+**
+** This function does not change the order in which changes appear within
+** the changeset. It merely reverses the sense of each individual change.
+**
+** If successful, a pointer to a buffer containing the inverted changeset
+** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and
+** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are
+** zeroed and an SQLite error code returned.
+**
+** It is the responsibility of the caller to eventually call sqlite3_free()
+** on the *ppOut pointer to free the buffer allocation following a successful
+** call to this function.
+**
+** WARNING/TODO: This function currently assumes that the input is a valid
+** changeset. If it is not, the results are undefined.
+*/
+int sqlite3changeset_invert(
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+/*
+** CAPI3REF: Concatenate Two Changeset Objects
+**
+** This function is used to concatenate two changesets, A and B, into a
+** single changeset. The result is a changeset equivalent to applying
+** changeset A followed by changeset B.
+**
+** This function combines the two input changesets using an
+** sqlite3_changegroup object. Calling it produces similar results as the
+** following code fragment:
+**
+** sqlite3_changegroup *pGrp;
+** rc = sqlite3_changegroup_new(&pGrp);
+** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
+** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
+** if( rc==SQLITE_OK ){
+** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
+** }else{
+** *ppOut = 0;
+** *pnOut = 0;
+** }
+**
+** Refer to the sqlite3_changegroup documentation below for details.
+*/
+int sqlite3changeset_concat(
+ int nA, /* Number of bytes in buffer pA */
+ void *pA, /* Pointer to buffer containing changeset A */
+ int nB, /* Number of bytes in buffer pB */
+ void *pB, /* Pointer to buffer containing changeset B */
+ int *pnOut, /* OUT: Number of bytes in output changeset */
+ void **ppOut /* OUT: Buffer containing output changeset */
+);
+
+
+/*
+** CAPI3REF: Changegroup Handle
+*/
+typedef struct sqlite3_changegroup sqlite3_changegroup;
+
+/*
+** CAPI3REF: Create A New Changegroup Object
+**
+** An sqlite3_changegroup object is used to combine two or more changesets
+** (or patchsets) into a single changeset (or patchset). A single changegroup
+** object may combine changesets or patchsets, but not both. The output is
+** always in the same format as the input.
+**
+** If successful, this function returns SQLITE_OK and populates (*pp) with
+** a pointer to a new sqlite3_changegroup object before returning. The caller
+** should eventually free the returned object using a call to
+** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
+** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
+**
+** The usual usage pattern for an sqlite3_changegroup object is as follows:
+**
+** <ul>
+** <li> It is created using a call to sqlite3changegroup_new().
+**
+** <li> Zero or more changesets (or patchsets) are added to the object
+** by calling sqlite3changegroup_add().
+**
+** <li> The result of combining all input changesets together is obtained
+** by the application via a call to sqlite3changegroup_output().
+**
+** <li> The object is deleted using a call to sqlite3changegroup_delete().
+** </ul>
+**
+** Any number of calls to add() and output() may be made between the calls to
+** new() and delete(), and in any order.
+**
+** As well as the regular sqlite3changegroup_add() and
+** sqlite3changegroup_output() functions, also available are the streaming
+** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
+*/
+int sqlite3changegroup_new(sqlite3_changegroup **pp);
+
+/*
+** CAPI3REF: Add A Changeset To A Changegroup
+**
+** Add all changes within the changeset (or patchset) in buffer pData (size
+** nData bytes) to the changegroup.
+**
+** If the buffer contains a patchset, then all prior calls to this function
+** on the same changegroup object must also have specified patchsets. Or, if
+** the buffer contains a changeset, so must have the earlier calls to this
+** function. Otherwise, SQLITE_ERROR is returned and no changes are added
+** to the changegroup.
+**
+** Rows within the changeset and changegroup are identified by the values in
+** their PRIMARY KEY columns. A change in the changeset is considered to
+** apply to the same row as a change already present in the changegroup if
+** the two rows have the same primary key.
+**
+** Changes to rows that do not already appear in the changegroup are
+** simply copied into it. Or, if both the new changeset and the changegroup
+** contain changes that apply to a single row, the final contents of the
+** changegroup depends on the type of each change, as follows:
+**
+** <table border=1 style="margin-left:8ex;margin-right:8ex">
+** <tr><th style="white-space:pre">Existing Change </th>
+** <th style="white-space:pre">New Change </th>
+** <th>Output Change
+** <tr><td>INSERT <td>INSERT <td>
+** The new change is ignored. This case does not occur if the new
+** changeset was recorded immediately after the changesets already
+** added to the changegroup.
+** <tr><td>INSERT <td>UPDATE <td>
+** The INSERT change remains in the changegroup. The values in the
+** INSERT change are modified as if the row was inserted by the
+** existing change and then updated according to the new change.
+** <tr><td>INSERT <td>DELETE <td>
+** The existing INSERT is removed from the changegroup. The DELETE is
+** not added.
+** <tr><td>UPDATE <td>INSERT <td>
+** The new change is ignored. This case does not occur if the new
+** changeset was recorded immediately after the changesets already
+** added to the changegroup.
+** <tr><td>UPDATE <td>UPDATE <td>
+** The existing UPDATE remains within the changegroup. It is amended
+** so that the accompanying values are as if the row was updated once
+** by the existing change and then again by the new change.
+** <tr><td>UPDATE <td>DELETE <td>
+** The existing UPDATE is replaced by the new DELETE within the
+** changegroup.
+** <tr><td>DELETE <td>INSERT <td>
+** If one or more of the column values in the row inserted by the
+** new change differ from those in the row deleted by the existing
+** change, the existing DELETE is replaced by an UPDATE within the
+** changegroup. Otherwise, if the inserted row is exactly the same
+** as the deleted row, the existing DELETE is simply discarded.
+** <tr><td>DELETE <td>UPDATE <td>
+** The new change is ignored. This case does not occur if the new
+** changeset was recorded immediately after the changesets already
+** added to the changegroup.
+** <tr><td>DELETE <td>DELETE <td>
+** The new change is ignored. This case does not occur if the new
+** changeset was recorded immediately after the changesets already
+** added to the changegroup.
+** </table>
+**
+** If the new changeset contains changes to a table that is already present
+** in the changegroup, then the number of columns and the position of the
+** primary key columns for the table must be consistent. If this is not the
+** case, this function fails with SQLITE_SCHEMA. If the input changeset
+** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
+** returned. Or, if an out-of-memory condition occurs during processing, this
+** function returns SQLITE_NOMEM. In all cases, if an error occurs the
+** final contents of the changegroup is undefined.
+**
+** If no error occurs, SQLITE_OK is returned.
+*/
+int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
+
+/*
+** CAPI3REF: Obtain A Composite Changeset From A Changegroup
+**
+** Obtain a buffer containing a changeset (or patchset) representing the
+** current contents of the changegroup. If the inputs to the changegroup
+** were themselves changesets, the output is a changeset. Or, if the
+** inputs were patchsets, the output is also a patchset.
+**
+** As with the output of the sqlite3session_changeset() and
+** sqlite3session_patchset() functions, all changes related to a single
+** table are grouped together in the output of this function. Tables appear
+** in the same order as for the very first changeset added to the changegroup.
+** If the second or subsequent changesets added to the changegroup contain
+** changes for tables that do not appear in the first changeset, they are
+** appended onto the end of the output changeset, again in the order in
+** which they are first encountered.
+**
+** If an error occurs, an SQLite error code is returned and the output
+** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
+** is returned and the output variables are set to the size of and a
+** pointer to the output buffer, respectively. In this case it is the
+** responsibility of the caller to eventually free the buffer using a
+** call to sqlite3_free().
+*/
+int sqlite3changegroup_output(
+ sqlite3_changegroup*,
+ int *pnData, /* OUT: Size of output buffer in bytes */
+ void **ppData /* OUT: Pointer to output buffer */
+);
+
+/*
+** CAPI3REF: Delete A Changegroup Object
+*/
+void sqlite3changegroup_delete(sqlite3_changegroup*);
+
+/*
+** CAPI3REF: Apply A Changeset To A Database
+**
+** Apply a changeset to a database. This function attempts to update the
+** "main" database attached to handle db with the changes found in the
+** changeset passed via the second and third arguments.
+**
+** The fourth argument (xFilter) passed to this function is the "filter
+** callback". If it is not NULL, then for each table affected by at least one
+** change in the changeset, the filter callback is invoked with
+** the table name as the second argument, and a copy of the context pointer
+** passed as the sixth argument to this function as the first. If the "filter
+** callback" returns zero, then no attempt is made to apply any changes to
+** the table. Otherwise, if the return value is non-zero or the xFilter
+** argument to this function is NULL, all changes related to the table are
+** attempted.
+**
+** For each table that is not excluded by the filter callback, this function
+** tests that the target database contains a compatible table. A table is
+** considered compatible if all of the following are true:
+**
+** <ul>
+** <li> The table has the same name as the name recorded in the
+** changeset, and
+** <li> The table has the same number of columns as recorded in the
+** changeset, and
+** <li> The table has primary key columns in the same position as
+** recorded in the changeset.
+** </ul>
+**
+** If there is no compatible table, it is not an error, but none of the
+** changes associated with the table are applied. A warning message is issued
+** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
+** one such warning is issued for each table in the changeset.
+**
+** For each change for which there is a compatible table, an attempt is made
+** to modify the table contents according to the UPDATE, INSERT or DELETE
+** change. If a change cannot be applied cleanly, the conflict handler
+** function passed as the fifth argument to sqlite3changeset_apply() may be
+** invoked. A description of exactly when the conflict handler is invoked for
+** each type of change is below.
+**
+** Unlike the xFilter argument, xConflict may not be passed NULL. The results
+** of passing anything other than a valid function pointer as the xConflict
+** argument are undefined.
+**
+** Each time the conflict handler function is invoked, it must return one
+** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
+** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
+** if the second argument passed to the conflict handler is either
+** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
+** returns an illegal value, any changes already made are rolled back and
+** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
+** actions are taken by sqlite3changeset_apply() depending on the value
+** returned by each invocation of the conflict-handler function. Refer to
+** the documentation for the three
+** [SQLITE_CHANGESET_OMIT|available return values] for details.
+**
+** <dl>
+** <dt>DELETE Changes<dd>
+** For each DELETE change, this function checks if the target database
+** contains a row with the same primary key value (or values) as the
+** original row values stored in the changeset. If it does, and the values
+** stored in all non-primary key columns also match the values stored in
+** the changeset the row is deleted from the target database.
+**
+** If a row with matching primary key values is found, but one or more of
+** the non-primary key fields contains a value different from the original
+** row value stored in the changeset, the conflict-handler function is
+** invoked with [SQLITE_CHANGESET_DATA] as the second argument.
+**
+** If no row with matching primary key values is found in the database,
+** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
+** passed as the second argument.
+**
+** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT
+** (which can only happen if a foreign key constraint is violated), the
+** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT]
+** passed as the second argument. This includes the case where the DELETE
+** operation is attempted because an earlier call to the conflict handler
+** function returned [SQLITE_CHANGESET_REPLACE].
+**
+** <dt>INSERT Changes<dd>
+** For each INSERT change, an attempt is made to insert the new row into
+** the database.
+**
+** If the attempt to insert the row fails because the database already
+** contains a row with the same primary key values, the conflict handler
+** function is invoked with the second argument set to
+** [SQLITE_CHANGESET_CONFLICT].
+**
+** If the attempt to insert the row fails because of some other constraint
+** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
+** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
+** This includes the case where the INSERT operation is re-attempted because
+** an earlier call to the conflict handler function returned
+** [SQLITE_CHANGESET_REPLACE].
+**
+** <dt>UPDATE Changes<dd>
+** For each UPDATE change, this function checks if the target database
+** contains a row with the same primary key value (or values) as the
+** original row values stored in the changeset. If it does, and the values
+** stored in all non-primary key columns also match the values stored in
+** the changeset the row is updated within the target database.
+**
+** If a row with matching primary key values is found, but one or more of
+** the non-primary key fields contains a value different from an original
+** row value stored in the changeset, the conflict-handler function is
+** invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
+** UPDATE changes only contain values for non-primary key fields that are
+** to be modified, only those fields need to match the original values to
+** avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
+**
+** If no row with matching primary key values is found in the database,
+** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
+** passed as the second argument.
+**
+** If the UPDATE operation is attempted, but SQLite returns
+** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
+** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
+** This includes the case where the UPDATE operation is attempted after
+** an earlier call to the conflict handler function returned
+** [SQLITE_CHANGESET_REPLACE].
+** </dl>
+**
+** It is safe to execute SQL statements, including those that write to the
+** table that the callback related to, from within the xConflict callback.
+** This can be used to further customize the applications conflict
+** resolution strategy.
+**
+** All changes made by this function are enclosed in a savepoint transaction.
+** If any other error (aside from a constraint failure when attempting to
+** write to the target database) occurs, then the savepoint transaction is
+** rolled back, restoring the target database to its original state, and an
+** SQLite error code returned.
+*/
+int sqlite3changeset_apply(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int nChangeset, /* Size of changeset in bytes */
+ void *pChangeset, /* Changeset blob */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx /* First argument passed to xConflict */
+);
+
+/*
+** CAPI3REF: Constants Passed To The Conflict Handler
+**
+** Values that may be passed as the second argument to a conflict-handler.
+**
+** <dl>
+** <dt>SQLITE_CHANGESET_DATA<dd>
+** The conflict handler is invoked with CHANGESET_DATA as the second argument
+** when processing a DELETE or UPDATE change if a row with the required
+** PRIMARY KEY fields is present in the database, but one or more other
+** (non primary-key) fields modified by the update do not contain the
+** expected "before" values.
+**
+** The conflicting row, in this case, is the database row with the matching
+** primary key.
+**
+** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
+** The conflict handler is invoked with CHANGESET_NOTFOUND as the second
+** argument when processing a DELETE or UPDATE change if a row with the
+** required PRIMARY KEY fields is not present in the database.
+**
+** There is no conflicting row in this case. The results of invoking the
+** sqlite3changeset_conflict() API are undefined.
+**
+** <dt>SQLITE_CHANGESET_CONFLICT<dd>
+** CHANGESET_CONFLICT is passed as the second argument to the conflict
+** handler while processing an INSERT change if the operation would result
+** in duplicate primary key values.
+**
+** The conflicting row in this case is the database row with the matching
+** primary key.
+**
+** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
+** If foreign key handling is enabled, and applying a changeset leaves the
+** database in a state containing foreign key violations, the conflict
+** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
+** exactly once before the changeset is committed. If the conflict handler
+** returns CHANGESET_OMIT, the changes, including those that caused the
+** foreign key constraint violation, are committed. Or, if it returns
+** CHANGESET_ABORT, the changeset is rolled back.
+**
+** No current or conflicting row information is provided. The only function
+** it is possible to call on the supplied sqlite3_changeset_iter handle
+** is sqlite3changeset_fk_conflicts().
+**
+** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
+** If any other constraint violation occurs while applying a change (i.e.
+** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
+** invoked with CHANGESET_CONSTRAINT as the second argument.
+**
+** There is no conflicting row in this case. The results of invoking the
+** sqlite3changeset_conflict() API are undefined.
+**
+** </dl>
+*/
+#define SQLITE_CHANGESET_DATA 1
+#define SQLITE_CHANGESET_NOTFOUND 2
+#define SQLITE_CHANGESET_CONFLICT 3
+#define SQLITE_CHANGESET_CONSTRAINT 4
+#define SQLITE_CHANGESET_FOREIGN_KEY 5
+
+/*
+** CAPI3REF: Constants Returned By The Conflict Handler
+**
+** A conflict handler callback must return one of the following three values.
+**
+** <dl>
+** <dt>SQLITE_CHANGESET_OMIT<dd>
+** If a conflict handler returns this value no special action is taken. The
+** change that caused the conflict is not applied. The session module
+** continues to the next change in the changeset.
+**
+** <dt>SQLITE_CHANGESET_REPLACE<dd>
+** This value may only be returned if the second argument to the conflict
+** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
+** is not the case, any changes applied so far are rolled back and the
+** call to sqlite3changeset_apply() returns SQLITE_MISUSE.
+**
+** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
+** handler, then the conflicting row is either updated or deleted, depending
+** on the type of change.
+**
+** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict
+** handler, then the conflicting row is removed from the database and a
+** second attempt to apply the change is made. If this second attempt fails,
+** the original row is restored to the database before continuing.
+**
+** <dt>SQLITE_CHANGESET_ABORT<dd>
+** If this value is returned, any changes applied so far are rolled back
+** and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
+** </dl>
+*/
+#define SQLITE_CHANGESET_OMIT 0
+#define SQLITE_CHANGESET_REPLACE 1
+#define SQLITE_CHANGESET_ABORT 2
+
+/*
+** CAPI3REF: Streaming Versions of API functions.
+**
+** The six streaming API xxx_strm() functions serve similar purposes to the
+** corresponding non-streaming API functions:
+**
+** <table border=1 style="margin-left:8ex;margin-right:8ex">
+** <tr><th>Streaming function<th>Non-streaming equivalent</th>
+** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply]
+** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat]
+** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert]
+** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start]
+** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset]
+** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset]
+** </table>
+**
+** Non-streaming functions that accept changesets (or patchsets) as input
+** require that the entire changeset be stored in a single buffer in memory.
+** Similarly, those that return a changeset or patchset do so by returning
+** a pointer to a single large buffer allocated using sqlite3_malloc().
+** Normally this is convenient. However, if an application running in a
+** low-memory environment is required to handle very large changesets, the
+** large contiguous memory allocations required can become onerous.
+**
+** In order to avoid this problem, instead of a single large buffer, input
+** is passed to a streaming API functions by way of a callback function that
+** the sessions module invokes to incrementally request input data as it is
+** required. In all cases, a pair of API function parameters such as
+**
+** <pre>
+** &nbsp; int nChangeset,
+** &nbsp; void *pChangeset,
+** </pre>
+**
+** Is replaced by:
+**
+** <pre>
+** &nbsp; int (*xInput)(void *pIn, void *pData, int *pnData),
+** &nbsp; void *pIn,
+** </pre>
+**
+** Each time the xInput callback is invoked by the sessions module, the first
+** argument passed is a copy of the supplied pIn context pointer. The second
+** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
+** error occurs the xInput method should copy up to (*pnData) bytes of data
+** into the buffer and set (*pnData) to the actual number of bytes copied
+** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
+** should be set to zero to indicate this. Or, if an error occurs, an SQLite
+** error code should be returned. In all cases, if an xInput callback returns
+** an error, all processing is abandoned and the streaming API function
+** returns a copy of the error code to the caller.
+**
+** In the case of sqlite3changeset_start_strm(), the xInput callback may be
+** invoked by the sessions module at any point during the lifetime of the
+** iterator. If such an xInput callback returns an error, the iterator enters
+** an error state, whereby all subsequent calls to iterator functions
+** immediately fail with the same error code as returned by xInput.
+**
+** Similarly, streaming API functions that return changesets (or patchsets)
+** return them in chunks by way of a callback function instead of via a
+** pointer to a single large buffer. In this case, a pair of parameters such
+** as:
+**
+** <pre>
+** &nbsp; int *pnChangeset,
+** &nbsp; void **ppChangeset,
+** </pre>
+**
+** Is replaced by:
+**
+** <pre>
+** &nbsp; int (*xOutput)(void *pOut, const void *pData, int nData),
+** &nbsp; void *pOut
+** </pre>
+**
+** The xOutput callback is invoked zero or more times to return data to
+** the application. The first parameter passed to each call is a copy of the
+** pOut pointer supplied by the application. The second parameter, pData,
+** points to a buffer nData bytes in size containing the chunk of output
+** data being returned. If the xOutput callback successfully processes the
+** supplied data, it should return SQLITE_OK to indicate success. Otherwise,
+** it should return some other SQLite error code. In this case processing
+** is immediately abandoned and the streaming API function returns a copy
+** of the xOutput error code to the application.
+**
+** The sessions module never invokes an xOutput callback with the third
+** parameter set to a value less than or equal to zero. Other than this,
+** no guarantees are made as to the size of the chunks of data returned.
+*/
+int sqlite3changeset_apply_strm(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
+ void *pIn, /* First arg for xInput */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx /* First argument passed to xConflict */
+);
+int sqlite3changeset_concat_strm(
+ int (*xInputA)(void *pIn, void *pData, int *pnData),
+ void *pInA,
+ int (*xInputB)(void *pIn, void *pData, int *pnData),
+ void *pInB,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+int sqlite3changeset_invert_strm(
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+int sqlite3changeset_start_strm(
+ sqlite3_changeset_iter **pp,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn
+);
+int sqlite3session_changeset_strm(
+ sqlite3_session *pSession,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+int sqlite3session_patchset_strm(
+ sqlite3_session *pSession,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+int sqlite3changegroup_add_strm(sqlite3_changegroup*,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn
+);
+int sqlite3changegroup_output_strm(sqlite3_changegroup*,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+
+
+/*
+** Make sure we can call this stuff from C++.
+*/
+#if 0
+}
+#endif
+
+#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */
+
+/******** End of sqlite3session.h *********/
+/******** Begin file fts5.h *********/
/*
** 2014 May 31
**
@@ -8469,11 +10260,13 @@ struct Fts5PhraseIter {
** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
**
** with $p set to a phrase equivalent to the phrase iPhrase of the
-** current query is executed. For each row visited, the callback function
-** passed as the fourth argument is invoked. The context and API objects
-** passed to the callback function may be used to access the properties of
-** each matched row. Invoking Api.xUserData() returns a copy of the pointer
-** passed as the third argument to pUserData.
+** current query is executed. Any column filter that applies to
+** phrase iPhrase of the current query is included in $p. For each
+** row visited, the callback function passed as the fourth argument
+** is invoked. The context and API objects passed to the callback
+** function may be used to access the properties of each matched row.
+** Invoking Api.xUserData() returns a copy of the pointer passed as
+** the third argument to pUserData.
**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
@@ -8642,7 +10435,7 @@ struct Fts5ExtensionApi {
** behaviour. The structure methods are expected to function as follows:
**
** xCreate:
-** This function is used to allocate and inititalize a tokenizer instance.
+** This function is used to allocate and initialize a tokenizer instance.
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
@@ -8902,7 +10695,7 @@ struct fts5_api {
#endif /* _FTS5_H */
-
+/******** End of fts5.h *********/
/************** End of sqlite3.h *********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -9020,13 +10813,13 @@ struct fts5_api {
** The suggested maximum number of in-memory pages to use for
** the main database table and for temporary tables.
**
-** IMPLEMENTATION-OF: R-31093-59126 The default suggested cache size
-** is 2000 pages.
+** IMPLEMENTATION-OF: R-30185-15359 The default suggested cache size is -2000,
+** which means the cache size is limited to 2048000 bytes of memory.
** IMPLEMENTATION-OF: R-48205-43578 The default suggested cache size can be
** altered using the SQLITE_DEFAULT_CACHE_SIZE compile-time options.
*/
#ifndef SQLITE_DEFAULT_CACHE_SIZE
-# define SQLITE_DEFAULT_CACHE_SIZE 2000
+# define SQLITE_DEFAULT_CACHE_SIZE -2000
#endif
/*
@@ -9039,8 +10832,9 @@ struct fts5_api {
/*
** The maximum number of attached databases. This must be between 0
-** and 62. The upper bound on 62 is because a 64-bit integer bitmap
-** is used internally to track attached databases.
+** and 125. The upper bound of 125 is because the attached databases are
+** counted using a signed 8-bit integer which has a maximum value of 127
+** and we have to allow 2 extra counts for the "main" and "temp" databases.
*/
#ifndef SQLITE_MAX_ATTACHED
# define SQLITE_MAX_ATTACHED 10
@@ -9075,7 +10869,7 @@ struct fts5_api {
** The default size of a database page.
*/
#ifndef SQLITE_DEFAULT_PAGE_SIZE
-# define SQLITE_DEFAULT_PAGE_SIZE 1024
+# define SQLITE_DEFAULT_PAGE_SIZE 4096
#endif
#if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE
# undef SQLITE_DEFAULT_PAGE_SIZE
@@ -9156,7 +10950,7 @@ struct fts5_api {
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
**
-** The correct "ANSI" way to do this is to use the intptr_t type.
+** The correct "ANSI" way to do this is to use the intptr_t type.
** Unfortunately, that typedef is not available on all compilers, or
** if it is available, it requires an #include of specific headers
** that vary from one machine to the next.
@@ -9181,21 +10975,6 @@ struct fts5_api {
#endif
/*
-** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to
-** something between S (inclusive) and E (exclusive).
-**
-** In other words, S is a buffer and E is a pointer to the first byte after
-** the end of buffer S. This macro returns true if P points to something
-** contained within the buffer S.
-*/
-#if defined(HAVE_STDINT_H)
-# define SQLITE_WITHIN(P,S,E) \
- ((uintptr_t)(P)>=(uintptr_t)(S) && (uintptr_t)(P)<(uintptr_t)(E))
-#else
-# define SQLITE_WITHIN(P,S,E) ((P)>=(S) && (P)<(E))
-#endif
-
-/*
** A macro to hint to the compiler that a function should not be
** inlined.
*/
@@ -9213,7 +10992,7 @@ struct fts5_api {
** the SQLITE_DISABLE_INTRINSIC define.
*/
#if !defined(SQLITE_DISABLE_INTRINSIC)
-# if defined(_MSC_VER) && _MSC_VER>=1300
+# if defined(_MSC_VER) && _MSC_VER>=1400
# if !defined(_WIN32_WCE)
# include <intrin.h>
# pragma intrinsic(_byteswap_ushort)
@@ -9323,7 +11102,7 @@ struct fts5_api {
** is set. Thus NDEBUG becomes an opt-in rather than an opt-out
** feature.
*/
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
@@ -9338,7 +11117,7 @@ struct fts5_api {
#endif
/*
-** The testcase() macro is used to aid in coverage testing. When
+** The testcase() macro is used to aid in coverage testing. When
** doing coverage testing, the condition inside the argument to
** testcase() must be evaluated both true and false in order to
** get full branch coverage. The testcase() macro is inserted
@@ -9384,7 +11163,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
#endif
/*
-** The ALWAYS and NEVER macros surround boolean expressions which
+** The ALWAYS and NEVER macros surround boolean expressions which
** are intended to always be true or false, respectively. Such
** expressions could be omitted from the code completely. But they
** are included in a few cases in order to enhance the resilience
@@ -9398,7 +11177,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
** be true and false so that the unreachable code they specify will
** not be counted as untested code.
*/
-#if defined(SQLITE_COVERAGE_TEST)
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
# define ALWAYS(X) (1)
# define NEVER(X) (0)
#elif !defined(NDEBUG)
@@ -9451,6 +11230,13 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
#endif
/*
+** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN
+*/
+#ifdef SQLITE_OMIT_EXPLAIN
+# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
+#endif
+
+/*
** Return true (non-zero) if the input is an integer that is too large
** to fit in 32-bits. This macro is used inside of various testcase()
** macros to verify that we have tested SQLite for large-file support.
@@ -9483,8 +11269,8 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
** This is the header file for the generic hash-table implementation
** used in SQLite.
*/
-#ifndef _SQLITE_HASH_H_
-#define _SQLITE_HASH_H_
+#ifndef SQLITE_HASH_H
+#define SQLITE_HASH_H
/* Forward declarations of structures. */
typedef struct Hash Hash;
@@ -9564,7 +11350,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
*/
/* #define sqliteHashCount(H) ((H)->count) // NOT USED */
-#endif /* _SQLITE_HASH_H_ */
+#endif /* SQLITE_HASH_H */
/************** End of hash.h ************************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -9596,76 +11382,76 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_AS 24
#define TK_WITHOUT 25
#define TK_COMMA 26
-#define TK_ID 27
-#define TK_INDEXED 28
-#define TK_ABORT 29
-#define TK_ACTION 30
-#define TK_AFTER 31
-#define TK_ANALYZE 32
-#define TK_ASC 33
-#define TK_ATTACH 34
-#define TK_BEFORE 35
-#define TK_BY 36
-#define TK_CASCADE 37
-#define TK_CAST 38
-#define TK_COLUMNKW 39
-#define TK_CONFLICT 40
-#define TK_DATABASE 41
-#define TK_DESC 42
-#define TK_DETACH 43
-#define TK_EACH 44
-#define TK_FAIL 45
-#define TK_FOR 46
-#define TK_IGNORE 47
-#define TK_INITIALLY 48
-#define TK_INSTEAD 49
-#define TK_LIKE_KW 50
-#define TK_MATCH 51
-#define TK_NO 52
-#define TK_KEY 53
-#define TK_OF 54
-#define TK_OFFSET 55
-#define TK_PRAGMA 56
-#define TK_RAISE 57
-#define TK_RECURSIVE 58
-#define TK_REPLACE 59
-#define TK_RESTRICT 60
-#define TK_ROW 61
-#define TK_TRIGGER 62
-#define TK_VACUUM 63
-#define TK_VIEW 64
-#define TK_VIRTUAL 65
-#define TK_WITH 66
-#define TK_REINDEX 67
-#define TK_RENAME 68
-#define TK_CTIME_KW 69
-#define TK_ANY 70
-#define TK_OR 71
-#define TK_AND 72
-#define TK_IS 73
-#define TK_BETWEEN 74
-#define TK_IN 75
-#define TK_ISNULL 76
-#define TK_NOTNULL 77
-#define TK_NE 78
-#define TK_EQ 79
-#define TK_GT 80
-#define TK_LE 81
-#define TK_LT 82
-#define TK_GE 83
-#define TK_ESCAPE 84
-#define TK_BITAND 85
-#define TK_BITOR 86
-#define TK_LSHIFT 87
-#define TK_RSHIFT 88
-#define TK_PLUS 89
-#define TK_MINUS 90
-#define TK_STAR 91
-#define TK_SLASH 92
-#define TK_REM 93
-#define TK_CONCAT 94
-#define TK_COLLATE 95
-#define TK_BITNOT 96
+#define TK_OR 27
+#define TK_AND 28
+#define TK_IS 29
+#define TK_MATCH 30
+#define TK_LIKE_KW 31
+#define TK_BETWEEN 32
+#define TK_IN 33
+#define TK_ISNULL 34
+#define TK_NOTNULL 35
+#define TK_NE 36
+#define TK_EQ 37
+#define TK_GT 38
+#define TK_LE 39
+#define TK_LT 40
+#define TK_GE 41
+#define TK_ESCAPE 42
+#define TK_BITAND 43
+#define TK_BITOR 44
+#define TK_LSHIFT 45
+#define TK_RSHIFT 46
+#define TK_PLUS 47
+#define TK_MINUS 48
+#define TK_STAR 49
+#define TK_SLASH 50
+#define TK_REM 51
+#define TK_CONCAT 52
+#define TK_COLLATE 53
+#define TK_BITNOT 54
+#define TK_ID 55
+#define TK_INDEXED 56
+#define TK_ABORT 57
+#define TK_ACTION 58
+#define TK_AFTER 59
+#define TK_ANALYZE 60
+#define TK_ASC 61
+#define TK_ATTACH 62
+#define TK_BEFORE 63
+#define TK_BY 64
+#define TK_CASCADE 65
+#define TK_CAST 66
+#define TK_COLUMNKW 67
+#define TK_CONFLICT 68
+#define TK_DATABASE 69
+#define TK_DESC 70
+#define TK_DETACH 71
+#define TK_EACH 72
+#define TK_FAIL 73
+#define TK_FOR 74
+#define TK_IGNORE 75
+#define TK_INITIALLY 76
+#define TK_INSTEAD 77
+#define TK_NO 78
+#define TK_KEY 79
+#define TK_OF 80
+#define TK_OFFSET 81
+#define TK_PRAGMA 82
+#define TK_RAISE 83
+#define TK_RECURSIVE 84
+#define TK_REPLACE 85
+#define TK_RESTRICT 86
+#define TK_ROW 87
+#define TK_TRIGGER 88
+#define TK_VACUUM 89
+#define TK_VIEW 90
+#define TK_VIRTUAL 91
+#define TK_WITH 92
+#define TK_REINDEX 93
+#define TK_RENAME 94
+#define TK_CTIME_KW 95
+#define TK_ANY 96
#define TK_STRING 97
#define TK_JOIN_KW 98
#define TK_CONSTRAINT 99
@@ -9701,9 +11487,9 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_LIMIT 129
#define TK_WHERE 130
#define TK_INTO 131
-#define TK_INTEGER 132
-#define TK_FLOAT 133
-#define TK_BLOB 134
+#define TK_FLOAT 132
+#define TK_BLOB 133
+#define TK_INTEGER 134
#define TK_VARIABLE 135
#define TK_CASE 136
#define TK_WHEN 137
@@ -9727,9 +11513,12 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
#define TK_UMINUS 155
#define TK_UPLUS 156
#define TK_REGISTER 157
-#define TK_ASTERISK 158
-#define TK_SPACE 159
-#define TK_ILLEGAL 160
+#define TK_VECTOR 158
+#define TK_SELECT_COLUMN 159
+#define TK_ASTERISK 160
+#define TK_SPAN 161
+#define TK_SPACE 162
+#define TK_ILLEGAL 163
/* The token codes above must all fit in 8 bits */
#define TKFLG_MASK 0xff
@@ -9768,7 +11557,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
/*
** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0
-** afterward. Having this macro allows us to cause the C compiler
+** afterward. Having this macro allows us to cause the C compiler
** to omit code used by TEMP tables without messy #ifndef statements.
*/
#ifdef SQLITE_OMIT_TEMPDB
@@ -9807,7 +11596,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
/*
** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
-** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
+** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
** to zero.
*/
#if SQLITE_TEMP_STORE==3 || SQLITE_THREADSAFE==0
@@ -9846,8 +11635,12 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
/*
** Macros to compute minimum and maximum of two numbers.
*/
-#define MIN(A,B) ((A)<(B)?(A):(B))
-#define MAX(A,B) ((A)>(B)?(A):(B))
+#ifndef MIN
+# define MIN(A,B) ((A)<(B)?(A):(B))
+#endif
+#ifndef MAX
+# define MAX(A,B) ((A)>(B)?(A):(B))
+#endif
/*
** Swap two objects of type TYPE.
@@ -9955,7 +11748,7 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
** 4 -> 20 1000 -> 99 1048576 -> 200
** 10 -> 33 1024 -> 100 4294967296 -> 320
**
-** The LogEst can be negative to indicate fractional values.
+** The LogEst can be negative to indicate fractional values.
** Examples:
**
** 0.5 -> -10 0.1 -> -33 0.0625 -> -40
@@ -9976,6 +11769,27 @@ typedef INT16_TYPE LogEst;
# endif
#endif
+/* The uptr type is an unsigned integer large enough to hold a pointer
+*/
+#if defined(HAVE_STDINT_H)
+ typedef uintptr_t uptr;
+#elif SQLITE_PTRSIZE==4
+ typedef u32 uptr;
+#else
+ typedef u64 uptr;
+#endif
+
+/*
+** The SQLITE_WITHIN(P,S,E) macro checks to see if pointer P points to
+** something between S (inclusive) and E (exclusive).
+**
+** In other words, S is a buffer and E is a pointer to the first byte after
+** the end of buffer S. This macro returns true if P points to something
+** contained within the buffer S.
+*/
+#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
+
+
/*
** Macros to determine whether the machine is big or little endian,
** and whether or not that determination is run-time or compile-time.
@@ -10021,7 +11835,7 @@ typedef INT16_TYPE LogEst;
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
-/*
+/*
** Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
*/
@@ -10115,7 +11929,7 @@ typedef INT16_TYPE LogEst;
/*
** An instance of the following structure is used to store the busy-handler
-** callback for a given sqlite handle.
+** callback for a given sqlite handle.
**
** The sqlite.busyHandler member of the sqlite struct contains the busy
** callback for the database handle. Each pager opened via the sqlite
@@ -10160,9 +11974,9 @@ struct BusyHandler {
/*
** The following value as a destructor means to use sqlite3DbFree().
-** The sqlite3DbFree() routine requires two parameters instead of the
-** one parameter that destructors normally want. So we have to introduce
-** this magic value that the code knows to handle differently. Any
+** The sqlite3DbFree() routine requires two parameters instead of the
+** one parameter that destructors normally want. So we have to introduce
+** this magic value that the code knows to handle differently. Any
** pointer will work here as long as it is distinct from SQLITE_STATIC
** and SQLITE_TRANSIENT.
*/
@@ -10186,19 +12000,19 @@ struct BusyHandler {
#define SQLITE_WSD const
#define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v)))
#define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config)
-SQLITE_API int SQLITE_STDCALL sqlite3_wsd_init(int N, int J);
-SQLITE_API void *SQLITE_STDCALL sqlite3_wsd_find(void *K, int L);
+SQLITE_API int sqlite3_wsd_init(int N, int J);
+SQLITE_API void *sqlite3_wsd_find(void *K, int L);
#else
- #define SQLITE_WSD
+ #define SQLITE_WSD
#define GLOBAL(t,v) v
#define sqlite3GlobalConfig sqlite3Config
#endif
/*
** The following macros are used to suppress compiler warnings and to
-** make it clear to human readers when a function parameter is deliberately
+** make it clear to human readers when a function parameter is deliberately
** left unused within the body of a function. This usually happens when
-** a function is called via a function pointer. For example the
+** a function is called via a function pointer. For example the
** implementation of an SQL aggregate step callback may not use the
** parameter indicating the number of arguments passed to the aggregate,
** if it knows that this is enforced elsewhere.
@@ -10241,6 +12055,7 @@ typedef struct LookasideSlot LookasideSlot;
typedef struct Module Module;
typedef struct NameContext NameContext;
typedef struct Parse Parse;
+typedef struct PreUpdate PreUpdate;
typedef struct PrintfArguments PrintfArguments;
typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
@@ -10263,8 +12078,16 @@ typedef struct Walker Walker;
typedef struct WhereInfo WhereInfo;
typedef struct With With;
+/* A VList object records a mapping between parameters/variables/wildcards
+** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
+** variable number associated with that parameter. See the format description
+** on the sqlite3VListAdd() routine for more information. A VList is really
+** just an array of integers.
+*/
+typedef int VList;
+
/*
-** Defer sourcing vdbe.h and btree.h until after the "u8" and
+** Defer sourcing vdbe.h and btree.h until after the "u8" and
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
** pointer types (i.e. FuncDef) defined above.
*/
@@ -10285,8 +12108,8 @@ typedef struct With With;
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
*/
-#ifndef _BTREE_H_
-#define _BTREE_H_
+#ifndef SQLITE_BTREE_H
+#define SQLITE_BTREE_H
/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
@@ -10311,6 +12134,7 @@ typedef struct With With;
typedef struct Btree Btree;
typedef struct BtCursor BtCursor;
typedef struct BtShared BtShared;
+typedef struct BtreePayload BtreePayload;
SQLITE_PRIVATE int sqlite3BtreeOpen(
@@ -10340,7 +12164,6 @@ SQLITE_PRIVATE int sqlite3BtreeSetSpillSize(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
#endif
SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
-SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*);
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
@@ -10362,7 +12185,9 @@ SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*);
SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*);
SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree);
+#ifndef SQLITE_OMIT_SHARED_CACHE
SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock);
+#endif
SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int);
SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *);
@@ -10523,26 +12348,54 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags);
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
-SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
- const void *pData, int nData,
- int nZero, int bias, int seekResult);
+/* An instance of the BtreePayload object describes the content of a single
+** entry in either an index or table btree.
+**
+** Index btrees (used for indexes and also WITHOUT ROWID tables) contain
+** an arbitrary key and no data. These btrees have pKey,nKey set to their
+** key and pData,nData,nZero set to zero.
+**
+** Table btrees (used for rowid tables) contain an integer rowid used as
+** the key and passed in the nKey field. The pKey field is zero.
+** pData,nData hold the content of the new entry. nZero extra zero bytes
+** are appended to the end of the content when constructing the entry.
+**
+** This object is used to pass information into sqlite3BtreeInsert(). The
+** same information used to be passed as five separate parameters. But placing
+** the information into this object helps to keep the interface more
+** organized and understandable, and it also helps the resulting code to
+** run a little faster by using fewer registers for parameter passing.
+*/
+struct BtreePayload {
+ const void *pKey; /* Key content for indexes. NULL for tables */
+ sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */
+ const void *pData; /* Data for tables. NULL for indexes */
+ struct Mem *aMem; /* First of nMem value in the unpacked pKey */
+ u16 nMem; /* Number of aMem[] value. Might be zero */
+ int nData; /* Size of pData. 0 if none. */
+ int nZero; /* Extra zero data appended after pData,nData */
+};
+
+SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
+ int bias, int seekResult);
SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes);
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes);
SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes);
SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*);
SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes);
-SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
-SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
-SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt);
-SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt);
-SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
-SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
+SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*);
+SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
+SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
+SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
+#ifndef SQLITE_OMIT_INCRBLOB
+SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *);
+#endif
SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *);
SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
@@ -10552,6 +12405,7 @@ SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void);
#ifndef NDEBUG
SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
+SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*);
#ifndef SQLITE_OMIT_BTREECOUNT
SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *, i64 *);
@@ -10576,11 +12430,13 @@ SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*);
SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*);
SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
+SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree*);
#else
# define sqlite3BtreeEnter(X)
# define sqlite3BtreeEnterAll(X)
# define sqlite3BtreeSharable(X) 0
# define sqlite3BtreeEnterCursor(X)
+# define sqlite3BtreeConnectionCount(X) 1
#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE
@@ -10605,7 +12461,7 @@ SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
#endif
-#endif /* _BTREE_H_ */
+#endif /* SQLITE_BTREE_H */
/************** End of btree.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -10628,8 +12484,8 @@ SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*);
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
*/
-#ifndef _SQLITE_VDBE_H_
-#define _SQLITE_VDBE_H_
+#ifndef SQLITE_VDBE_H
+#define SQLITE_VDBE_H
/* #include <stdio.h> */
/*
@@ -10654,7 +12510,7 @@ typedef struct SubProgram SubProgram;
struct VdbeOp {
u8 opcode; /* What operation to perform */
signed char p4type; /* One of the P4_xxx constants for p4 */
- u8 opflags; /* Mask of the OPFLG_* flags in opcodes.h */
+ u8 notUsed1;
u8 p5; /* Fifth parameter is an unsigned character */
int p1; /* First operand */
int p2; /* Second parameter (often the jump destination) */
@@ -10673,6 +12529,7 @@ struct VdbeOp {
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
int *ai; /* Used when p4type is P4_INTARRAY */
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
+ Table *pTab; /* Used when p4type is P4_TABLE */
#ifdef SQLITE_ENABLE_CURSOR_HINTS
Expr *pExpr; /* Used when p4type is P4_EXPR */
#endif
@@ -10700,7 +12557,6 @@ struct SubProgram {
int nOp; /* Elements in aOp[] */
int nMem; /* Number of memory cells required */
int nCsr; /* Number of cursors required */
- int nOnce; /* Number of OP_Once instructions */
void *token; /* id that may be used to recursive triggers */
SubProgram *pNext; /* Next sub-program already visited */
};
@@ -10723,21 +12579,21 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_NOTUSED 0 /* The P4 parameter is not used */
#define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */
#define P4_STATIC (-2) /* Pointer to a static string */
-#define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */
-#define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */
-#define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */
-#define P4_EXPR (-7) /* P4 is a pointer to an Expr tree */
-#define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */
+#define P4_COLLSEQ (-3) /* P4 is a pointer to a CollSeq structure */
+#define P4_FUNCDEF (-4) /* P4 is a pointer to a FuncDef structure */
+#define P4_KEYINFO (-5) /* P4 is a pointer to a KeyInfo structure */
+#define P4_EXPR (-6) /* P4 is a pointer to an Expr tree */
+#define P4_MEM (-7) /* P4 is a pointer to a Mem* structure */
#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */
-#define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */
-#define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */
-#define P4_REAL (-12) /* P4 is a 64-bit floating point value */
-#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
-#define P4_INT32 (-14) /* P4 is a 32-bit signed integer */
-#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
-#define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */
-#define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
-#define P4_FUNCCTX (-20) /* P4 is a pointer to an sqlite3_context object */
+#define P4_VTAB (-8) /* P4 is a pointer to an sqlite3_vtab structure */
+#define P4_REAL (-9) /* P4 is a 64-bit floating point value */
+#define P4_INT64 (-10) /* P4 is a 64-bit signed integer */
+#define P4_INT32 (-11) /* P4 is a 32-bit signed integer */
+#define P4_INTARRAY (-12) /* P4 is a vector of 32-bit integers */
+#define P4_SUBPROGRAM (-13) /* P4 is a pointer to a SubProgram structure */
+#define P4_ADVANCE (-14) /* P4 is a pointer to BtreeNext() or BtreePrev() */
+#define P4_TABLE (-15) /* P4 is a pointer to a Table structure */
+#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
@@ -10795,150 +12651,150 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_VUpdate 12 /* synopsis: data=r[P3@P2] */
#define OP_Goto 13
#define OP_Gosub 14
-#define OP_Return 15
-#define OP_InitCoroutine 16
-#define OP_EndCoroutine 17
-#define OP_Yield 18
+#define OP_InitCoroutine 15
+#define OP_Yield 16
+#define OP_MustBeInt 17
+#define OP_Jump 18
#define OP_Not 19 /* same as TK_NOT, synopsis: r[P2]= !r[P1] */
-#define OP_HaltIfNull 20 /* synopsis: if r[P3]=null halt */
-#define OP_Halt 21
-#define OP_Integer 22 /* synopsis: r[P2]=P1 */
-#define OP_Int64 23 /* synopsis: r[P2]=P4 */
-#define OP_String 24 /* synopsis: r[P2]='P4' (len=P1) */
-#define OP_Null 25 /* synopsis: r[P2..P3]=NULL */
-#define OP_SoftNull 26 /* synopsis: r[P1]=NULL */
-#define OP_Blob 27 /* synopsis: r[P2]=P4 (len=P1) */
-#define OP_Variable 28 /* synopsis: r[P2]=parameter(P1,P4) */
-#define OP_Move 29 /* synopsis: r[P2@P3]=r[P1@P3] */
-#define OP_Copy 30 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
-#define OP_SCopy 31 /* synopsis: r[P2]=r[P1] */
-#define OP_IntCopy 32 /* synopsis: r[P2]=r[P1] */
-#define OP_ResultRow 33 /* synopsis: output=r[P1@P2] */
-#define OP_CollSeq 34
-#define OP_Function0 35 /* synopsis: r[P3]=func(r[P2@P5]) */
-#define OP_Function 36 /* synopsis: r[P3]=func(r[P2@P5]) */
-#define OP_AddImm 37 /* synopsis: r[P1]=r[P1]+P2 */
-#define OP_MustBeInt 38
-#define OP_RealAffinity 39
-#define OP_Cast 40 /* synopsis: affinity(r[P1]) */
-#define OP_Permutation 41
-#define OP_Compare 42 /* synopsis: r[P1@P3] <-> r[P2@P3] */
-#define OP_Jump 43
-#define OP_Once 44
-#define OP_If 45
-#define OP_IfNot 46
-#define OP_Column 47 /* synopsis: r[P3]=PX */
-#define OP_Affinity 48 /* synopsis: affinity(r[P1@P2]) */
-#define OP_MakeRecord 49 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
-#define OP_Count 50 /* synopsis: r[P2]=count() */
-#define OP_ReadCookie 51
-#define OP_SetCookie 52
-#define OP_ReopenIdx 53 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenRead 54 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenWrite 55 /* synopsis: root=P2 iDb=P3 */
-#define OP_OpenAutoindex 56 /* synopsis: nColumn=P2 */
-#define OP_OpenEphemeral 57 /* synopsis: nColumn=P2 */
-#define OP_SorterOpen 58
-#define OP_SequenceTest 59 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
-#define OP_OpenPseudo 60 /* synopsis: P3 columns in r[P2] */
-#define OP_Close 61
-#define OP_ColumnsUsed 62
-#define OP_SeekLT 63 /* synopsis: key=r[P3@P4] */
-#define OP_SeekLE 64 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGE 65 /* synopsis: key=r[P3@P4] */
-#define OP_SeekGT 66 /* synopsis: key=r[P3@P4] */
-#define OP_NoConflict 67 /* synopsis: key=r[P3@P4] */
-#define OP_NotFound 68 /* synopsis: key=r[P3@P4] */
-#define OP_Found 69 /* synopsis: key=r[P3@P4] */
-#define OP_NotExists 70 /* synopsis: intkey=r[P3] */
-#define OP_Or 71 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
-#define OP_And 72 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
-#define OP_Sequence 73 /* synopsis: r[P2]=cursor[P1].ctr++ */
-#define OP_NewRowid 74 /* synopsis: r[P2]=rowid */
-#define OP_Insert 75 /* synopsis: intkey=r[P3] data=r[P2] */
-#define OP_IsNull 76 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
-#define OP_NotNull 77 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
-#define OP_Ne 78 /* same as TK_NE, synopsis: if r[P1]!=r[P3] goto P2 */
-#define OP_Eq 79 /* same as TK_EQ, synopsis: if r[P1]==r[P3] goto P2 */
-#define OP_Gt 80 /* same as TK_GT, synopsis: if r[P1]>r[P3] goto P2 */
-#define OP_Le 81 /* same as TK_LE, synopsis: if r[P1]<=r[P3] goto P2 */
-#define OP_Lt 82 /* same as TK_LT, synopsis: if r[P1]<r[P3] goto P2 */
-#define OP_Ge 83 /* same as TK_GE, synopsis: if r[P1]>=r[P3] goto P2 */
-#define OP_InsertInt 84 /* synopsis: intkey=P3 data=r[P2] */
-#define OP_BitAnd 85 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
-#define OP_BitOr 86 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
-#define OP_ShiftLeft 87 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
-#define OP_ShiftRight 88 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
-#define OP_Add 89 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
-#define OP_Subtract 90 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
-#define OP_Multiply 91 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
-#define OP_Divide 92 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
-#define OP_Remainder 93 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
-#define OP_Concat 94 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
-#define OP_Delete 95
-#define OP_BitNot 96 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
+#define OP_Once 20
+#define OP_If 21
+#define OP_IfNot 22
+#define OP_SeekLT 23 /* synopsis: key=r[P3@P4] */
+#define OP_SeekLE 24 /* synopsis: key=r[P3@P4] */
+#define OP_SeekGE 25 /* synopsis: key=r[P3@P4] */
+#define OP_SeekGT 26 /* synopsis: key=r[P3@P4] */
+#define OP_Or 27 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
+#define OP_And 28 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
+#define OP_NoConflict 29 /* synopsis: key=r[P3@P4] */
+#define OP_NotFound 30 /* synopsis: key=r[P3@P4] */
+#define OP_Found 31 /* synopsis: key=r[P3@P4] */
+#define OP_SeekRowid 32 /* synopsis: intkey=r[P3] */
+#define OP_NotExists 33 /* synopsis: intkey=r[P3] */
+#define OP_IsNull 34 /* same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
+#define OP_NotNull 35 /* same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
+#define OP_Ne 36 /* same as TK_NE, synopsis: IF r[P3]!=r[P1] */
+#define OP_Eq 37 /* same as TK_EQ, synopsis: IF r[P3]==r[P1] */
+#define OP_Gt 38 /* same as TK_GT, synopsis: IF r[P3]>r[P1] */
+#define OP_Le 39 /* same as TK_LE, synopsis: IF r[P3]<=r[P1] */
+#define OP_Lt 40 /* same as TK_LT, synopsis: IF r[P3]<r[P1] */
+#define OP_Ge 41 /* same as TK_GE, synopsis: IF r[P3]>=r[P1] */
+#define OP_ElseNotEq 42 /* same as TK_ESCAPE */
+#define OP_BitAnd 43 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
+#define OP_BitOr 44 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
+#define OP_ShiftLeft 45 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
+#define OP_ShiftRight 46 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
+#define OP_Add 47 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
+#define OP_Subtract 48 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
+#define OP_Multiply 49 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
+#define OP_Divide 50 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
+#define OP_Remainder 51 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
+#define OP_Concat 52 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
+#define OP_Last 53
+#define OP_BitNot 54 /* same as TK_BITNOT, synopsis: r[P1]= ~r[P1] */
+#define OP_SorterSort 55
+#define OP_Sort 56
+#define OP_Rewind 57
+#define OP_IdxLE 58 /* synopsis: key=r[P3@P4] */
+#define OP_IdxGT 59 /* synopsis: key=r[P3@P4] */
+#define OP_IdxLT 60 /* synopsis: key=r[P3@P4] */
+#define OP_IdxGE 61 /* synopsis: key=r[P3@P4] */
+#define OP_RowSetRead 62 /* synopsis: r[P3]=rowset(P1) */
+#define OP_RowSetTest 63 /* synopsis: if r[P3] in rowset(P1) goto P2 */
+#define OP_Program 64
+#define OP_FkIfZero 65 /* synopsis: if fkctr[P1]==0 goto P2 */
+#define OP_IfPos 66 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
+#define OP_IfNotZero 67 /* synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
+#define OP_DecrJumpZero 68 /* synopsis: if (--r[P1])==0 goto P2 */
+#define OP_IncrVacuum 69
+#define OP_VNext 70
+#define OP_Init 71 /* synopsis: Start at P2 */
+#define OP_Return 72
+#define OP_EndCoroutine 73
+#define OP_HaltIfNull 74 /* synopsis: if r[P3]=null halt */
+#define OP_Halt 75
+#define OP_Integer 76 /* synopsis: r[P2]=P1 */
+#define OP_Int64 77 /* synopsis: r[P2]=P4 */
+#define OP_String 78 /* synopsis: r[P2]='P4' (len=P1) */
+#define OP_Null 79 /* synopsis: r[P2..P3]=NULL */
+#define OP_SoftNull 80 /* synopsis: r[P1]=NULL */
+#define OP_Blob 81 /* synopsis: r[P2]=P4 (len=P1) */
+#define OP_Variable 82 /* synopsis: r[P2]=parameter(P1,P4) */
+#define OP_Move 83 /* synopsis: r[P2@P3]=r[P1@P3] */
+#define OP_Copy 84 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
+#define OP_SCopy 85 /* synopsis: r[P2]=r[P1] */
+#define OP_IntCopy 86 /* synopsis: r[P2]=r[P1] */
+#define OP_ResultRow 87 /* synopsis: output=r[P1@P2] */
+#define OP_CollSeq 88
+#define OP_Function0 89 /* synopsis: r[P3]=func(r[P2@P5]) */
+#define OP_Function 90 /* synopsis: r[P3]=func(r[P2@P5]) */
+#define OP_AddImm 91 /* synopsis: r[P1]=r[P1]+P2 */
+#define OP_RealAffinity 92
+#define OP_Cast 93 /* synopsis: affinity(r[P1]) */
+#define OP_Permutation 94
+#define OP_Compare 95 /* synopsis: r[P1@P3] <-> r[P2@P3] */
+#define OP_Column 96 /* synopsis: r[P3]=PX */
#define OP_String8 97 /* same as TK_STRING, synopsis: r[P2]='P4' */
-#define OP_ResetCount 98
-#define OP_SorterCompare 99 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
-#define OP_SorterData 100 /* synopsis: r[P2]=data */
-#define OP_RowKey 101 /* synopsis: r[P2]=key */
-#define OP_RowData 102 /* synopsis: r[P2]=data */
-#define OP_Rowid 103 /* synopsis: r[P2]=rowid */
-#define OP_NullRow 104
-#define OP_Last 105
-#define OP_SorterSort 106
-#define OP_Sort 107
-#define OP_Rewind 108
-#define OP_SorterInsert 109
-#define OP_IdxInsert 110 /* synopsis: key=r[P2] */
-#define OP_IdxDelete 111 /* synopsis: key=r[P2@P3] */
-#define OP_Seek 112 /* synopsis: Move P3 to P1.rowid */
-#define OP_IdxRowid 113 /* synopsis: r[P2]=rowid */
-#define OP_IdxLE 114 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGT 115 /* synopsis: key=r[P3@P4] */
-#define OP_IdxLT 116 /* synopsis: key=r[P3@P4] */
-#define OP_IdxGE 117 /* synopsis: key=r[P3@P4] */
-#define OP_Destroy 118
-#define OP_Clear 119
-#define OP_ResetSorter 120
-#define OP_CreateIndex 121 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_CreateTable 122 /* synopsis: r[P2]=root iDb=P1 */
-#define OP_ParseSchema 123
-#define OP_LoadAnalysis 124
-#define OP_DropTable 125
-#define OP_DropIndex 126
-#define OP_DropTrigger 127
-#define OP_IntegrityCk 128
-#define OP_RowSetAdd 129 /* synopsis: rowset(P1)=r[P2] */
-#define OP_RowSetRead 130 /* synopsis: r[P3]=rowset(P1) */
-#define OP_RowSetTest 131 /* synopsis: if r[P3] in rowset(P1) goto P2 */
-#define OP_Program 132
-#define OP_Real 133 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
-#define OP_Param 134
-#define OP_FkCounter 135 /* synopsis: fkctr[P1]+=P2 */
-#define OP_FkIfZero 136 /* synopsis: if fkctr[P1]==0 goto P2 */
-#define OP_MemMax 137 /* synopsis: r[P1]=max(r[P1],r[P2]) */
-#define OP_IfPos 138 /* synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
-#define OP_OffsetLimit 139 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
-#define OP_IfNotZero 140 /* synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2 */
-#define OP_DecrJumpZero 141 /* synopsis: if (--r[P1])==0 goto P2 */
-#define OP_JumpZeroIncr 142 /* synopsis: if (r[P1]++)==0 ) goto P2 */
-#define OP_AggStep0 143 /* synopsis: accum=r[P3] step(r[P2@P5]) */
-#define OP_AggStep 144 /* synopsis: accum=r[P3] step(r[P2@P5]) */
-#define OP_AggFinal 145 /* synopsis: accum=r[P1] N=P2 */
-#define OP_IncrVacuum 146
-#define OP_Expire 147
-#define OP_TableLock 148 /* synopsis: iDb=P1 root=P2 write=P3 */
-#define OP_VBegin 149
-#define OP_VCreate 150
-#define OP_VDestroy 151
-#define OP_VOpen 152
-#define OP_VColumn 153 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VNext 154
-#define OP_VRename 155
-#define OP_Pagecount 156
-#define OP_MaxPgcnt 157
-#define OP_Init 158 /* synopsis: Start at P2 */
+#define OP_Affinity 98 /* synopsis: affinity(r[P1@P2]) */
+#define OP_MakeRecord 99 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
+#define OP_Count 100 /* synopsis: r[P2]=count() */
+#define OP_ReadCookie 101
+#define OP_SetCookie 102
+#define OP_ReopenIdx 103 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenRead 104 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenWrite 105 /* synopsis: root=P2 iDb=P3 */
+#define OP_OpenAutoindex 106 /* synopsis: nColumn=P2 */
+#define OP_OpenEphemeral 107 /* synopsis: nColumn=P2 */
+#define OP_SorterOpen 108
+#define OP_SequenceTest 109 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
+#define OP_OpenPseudo 110 /* synopsis: P3 columns in r[P2] */
+#define OP_Close 111
+#define OP_ColumnsUsed 112
+#define OP_Sequence 113 /* synopsis: r[P2]=cursor[P1].ctr++ */
+#define OP_NewRowid 114 /* synopsis: r[P2]=rowid */
+#define OP_Insert 115 /* synopsis: intkey=r[P3] data=r[P2] */
+#define OP_InsertInt 116 /* synopsis: intkey=P3 data=r[P2] */
+#define OP_Delete 117
+#define OP_ResetCount 118
+#define OP_SorterCompare 119 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
+#define OP_SorterData 120 /* synopsis: r[P2]=data */
+#define OP_RowData 121 /* synopsis: r[P2]=data */
+#define OP_Rowid 122 /* synopsis: r[P2]=rowid */
+#define OP_NullRow 123
+#define OP_SorterInsert 124 /* synopsis: key=r[P2] */
+#define OP_IdxInsert 125 /* synopsis: key=r[P2] */
+#define OP_IdxDelete 126 /* synopsis: key=r[P2@P3] */
+#define OP_Seek 127 /* synopsis: Move P3 to P1.rowid */
+#define OP_IdxRowid 128 /* synopsis: r[P2]=rowid */
+#define OP_Destroy 129
+#define OP_Clear 130
+#define OP_ResetSorter 131
+#define OP_Real 132 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
+#define OP_CreateIndex 133 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_CreateTable 134 /* synopsis: r[P2]=root iDb=P1 */
+#define OP_ParseSchema 135
+#define OP_LoadAnalysis 136
+#define OP_DropTable 137
+#define OP_DropIndex 138
+#define OP_DropTrigger 139
+#define OP_IntegrityCk 140
+#define OP_RowSetAdd 141 /* synopsis: rowset(P1)=r[P2] */
+#define OP_Param 142
+#define OP_FkCounter 143 /* synopsis: fkctr[P1]+=P2 */
+#define OP_MemMax 144 /* synopsis: r[P1]=max(r[P1],r[P2]) */
+#define OP_OffsetLimit 145 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
+#define OP_AggStep0 146 /* synopsis: accum=r[P3] step(r[P2@P5]) */
+#define OP_AggStep 147 /* synopsis: accum=r[P3] step(r[P2@P5]) */
+#define OP_AggFinal 148 /* synopsis: accum=r[P1] N=P2 */
+#define OP_Expire 149
+#define OP_TableLock 150 /* synopsis: iDb=P1 root=P2 write=P3 */
+#define OP_VBegin 151
+#define OP_VCreate 152
+#define OP_VDestroy 153
+#define OP_VOpen 154
+#define OP_VColumn 155 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VRename 156
+#define OP_Pagecount 157
+#define OP_MaxPgcnt 158
#define OP_CursorHint 159
#define OP_Noop 160
#define OP_Explain 161
@@ -10955,27 +12811,35 @@ typedef struct VdbeOpList VdbeOpList;
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
#define OPFLG_INITIALIZER {\
/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,\
-/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x02,\
-/* 16 */ 0x01, 0x02, 0x03, 0x12, 0x08, 0x00, 0x10, 0x10,\
-/* 24 */ 0x10, 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10,\
-/* 32 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02,\
-/* 40 */ 0x02, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x00,\
-/* 48 */ 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,\
-/* 56 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,\
-/* 64 */ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x26,\
-/* 72 */ 0x26, 0x10, 0x10, 0x00, 0x03, 0x03, 0x0b, 0x0b,\
-/* 80 */ 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x26, 0x26, 0x26,\
-/* 88 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\
-/* 96 */ 0x12, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
-/* 104 */ 0x00, 0x01, 0x01, 0x01, 0x01, 0x04, 0x04, 0x00,\
-/* 112 */ 0x00, 0x10, 0x01, 0x01, 0x01, 0x01, 0x10, 0x00,\
-/* 120 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 128 */ 0x00, 0x06, 0x23, 0x0b, 0x01, 0x10, 0x10, 0x00,\
-/* 136 */ 0x01, 0x04, 0x03, 0x1a, 0x03, 0x03, 0x03, 0x00,\
-/* 144 */ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 152 */ 0x00, 0x00, 0x01, 0x00, 0x10, 0x10, 0x01, 0x00,\
+/* 8 */ 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01,\
+/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x03, 0x03, 0x09,\
+/* 24 */ 0x09, 0x09, 0x09, 0x26, 0x26, 0x09, 0x09, 0x09,\
+/* 32 */ 0x09, 0x09, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
+/* 40 */ 0x0b, 0x0b, 0x01, 0x26, 0x26, 0x26, 0x26, 0x26,\
+/* 48 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x01, 0x12, 0x01,\
+/* 56 */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x23, 0x0b,\
+/* 64 */ 0x01, 0x01, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01,\
+/* 72 */ 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10, 0x10,\
+/* 80 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,\
+/* 88 */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,\
+/* 96 */ 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
+/* 104 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 112 */ 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 120 */ 0x00, 0x00, 0x10, 0x00, 0x04, 0x04, 0x00, 0x00,\
+/* 128 */ 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00,\
+/* 136 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x10, 0x00,\
+/* 144 */ 0x04, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
+/* 152 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,\
/* 160 */ 0x00, 0x00,}
+/* The sqlite3P2Values() routine is able to run faster if it knows
+** the value of the largest JUMP opcode. The smaller the maximum
+** JUMP opcode the better, so the mkopcodeh.tcl script that
+** generated this include file strives to group all JUMP opcodes
+** together near the beginning of the list.
+*/
+#define SQLITE_MX_JUMP_OPCODE 71 /* Maximum JUMP opcode */
+
/************** End of opcodes.h *********************************************/
/************** Continuing where we left off in vdbe.h ***********************/
@@ -11011,11 +12875,13 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N);
+SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
+SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*);
@@ -11045,7 +12911,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(int, const void *, UnpackedRecord *, int);
-SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
+SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo*);
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*);
SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
@@ -11120,7 +12986,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch
# define sqlite3VdbeScanStatus(a,b,c,d,e)
#endif
-#endif
+#endif /* SQLITE_VDBE_H */
/************** End of vdbe.h ************************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -11142,8 +13008,8 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const ch
** at a time and provides a journal for rollback.
*/
-#ifndef _PAGER_H_
-#define _PAGER_H_
+#ifndef SQLITE_PAGER_H
+#define SQLITE_PAGER_H
/*
** Default maximum size for persistent journal files. A negative
@@ -11196,7 +13062,11 @@ typedef struct PgHdr DbPage;
#define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
-** Numeric constants that encode the journalmode.
+** Numeric constants that encode the journalmode.
+**
+** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
+** are exposed in the API via the "PRAGMA journal_mode" command and
+** therefore cannot be changed without a compatibility break.
*/
#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
@@ -11214,6 +13084,11 @@ typedef struct PgHdr DbPage;
/*
** Flags for sqlite3PagerSetFlags()
+**
+** Value constraints (enforced via assert()):
+** PAGER_FULLFSYNC == SQLITE_FullFSync
+** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
+** PAGER_CACHE_SPILL == SQLITE_CacheSpill
*/
#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
@@ -11241,7 +13116,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int,
void(*)(DbPage*)
);
-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
/* Functions used to configure a Pager object. */
@@ -11292,15 +13167,19 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
#ifndef SQLITE_OMIT_WAL
-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager);
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
+SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager);
# ifdef SQLITE_ENABLE_SNAPSHOT
SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
+SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
# endif
+#else
+# define sqlite3PagerUseWal(x) 0
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
@@ -11319,11 +13198,10 @@ SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
-SQLITE_PRIVATE int sqlite3PagerNosync(Pager*);
SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
-SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *);
+SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
/* Functions used to truncate the database file. */
@@ -11350,7 +13228,7 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
# define enable_simulated_io_errors()
#endif
-#endif /* _PAGER_H_ */
+#endif /* SQLITE_PAGER_H */
/************** End of pager.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
@@ -11384,7 +13262,7 @@ struct PgHdr {
sqlite3_pcache_page *pPage; /* Pcache object page handle */
void *pData; /* Page data */
void *pExtra; /* Extra content */
- PgHdr *pDirty; /* Transient list of dirty pages */
+ PgHdr *pDirty; /* Transient list of dirty sorted by pgno */
Pager *pPager; /* The pager this page is part of */
Pgno pgno; /* Page number for this page */
#ifdef SQLITE_CHECK_PAGES
@@ -11409,11 +13287,10 @@ struct PgHdr {
#define PGHDR_WRITEABLE 0x004 /* Journaled and ready to modify */
#define PGHDR_NEED_SYNC 0x008 /* Fsync the rollback journal before
** writing this page to the database */
-#define PGHDR_NEED_READ 0x010 /* Content is unread */
-#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
-#define PGHDR_MMAP 0x040 /* This is an mmap page object */
+#define PGHDR_DONT_WRITE 0x010 /* Do not write content to disk */
+#define PGHDR_MMAP 0x020 /* This is an mmap page object */
-#define PGHDR_WAL_APPEND 0x080 /* Appended to wal file */
+#define PGHDR_WAL_APPEND 0x040 /* Appended to wal file */
/* Initialize and shutdown the page cache subsystem */
SQLITE_PRIVATE int sqlite3PcacheInitialize(void);
@@ -11457,6 +13334,7 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache
SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */
SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */
SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */
+SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache*);
/* Change a page number. Used by incr-vacuum. */
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr*, Pgno);
@@ -11495,6 +13373,11 @@ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
#endif
+#if defined(SQLITE_DEBUG)
+/* Check invariants on a PgHdr object */
+SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr*);
+#endif
+
/* Set and get the suggested cache-size for the specified pager-cache.
**
** If no global maximum is configured, then the system attempts to limit
@@ -11531,11 +13414,13 @@ SQLITE_PRIVATE void sqlite3PCacheSetDefault(void);
SQLITE_PRIVATE int sqlite3HeaderSizePcache(void);
SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
+/* Number of dirty pages as a percentage of the configured cache size */
+SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache*);
+
#endif /* _PCACHE_H_ */
/************** End of pcache.h **********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
-
/************** Include os.h in the middle of sqliteInt.h ********************/
/************** Begin file os.h **********************************************/
/*
@@ -11581,8 +13466,8 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
** This file contains pre-processor directives related to operating system
** detection and/or setup.
*/
-#ifndef _OS_SETUP_H_
-#define _OS_SETUP_H_
+#ifndef SQLITE_OS_SETUP_H
+#define SQLITE_OS_SETUP_H
/*
** Figure out if we are dealing with Unix, Windows, or some other operating
@@ -11622,7 +13507,7 @@ SQLITE_PRIVATE int sqlite3HeaderSizePcache1(void);
# endif
#endif
-#endif /* _OS_SETUP_H_ */
+#endif /* SQLITE_OS_SETUP_H */
/************** End of os_setup.h ********************************************/
/************** Continuing where we left off in os.h *************************/
@@ -11761,7 +13646,7 @@ SQLITE_PRIVATE int sqlite3OsInit(void);
/*
** Functions for accessing sqlite3_file methods
*/
-SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file*);
+SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
@@ -11798,6 +13683,7 @@ SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
+SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
/*
@@ -11805,7 +13691,7 @@ SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
** sqlite3_malloc() to obtain space for the file-handle structure.
*/
SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
-SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
+SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
#endif /* _SQLITE_OS_H_ */
@@ -11887,6 +13773,36 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
/************** End of mutex.h ***********************************************/
/************** Continuing where we left off in sqliteInt.h ******************/
+/* The SQLITE_EXTRA_DURABLE compile-time option used to set the default
+** synchronous setting to EXTRA. It is no longer supported.
+*/
+#ifdef SQLITE_EXTRA_DURABLE
+# warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE
+# define SQLITE_DEFAULT_SYNCHRONOUS 3
+#endif
+
+/*
+** Default synchronous levels.
+**
+** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ
+** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1.
+**
+** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS
+** OFF 1 0
+** NORMAL 2 1
+** FULL 3 2
+** EXTRA 4 3
+**
+** The "PRAGMA synchronous" statement also uses the zero-based numbers.
+** In other words, the zero-based numbers are used for all external interfaces
+** and the one-based values are used internally.
+*/
+#ifndef SQLITE_DEFAULT_SYNCHRONOUS
+# define SQLITE_DEFAULT_SYNCHRONOUS (PAGER_SYNCHRONOUS_FULL-1)
+#endif
+#ifndef SQLITE_DEFAULT_WAL_SYNCHRONOUS
+# define SQLITE_DEFAULT_WAL_SYNCHRONOUS SQLITE_DEFAULT_SYNCHRONOUS
+#endif
/*
** Each database file to be accessed by the system is an instance
@@ -11896,9 +13812,10 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *);
** databases may be attached.
*/
struct Db {
- char *zName; /* Name of this database */
+ char *zDbSName; /* Name of this database. (schema name, not filename) */
Btree *pBt; /* The B*Tree structure for this database file */
u8 safety_level; /* How aggressive at syncing data to disk */
+ u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */
Schema *pSchema; /* Pointer to database schema (possibly shared) */
};
@@ -11909,7 +13826,7 @@ struct Db {
** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
** In shared cache mode, a single Schema object can be shared by multiple
** Btrees that refer to the same underlying BtShared object.
-**
+**
** Schema objects are automatically deallocated when the last Btree that
** references them is destroyed. The TEMP Schema is manually freed by
** sqlite3_close().
@@ -11934,7 +13851,7 @@ struct Schema {
};
/*
-** These macros can be used to test, set, or clear bits in the
+** These macros can be used to test, set, or clear bits in the
** Db.pSchema->flags field.
*/
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P))
@@ -11998,13 +13915,15 @@ struct LookasideSlot {
};
/*
-** A hash table for function definitions.
+** A hash table for built-in function definitions. (Application-defined
+** functions use a regular table table from hash.h.)
**
** Hash each FuncDef structure into one of the FuncDefHash.a[] slots.
-** Collisions are on the FuncDef.pHash chain.
+** Collisions are on the FuncDef.u.pHash chain.
*/
+#define SQLITE_FUNC_HASH_SZ 23
struct FuncDefHash {
- FuncDef *a[23]; /* Hash table for functions */
+ FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */
};
#ifdef SQLITE_USER_AUTHENTICATION
@@ -12045,6 +13964,15 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
const char*);
#endif
+#ifndef SQLITE_OMIT_DEPRECATED
+/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
+** in the style of sqlite3_trace()
+*/
+#define SQLITE_TRACE_LEGACY 0x80
+#else
+#define SQLITE_TRACE_LEGACY 0
+#endif /* SQLITE_OMIT_DEPRECATED */
+
/*
** Each database connection is an instance of the following structure.
@@ -12062,6 +13990,7 @@ struct sqlite3 {
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */
+ int iSysErrno; /* Errno value from last system error */
u16 dbOptFlags; /* Flags to enable/disable optimizations */
u8 enc; /* Text encoding */
u8 autoCommit; /* The auto-commit flag. */
@@ -12073,6 +14002,7 @@ struct sqlite3 {
u8 suppressErr; /* Do not issue error messages if true */
u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
+ u8 mTrace; /* zero or more SQLITE_TRACE flags */
int nextPagesize; /* Pagesize after VACUUM if >0 */
u32 magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
@@ -12093,16 +14023,23 @@ struct sqlite3 {
int nVDestroy; /* Number of active OP_VDestroy operations */
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
- void (*xTrace)(void*,const char*); /* Trace function */
+ int (*xTrace)(u32,void*,void*,void*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */
void (*xProfile)(void*,const char*,u64); /* Profiling function */
void *pProfileArg; /* Argument to profile function */
- void *pCommitArg; /* Argument to xCommitCallback() */
+ void *pCommitArg; /* Argument to xCommitCallback() */
int (*xCommitCallback)(void*); /* Invoked at every commit. */
- void *pRollbackArg; /* Argument to xRollbackCallback() */
+ void *pRollbackArg; /* Argument to xRollbackCallback() */
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
void *pUpdateArg;
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ void *pPreUpdateArg; /* First argument to xPreUpdateCallback */
+ void (*xPreUpdateCallback)( /* Registered using sqlite3_preupdate_hook() */
+ void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64
+ );
+ PreUpdate *pPreUpdate; /* Context for active pre-update callback */
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
#ifndef SQLITE_OMIT_WAL
int (*xWalCallback)(void *, sqlite3 *, const char *, int);
void *pWalArg;
@@ -12132,7 +14069,7 @@ struct sqlite3 {
VTable **aVTrans; /* Virtual tables with open transactions */
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
#endif
- FuncDefHash aFunc; /* Hash table of connection functions */
+ Hash aFunc; /* Hash table of connection functions */
Hash aCollSeq; /* All collating sequences */
BusyHandler busyHandler; /* Busy callback */
Db aDbStatic[2]; /* Static space for the 2 default backends */
@@ -12144,8 +14081,8 @@ struct sqlite3 {
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
- /* The following variables are all protected by the STATIC_MASTER
- ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
+ /* The following variables are all protected by the STATIC_MASTER
+ ** mutex, not by sqlite3.mutex. They are used by code in notify.c.
**
** When X.pUnlockConnection==Y, that means that X is waiting for Y to
** unlock so that it can proceed.
@@ -12173,6 +14110,11 @@ struct sqlite3 {
/*
** Possible values for the sqlite3.flags.
+**
+** Value constraints (enforced via assert()):
+** SQLITE_FullFSync == PAGER_FULLFSYNC
+** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
+** SQLITE_CacheSpill == PAGER_CACHE_SPILL
*/
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */
@@ -12200,12 +14142,15 @@ struct sqlite3 {
#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */
#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */
#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */
-#define SQLITE_EnableTrigger 0x00800000 /* True to enable triggers */
-#define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */
-#define SQLITE_QueryOnly 0x02000000 /* Disable database changes */
-#define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */
-#define SQLITE_Vacuum 0x08000000 /* Currently in a VACUUM */
-#define SQLITE_CellSizeCk 0x10000000 /* Check btree cell sizes on load */
+#define SQLITE_LoadExtFunc 0x00800000 /* Enable load_extension() SQL func */
+#define SQLITE_EnableTrigger 0x01000000 /* True to enable triggers */
+#define SQLITE_DeferFKs 0x02000000 /* Defer all FK constraints */
+#define SQLITE_QueryOnly 0x04000000 /* Disable database changes */
+#define SQLITE_VdbeEQP 0x08000000 /* Debug EXPLAIN QUERY PLAN */
+#define SQLITE_Vacuum 0x10000000 /* Currently in a VACUUM */
+#define SQLITE_CellSizeCk 0x20000000 /* Check btree cell sizes on load */
+#define SQLITE_Fts3Tokenizer 0x40000000 /* Enable fts3_tokenizer(2) */
+#define SQLITE_NoCkptOnClose 0x80000000 /* No checkpoint on close()/DETACH */
/*
@@ -12231,13 +14176,8 @@ struct sqlite3 {
/*
** Macros for testing whether or not optimizations are enabled or disabled.
*/
-#ifndef SQLITE_OMIT_BUILTIN_TEST
#define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0)
#define OptimizationEnabled(db, mask) (((db)->dbOptFlags&(mask))==0)
-#else
-#define OptimizationDisabled(db, mask) 0
-#define OptimizationEnabled(db, mask) 1
-#endif
/*
** Return true if it OK to factor constant expressions into the initialization
@@ -12259,27 +14199,33 @@ struct sqlite3 {
/*
** Each SQL function is defined by an instance of the following
-** structure. A pointer to this structure is stored in the sqlite.aFunc
-** hash table. When multiple functions have the same name, the hash table
-** points to a linked list of these structures.
+** structure. For global built-in functions (ex: substr(), max(), count())
+** a pointer to this structure is held in the sqlite3BuiltinFunctions object.
+** For per-connection application-defined functions, a pointer to this
+** structure is held in the db->aHash hash table.
+**
+** The u.pHash field is used by the global built-ins. The u.pDestructor
+** field is used by per-connection app-def functions.
*/
struct FuncDef {
- i16 nArg; /* Number of arguments. -1 means unlimited */
+ i8 nArg; /* Number of arguments. -1 means unlimited */
u16 funcFlags; /* Some combination of SQLITE_FUNC_* */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
void (*xSFunc)(sqlite3_context*,int,sqlite3_value**); /* func or agg-step */
void (*xFinalize)(sqlite3_context*); /* Agg finalizer */
- char *zName; /* SQL name of the function. */
- FuncDef *pHash; /* Next with a different name but the same hash */
- FuncDestructor *pDestructor; /* Reference counted destructor function */
+ const char *zName; /* SQL name of the function. */
+ union {
+ FuncDef *pHash; /* Next with a different name but the same hash */
+ FuncDestructor *pDestructor; /* Reference counted destructor function */
+ } u;
};
/*
** This structure encapsulates a user-function destructor callback (as
** configured using create_function_v2()) and a reference counter. When
** create_function_v2() is called to create a function with a destructor,
-** a single object of this type is allocated. FuncDestructor.nRef is set to
+** a single object of this type is allocated. FuncDestructor.nRef is set to
** the number of FuncDef objects created (either 1 or 3, depending on whether
** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor
** member of each of the new FuncDef objects is set to point to the allocated
@@ -12300,6 +14246,13 @@ struct FuncDestructor {
** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. And
** SQLITE_FUNC_CONSTANT must be the same as SQLITE_DETERMINISTIC. There
** are assert() statements in the code to verify this.
+**
+** Value constraints (enforced via assert()):
+** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg
+** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
+** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
+** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
+** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API
*/
#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
#define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */
@@ -12321,10 +14274,10 @@ struct FuncDestructor {
** used to create the initializers for the FuncDef structures.
**
** FUNCTION(zName, nArg, iArg, bNC, xFunc)
-** Used to create a scalar function definition of a function zName
+** Used to create a scalar function definition of a function zName
** implemented by C function xFunc that accepts nArg arguments. The
** value passed as iArg is cast to a (void*) and made available
-** as the user-data (sqlite3_user_data()) for the function. If
+** as the user-data (sqlite3_user_data()) for the function. If
** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
**
** VFUNCTION(zName, nArg, iArg, bNC, xFunc)
@@ -12343,8 +14296,8 @@ struct FuncDestructor {
** FUNCTION().
**
** LIKEFUNC(zName, nArg, pArg, flags)
-** Used to create a scalar function definition of a function zName
-** that accepts nArg arguments and is implemented by a call to C
+** Used to create a scalar function definition of a function zName
+** that accepts nArg arguments and is implemented by a call to C
** function likeFunc. Argument pArg is cast to a (void *) and made
** available as the function user-data (sqlite3_user_data()). The
** FuncDef.flags variable is set to the value passed as the flags
@@ -12352,28 +14305,28 @@ struct FuncDestructor {
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
{nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, 0, 0}
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, #zName, {0} }
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
{nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
- pArg, 0, xFunc, 0, #zName, 0, 0}
+ pArg, 0, xFunc, 0, #zName, }
#define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
- (void *)arg, 0, likeFunc, 0, #zName, 0, 0}
+ (void *)arg, 0, likeFunc, 0, #zName, {0} }
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
- SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0}
+ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
- SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName,0,0}
+ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,#zName, {0}}
/*
** All current savepoints are stored in a linked list starting at
@@ -12415,10 +14368,8 @@ struct Module {
** of this structure.
*/
struct Column {
- char *zName; /* Name of this column */
+ char *zName; /* Name of this column, \000, then the type */
Expr *pDflt; /* Default value of this column */
- char *zDflt; /* Original text of the default value */
- char *zType; /* Data type for this column */
char *zColl; /* Collating sequence. If NULL, use the default */
u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
char affinity; /* One of the SQLITE_AFF_... values */
@@ -12430,6 +14381,7 @@ struct Column {
*/
#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
+#define COLFLAG_HASTYPE 0x0004 /* Type name follows column name */
/*
** A "Collating Sequence" is defined by an instance of the following
@@ -12460,7 +14412,7 @@ struct CollSeq {
**
** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and
** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve
-** the speed a little by numbering the values consecutively.
+** the speed a little by numbering the values consecutively.
**
** But rather than start with 0 or 1, we begin with 'A'. That way,
** when multiple affinity types are concatenated into a string and
@@ -12479,7 +14431,7 @@ struct CollSeq {
/*
** The SQLITE_AFF_MASK values masks off the significant bits of an
-** affinity value.
+** affinity value.
*/
#define SQLITE_AFF_MASK 0x47
@@ -12492,6 +14444,7 @@ struct CollSeq {
** operator is NULL. It is added to certain comparison operators to
** prove that the operands are always NOT NULL.
*/
+#define SQLITE_KEEPNULL 0x08 /* Used by vector == or <> */
#define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */
#define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */
#define SQLITE_NULLEQ 0x80 /* NULL=NULL */
@@ -12499,20 +14452,20 @@ struct CollSeq {
/*
** An object of this type is created for each virtual table present in
-** the database schema.
+** the database schema.
**
** If the database schema is shared, then there is one instance of this
** structure for each database connection (sqlite3*) that uses the shared
** schema. This is because each database connection requires its own unique
-** instance of the sqlite3_vtab* handle used to access the virtual table
-** implementation. sqlite3_vtab* handles can not be shared between
-** database connections, even when the rest of the in-memory database
+** instance of the sqlite3_vtab* handle used to access the virtual table
+** implementation. sqlite3_vtab* handles can not be shared between
+** database connections, even when the rest of the in-memory database
** schema is shared, as the implementation often stores the database
** connection handle passed to it via the xConnect() or xCreate() method
** during initialization internally. This database connection handle may
-** then be used by the virtual table implementation to access real tables
-** within the database. So that they appear as part of the callers
-** transaction, these accesses need to be made via the same database
+** then be used by the virtual table implementation to access real tables
+** within the database. So that they appear as part of the callers
+** transaction, these accesses need to be made via the same database
** connection as that used to execute SQL operations on the virtual table.
**
** All VTable objects that correspond to a single table in a shared
@@ -12524,19 +14477,19 @@ struct CollSeq {
** sqlite3_vtab* handle in the compiled query.
**
** When an in-memory Table object is deleted (for example when the
-** schema is being reloaded for some reason), the VTable objects are not
-** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
+** schema is being reloaded for some reason), the VTable objects are not
+** deleted and the sqlite3_vtab* handles are not xDisconnect()ed
** immediately. Instead, they are moved from the Table.pVTable list to
** another linked list headed by the sqlite3.pDisconnect member of the
-** corresponding sqlite3 structure. They are then deleted/xDisconnected
+** corresponding sqlite3 structure. They are then deleted/xDisconnected
** next time a statement is prepared using said sqlite3*. This is done
** to avoid deadlock issues involving multiple sqlite3.mutex mutexes.
** Refer to comments above function sqlite3VtabUnlockList() for an
** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect
** list without holding the corresponding sqlite3.mutex mutex.
**
-** The memory for objects of this type is always allocated by
-** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
+** The memory for objects of this type is always allocated by
+** sqlite3DbMalloc(), using the connection handle stored in VTable.db as
** the first argument.
*/
struct VTable {
@@ -12563,9 +14516,9 @@ struct Table {
ExprList *pCheck; /* All CHECK constraints */
/* ... also used as column name list in a VIEW */
int tnum; /* Root BTree page for this table */
+ u32 nTabRef; /* Number of pointers to this Table */
i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
i16 nCol; /* Number of columns in this table */
- u16 nRef; /* Number of pointers to this Table */
LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
LogEst szTabRow; /* Estimated size of each table row in bytes */
#ifdef SQLITE_ENABLE_COSTMULT
@@ -12704,7 +14657,7 @@ struct FKey {
** key is set to NULL. CASCADE means that a DELETE or UPDATE of the
** referenced table row is propagated into the row that holds the
** foreign key.
-**
+**
** The following symbolic values are used to record which type
** of action to take.
*/
@@ -12725,7 +14678,7 @@ struct FKey {
/*
** An instance of the following structure is passed as the first
-** argument to sqlite3VdbeKeyCompare and is used to control the
+** argument to sqlite3VdbeKeyCompare and is used to control the
** comparison of the two index keys.
**
** Note that aSortOrder[] and aColl[] have nField+1 slots. There
@@ -12766,7 +14719,7 @@ struct KeyInfo {
** The key comparison functions actually return default_rc when they find
** an equals comparison. default_rc can be -1, 0, or +1. If there are
** multiple entries in the b-tree with the same key (when only looking
-** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to
+** at the first pKeyInfo->nFields,) then default_rc can be set to -1 to
** cause the search to find the last match, or +1 to cause the search to
** find the first match.
**
@@ -12803,7 +14756,7 @@ struct UnpackedRecord {
** In the Table structure describing Ex1, nCol==3 because there are
** three columns in the table. In the Index structure describing
** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed.
-** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the
+** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the
** first column to be indexed (c3) has an index of 2 in Ex1.aCol[].
** The second column to be indexed (c1) has an index of 0 in
** Ex1.aCol[], hence Ex2.aiColumn[1]==0.
@@ -12811,7 +14764,7 @@ struct UnpackedRecord {
** The Index.onError field determines whether or not the indexed columns
** must be unique and what to do if they are not. When Index.onError=OE_None,
** it means this is not a unique index. Otherwise it is a unique index
-** and the value of Index.onError indicate the which conflict resolution
+** and the value of Index.onError indicate the which conflict resolution
** algorithm to employ whenever an attempt is made to insert a non-unique
** element.
**
@@ -12876,7 +14829,7 @@ struct Index {
#define XN_EXPR (-2) /* Indexed column is an expression */
/*
-** Each sample stored in the sqlite_stat3 table is represented in memory
+** Each sample stored in the sqlite_stat3 table is represented in memory
** using a structure of this type. See documentation at the top of the
** analyze.c source file for additional information.
*/
@@ -12971,9 +14924,9 @@ typedef int ynVar;
** to represent the greater-than-or-equal-to operator in the expression
** tree.
**
-** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
+** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
** or TK_STRING), then Expr.token contains the text of the SQL literal. If
-** the expression is a variable (TK_VARIABLE), then Expr.token contains the
+** the expression is a variable (TK_VARIABLE), then Expr.token contains the
** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
** then Expr.token contains the name of the function.
**
@@ -12984,7 +14937,7 @@ typedef int ynVar;
** a CASE expression or an IN expression of the form "<lhs> IN (<y>, <z>...)".
** Expr.x.pSelect is used if the expression is a sub-select or an expression of
** the form "<lhs> IN (SELECT ...)". If the EP_xIsSelect bit is set in the
-** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
+** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is
** valid.
**
** An expression of the form ID or ID.ID refers to a column in a table.
@@ -12995,8 +14948,8 @@ typedef int ynVar;
** value is also stored in the Expr.iAgg column in the aggregate so that
** it can be accessed after all aggregates are computed.
**
-** If the expression is an unbound variable marker (a question mark
-** character '?' in the original SQL) then the Expr.iTable holds the index
+** If the expression is an unbound variable marker (a question mark
+** character '?' in the original SQL) then the Expr.iTable holds the index
** number for that variable.
**
** If the expression is a subquery then Expr.iColumn holds an integer
@@ -13035,7 +14988,7 @@ struct Expr {
/* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
** space is allocated for the fields below this point. An attempt to
- ** access them will result in a segfault or malfunction.
+ ** access them will result in a segfault or malfunction.
*********************************************************************/
Expr *pLeft; /* Left subnode */
@@ -13056,9 +15009,11 @@ struct Expr {
int iTable; /* TK_COLUMN: cursor number of table holding column
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old
- ** EP_Unlikely: 134217728 times likelihood */
+ ** EP_Unlikely: 134217728 times likelihood
+ ** TK_SELECT: 1st register of result vector */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
- ** TK_VARIABLE: variable number (always >= 1). */
+ ** TK_VARIABLE: variable number (always >= 1).
+ ** TK_SELECT_COLUMN: column of the result vector */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
u8 op2; /* TK_REGISTER: original value of Expr.op
@@ -13094,6 +15049,7 @@ struct Expr {
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
#define EP_Alias 0x400000 /* Is an alias for a result set column */
+#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
/*
** Combinations of two or more EP_* flags
@@ -13101,7 +15057,7 @@ struct Expr {
#define EP_Propagate (EP_Collate|EP_Subquery) /* Propagate these bits up tree */
/*
-** These macros can be used to test, set, or clear bits in the
+** These macros can be used to test, set, or clear bits in the
** Expr.flags field.
*/
#define ExprHasProperty(E,P) (((E)->flags&(P))!=0)
@@ -13120,8 +15076,8 @@ struct Expr {
#endif
/*
-** Macros to determine the number of bytes required by a normal Expr
-** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
+** Macros to determine the number of bytes required by a normal Expr
+** struct, an Expr struct with the EP_Reduced flag set in Expr.flags
** and an Expr struct with the EP_TokenOnly flag set.
*/
#define EXPR_FULLSIZE sizeof(Expr) /* Full size */
@@ -13129,7 +15085,7 @@ struct Expr {
#define EXPR_TOKENONLYSIZE offsetof(Expr,pLeft) /* Fewer features */
/*
-** Flags passed to the sqlite3ExprDup() function. See the header comment
+** Flags passed to the sqlite3ExprDup() function. See the header comment
** above sqlite3ExprDup() for details.
*/
#define EXPRDUP_REDUCE 0x0001 /* Used reduced-size Expr nodes */
@@ -13211,7 +15167,11 @@ struct IdList {
** tables in a join to 32 instead of 64. But it also reduces the size
** of the library by 738 bytes on ix86.
*/
-typedef u64 Bitmask;
+#ifdef SQLITE_BITMASK_TYPE
+ typedef SQLITE_BITMASK_TYPE Bitmask;
+#else
+ typedef u64 Bitmask;
+#endif
/*
** The number of bits in a Bitmask. "BMS" means "BitMask Size".
@@ -13223,6 +15183,7 @@ typedef u64 Bitmask;
*/
#define MASKBIT(n) (((Bitmask)1)<<(n))
#define MASKBIT32(n) (((unsigned int)1)<<(n))
+#define ALLBITS ((Bitmask)-1)
/*
** The following structure describes the FROM clause of a SELECT statement.
@@ -13257,7 +15218,7 @@ struct SrcList {
int regReturn; /* Register holding return address of addrFillSub */
int regResult; /* Registers holding results of a co-routine */
struct {
- u8 jointype; /* Type of join between this able and the previous */
+ u8 jointype; /* Type of join between this table and the previous */
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
unsigned isTabFunc :1; /* True if table-valued-function syntax */
@@ -13295,22 +15256,28 @@ struct SrcList {
/*
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()
** and the WhereInfo.wctrlFlags member.
+**
+** Value constraints (enforced via assert()):
+** WHERE_USE_LIMIT == SF_FixedLimit
*/
#define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */
#define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */
#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */
#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */
-#define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */
-#define WHERE_OMIT_OPEN_CLOSE 0x0010 /* Table cursors are already open */
-#define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */
-#define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */
-#define WHERE_NO_AUTOINDEX 0x0080 /* Disallow automatic indexes */
-#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */
-#define WHERE_DISTINCTBY 0x0200 /* pOrderby is really a DISTINCT clause */
-#define WHERE_WANT_DISTINCT 0x0400 /* All output needs to be distinct */
-#define WHERE_SORTBYGROUP 0x0800 /* Support sqlite3WhereIsSorted() */
-#define WHERE_REOPEN_IDX 0x1000 /* Try to use OP_ReopenIdx */
-#define WHERE_ONEPASS_MULTIROW 0x2000 /* ONEPASS is ok with multiple rows */
+#define WHERE_ONEPASS_MULTIROW 0x0008 /* ONEPASS is ok with multiple rows */
+#define WHERE_DUPLICATES_OK 0x0010 /* Ok to return a row more than once */
+#define WHERE_OR_SUBCLAUSE 0x0020 /* Processing a sub-WHERE as part of
+ ** the OR optimization */
+#define WHERE_GROUPBY 0x0040 /* pOrderBy is really a GROUP BY */
+#define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */
+#define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */
+#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */
+#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */
+#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
+ /* 0x1000 not currently used */
+ /* 0x2000 not currently used */
+#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
+ /* 0x8000 not currently used */
/* Allowed return values from sqlite3WhereIsDistinct()
*/
@@ -13328,12 +15295,12 @@ struct SrcList {
** pEList corresponds to the result set of a SELECT and is NULL for
** other statements.
**
-** NameContexts can be nested. When resolving names, the inner-most
+** NameContexts can be nested. When resolving names, the inner-most
** context is searched first. If no match is found, the next outer
** context is checked. If there is still no match, the next context
** is checked. This process continues until either a match is found
** or all contexts are check. When a match is found, the nRef member of
-** the context containing the match is incremented.
+** the context containing the match is incremented.
**
** Each subquery gets a new NameContext. The pNext field points to the
** NameContext in the parent query. Thus the process of scanning the
@@ -13354,16 +15321,18 @@ struct NameContext {
/*
** Allowed values for the NameContext, ncFlags field.
**
-** Note: NC_MinMaxAgg must have the same value as SF_MinMaxAgg and
-** SQLITE_FUNC_MINMAX.
-**
+** Value constraints (all checked via assert()):
+** NC_HasAgg == SF_HasAgg
+** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX
+**
*/
#define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */
-#define NC_HasAgg 0x0002 /* One or more aggregate functions seen */
+#define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */
#define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */
-#define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */
+#define NC_HasAgg 0x0010 /* One or more aggregate functions seen */
#define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */
+#define NC_VarSelect 0x0040 /* A correlated subquery has been seen */
#define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */
/*
@@ -13389,13 +15358,13 @@ struct NameContext {
struct Select {
ExprList *pEList; /* The fields of the result */
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
- u16 selFlags; /* Various SF_* values */
+ LogEst nSelectRow; /* Estimated number of result rows */
+ u32 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
#if SELECTTRACE_ENABLED
char zSelName[12]; /* Symbolic name of this SELECT use for debugging */
#endif
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
- u64 nSelectRow; /* Estimated number of result rows */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
@@ -13411,23 +15380,30 @@ struct Select {
/*
** Allowed values for Select.selFlags. The "SF" prefix stands for
** "Select Flag".
-*/
-#define SF_Distinct 0x0001 /* Output should be DISTINCT */
-#define SF_All 0x0002 /* Includes the ALL keyword */
-#define SF_Resolved 0x0004 /* Identifiers have been resolved */
-#define SF_Aggregate 0x0008 /* Contains aggregate functions */
-#define SF_UsesEphemeral 0x0010 /* Uses the OpenEphemeral opcode */
-#define SF_Expanded 0x0020 /* sqlite3SelectExpand() called on this */
-#define SF_HasTypeInfo 0x0040 /* FROM subqueries have Table metadata */
-#define SF_Compound 0x0080 /* Part of a compound query */
-#define SF_Values 0x0100 /* Synthesized from VALUES clause */
-#define SF_MultiValue 0x0200 /* Single VALUES term with multiple rows */
-#define SF_NestedFrom 0x0400 /* Part of a parenthesized FROM clause */
-#define SF_MaybeConvert 0x0800 /* Need convertCompoundSelectToSubquery() */
-#define SF_MinMaxAgg 0x1000 /* Aggregate containing min() or max() */
-#define SF_Recursive 0x2000 /* The recursive part of a recursive CTE */
-#define SF_Converted 0x4000 /* By convertCompoundSelectToSubquery() */
-#define SF_IncludeHidden 0x8000 /* Include hidden columns in output */
+**
+** Value constraints (all checked via assert())
+** SF_HasAgg == NC_HasAgg
+** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX
+** SF_FixedLimit == WHERE_USE_LIMIT
+*/
+#define SF_Distinct 0x00001 /* Output should be DISTINCT */
+#define SF_All 0x00002 /* Includes the ALL keyword */
+#define SF_Resolved 0x00004 /* Identifiers have been resolved */
+#define SF_Aggregate 0x00008 /* Contains agg functions or a GROUP BY */
+#define SF_HasAgg 0x00010 /* Contains aggregate functions */
+#define SF_UsesEphemeral 0x00020 /* Uses the OpenEphemeral opcode */
+#define SF_Expanded 0x00040 /* sqlite3SelectExpand() called on this */
+#define SF_HasTypeInfo 0x00080 /* FROM subqueries have Table metadata */
+#define SF_Compound 0x00100 /* Part of a compound query */
+#define SF_Values 0x00200 /* Synthesized from VALUES clause */
+#define SF_MultiValue 0x00400 /* Single VALUES term with multiple rows */
+#define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */
+#define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */
+#define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */
+#define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */
+#define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */
+#define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */
+#define SF_IncludeHidden 0x20000 /* Include hidden columns in output */
/*
@@ -13435,7 +15411,7 @@ struct Select {
** by one of the following macros. The "SRT" prefix means "SELECT Result
** Type".
**
-** SRT_Union Store results as a key in a temporary index
+** SRT_Union Store results as a key in a temporary index
** identified by pDest->iSDParm.
**
** SRT_Except Remove results from the temporary index pDest->iSDParm.
@@ -13459,7 +15435,7 @@ struct Select {
** of the query. This destination implies "LIMIT 1".
**
** SRT_Set The result must be a single column. Store each
-** row of result as the key in table pDest->iSDParm.
+** row of result as the key in table pDest->iSDParm.
** Apply the affinity pDest->affSdst before storing
** results. Used to implement "IN (SELECT ...)".
**
@@ -13519,7 +15495,7 @@ struct Select {
*/
struct SelectDest {
u8 eDest; /* How to dispose of the results. On of SRT_* above. */
- char affSdst; /* Affinity used when eDest==SRT_Set */
+ char *zAffSdst; /* Affinity used when eDest==SRT_Set */
int iSDParm; /* A parameter used by the eDest disposal method */
int iSdst; /* Base register where results are written */
int nSdst; /* Number of registers allocated */
@@ -13527,7 +15503,7 @@ struct SelectDest {
};
/*
-** During code generation of statements that do inserts into AUTOINCREMENT
+** During code generation of statements that do inserts into AUTOINCREMENT
** tables, the following information is attached to the Table.u.autoInc.p
** pointer of each autoincrement table to record some side information that
** the code generator needs. We have to keep per-table autoincrement
@@ -13550,7 +15526,7 @@ struct AutoincInfo {
#endif
/*
-** At least one instance of the following structure is created for each
+** At least one instance of the following structure is created for each
** trigger that may be fired while parsing an INSERT, UPDATE or DELETE
** statement. All such objects are stored in the linked list headed at
** Parse.pTriggerPrg and deleted once statement compilation has been
@@ -13563,7 +15539,7 @@ struct AutoincInfo {
** values for both pTrigger and orconf.
**
** The TriggerPrg.aColmask[0] variable is set to a mask of old.* columns
-** accessed (or set to 0 for triggers fired as a result of INSERT
+** accessed (or set to 0 for triggers fired as a result of INSERT
** statements). Similarly, the TriggerPrg.aColmask[1] variable is set to
** a mask of new.* columns used by the program.
*/
@@ -13604,7 +15580,7 @@ struct TriggerPrg {
** is constant but the second part is reset at the beginning and end of
** each recursion.
**
-** The nTableLock and aTableLock variables are only used if the shared-cache
+** The nTableLock and aTableLock variables are only used if the shared-cache
** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are
** used to store the set of table-locks required by the statement being
** compiled. Function sqlite3TableLock() is used to add entries to the
@@ -13624,36 +15600,24 @@ struct Parse {
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
u8 okConstFactor; /* OK to factor out constants */
u8 disableLookaside; /* Number of times lookaside has been disabled */
- int aTempReg[8]; /* Holding area for temporary registers */
+ u8 nColCache; /* Number of entries in aColCache[] */
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
- int nSet; /* Number of sets used so far */
- int nOnce; /* Number of OP_Once instructions so far */
int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
- int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */
int ckBase; /* Base register of data during check constraints */
int iSelfTab; /* Table of an index whose exprs are being coded */
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
int nLabel; /* Number of labels used */
int *aLabel; /* Space to hold the labels */
- struct yColCache {
- int iTable; /* Table cursor number */
- i16 iColumn; /* Table column number */
- u8 tempReg; /* iReg is a temp register that needs to be freed */
- int iLevel; /* Nesting level */
- int iReg; /* Reg with value of this column. 0 means none. */
- int lru; /* Least recently used entry has the smallest value */
- } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
ExprList *pConstExpr;/* Constant expressions */
Token constraintName;/* Name of the constraint currently being parsed */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
- int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */
int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
@@ -13666,8 +15630,6 @@ struct Parse {
TableLock *aTableLock; /* Required table locks for shared-cache mode */
#endif
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */
-
- /* Information used while coding trigger programs. */
Parse *pToplevel; /* Parse structure for main program (or NULL) */
Table *pTriggerTab; /* Table triggers are being coded for */
int addrCrTab; /* Address of OP_CreateTable opcode on CREATE TABLE */
@@ -13678,35 +15640,50 @@ struct Parse {
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
u8 disableTriggers; /* True to disable triggers */
+ /**************************************************************************
+ ** Fields above must be initialized to zero. The fields that follow,
+ ** down to the beginning of the recursive section, do not need to be
+ ** initialized as they will be set before being used. The boundary is
+ ** determined by offsetof(Parse,aColCache).
+ **************************************************************************/
+
+ struct yColCache {
+ int iTable; /* Table cursor number */
+ i16 iColumn; /* Table column number */
+ u8 tempReg; /* iReg is a temp register that needs to be freed */
+ int iLevel; /* Nesting level */
+ int iReg; /* Reg with value of this column. 0 means none. */
+ int lru; /* Least recently used entry has the smallest value */
+ } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
+ int aTempReg[8]; /* Holding area for temporary registers */
+ Token sNameToken; /* Token with unqualified schema object name */
+
/************************************************************************
** Above is constant between recursions. Below is reset before and after
** each recursion. The boundary between these two regions is determined
- ** using offsetof(Parse,nVar) so the nVar field must be the first field
- ** in the recursive region.
+ ** using offsetof(Parse,sLastToken) so the sLastToken field must be the
+ ** first field in the recursive region.
************************************************************************/
+ Token sLastToken; /* The last token parsed */
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
- int nzVar; /* Number of available slots in azVar[] */
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
u8 explain; /* True if the EXPLAIN flag is found on the query */
#ifndef SQLITE_OMIT_VIRTUALTABLE
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
int nVtabLock; /* Number of virtual tables to lock */
#endif
- int nAlias; /* Number of aliased result set columns */
int nHeight; /* Expression tree height of current sub-select */
#ifndef SQLITE_OMIT_EXPLAIN
int iSelectId; /* ID of current select for EXPLAIN output */
int iNextSelectId; /* Next available select ID for EXPLAIN output */
#endif
- char **azVar; /* Pointers to names of parameters */
+ VList *pVList; /* Mapping between variable names and numbers */
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
const char *zTail; /* All SQL text past the last semicolon parsed */
Table *pNewTable; /* A table being constructed by CREATE TABLE */
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
- Token sNameToken; /* Token with unqualified schema object name */
- Token sLastToken; /* The last token parsed */
#ifndef SQLITE_OMIT_VIRTUALTABLE
Token sArg; /* Complete text of a module argument */
Table **apVtabLock; /* Pointer to virtual tables needing locking */
@@ -13718,6 +15695,14 @@ struct Parse {
};
/*
+** Sizes and pointers of various parts of the Parse object.
+*/
+#define PARSE_HDR_SZ offsetof(Parse,aColCache) /* Recursive part w/o aColCache*/
+#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */
+#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */
+#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */
+
+/*
** Return true if currently inside an sqlite3_declare_vtab() call.
*/
#ifdef SQLITE_OMIT_VIRTUALTABLE
@@ -13737,6 +15722,15 @@ struct AuthContext {
/*
** Bitfield flags for P5 value in various opcodes.
+**
+** Value constraints (enforced via assert()):
+** OPFLAG_LENGTHARG == SQLITE_FUNC_LENGTH
+** OPFLAG_TYPEOFARG == SQLITE_FUNC_TYPEOF
+** OPFLAG_BULKCSR == BTREE_BULKLOAD
+** OPFLAG_SEEKEQ == BTREE_SEEK_EQ
+** OPFLAG_FORDELETE == BTREE_FORDELETE
+** OPFLAG_SAVEPOSITION == BTREE_SAVEPOSITION
+** OPFLAG_AUXDELETE == BTREE_AUXDELETE
*/
#define OPFLAG_NCHANGE 0x01 /* OP_Insert: Set to update db->nChange */
/* Also used in P2 (not P5) of OP_Delete */
@@ -13745,6 +15739,9 @@ struct AuthContext {
#define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */
#define OPFLAG_APPEND 0x08 /* This is likely to be an append */
#define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */
+#endif
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
@@ -13757,10 +15754,10 @@ struct AuthContext {
/*
* Each trigger present in the database schema is stored as an instance of
- * struct Trigger.
+ * struct Trigger.
*
* Pointers to instances of struct Trigger are stored in two ways.
- * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
+ * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
* database). This allows Trigger structures to be retrieved by name.
* 2. All triggers associated with a single table form a linked list, using the
* pNext member of struct Trigger. A pointer to the first element of the
@@ -13786,7 +15783,7 @@ struct Trigger {
/*
** A trigger is either a BEFORE or an AFTER trigger. The following constants
-** determine which.
+** determine which.
**
** If there are multiple triggers, you might of some BEFORE and some AFTER.
** In that cases, the constants below can be ORed together.
@@ -13796,15 +15793,15 @@ struct Trigger {
/*
* An instance of struct TriggerStep is used to store a single SQL statement
- * that is a part of a trigger-program.
+ * that is a part of a trigger-program.
*
* Instances of struct TriggerStep are stored in a singly linked list (linked
- * using the "pNext" member) referenced by the "step_list" member of the
+ * using the "pNext" member) referenced by the "step_list" member of the
* associated struct Trigger instance. The first element of the linked list is
* the first step of the trigger-program.
- *
+ *
* The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
- * "SELECT" statement. The meanings of the other members is determined by the
+ * "SELECT" statement. The meanings of the other members is determined by the
* value of "op" as follows:
*
* (op == TK_INSERT)
@@ -13814,7 +15811,7 @@ struct Trigger {
* zTarget -> Dequoted name of the table to insert into.
* pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
* this stores values to be inserted. Otherwise NULL.
- * pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
+ * pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
* statement, then this stores the column-names to be
* inserted into.
*
@@ -13822,7 +15819,7 @@ struct Trigger {
* zTarget -> Dequoted name of the table to delete from.
* pWhere -> The WHERE clause of the DELETE statement if one is specified.
* Otherwise NULL.
- *
+ *
* (op == TK_UPDATE)
* zTarget -> Dequoted name of the table to update.
* pWhere -> The WHERE clause of the UPDATE statement if one is specified.
@@ -13830,7 +15827,7 @@ struct Trigger {
* pExprList -> A list of the columns to update and the expressions to update
* them to. See sqlite3Update() documentation of "pChanges"
* argument.
- *
+ *
*/
struct TriggerStep {
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
@@ -13848,7 +15845,7 @@ struct TriggerStep {
/*
** The following structure contains information used by the sqliteFix...
** routines as they walk the parse tree to make database references
-** explicit.
+** explicit.
*/
typedef struct DbFixer DbFixer;
struct DbFixer {
@@ -13909,6 +15906,7 @@ struct Sqlite3Config {
int neverCorrupt; /* Database is always well-formed */
int szLookaside; /* Default lookaside buffer size */
int nLookaside; /* Default lookaside buffer count */
+ int nStmtSpill; /* Stmt-journal spill-to-disk threshold */
sqlite3_mem_methods m; /* Low-level memory allocation interface */
sqlite3_mutex_methods mutex; /* Low-level mutex interface */
sqlite3_pcache_methods2 pcache2; /* Low-level page-cache interface */
@@ -13948,10 +15946,11 @@ struct Sqlite3Config {
void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */
void *pVdbeBranchArg; /* 1st argument */
#endif
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
#endif
int bLocaltimeFault; /* True to fail localtime() calls */
+ int iOnceResetThreshold; /* When to reset OP_Once counters */
};
/*
@@ -13990,6 +15989,7 @@ struct Walker {
struct SrcCount *pSrcCount; /* Counting column references */
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
int *aiCol; /* array of column indexes */
+ struct IdxCover *pIdxCover; /* Check for index coverage */
} u;
};
@@ -14058,6 +16058,15 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__)
#define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
#define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3NomemError(int);
+SQLITE_PRIVATE int sqlite3IoerrnomemError(int);
+# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__)
+# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__)
+#else
+# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
+# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM
+#endif
/*
** FTS3 and FTS4 both require virtual table support
@@ -14098,6 +16107,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
# define sqlite3Isdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x04)
# define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
# define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
+# define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
#else
# define sqlite3Toupper(x) toupper((unsigned char)(x))
# define sqlite3Isspace(x) isspace((unsigned char)(x))
@@ -14106,6 +16116,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
# define sqlite3Isdigit(x) isdigit((unsigned char)(x))
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlite3Tolower(x) tolower((unsigned char)(x))
+# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
#endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
SQLITE_PRIVATE int sqlite3IsIdChar(u8);
@@ -14114,8 +16125,9 @@ SQLITE_PRIVATE int sqlite3IsIdChar(u8);
/*
** Internal function prototypes
*/
-#define sqlite3StrICmp sqlite3_stricmp
+SQLITE_PRIVATE int sqlite3StrICmp(const char*,const char*);
SQLITE_PRIVATE int sqlite3Strlen30(const char*);
+SQLITE_PRIVATE char *sqlite3ColumnType(Column*,char*);
#define sqlite3StrNICmp sqlite3_strnicmp
SQLITE_PRIVATE int sqlite3MallocInit(void);
@@ -14138,7 +16150,7 @@ SQLITE_PRIVATE void sqlite3ScratchFree(void*);
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
SQLITE_PRIVATE void sqlite3PageFree(void*);
SQLITE_PRIVATE void sqlite3MemSetDefault(void);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void));
#endif
SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
@@ -14154,18 +16166,22 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
#ifdef SQLITE_USE_ALLOCA
# define sqlite3StackAllocRaw(D,N) alloca(N)
# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N)
-# define sqlite3StackFree(D,P)
+# define sqlite3StackFree(D,P)
#else
# define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N)
# define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N)
# define sqlite3StackFree(D,P) sqlite3DbFree(D,P)
#endif
-#ifdef SQLITE_ENABLE_MEMSYS3
-SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
-#endif
+/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they
+** are, disable MEMSYS3
+*/
#ifdef SQLITE_ENABLE_MEMSYS5
SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
+#undef SQLITE_ENABLE_MEMSYS3
+#endif
+#ifdef SQLITE_ENABLE_MEMSYS3
+SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void);
#endif
@@ -14220,6 +16236,7 @@ SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*);
#if defined(SQLITE_DEBUG)
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
+SQLITE_PRIVATE void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*);
SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8);
@@ -14228,7 +16245,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8);
SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*);
SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...);
-SQLITE_PRIVATE int sqlite3Dequote(char*);
+SQLITE_PRIVATE void sqlite3Dequote(char*);
SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*);
SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int);
SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **);
@@ -14238,15 +16255,20 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);
SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int);
SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int);
SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*);
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int);
+#endif
SQLITE_PRIVATE Expr *sqlite3ExprAlloc(sqlite3*,int,const Token*,int);
SQLITE_PRIVATE Expr *sqlite3Expr(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*);
-SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*);
+SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
+SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*);
-SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*);
+SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
+SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*);
@@ -14255,12 +16277,16 @@ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**);
SQLITE_PRIVATE int sqlite3InitCallback(void*, int, char**, char**);
SQLITE_PRIVATE void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3*,const char *zName);
+#endif
SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
+SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*);
SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*);
SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
@@ -14271,20 +16297,18 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*);
#else
# define sqlite3ColumnPropertiesFromName(T,C) /* no-op */
#endif
-SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*);
+SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*);
SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
-SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*);
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*);
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
sqlite3_vfs**,char**,char **);
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
-SQLITE_PRIVATE int sqlite3CodeOnce(Parse *);
-#ifdef SQLITE_OMIT_BUILTIN_TEST
+#ifdef SQLITE_UNTESTABLE
# define sqlite3FaultSim(X) SQLITE_OK
#else
SQLITE_PRIVATE int sqlite3FaultSim(int);
@@ -14297,7 +16321,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32);
SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*);
SQLITE_PRIVATE void sqlite3BitvecDestroy(Bitvec*);
SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec*);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int,int*);
#endif
@@ -14344,12 +16368,12 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*);
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*);
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*);
SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
-SQLITE_PRIVATE Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
- Expr*, int, int);
+SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
+ Expr*, int, int, u8);
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
- Expr*,ExprList*,u16,Expr*,Expr*);
+ Expr*,ExprList*,u32,Expr*,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
@@ -14361,9 +16385,10 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
-SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo*);
+SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*);
+SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
@@ -14393,26 +16418,30 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
#define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */
+#define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */
SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);
SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
-SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
-SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
+#define LOCATE_VIEW 0x01
+#define LOCATE_NOERR 0x02
+SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*);
+SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
-SQLITE_PRIVATE void sqlite3Vacuum(Parse*);
-SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*);
+SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*);
+SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int);
SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*);
SQLITE_PRIVATE int sqlite3ExprCompare(Expr*, Expr*, int);
SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int);
SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr*, Expr*, int);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
+SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3PrngSaveState(void);
SQLITE_PRIVATE void sqlite3PrngRestoreState(void);
#endif
@@ -14461,11 +16490,11 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select*,const char*);
#else
# define sqlite3SelectSetName(A,B)
#endif
-SQLITE_PRIVATE void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*);
-SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,u8);
-SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3*);
+SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
+SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
+SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
-SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void);
+SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);
SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*);
SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);
@@ -14544,7 +16573,14 @@ SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst);
#ifndef SQLITE_OMIT_VIRTUALTABLE
SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double);
#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
+ defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
+ defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst);
+#endif
+SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int);
+SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int);
+SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int);
/*
** Routines to read and write variable-length integers. These used to
@@ -14574,11 +16610,13 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
+SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int);
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
+SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int);
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
@@ -14611,7 +16649,7 @@ SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8);
SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
-SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
+SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value*);
SQLITE_PRIVATE void sqlite3ValueFree(sqlite3_value*);
@@ -14626,7 +16664,7 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
SQLITE_PRIVATE const Token sqlite3IntTokens[];
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
-SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
#ifndef SQLITE_OMIT_WSD
SQLITE_PRIVATE int sqlite3PendingByte;
#endif
@@ -14638,7 +16676,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *, int *);
SQLITE_PRIVATE void sqlite3NestedParse(Parse*, const char*, ...);
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*);
-SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *, Expr *, int, int);
+SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr *, int, int);
SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
SQLITE_PRIVATE int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
@@ -14671,7 +16709,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*);
#endif
-SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
+SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
void (*)(sqlite3_context*,int,sqlite3_value **),
void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
FuncDestructor *pDestructor
@@ -14693,12 +16731,20 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *);
SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
+#ifndef SQLITE_OMIT_SUBQUERY
+SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse*, Expr*);
+#else
+# define sqlite3ExprCheckIN(x,y) SQLITE_OK
+#endif
+
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void);
-SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(Parse*,Index*,UnpackedRecord**,Expr*,u8,int,int*);
+SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(
+ Parse*,Index*,UnpackedRecord**,Expr*,int,int,int*);
SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**);
SQLITE_PRIVATE void sqlite3Stat4ProbeFree(UnpackedRecord*);
SQLITE_PRIVATE int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**);
+SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3*, Index*, int);
#endif
/*
@@ -14734,7 +16780,7 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*);
# define sqlite3VtabRollback(X)
# define sqlite3VtabCommit(X)
# define sqlite3VtabInSync(db) 0
-# define sqlite3VtabLock(X)
+# define sqlite3VtabLock(X)
# define sqlite3VtabUnlock(X)
# define sqlite3VtabUnlockList(X)
# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK
@@ -14751,6 +16797,13 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*);
SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int);
SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3*, Table*);
+SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
+ sqlite3*,
+ const char*,
+ const sqlite3_module*,
+ void*,
+ void(*)(void*)
+ );
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
@@ -14792,7 +16845,7 @@ SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8);
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
** key functionality is available. If OMIT_TRIGGER is defined but
** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In
-** this case foreign keys are parsed, but no other functionality is
+** this case foreign keys are parsed, but no other functionality is
** provided (enforcement of FK constraints requires the triggers sub-system).
*/
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
@@ -14826,10 +16879,10 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**);
/*
** The interface to the code in fault.c used for identifying "benign"
-** malloc failures. This is only present if SQLITE_OMIT_BUILTIN_TEST
+** malloc failures. This is only present if SQLITE_UNTESTABLE
** is not defined.
*/
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE void sqlite3BeginBenignMalloc(void);
SQLITE_PRIVATE void sqlite3EndBenignMalloc(void);
#else
@@ -14851,21 +16904,16 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void);
#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */
#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */
#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */
-SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*);
+SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
+SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
+SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
-SQLITE_PRIVATE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
-SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *);
SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *);
-SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p);
-#else
- #define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
- #define sqlite3JournalExists(p) 1
#endif
+SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p);
SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);
-SQLITE_PRIVATE int sqlite3MemJournalSize(void);
-SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *);
SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
#if SQLITE_MAX_EXPR_DEPTH>0
@@ -14896,7 +16944,7 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE*, char *);
/*
** If the SQLITE_ENABLE IOTRACE exists then the global variable
** sqlite3IoTrace is a pointer to a printf-like routine used to
-** print I/O tracing messages.
+** print I/O tracing messages.
*/
#ifdef SQLITE_ENABLE_IOTRACE
# define IOTRACE(A) if( sqlite3IoTrace ){ sqlite3IoTrace A; }
@@ -14930,7 +16978,7 @@ SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);
** that allocations that might have been satisfied by lookaside are not
** passed back to non-lookaside free() routines. Asserts such as the
** example above are placed on the non-lookaside free() routines to verify
-** this constraint.
+** this constraint.
**
** All of this is no-op for a production build. It only comes into
** play when the SQLITE_MEMDEBUG compile-time option is used.
@@ -14961,7 +17009,13 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread*, void**);
SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
#endif
-#endif /* _SQLITEINT_H_ */
+SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr);
+SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr);
+SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int);
+SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int);
+SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*);
+
+#endif /* SQLITEINT_H */
/************** End of sqliteInt.h *******************************************/
/************** Begin file global.c ******************************************/
@@ -15037,6 +17091,7 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
** isxdigit() 0x08
** toupper() 0x20
** SQLite identifier character 0x40
+** Quote character 0x80
**
** Bit 0x20 is set if the mapped character requires translation to upper
** case. i.e. if the character is a lower-case ASCII character.
@@ -15045,16 +17100,13 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
**
** (x & ~(map[x]&0x20))
**
-** Standard function tolower() is implemented using the sqlite3UpperToLower[]
+** The equivalent of tolower() is implemented using the sqlite3UpperToLower[]
** array. tolower() is used more often than toupper() by SQLite.
**
-** Bit 0x40 is set if the character non-alphanumeric and can be used in an
+** Bit 0x40 is set if the character is non-alphanumeric and can be used in an
** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any
** non-ASCII UTF character. Hence the test for whether or not a character is
** part of an identifier is 0x46.
-**
-** SQLite's versions are identical to the standard versions assuming a
-** locale of "C". They are implemented as macros in sqliteInt.h.
*/
#ifdef SQLITE_ASCII
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
@@ -15062,7 +17114,7 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, /* 08..0f ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10..17 ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 18..1f ........ */
- 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, /* 20..27 !"#$%&' */
+ 0x01, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x80, /* 20..27 !"#$%&' */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 28..2f ()*+,-./ */
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, /* 30..37 01234567 */
0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 38..3f 89:;<=>? */
@@ -15070,8 +17122,8 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02, /* 40..47 @ABCDEFG */
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 48..4f HIJKLMNO */
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, /* 50..57 PQRSTUVW */
- 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
- 0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
+ 0x02, 0x02, 0x02, 0x80, 0x00, 0x00, 0x00, 0x40, /* 58..5f XYZ[\]^_ */
+ 0x80, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22, /* 60..67 `abcdefg */
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 68..6f hijklmno */
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, /* 70..77 pqrstuvw */
0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, /* 78..7f xyz{|}~. */
@@ -15126,6 +17178,18 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
# define SQLITE_SORTER_PMASZ 250
#endif
+/* Statement journals spill to disk when their size exceeds the following
+** threshold (in bytes). 0 means that statement journals are created and
+** written to disk immediately (the default behavior for SQLite versions
+** before 3.12.0). -1 means always keep the entire statement journal in
+** memory. (The statement journal is also always held entirely in memory
+** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this
+** setting.)
+*/
+#ifndef SQLITE_STMTJRNL_SPILL
+# define SQLITE_STMTJRNL_SPILL (64*1024)
+#endif
+
/*
** The following singleton contains the global configuration for
** the SQLite library.
@@ -15138,8 +17202,9 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
0x7ffffffe, /* mxStrlen */
0, /* neverCorrupt */
- 128, /* szLookaside */
- 500, /* nLookaside */
+ 512, /* szLookaside */
+ 125, /* nLookaside */
+ SQLITE_STMTJRNL_SPILL, /* nStmtSpill */
{0,0,0,0,0,0,0,0}, /* m */
{0,0,0,0,0,0,0,0,0}, /* mutex */
{0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
@@ -15175,10 +17240,11 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* xVdbeBranch */
0, /* pVbeBranchArg */
#endif
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
0, /* xTestCallback */
#endif
- 0 /* bLocaltimeFault */
+ 0, /* bLocaltimeFault */
+ 0x7ffffffe /* iOnceResetThreshold */
};
/*
@@ -15186,7 +17252,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
** database connections. After initialization, this table is
** read-only.
*/
-SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
/*
** Constant tokens for values 0 and 1.
@@ -15201,7 +17267,7 @@ SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
** The value of the "pending" byte must be 0x40000000 (1 byte past the
** 1-gibabyte boundary) in a compatible database. SQLite never uses
** the database page that contains the pending byte. It never attempts
-** to read or write that page. The pending byte page is set assign
+** to read or write that page. The pending byte page is set aside
** for use by the VFS layers as space for managing file locks.
**
** During testing, it is often desirable to move the pending byte to
@@ -15282,6 +17348,15 @@ static const char * const azCompileOpt[] = {
#if SQLITE_CHECK_PAGES
"CHECK_PAGES",
#endif
+#if defined(__clang__) && defined(__clang_major__)
+ "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "."
+ CTIMEOPT_VAL(__clang_minor__) "."
+ CTIMEOPT_VAL(__clang_patchlevel__),
+#elif defined(_MSC_VER)
+ "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER),
+#elif defined(__GNUC__) && defined(__VERSION__)
+ "COMPILER=gcc-" __VERSION__,
+#endif
#if SQLITE_COVERAGE_TEST
"COVERAGE_TEST",
#endif
@@ -15294,6 +17369,9 @@ static const char * const azCompileOpt[] = {
#if defined(SQLITE_DEFAULT_MMAP_SIZE) && !defined(SQLITE_DEFAULT_MMAP_SIZE_xc)
"DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
#endif
+#if SQLITE_DIRECT_OVERFLOW_READ
+ "DIRECT_OVERFLOW_READ",
+#endif
#if SQLITE_DISABLE_DIRSYNC
"DISABLE_DIRSYNC",
#endif
@@ -15301,7 +17379,7 @@ static const char * const azCompileOpt[] = {
"DISABLE_LFS",
#endif
#if SQLITE_ENABLE_8_3_NAMES
- "ENABLE_8_3_NAMES",
+ "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
#endif
#if SQLITE_ENABLE_API_ARMOR
"ENABLE_API_ARMOR",
@@ -15380,6 +17458,9 @@ static const char * const azCompileOpt[] = {
#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
"ENABLE_UPDATE_DELETE_LIMIT",
#endif
+#if defined(SQLITE_ENABLE_URI_00_ERROR)
+ "ENABLE_URI_00_ERROR",
+#endif
#if SQLITE_HAS_CODEC
"HAS_CODEC",
#endif
@@ -15455,9 +17536,6 @@ static const char * const azCompileOpt[] = {
#if SQLITE_OMIT_BTREECOUNT
"OMIT_BTREECOUNT",
#endif
-#if SQLITE_OMIT_BUILTIN_TEST
- "OMIT_BUILTIN_TEST",
-#endif
#if SQLITE_OMIT_CAST
"OMIT_CAST",
#endif
@@ -15620,6 +17698,9 @@ static const char * const azCompileOpt[] = {
#if defined(SQLITE_THREADSAFE)
"THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
#endif
+#if SQLITE_UNTESTABLE
+ "UNTESTABLE"
+#endif
#if SQLITE_USE_ALLOCA
"USE_ALLOCA",
#endif
@@ -15641,7 +17722,7 @@ static const char * const azCompileOpt[] = {
** The name can optionally begin with "SQLITE_" but the "SQLITE_" prefix
** is not required for a match.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName){
+SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
int i, n;
#if SQLITE_ENABLE_API_ARMOR
@@ -15669,7 +17750,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName){
** Return the N-th compile-time option string. If N is out of range,
** return a NULL pointer.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
+SQLITE_API const char *sqlite3_compileoption_get(int N){
if( N>=0 && N<ArraySize(azCompileOpt) ){
return azCompileOpt[N];
}
@@ -15715,8 +17796,8 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N){
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
*/
-#ifndef _VDBEINT_H_
-#define _VDBEINT_H_
+#ifndef SQLITE_VDBEINT_H
+#define SQLITE_VDBEINT_H
/*
** The maximum number of times that a statement will try to reparse
@@ -15752,9 +17833,6 @@ typedef unsigned Bool;
/* Opaque type used by code in vdbesort.c */
typedef struct VdbeSorter VdbeSorter;
-/* Opaque type used by the explainer */
-typedef struct Explain Explain;
-
/* Elements of the linked list at Vdbe.pAuxData */
typedef struct AuxData AuxData;
@@ -15776,59 +17854,68 @@ typedef struct AuxData AuxData;
*/
typedef struct VdbeCursor VdbeCursor;
struct VdbeCursor {
- u8 eCurType; /* One of the CURTYPE_* values above */
- i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
- u8 nullRow; /* True if pointing to a row with no data */
- u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
- u8 isTable; /* True for rowid tables. False for indexes */
+ u8 eCurType; /* One of the CURTYPE_* values above */
+ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
+ u8 nullRow; /* True if pointing to a row with no data */
+ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
+ u8 isTable; /* True for rowid tables. False for indexes */
#ifdef SQLITE_DEBUG
- u8 seekOp; /* Most recent seek operation on this cursor */
- u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
-#endif
- Bool isEphemeral:1; /* True for an ephemeral table */
- Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
- Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
- Pgno pgnoRoot; /* Root page of the open btree cursor */
- i16 nField; /* Number of fields in the header */
- u16 nHdrParsed; /* Number of header fields parsed so far */
+ u8 seekOp; /* Most recent seek operation on this cursor */
+ u8 wrFlag; /* The wrFlag argument to sqlite3BtreeCursor() */
+#endif
+ Bool isEphemeral:1; /* True for an ephemeral table */
+ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
+ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
+ Btree *pBtx; /* Separate file holding temporary table */
+ i64 seqCount; /* Sequence counter */
+ int *aAltMap; /* Mapping from table to index column numbers */
+
+ /* Cached OP_Column parse information is only valid if cacheStatus matches
+ ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
+ ** CACHE_STALE (0) and so setting cacheStatus=CACHE_STALE guarantees that
+ ** the cache is out of date. */
+ u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
+ int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0
+ ** if there have been no prior seeks on the cursor. */
+ /* NB: seekResult does not distinguish between "no seeks have ever occurred
+ ** on this cursor" and "the most recent seek was an exact match". */
+
+ /* When a new VdbeCursor is allocated, only the fields above are zeroed.
+ ** The fields that follow are uninitialized, and must be individually
+ ** initialized prior to first use. */
+ VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
union {
BtCursor *pCursor; /* CURTYPE_BTREE. Btree cursor */
sqlite3_vtab_cursor *pVCur; /* CURTYPE_VTAB. Vtab cursor */
int pseudoTableReg; /* CURTYPE_PSEUDO. Reg holding content. */
VdbeSorter *pSorter; /* CURTYPE_SORTER. Sorter object */
} uc;
- Btree *pBt; /* Separate file holding temporary table */
- KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
- int seekResult; /* Result of previous sqlite3BtreeMoveto() */
- i64 seqCount; /* Sequence counter */
- i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
- VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
- int *aAltMap; /* Mapping from table to index column numbers */
+ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
+ u32 iHdrOffset; /* Offset to next unparsed byte of the header */
+ Pgno pgnoRoot; /* Root page of the open btree cursor */
+ i16 nField; /* Number of fields in the header */
+ u16 nHdrParsed; /* Number of header fields parsed so far */
+ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
+ u32 *aOffset; /* Pointer to aType[nField] */
+ const u8 *aRow; /* Data for the current row, if all on one page */
+ u32 payloadSize; /* Total number of bytes in the record */
+ u32 szRow; /* Byte available in aRow */
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
- u64 maskUsed; /* Mask of columns used by this cursor */
+ u64 maskUsed; /* Mask of columns used by this cursor */
#endif
- /* Cached information about the header for the data record that the
- ** cursor is currently pointing to. Only valid if cacheStatus matches
- ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
- ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that
- ** the cache is out of date.
- **
- ** aRow might point to (ephemeral) data for the current row, or it might
- ** be NULL.
- */
- u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
- u32 payloadSize; /* Total number of bytes in the record */
- u32 szRow; /* Byte available in aRow */
- u32 iHdrOffset; /* Offset to next unparsed byte of the header */
- const u8 *aRow; /* Data for the current row, if all on one page */
- u32 *aOffset; /* Pointer to aType[nField] */
- u32 aType[1]; /* Type values for all entries in the record */
/* 2*nField extra array elements allocated for aType[], beyond the one
** static element declared in the structure. nField total array slots for
** aType[] and nField+1 array slots for aOffset[] */
+ u32 aType[1]; /* Type values record decode. MUST BE LAST */
};
+
+/*
+** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
+*/
+#define CACHE_STALE 0
+
/*
** When a sub-program is executed (OP_Program), a structure of this type
** is allocated to store the current value of the program counter, as
@@ -15857,15 +17944,14 @@ struct VdbeFrame {
Op *aOp; /* Program instructions for parent frame */
i64 *anExec; /* Event counters from parent frame */
Mem *aMem; /* Array of memory cells for parent frame */
- u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
void *token; /* Copy of SubProgram.token */
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
+ AuxData *pAuxData; /* Linked list of auxdata allocations */
int nCursor; /* Number of entries in apCsr */
int pc; /* Program Counter in parent (calling) frame */
int nOp; /* Size of aOp array */
int nMem; /* Number of entries in aMem */
- int nOnceFlag; /* Number of entries in aOnceFlag */
int nChildMem; /* Number of memory cells for child frame */
int nChildCsr; /* Number of cursors for child frame */
int nChange; /* Statement changes (Vdbe.nChange) */
@@ -15875,11 +17961,6 @@ struct VdbeFrame {
#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])
/*
-** A value for VdbeCursor.cacheValid that means the cache is always invalid.
-*/
-#define CACHE_STALE 0
-
-/*
** Internally, the vdbe manipulates nearly all SQL values as Mem
** structures. Each Mem struct may cache multiple representations (string,
** integer etc.) of the same value.
@@ -16019,18 +18100,6 @@ struct sqlite3_context {
sqlite3_value *argv[1]; /* Argument set */
};
-/*
-** An Explain object accumulates indented output which is helpful
-** in describing recursive data structures.
-*/
-struct Explain {
- Vdbe *pVdbe; /* Attach the explanation to this Vdbe */
- StrAccum str; /* The string being accumulated */
- int nIndent; /* Number of elements in aIndent */
- u16 aIndent[100]; /* Levels of indentation */
- char zBase[100]; /* Initial space */
-};
-
/* A bitfield type for use inside of structures. Always follow with :N where
** N is the number of bits.
*/
@@ -16055,53 +18124,56 @@ struct ScanStatus {
*/
struct Vdbe {
sqlite3 *db; /* The database connection that owns this statement */
+ Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
+ Parse *pParse; /* Parsing context used to create this Vdbe */
+ ynVar nVar; /* Number of entries in aVar[] */
+ u32 magic; /* Magic number for sanity checking */
+ int nMem; /* Number of memory locations currently allocated */
+ int nCursor; /* Number of slots in apCsr[] */
+ u32 cacheCtr; /* VdbeCursor row cache generation counter */
+ int pc; /* The program counter */
+ int rc; /* Value to return */
+ int nChange; /* Number of db changes made since last reset */
+ int iStatement; /* Statement number (or 0 if has not opened stmt) */
+ i64 iCurrentTime; /* Value of julianday('now') for this statement */
+ i64 nFkConstraint; /* Number of imm. FK constraints this VM */
+ i64 nStmtDefCons; /* Number of def. constraints when stmt started */
+ i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
+
+ /* When allocating a new Vdbe object, all of the fields below should be
+ ** initialized to zero or NULL */
+
Op *aOp; /* Space to hold the virtual machine's program */
Mem *aMem; /* The memory locations */
Mem **apArg; /* Arguments to currently executing user function */
Mem *aColName; /* Column names to return */
Mem *pResultSet; /* Pointer to an array of results */
- Parse *pParse; /* Parsing context used to create this Vdbe */
- int nMem; /* Number of memory locations currently allocated */
- int nOp; /* Number of instructions in the program */
- int nCursor; /* Number of slots in apCsr[] */
- u32 magic; /* Magic number for sanity checking */
char *zErrMsg; /* Error message written here */
- Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
VdbeCursor **apCsr; /* One element of this array for each open cursor */
Mem *aVar; /* Values for the OP_Variable opcode. */
- char **azVar; /* Name of variables */
- ynVar nVar; /* Number of entries in aVar[] */
- ynVar nzVar; /* Number of entries in azVar[] */
- u32 cacheCtr; /* VdbeCursor row cache generation counter */
- int pc; /* The program counter */
- int rc; /* Value to return */
+ VList *pVList; /* Name of variables */
+#ifndef SQLITE_OMIT_TRACE
+ i64 startTime; /* Time when query started - used for profiling */
+#endif
+ int nOp; /* Number of instructions in the program */
#ifdef SQLITE_DEBUG
int rcApp; /* errcode set by sqlite3_result_error_code() */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
+ bft expired:1; /* True if the VM needs to be recompiled */
+ bft doingRerun:1; /* True if rerunning after an auto-reprepare */
bft explain:2; /* True if EXPLAIN present on SQL command */
bft changeCntOn:1; /* True to update the change-counter */
- bft expired:1; /* True if the VM needs to be recompiled */
bft runOnlyOnce:1; /* Automatically expire on reset */
bft usesStmtJournal:1; /* True if uses a statement journal */
bft readOnly:1; /* True for statements that do not write */
bft bIsReader:1; /* True for statements that read */
bft isPrepareV2:1; /* True if prepared with prepare_v2() */
- bft doingRerun:1; /* True if rerunning after an auto-reprepare */
- int nChange; /* Number of db changes made since last reset */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
- int iStatement; /* Statement number (or 0 if has not opened stmt) */
u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */
-#ifndef SQLITE_OMIT_TRACE
- i64 startTime; /* Time when query started - used for profiling */
-#endif
- i64 iCurrentTime; /* Value of julianday('now') for this statement */
- i64 nFkConstraint; /* Number of imm. FK constraints this VM */
- i64 nStmtDefCons; /* Number of def. constraints when stmt started */
- i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
char *zSql; /* Text of the SQL statement that generated this */
void *pFree; /* Free this when deleting the vdbe */
VdbeFrame *pFrame; /* Parent frame */
@@ -16109,8 +18181,6 @@ struct Vdbe {
int nFrame; /* Number of frames in pFrame list */
u32 expmask; /* Binding to these vars invalidates VM */
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
- int nOnceFlag; /* Size of array aOnceFlag[] */
- u8 *aOnceFlag; /* Flags for OP_Once */
AuxData *pAuxData; /* Linked list of auxdata allocations */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
i64 *anExec; /* Number of times each op has been executed */
@@ -16122,10 +18192,30 @@ struct Vdbe {
/*
** The following are allowed values for Vdbe.magic
*/
-#define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */
-#define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */
-#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
-#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
+#define VDBE_MAGIC_INIT 0x16bceaa5 /* Building a VDBE program */
+#define VDBE_MAGIC_RUN 0x2df20da3 /* VDBE is ready to execute */
+#define VDBE_MAGIC_HALT 0x319c2973 /* VDBE has completed execution */
+#define VDBE_MAGIC_RESET 0x48fa9f76 /* Reset and ready to run again */
+#define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */
+
+/*
+** Structure used to store the context required by the
+** sqlite3_preupdate_*() API functions.
+*/
+struct PreUpdate {
+ Vdbe *v;
+ VdbeCursor *pCsr; /* Cursor to read old values from */
+ int op; /* One of SQLITE_INSERT, UPDATE, DELETE */
+ u8 *aRecord; /* old.* database record */
+ KeyInfo keyinfo;
+ UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */
+ UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
+ int iNewReg; /* Register for new.* values */
+ i64 iKey1; /* First key value passed to hook */
+ i64 iKey2; /* Second key value passed to hook */
+ Mem *aNew; /* Array of new.* values */
+ Table *pTab; /* Schema object being upated */
+};
/*
** Function prototypes
@@ -16143,7 +18233,7 @@ SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem*, int, u32*);
SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
+SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
@@ -16177,7 +18267,7 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem*,u8,u8);
-SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
+SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*);
SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
@@ -16186,6 +18276,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int n);
SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *, int);
SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*);
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int);
+#endif
SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
SQLITE_PRIVATE int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
@@ -16235,7 +18328,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *);
#define ExpandBlob(P) SQLITE_OK
#endif
-#endif /* !defined(_VDBEINT_H_) */
+#endif /* !defined(SQLITE_VDBEINT_H) */
/************** End of vdbeInt.h *********************************************/
/************** Continuing where we left off in status.c *********************/
@@ -16356,7 +18449,7 @@ SQLITE_PRIVATE void sqlite3StatusHighwater(int op, int X){
/*
** Query status information.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+SQLITE_API int sqlite3_status64(
int op,
sqlite3_int64 *pCurrent,
sqlite3_int64 *pHighwater,
@@ -16381,8 +18474,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
(void)pMutex; /* Prevent warning when SQLITE_THREADSAFE=0 */
return SQLITE_OK;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
- sqlite3_int64 iCur, iHwtr;
+SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag){
+ sqlite3_int64 iCur = 0, iHwtr = 0;
int rc;
#ifdef SQLITE_ENABLE_API_ARMOR
if( pCurrent==0 || pHighwater==0 ) return SQLITE_MISUSE_BKPT;
@@ -16398,7 +18491,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwa
/*
** Query status information for a single database connection
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
+SQLITE_API int sqlite3_db_status(
sqlite3 *db, /* The database connection whose status is desired */
int op, /* Status verb */
int *pCurrent, /* Write current value here */
@@ -16443,6 +18536,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
** by all pagers associated with the given database connection. The
** highwater mark is meaningless and is returned as zero.
*/
+ case SQLITE_DBSTATUS_CACHE_USED_SHARED:
case SQLITE_DBSTATUS_CACHE_USED: {
int totalUsed = 0;
int i;
@@ -16451,7 +18545,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
Pager *pPager = sqlite3BtreePager(pBt);
- totalUsed += sqlite3PagerMemUsed(pPager);
+ int nByte = sqlite3PagerMemUsed(pPager);
+ if( op==SQLITE_DBSTATUS_CACHE_USED_SHARED ){
+ nByte = nByte / sqlite3BtreeConnectionCount(pBt);
+ }
+ totalUsed += nByte;
}
}
sqlite3BtreeLeaveAll(db);
@@ -16623,22 +18721,33 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(
#ifndef SQLITE_OMIT_DATETIME_FUNCS
+/*
+** The MSVC CRT on Windows CE may not have a localtime() function.
+** So declare a substitute. The substitute function itself is
+** defined in "os_win.c".
+*/
+#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
+ (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
+struct tm *__cdecl localtime(const time_t *);
+#endif
/*
** A structure for holding a single date and time.
*/
typedef struct DateTime DateTime;
struct DateTime {
- sqlite3_int64 iJD; /* The julian day number times 86400000 */
- int Y, M, D; /* Year, month, and day */
- int h, m; /* Hour and minutes */
- int tz; /* Timezone offset in minutes */
- double s; /* Seconds */
- char validYMD; /* True (1) if Y,M,D are valid */
- char validHMS; /* True (1) if h,m,s are valid */
- char validJD; /* True (1) if iJD is valid */
- char validTZ; /* True (1) if tz is valid */
- char tzSet; /* Timezone was set explicitly */
+ sqlite3_int64 iJD; /* The julian day number times 86400000 */
+ int Y, M, D; /* Year, month, and day */
+ int h, m; /* Hour and minutes */
+ int tz; /* Timezone offset in minutes */
+ double s; /* Seconds */
+ char validJD; /* True (1) if iJD is valid */
+ char rawS; /* Raw numeric value stored in s */
+ char validYMD; /* True (1) if Y,M,D are valid */
+ char validHMS; /* True (1) if h,m,s are valid */
+ char validTZ; /* True (1) if tz is valid */
+ char tzSet; /* Timezone was set explicitly */
+ char isError; /* An overflow has occurred */
};
@@ -16786,6 +18895,7 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
s = 0;
}
p->validJD = 0;
+ p->rawS = 0;
p->validHMS = 1;
p->h = h;
p->m = m;
@@ -16796,6 +18906,14 @@ static int parseHhMmSs(const char *zDate, DateTime *p){
}
/*
+** Put the DateTime object into its error state.
+*/
+static void datetimeError(DateTime *p){
+ memset(p, 0, sizeof(*p));
+ p->isError = 1;
+}
+
+/*
** Convert from YYYY-MM-DD HH:MM:SS to julian day. We always assume
** that the YYYY-MM-DD is according to the Gregorian calendar.
**
@@ -16814,6 +18932,10 @@ static void computeJD(DateTime *p){
M = 1;
D = 1;
}
+ if( Y<-4713 || Y>9999 || p->rawS ){
+ datetimeError(p);
+ return;
+ }
if( M<=2 ){
Y--;
M += 12;
@@ -16895,6 +19017,21 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
}
/*
+** Input "r" is a numeric quantity which might be a julian day number,
+** or the number of seconds since 1970. If the value if r is within
+** range of a julian day number, install it as such and set validJD.
+** If the value is a valid unix timestamp, put it in p->s and set p->rawS.
+*/
+static void setRawDateNumber(DateTime *p, double r){
+ p->s = r;
+ p->rawS = 1;
+ if( r>=0.0 && r<5373484.5 ){
+ p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
+ p->validJD = 1;
+ }
+}
+
+/*
** Attempt to parse the given string into a julian day number. Return
** the number of errors.
**
@@ -16923,13 +19060,30 @@ static int parseDateOrTime(
}else if( sqlite3StrICmp(zDate,"now")==0){
return setDateTimeToCurrent(context, p);
}else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
- p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
- p->validJD = 1;
+ setRawDateNumber(p, r);
return 0;
}
return 1;
}
+/* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999.
+** Multiplying this by 86400000 gives 464269060799999 as the maximum value
+** for DateTime.iJD.
+**
+** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with
+** such a large integer literal, so we have to encode it.
+*/
+#define INT_464269060799999 ((((i64)0x1a640)<<32)|0x1072fdff)
+
+/*
+** Return TRUE if the given julian day number is within range.
+**
+** The input is the JulianDay times 86400000.
+*/
+static int validJulianDay(sqlite3_int64 iJD){
+ return iJD>=0 && iJD<=INT_464269060799999;
+}
+
/*
** Compute the Year, Month, and Day from the julian day number.
*/
@@ -16941,6 +19095,7 @@ static void computeYMD(DateTime *p){
p->M = 1;
p->D = 1;
}else{
+ assert( validJulianDay(p->iJD) );
Z = (int)((p->iJD + 43200000)/86400000);
A = (int)((Z - 1867216.25)/36524.25);
A = Z + 1 + A - (A/4);
@@ -16971,6 +19126,7 @@ static void computeHMS(DateTime *p){
s -= p->h*3600;
p->m = s/60;
p->s += s - p->m*60;
+ p->rawS = 0;
p->validHMS = 1;
}
@@ -16991,6 +19147,7 @@ static void clearYMD_HMS_TZ(DateTime *p){
p->validTZ = 0;
}
+#ifndef SQLITE_OMIT_LOCALTIME
/*
** On recent Windows platforms, the localtime_s() function is available
** as part of the "Secure CRT". It is essentially equivalent to
@@ -17009,7 +19166,6 @@ static void clearYMD_HMS_TZ(DateTime *p){
#define HAVE_LOCALTIME_S 1
#endif
-#ifndef SQLITE_OMIT_LOCALTIME
/*
** The following routine implements the rough equivalent of localtime_r()
** using whatever operating-system specific localtime facility that
@@ -17032,14 +19188,14 @@ static int osLocaltime(time_t *t, struct tm *pTm){
#endif
sqlite3_mutex_enter(mutex);
pX = localtime(t);
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
#endif
if( pX ) *pTm = *pX;
sqlite3_mutex_leave(mutex);
rc = pX==0;
#else
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
#endif
#if HAVE_LOCALTIME_R
@@ -17110,7 +19266,9 @@ static sqlite3_int64 localtimeOffset(
y.validYMD = 1;
y.validHMS = 1;
y.validJD = 0;
+ y.rawS = 0;
y.validTZ = 0;
+ y.isError = 0;
computeJD(&y);
*pRc = SQLITE_OK;
return y.iJD - x.iJD;
@@ -17118,6 +19276,29 @@ static sqlite3_int64 localtimeOffset(
#endif /* SQLITE_OMIT_LOCALTIME */
/*
+** The following table defines various date transformations of the form
+**
+** 'NNN days'
+**
+** Where NNN is an arbitrary floating-point number and "days" can be one
+** of several units of time.
+*/
+static const struct {
+ u8 eType; /* Transformation type code */
+ u8 nName; /* Length of th name */
+ char *zName; /* Name of the transformation */
+ double rLimit; /* Maximum NNN value for this transform */
+ double rXform; /* Constant used for this transform */
+} aXformType[] = {
+ { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) },
+ { 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) },
+ { 0, 4, "hour", 128963628.0, 86400000.0/24.0 },
+ { 0, 3, "day", 5373485.0, 86400000.0 },
+ { 1, 5, "month", 176546.0, 30.0*86400000.0 },
+ { 2, 4, "year", 14713.0, 365.0*86400000.0 },
+};
+
+/*
** Process a modifier to a date-time stamp. The modifiers are
** as follows:
**
@@ -17141,17 +19322,15 @@ static sqlite3_int64 localtimeOffset(
** to context pCtx. If the error is an unrecognized modifier, no error is
** written to pCtx.
*/
-static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
+static int parseModifier(
+ sqlite3_context *pCtx, /* Function context */
+ const char *z, /* The text of the modifier */
+ int n, /* Length of zMod in bytes */
+ DateTime *p /* The date/time value to be modified */
+){
int rc = 1;
- int n;
double r;
- char *z, zBuf[30];
- z = zBuf;
- for(n=0; n<ArraySize(zBuf)-1 && zMod[n]; n++){
- z[n] = (char)sqlite3UpperToLower[(u8)zMod[n]];
- }
- z[n] = 0;
- switch( z[0] ){
+ switch(sqlite3UpperToLower[(u8)z[0]] ){
#ifndef SQLITE_OMIT_LOCALTIME
case 'l': {
/* localtime
@@ -17159,7 +19338,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** Assuming the current time value is UTC (a.k.a. GMT), shift it to
** show local time.
*/
- if( strcmp(z, "localtime")==0 ){
+ if( sqlite3_stricmp(z, "localtime")==0 ){
computeJD(p);
p->iJD += localtimeOffset(p, pCtx, &rc);
clearYMD_HMS_TZ(p);
@@ -17171,16 +19350,21 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
/*
** unixepoch
**
- ** Treat the current value of p->iJD as the number of
+ ** Treat the current value of p->s as the number of
** seconds since 1970. Convert to a real julian day number.
*/
- if( strcmp(z, "unixepoch")==0 && p->validJD ){
- p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000;
- clearYMD_HMS_TZ(p);
- rc = 0;
+ if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
+ r = p->s*1000.0 + 210866760000000.0;
+ if( r>=0.0 && r<464269060800000.0 ){
+ clearYMD_HMS_TZ(p);
+ p->iJD = (sqlite3_int64)r;
+ p->validJD = 1;
+ p->rawS = 0;
+ rc = 0;
+ }
}
#ifndef SQLITE_OMIT_LOCALTIME
- else if( strcmp(z, "utc")==0 ){
+ else if( sqlite3_stricmp(z, "utc")==0 ){
if( p->tzSet==0 ){
sqlite3_int64 c1;
computeJD(p);
@@ -17206,7 +19390,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** weekday N where 0==Sunday, 1==Monday, and so forth. If the
** date is already on the appropriate weekday, this is a no-op.
*/
- if( strncmp(z, "weekday ", 8)==0
+ if( sqlite3_strnicmp(z, "weekday ", 8)==0
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
&& (n=(int)r)==r && n>=0 && r<7 ){
sqlite3_int64 Z;
@@ -17229,7 +19413,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
** Move the date backwards to the beginning of the current day,
** or month or year.
*/
- if( strncmp(z, "start of ", 9)!=0 ) break;
+ if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
z += 9;
computeYMD(p);
p->validHMS = 1;
@@ -17237,15 +19421,15 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
p->s = 0.0;
p->validTZ = 0;
p->validJD = 0;
- if( strcmp(z,"month")==0 ){
+ if( sqlite3_stricmp(z,"month")==0 ){
p->D = 1;
rc = 0;
- }else if( strcmp(z,"year")==0 ){
+ }else if( sqlite3_stricmp(z,"year")==0 ){
computeYMD(p);
p->M = 1;
p->D = 1;
rc = 0;
- }else if( strcmp(z,"day")==0 ){
+ }else if( sqlite3_stricmp(z,"day")==0 ){
rc = 0;
}
break;
@@ -17263,6 +19447,7 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
case '8':
case '9': {
double rRounder;
+ int i;
for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
rc = 1;
@@ -17291,46 +19476,48 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
rc = 0;
break;
}
+
+ /* If control reaches this point, it means the transformation is
+ ** one of the forms like "+NNN days". */
z += n;
while( sqlite3Isspace(*z) ) z++;
n = sqlite3Strlen30(z);
if( n>10 || n<3 ) break;
- if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
+ if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
computeJD(p);
- rc = 0;
+ rc = 1;
rRounder = r<0 ? -0.5 : +0.5;
- if( n==3 && strcmp(z,"day")==0 ){
- p->iJD += (sqlite3_int64)(r*86400000.0 + rRounder);
- }else if( n==4 && strcmp(z,"hour")==0 ){
- p->iJD += (sqlite3_int64)(r*(86400000.0/24.0) + rRounder);
- }else if( n==6 && strcmp(z,"minute")==0 ){
- p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0)) + rRounder);
- }else if( n==6 && strcmp(z,"second")==0 ){
- p->iJD += (sqlite3_int64)(r*(86400000.0/(24.0*60.0*60.0)) + rRounder);
- }else if( n==5 && strcmp(z,"month")==0 ){
- int x, y;
- computeYMD_HMS(p);
- p->M += (int)r;
- x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
- p->Y += x;
- p->M -= x*12;
- p->validJD = 0;
- computeJD(p);
- y = (int)r;
- if( y!=r ){
- p->iJD += (sqlite3_int64)((r - y)*30.0*86400000.0 + rRounder);
- }
- }else if( n==4 && strcmp(z,"year")==0 ){
- int y = (int)r;
- computeYMD_HMS(p);
- p->Y += y;
- p->validJD = 0;
- computeJD(p);
- if( y!=r ){
- p->iJD += (sqlite3_int64)((r - y)*365.0*86400000.0 + rRounder);
+ for(i=0; i<ArraySize(aXformType); i++){
+ if( aXformType[i].nName==n
+ && sqlite3_strnicmp(aXformType[i].zName, z, n)==0
+ && r>-aXformType[i].rLimit && r<aXformType[i].rLimit
+ ){
+ switch( aXformType[i].eType ){
+ case 1: { /* Special processing to add months */
+ int x;
+ computeYMD_HMS(p);
+ p->M += (int)r;
+ x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
+ p->Y += x;
+ p->M -= x*12;
+ p->validJD = 0;
+ r -= (int)r;
+ break;
+ }
+ case 2: { /* Special processing to add years */
+ int y = (int)r;
+ computeYMD_HMS(p);
+ p->Y += y;
+ p->validJD = 0;
+ r -= (int)r;
+ break;
+ }
+ }
+ computeJD(p);
+ p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder);
+ rc = 0;
+ break;
}
- }else{
- rc = 1;
}
clearYMD_HMS_TZ(p);
break;
@@ -17357,7 +19544,7 @@ static int isDate(
sqlite3_value **argv,
DateTime *p
){
- int i;
+ int i, n;
const unsigned char *z;
int eType;
memset(p, 0, sizeof(*p));
@@ -17366,8 +19553,7 @@ static int isDate(
}
if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
|| eType==SQLITE_INTEGER ){
- p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
- p->validJD = 1;
+ setRawDateNumber(p, sqlite3_value_double(argv[0]));
}else{
z = sqlite3_value_text(argv[0]);
if( !z || parseDateOrTime(context, (char*)z, p) ){
@@ -17376,8 +19562,11 @@ static int isDate(
}
for(i=1; i<argc; i++){
z = sqlite3_value_text(argv[i]);
- if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
+ n = sqlite3_value_bytes(argv[i]);
+ if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1;
}
+ computeJD(p);
+ if( p->isError || !validJulianDay(p->iJD) ) return 1;
return 0;
}
@@ -17676,7 +19865,6 @@ static void currentTimeFunc(
){
time_t t;
char *zFormat = (char *)sqlite3_user_data(context);
- sqlite3 *db;
sqlite3_int64 iT;
struct tm *pTm;
struct tm sNow;
@@ -17709,7 +19897,7 @@ static void currentTimeFunc(
** external linkage.
*/
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
- static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
+ static FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS
DFUNCTION(julianday, -1, 0, 0, juliandayFunc ),
DFUNCTION(date, -1, 0, 0, dateFunc ),
@@ -17725,13 +19913,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
STR_FUNCTION(current_timestamp, 0, "%Y-%m-%d %H:%M:%S", 0, currentTimeFunc),
#endif
};
- int i;
- FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
- FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aDateTimeFuncs);
-
- for(i=0; i<ArraySize(aDateTimeFuncs); i++){
- sqlite3FuncDefInsert(pHash, &aFunc[i]);
- }
+ sqlite3InsertBuiltinFuncs(aDateTimeFuncs, ArraySize(aDateTimeFuncs));
}
/************** End of date.c ************************************************/
@@ -17751,9 +19933,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
** This file contains OS interface code that is common to all
** architectures.
*/
-#define _SQLITE_OS_C_ 1
/* #include "sqliteInt.h" */
-#undef _SQLITE_OS_C_
/*
** If we compile with the SQLITE_TEST macro set, then the following block
@@ -17804,9 +19984,9 @@ SQLITE_API int sqlite3_open_file_count = 0;
#if defined(SQLITE_TEST)
SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
#define DO_OS_MALLOC_TEST(x) \
- if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3IsMemJournal(x))) { \
+ if (sqlite3_memdebug_vfs_oom_test && (!x || !sqlite3JournalIsInMemory(x))) { \
void *pTstAlloc = sqlite3Malloc(10); \
- if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \
+ if (!pTstAlloc) return SQLITE_IOERR_NOMEM_BKPT; \
sqlite3_free(pTstAlloc); \
}
#else
@@ -17819,13 +19999,11 @@ SQLITE_API int sqlite3_memdebug_vfs_oom_test = 1;
** of this would be completely automatic if SQLite were coded using
** C++ instead of plain old C.
*/
-SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file *pId){
- int rc = SQLITE_OK;
+SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file *pId){
if( pId->pMethods ){
- rc = pId->pMethods->xClose(pId);
+ pId->pMethods->xClose(pId);
pId->pMethods = 0;
}
- return rc;
}
SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){
DO_OS_MALLOC_TEST(id);
@@ -18000,6 +20178,9 @@ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufO
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
}
+SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs *pVfs){
+ return pVfs->xGetLastError ? pVfs->xGetLastError(pVfs, 0, 0) : 0;
+}
SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
int rc;
/* IMPLEMENTATION-OF: R-49045-42493 SQLite will use the xCurrentTimeInt64()
@@ -18025,7 +20206,7 @@ SQLITE_PRIVATE int sqlite3OsOpenMalloc(
int flags,
int *pOutFlags
){
- int rc = SQLITE_NOMEM;
+ int rc;
sqlite3_file *pFile;
pFile = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile);
if( pFile ){
@@ -18035,15 +20216,15 @@ SQLITE_PRIVATE int sqlite3OsOpenMalloc(
}else{
*ppFile = pFile;
}
+ }else{
+ rc = SQLITE_NOMEM_BKPT;
}
return rc;
}
-SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){
- int rc = SQLITE_OK;
+SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){
assert( pFile );
- rc = sqlite3OsClose(pFile);
+ sqlite3OsClose(pFile);
sqlite3_free(pFile);
- return rc;
}
/*
@@ -18054,7 +20235,7 @@ SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *pFile){
*/
SQLITE_PRIVATE int sqlite3OsInit(void){
void *p = sqlite3_malloc(10);
- if( p==0 ) return SQLITE_NOMEM;
+ if( p==0 ) return SQLITE_NOMEM_BKPT;
sqlite3_free(p);
return sqlite3_os_init();
}
@@ -18069,7 +20250,7 @@ static sqlite3_vfs * SQLITE_WSD vfsList = 0;
** Locate a VFS by name. If no name is given, simply return the
** first VFS on the list.
*/
-SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfs){
+SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
sqlite3_vfs *pVfs = 0;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex;
@@ -18115,7 +20296,7 @@ static void vfsUnlink(sqlite3_vfs *pVfs){
** VFS multiple times. The new VFS becomes the default if makeDflt is
** true.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
+SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
MUTEX_LOGIC(sqlite3_mutex *mutex;)
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
@@ -18143,7 +20324,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDf
/*
** Unregister a VFS so that it is no longer accessible.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
+SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
@@ -18183,7 +20364,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
/* #include "sqliteInt.h" */
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
/*
** Global variables.
@@ -18241,7 +20422,7 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void){
}
}
-#endif /* #ifndef SQLITE_OMIT_BUILTIN_TEST */
+#endif /* #ifndef SQLITE_UNTESTABLE */
/************** End of fault.c ***********************************************/
/************** Begin file mem0.c ********************************************/
@@ -20494,7 +22675,7 @@ SQLITE_PRIVATE int sqlite3MutexEnd(void){
/*
** Retrieve a pointer to a static mutex or allocate a new dynamic one.
*/
-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int id){
+SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
if( id>SQLITE_MUTEX_RECURSIVE && sqlite3MutexInit() ) return 0;
@@ -20515,7 +22696,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MutexAlloc(int id){
/*
** Free a dynamic mutex.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
+SQLITE_API void sqlite3_mutex_free(sqlite3_mutex *p){
if( p ){
assert( sqlite3GlobalConfig.mutex.xMutexFree );
sqlite3GlobalConfig.mutex.xMutexFree(p);
@@ -20526,7 +22707,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex *p){
** Obtain the mutex p. If some other thread already has the mutex, block
** until it can be obtained.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
+SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
if( p ){
assert( sqlite3GlobalConfig.mutex.xMutexEnter );
sqlite3GlobalConfig.mutex.xMutexEnter(p);
@@ -20537,7 +22718,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex *p){
** Obtain the mutex p. If successful, return SQLITE_OK. Otherwise, if another
** thread holds the mutex and it cannot be obtained, return SQLITE_BUSY.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
+SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
int rc = SQLITE_OK;
if( p ){
assert( sqlite3GlobalConfig.mutex.xMutexTry );
@@ -20552,7 +22733,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex *p){
** is not currently entered. If a NULL pointer is passed as an argument
** this function is a no-op.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
+SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex *p){
if( p ){
assert( sqlite3GlobalConfig.mutex.xMutexLeave );
sqlite3GlobalConfig.mutex.xMutexLeave(p);
@@ -20564,11 +22745,11 @@ SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex *p){
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex *p){
+SQLITE_API int sqlite3_mutex_held(sqlite3_mutex *p){
assert( p==0 || sqlite3GlobalConfig.mutex.xMutexHeld );
return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex *p){
+SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
assert( p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld );
return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p);
}
@@ -21265,8 +23446,8 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
** This file contains inline asm code for retrieving "high-performance"
** counters for x86 class CPUs.
*/
-#ifndef _HWTIME_H_
-#define _HWTIME_H_
+#ifndef SQLITE_HWTIME_H
+#define SQLITE_HWTIME_H
/*
** The following routine only works on pentium-class (or newer) processors.
@@ -21334,7 +23515,7 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
#endif
-#endif /* !defined(_HWTIME_H_) */
+#endif /* !defined(SQLITE_HWTIME_H) */
/************** End of hwtime.h **********************************************/
/************** Continuing where we left off in os_common.h ******************/
@@ -21424,8 +23605,8 @@ SQLITE_API extern int sqlite3_open_file_count;
**
** This file contains code that is specific to Windows.
*/
-#ifndef _OS_WIN_H_
-#define _OS_WIN_H_
+#ifndef SQLITE_OS_WIN_H
+#define SQLITE_OS_WIN_H
/*
** Include the primary Windows SDK header file.
@@ -21497,7 +23678,7 @@ SQLITE_API extern int sqlite3_open_file_count;
# define SQLITE_OS_WIN_THREADS 0
#endif
-#endif /* _OS_WIN_H_ */
+#endif /* SQLITE_OS_WIN_H */
/************** End of os_win.h **********************************************/
/************** Continuing where we left off in mutex_w32.c ******************/
@@ -21600,8 +23781,8 @@ static int winMutex_isNt = -1; /* <0 means "need to query" */
*/
static LONG SQLITE_WIN32_VOLATILE winMutex_lock = 0;
-SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void); /* os_win.c */
-SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
+SQLITE_API int sqlite3_win32_is_nt(void); /* os_win.c */
+SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
static int winMutexInit(void){
/* The first to increment to 1 does actual initialization */
@@ -21901,7 +24082,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
** held by SQLite. An example of non-essential memory is memory used to
** cache database pages that are not currently in use.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int n){
+SQLITE_API int sqlite3_release_memory(int n){
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
return sqlite3PcacheReleaseMemory(n);
#else
@@ -21960,7 +24141,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3MallocMutex(void){
** that was invoked when memory usage grew too large. Now it is a
** no-op.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
+SQLITE_API int sqlite3_memory_alarm(
void(*xCallback)(void *pArg, sqlite3_int64 used,int N),
void *pArg,
sqlite3_int64 iThreshold
@@ -21976,7 +24157,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_memory_alarm(
** Set the soft heap-size limit for the library. Passing a zero or
** negative value indicates no limit.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 n){
+SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
sqlite3_int64 priorLimit;
sqlite3_int64 excess;
sqlite3_int64 nUsed;
@@ -21998,7 +24179,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64
if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
return priorLimit;
}
-SQLITE_API void SQLITE_STDCALL sqlite3_soft_heap_limit(int n){
+SQLITE_API void sqlite3_soft_heap_limit(int n){
if( n<0 ) n = 0;
sqlite3_soft_heap_limit64(n);
}
@@ -22067,7 +24248,7 @@ SQLITE_PRIVATE void sqlite3MallocEnd(void){
/*
** Return the amount of memory currently checked out.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
+SQLITE_API sqlite3_int64 sqlite3_memory_used(void){
sqlite3_int64 res, mx;
sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, 0);
return res;
@@ -22078,7 +24259,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void){
** checked out since either the beginning of this process
** or since the most recent reset.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag){
+SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
sqlite3_int64 res, mx;
sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &res, &mx, resetFlag);
return mx;
@@ -22158,13 +24339,13 @@ SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
** First make sure the memory subsystem is initialized, then do the
** allocation.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int n){
+SQLITE_API void *sqlite3_malloc(int n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
return n<=0 ? 0 : sqlite3Malloc(n);
}
-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64 n){
+SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
@@ -22307,7 +24488,7 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
return db->lookaside.sz;
}
}
-SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){
+SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return p ? sqlite3GlobalConfig.m.xSize(p) : 0;
@@ -22316,7 +24497,7 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void *p){
/*
** Free memory previously obtained from sqlite3Malloc().
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_free(void *p){
+SQLITE_API void sqlite3_free(void *p){
if( p==0 ) return; /* IMP: R-49053-54554 */
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
@@ -22400,7 +24581,7 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
nDiff = nNew - nOld;
- if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
+ if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
mem0.alarmThreshold-nDiff ){
sqlite3MallocAlarm(nDiff);
}
@@ -22425,14 +24606,14 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
** The public interface to sqlite3Realloc. Make sure that the memory
** subsystem is initialized prior to invoking sqliteRealloc.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void *pOld, int n){
+SQLITE_API void *sqlite3_realloc(void *pOld, int n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
if( n<0 ) n = 0; /* IMP: R-26507-47431 */
return sqlite3Realloc(pOld, n);
}
-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
+SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
#endif
@@ -22607,9 +24788,8 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
if( z==0 ){
return 0;
}
- n = sqlite3Strlen30(z) + 1;
- assert( (n&0x7fffffff)==n );
- zNew = sqlite3DbMallocRaw(db, (int)n);
+ n = strlen(z) + 1;
+ zNew = sqlite3DbMallocRaw(db, n);
if( zNew ){
memcpy(zNew, z, n);
}
@@ -22676,7 +24856,7 @@ SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){
static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
sqlite3OomClear(db);
sqlite3Error(db, SQLITE_NOMEM);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
/*
@@ -22723,26 +24903,26 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
-#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
-#define etFLOAT 2 /* Floating point. %f */
-#define etEXP 3 /* Exponentional notation. %e and %E */
-#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
-#define etSIZE 5 /* Return number of characters processed so far. %n */
-#define etSTRING 6 /* Strings. %s */
-#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
-#define etPERCENT 8 /* Percent symbol. %% */
-#define etCHARX 9 /* Characters. %c */
+#define etRADIX 0 /* Integer types. %d, %x, %o, and so forth */
+#define etFLOAT 1 /* Floating point. %f */
+#define etEXP 2 /* Exponentional notation. %e and %E */
+#define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */
+#define etSIZE 4 /* Return number of characters processed so far. %n */
+#define etSTRING 5 /* Strings. %s */
+#define etDYNSTRING 6 /* Dynamically allocated strings. %z */
+#define etPERCENT 7 /* Percent symbol. %% */
+#define etCHARX 8 /* Characters. %c */
/* The rest are extensions, not normally found in printf() */
-#define etSQLESCAPE 10 /* Strings with '\'' doubled. %q */
-#define etSQLESCAPE2 11 /* Strings with '\'' doubled and enclosed in '',
+#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */
+#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */
-#define etTOKEN 12 /* a pointer to a Token structure */
-#define etSRCLIST 13 /* a pointer to a SrcList */
-#define etPOINTER 14 /* The %p conversion */
-#define etSQLESCAPE3 15 /* %w -> Strings with '\"' doubled */
-#define etORDINAL 16 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
+#define etTOKEN 11 /* a pointer to a Token structure */
+#define etSRCLIST 12 /* a pointer to a SrcList */
+#define etPOINTER 13 /* The %p conversion */
+#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */
+#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
-#define etINVALID 0 /* Any unrecognized conversion type */
+#define etINVALID 16 /* Any unrecognized conversion type */
/*
@@ -22897,7 +25077,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
etByte flag_long; /* True if "l" flag is present */
etByte flag_longlong; /* True if the "ll" flag is present */
etByte done; /* Loop termination flag */
- etByte xtype = 0; /* Conversion paradigm */
+ etByte xtype = etINVALID; /* Conversion paradigm */
u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */
u8 useIntern; /* Ok to use internal conversions (ex: %T) */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
@@ -23549,7 +25729,7 @@ SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
assert( p->accError==0 || p->nAlloc==0 );
if( p->nChar+N >= p->nAlloc ){
enlargeAndAppend(p,z,N);
- }else{
+ }else if( N ){
assert( p->zText );
p->nChar += N;
memcpy(&p->zText[p->nChar-N], z, N);
@@ -23569,18 +25749,23 @@ SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum *p, const char *z){
** Return a pointer to the resulting string. Return a NULL
** pointer if any kind of error was encountered.
*/
+static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
+ assert( p->mxAlloc>0 && !isMalloced(p) );
+ p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
+ if( p->zText ){
+ memcpy(p->zText, p->zBase, p->nChar+1);
+ p->printfFlags |= SQLITE_PRINTF_MALLOCED;
+ }else{
+ setStrAccumError(p, STRACCUM_NOMEM);
+ }
+ return p->zText;
+}
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
assert( (p->zText==p->zBase)==!isMalloced(p) );
p->zText[p->nChar] = 0;
if( p->mxAlloc>0 && !isMalloced(p) ){
- p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
- if( p->zText ){
- memcpy(p->zText, p->zBase, p->nChar+1);
- p->printfFlags |= SQLITE_PRINTF_MALLOCED;
- }else{
- setStrAccumError(p, STRACCUM_NOMEM);
- }
+ return strAccumFinishRealloc(p);
}
}
return p->zText;
@@ -23659,7 +25844,7 @@ SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3 *db, const char *zFormat, ...){
** Print into memory obtained from sqlite3_malloc(). Omit the internal
** %-conversion extensions.
*/
-SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap){
+SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char *z;
char zBase[SQLITE_PRINT_BUF_SIZE];
StrAccum acc;
@@ -23683,7 +25868,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char *zFormat, va_list ap
** Print into memory obtained from sqlite3_malloc()(). Omit the internal
** %-conversion extensions.
*/
-SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){
+SQLITE_API char *sqlite3_mprintf(const char *zFormat, ...){
va_list ap;
char *z;
#ifndef SQLITE_OMIT_AUTOINIT
@@ -23708,7 +25893,7 @@ SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char *zFormat, ...){
**
** sqlite3_vsnprintf() is the varargs version.
*/
-SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
+SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_list ap){
StrAccum acc;
if( n<=0 ) return zBuf;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -23720,9 +25905,10 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int n, char *zBuf, const char
#endif
sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
sqlite3VXPrintf(&acc, zFormat, ap);
- return sqlite3StrAccumFinish(&acc);
+ zBuf[acc.nChar] = 0;
+ return zBuf;
}
-SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
+SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z;
va_list ap;
va_start(ap,zFormat);
@@ -23758,7 +25944,7 @@ static void renderLogMsg(int iErrCode, const char *zFormat, va_list ap){
/*
** Format and write a message to the log if logging is enabled.
*/
-SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...){
+SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
va_list ap; /* Vararg list */
if( sqlite3GlobalConfig.xLog ){
va_start(ap, zFormat);
@@ -23868,6 +26054,7 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
va_start(ap, zFormat);
sqlite3VXPrintf(&acc, zFormat, ap);
va_end(ap);
+ assert( acc.nChar>0 );
if( zBuf[acc.nChar-1]!='\n' ) sqlite3StrAccumAppend(&acc, "\n", 1);
sqlite3StrAccumFinish(&acc);
fprintf(stdout,"%s", zBuf);
@@ -23923,7 +26110,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m
/*
-** Generate a human-readable description of a the Select object.
+** Generate a human-readable description of a Select object.
*/
SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
int n = 0;
@@ -23935,9 +26122,10 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
sqlite3TreeViewPush(pView, 1);
}
do{
- sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x",
+ sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
- ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags
+ ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
+ (int)p->nSelectRow
);
if( cnt++ ) sqlite3TreeViewPop(pView);
if( p->pPrior ){
@@ -24141,6 +26329,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
case TK_ISNULL: zUniOp = "ISNULL"; break;
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
+ case TK_SPAN: {
+ sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken);
+ sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
+ break;
+ }
+
case TK_COLLATE: {
sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken);
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
@@ -24241,6 +26435,21 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
break;
}
#endif
+ case TK_MATCH: {
+ sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s",
+ pExpr->iTable, pExpr->iColumn, zFlgs);
+ sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
+ break;
+ }
+ case TK_VECTOR: {
+ sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR");
+ break;
+ }
+ case TK_SELECT_COLUMN: {
+ sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn);
+ sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0);
+ break;
+ }
default: {
sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
break;
@@ -24257,21 +26466,20 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
sqlite3TreeViewPop(pView);
}
+
/*
** Generate a human-readable explanation of an expression list.
*/
-SQLITE_PRIVATE void sqlite3TreeViewExprList(
+SQLITE_PRIVATE void sqlite3TreeViewBareExprList(
TreeView *pView,
const ExprList *pList,
- u8 moreToFollow,
const char *zLabel
){
- int i;
- pView = sqlite3TreeViewPush(pView, moreToFollow);
if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
if( pList==0 ){
sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
}else{
+ int i;
sqlite3TreeViewLine(pView, "%s", zLabel);
for(i=0; i<pList->nExpr; i++){
int j = pList->a[i].u.x.iOrderByCol;
@@ -24283,6 +26491,15 @@ SQLITE_PRIVATE void sqlite3TreeViewExprList(
if( j ) sqlite3TreeViewPop(pView);
}
}
+}
+SQLITE_PRIVATE void sqlite3TreeViewExprList(
+ TreeView *pView,
+ const ExprList *pList,
+ u8 moreToFollow,
+ const char *zLabel
+){
+ pView = sqlite3TreeViewPush(pView, moreToFollow);
+ sqlite3TreeViewBareExprList(pView, pList, zLabel);
sqlite3TreeViewPop(pView);
}
@@ -24322,7 +26539,7 @@ static SQLITE_WSD struct sqlite3PrngType {
/*
** Return N random bytes.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){
+SQLITE_API void sqlite3_randomness(int N, void *pBuf){
unsigned char t;
unsigned char *zBuf = pBuf;
@@ -24398,7 +26615,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *pBuf){
sqlite3_mutex_leave(mutex);
}
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
/*
** For testing purposes, we sometimes want to preserve the state of
** PRNG and restore the PRNG to its saved state at a later time, or
@@ -24423,7 +26640,7 @@ SQLITE_PRIVATE void sqlite3PrngRestoreState(void){
sizeof(sqlite3Prng)
);
}
-#endif /* SQLITE_OMIT_BUILTIN_TEST */
+#endif /* SQLITE_UNTESTABLE */
/************** End of random.c **********************************************/
/************** Begin file threads.c *****************************************/
@@ -24492,7 +26709,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
- if( p==0 ) return SQLITE_NOMEM;
+ if( p==0 ) return SQLITE_NOMEM_BKPT;
memset(p, 0, sizeof(*p));
p->xTask = xTask;
p->pIn = pIn;
@@ -24518,7 +26735,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
int rc;
assert( ppOut!=0 );
- if( NEVER(p==0) ) return SQLITE_NOMEM;
+ if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
if( p->done ){
*ppOut = p->pOut;
rc = SQLITE_OK;
@@ -24583,7 +26800,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
- if( p==0 ) return SQLITE_NOMEM;
+ if( p==0 ) return SQLITE_NOMEM_BKPT;
/* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
** function that returns SQLITE_ERROR when passed the argument 200, that
** forces worker threads to run sequentially and deterministically
@@ -24615,7 +26832,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
BOOL bRc;
assert( ppOut!=0 );
- if( NEVER(p==0) ) return SQLITE_NOMEM;
+ if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
if( p->xTask==0 ){
/* assert( p->id==GetCurrentThreadId() ); */
rc = WAIT_OBJECT_0;
@@ -24663,7 +26880,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
- if( p==0 ) return SQLITE_NOMEM;
+ if( p==0 ) return SQLITE_NOMEM_BKPT;
if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
p->xTask = xTask;
p->pIn = pIn;
@@ -24679,7 +26896,7 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
assert( ppOut!=0 );
- if( NEVER(p==0) ) return SQLITE_NOMEM;
+ if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
if( p->xTask ){
*ppOut = p->xTask(p->pIn);
}else{
@@ -24690,7 +26907,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
#if defined(SQLITE_TEST)
{
void *pTstAlloc = sqlite3Malloc(10);
- if (!pTstAlloc) return SQLITE_NOMEM;
+ if (!pTstAlloc) return SQLITE_NOMEM_BKPT;
sqlite3_free(pTstAlloc);
}
#endif
@@ -24937,7 +27154,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
rc = sqlite3VdbeMemMakeWriteable(pMem);
if( rc!=SQLITE_OK ){
assert( rc==SQLITE_NOMEM );
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
zIn = (u8*)pMem->z;
zTerm = &zIn[pMem->n&~1];
@@ -24979,7 +27196,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
zTerm = &zIn[pMem->n];
zOut = sqlite3DbMallocRaw(pMem->db, len);
if( !zOut ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
z = zOut;
@@ -25281,7 +27498,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int x){
** Return whatever integer value the test callback returns, or return
** SQLITE_OK if no test callback is installed.
*/
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
SQLITE_PRIVATE int sqlite3FaultSim(int iTest){
int (*xCallback)(int) = sqlite3GlobalConfig.xTestCallback;
return xCallback ? xCallback(iTest) : SQLITE_OK;
@@ -25349,12 +27566,48 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
}
/*
+** Return the declared type of a column. Or return zDflt if the column
+** has no declared type.
+**
+** The column type is an extra string stored after the zero-terminator on
+** the column name if and only if the COLFLAG_HASTYPE flag is set.
+*/
+SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){
+ if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt;
+ return pCol->zName + strlen(pCol->zName) + 1;
+}
+
+/*
+** Helper function for sqlite3Error() - called rarely. Broken out into
+** a separate routine to avoid unnecessary register saves on entry to
+** sqlite3Error().
+*/
+static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){
+ if( db->pErr ) sqlite3ValueSetNull(db->pErr);
+ sqlite3SystemError(db, err_code);
+}
+
+/*
** Set the current error code to err_code and clear any prior error message.
+** Also set iSysErrno (by calling sqlite3System) if the err_code indicates
+** that would be appropriate.
*/
SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){
assert( db!=0 );
db->errCode = err_code;
- if( db->pErr ) sqlite3ValueSetNull(db->pErr);
+ if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code);
+}
+
+/*
+** Load the sqlite3.iSysErrno field if that is an appropriate thing
+** to do based on the SQLite error code in rc.
+*/
+SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){
+ if( rc==SQLITE_IOERR_NOMEM ) return;
+ rc &= 0xff;
+ if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
+ db->iSysErrno = sqlite3OsGetLastError(db->pVfs);
+ }
}
/*
@@ -25381,6 +27634,7 @@ SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){
assert( db!=0 );
db->errCode = err_code;
+ sqlite3SystemError(db, err_code);
if( zFormat==0 ){
sqlite3Error(db, err_code);
}else if( db->pErr || (db->pErr = sqlite3ValueNew(db))!=0 ){
@@ -25444,18 +27698,13 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
** brackets from around identifiers. For example: "[a-b-c]" becomes
** "a-b-c".
*/
-SQLITE_PRIVATE int sqlite3Dequote(char *z){
+SQLITE_PRIVATE void sqlite3Dequote(char *z){
char quote;
int i, j;
- if( z==0 ) return -1;
+ if( z==0 ) return;
quote = z[0];
- switch( quote ){
- case '\'': break;
- case '"': break;
- case '`': break; /* For MySQL compatibility */
- case '[': quote = ']'; break; /* For MS SqlServer compatibility */
- default: return -1;
- }
+ if( !sqlite3Isquote(quote) ) return;
+ if( quote=='[' ) quote = ']';
for(i=1, j=0;; i++){
assert( z[i] );
if( z[i]==quote ){
@@ -25470,7 +27719,6 @@ SQLITE_PRIVATE int sqlite3Dequote(char *z){
}
}
z[j] = 0;
- return j;
}
/*
@@ -25494,19 +27742,28 @@ SQLITE_PRIVATE void sqlite3TokenInit(Token *p, char *z){
** case-independent fashion, using the same definition of "case
** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *zLeft, const char *zRight){
- register unsigned char *a, *b;
+SQLITE_API int sqlite3_stricmp(const char *zLeft, const char *zRight){
if( zLeft==0 ){
return zRight ? -1 : 0;
}else if( zRight==0 ){
return 1;
}
+ return sqlite3StrICmp(zLeft, zRight);
+}
+SQLITE_PRIVATE int sqlite3StrICmp(const char *zLeft, const char *zRight){
+ unsigned char *a, *b;
+ int c;
a = (unsigned char *)zLeft;
b = (unsigned char *)zRight;
- while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
- return UpperToLower[*a] - UpperToLower[*b];
+ for(;;){
+ c = (int)UpperToLower[*a] - (int)UpperToLower[*b];
+ if( c || *a==0 ) break;
+ a++;
+ b++;
+ }
+ return c;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
+SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
register unsigned char *a, *b;
if( zLeft==0 ){
return zRight ? -1 : 0;
@@ -25554,7 +27811,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
int eValid = 1; /* True exponent is either not used or is well-formed */
double result;
int nDigits = 0;
- int nonNum = 0;
+ int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
*pResult = 0.0; /* Default return value, in case of an error */
@@ -25567,7 +27824,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
for(i=3-enc; i<length && z[i]==0; i+=2){}
nonNum = i<length;
- zEnd = z+i+enc-3;
+ zEnd = &z[i^1];
z += (enc&1);
}
@@ -25583,9 +27840,6 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
z+=incr;
}
- /* skip leading zeroes */
- while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++;
-
/* copy max significant digits to significand */
while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
s = s*10 + (*z - '0');
@@ -25602,12 +27856,13 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
z+=incr;
/* copy digits from after decimal to significand
** (decrease exponent by d to shift decimal right) */
- while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
- s = s*10 + (*z - '0');
- z+=incr, nDigits++, d--;
+ while( z<zEnd && sqlite3Isdigit(*z) ){
+ if( s<((LARGEST_INT64-9)/10) ){
+ s = s*10 + (*z - '0');
+ d--;
+ }
+ z+=incr, nDigits++;
}
- /* skip non-significant digits */
- while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
}
if( z>=zEnd ) goto do_atof_calc;
@@ -25615,7 +27870,12 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
if( *z=='e' || *z=='E' ){
z+=incr;
eValid = 0;
- if( z>=zEnd ) goto do_atof_calc;
+
+ /* This branch is needed to avoid a (harmless) buffer overread. The
+ ** special comment alerts the mutation tester that the correct answer
+ ** is obtained even if the branch is omitted */
+ if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/
+
/* get sign of exponent */
if( *z=='-' ){
esign = -1;
@@ -25632,9 +27892,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
}
/* skip trailing spaces */
- if( nDigits && eValid ){
- while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
- }
+ while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
do_atof_calc:
/* adjust exponent by d, and update sign */
@@ -25646,41 +27904,51 @@ do_atof_calc:
esign = 1;
}
- /* if 0 significand */
- if( !s ) {
- /* In the IEEE 754 standard, zero is signed.
- ** Add the sign if we've seen at least one digit */
- result = (sign<0 && nDigits) ? -(double)0 : (double)0;
+ if( s==0 ) {
+ /* In the IEEE 754 standard, zero is signed. */
+ result = sign<0 ? -(double)0 : (double)0;
} else {
- /* attempt to reduce exponent */
- if( esign>0 ){
- while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10;
- }else{
- while( !(s%10) && e>0 ) e--,s/=10;
+ /* Attempt to reduce exponent.
+ **
+ ** Branches that are not required for the correct answer but which only
+ ** help to obtain the correct answer faster are marked with special
+ ** comments, as a hint to the mutation tester.
+ */
+ while( e>0 ){ /*OPTIMIZATION-IF-TRUE*/
+ if( esign>0 ){
+ if( s>=(LARGEST_INT64/10) ) break; /*OPTIMIZATION-IF-FALSE*/
+ s *= 10;
+ }else{
+ if( s%10!=0 ) break; /*OPTIMIZATION-IF-FALSE*/
+ s /= 10;
+ }
+ e--;
}
/* adjust the sign of significand */
s = sign<0 ? -s : s;
- /* if exponent, scale significand as appropriate
- ** and store in result. */
- if( e ){
+ if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
+ result = (double)s;
+ }else{
LONGDOUBLE_TYPE scale = 1.0;
/* attempt to handle extremely small/large numbers better */
- if( e>307 && e<342 ){
- while( e%308 ) { scale *= 1.0e+1; e -= 1; }
- if( esign<0 ){
- result = s / scale;
- result /= 1.0e+308;
- }else{
- result = s * scale;
- result *= 1.0e+308;
- }
- }else if( e>=342 ){
- if( esign<0 ){
- result = 0.0*s;
- }else{
- result = 1e308*1e308*s; /* Infinity */
+ if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
+ if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
+ while( e%308 ) { scale *= 1.0e+1; e -= 1; }
+ if( esign<0 ){
+ result = s / scale;
+ result /= 1.0e+308;
+ }else{
+ result = s * scale;
+ result *= 1.0e+308;
+ }
+ }else{ assert( e>=342 );
+ if( esign<0 ){
+ result = 0.0*s;
+ }else{
+ result = 1e308*1e308*s; /* Infinity */
+ }
}
}else{
/* 1.0e+22 is the largest power of 10 than can be
@@ -25693,8 +27961,6 @@ do_atof_calc:
result = s * scale;
}
}
- } else {
- result = (double)s;
}
}
@@ -25702,7 +27968,7 @@ do_atof_calc:
*pResult = result;
/* return true if number and no extra non-whitespace chracters after */
- return z>=zEnd && nDigits>0 && eValid && nonNum==0;
+ return z==zEnd && nDigits>0 && eValid && nonNum==0;
#else
return !sqlite3Atoi64(z, pResult, length, enc);
#endif /* SQLITE_OMIT_FLOATING_POINT */
@@ -25764,7 +28030,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
int neg = 0; /* assume positive */
int i;
int c = 0;
- int nonNum = 0;
+ int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */
const char *zStart;
const char *zEnd = zNum + length;
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
@@ -25775,7 +28041,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
for(i=3-enc; i<length && zNum[i]==0; i+=2){}
nonNum = i<length;
- zEnd = zNum+i+enc-3;
+ zEnd = &zNum[i^1];
zNum += (enc&1);
}
while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
@@ -25802,8 +28068,11 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
testcase( i==18 );
testcase( i==19 );
testcase( i==20 );
- if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum)
- || i>19*incr || nonNum ){
+ if( &zNum[i]<zEnd /* Extra bytes at the end */
+ || (i==0 && zStart==zNum) /* No digits */
+ || i>19*incr /* Too many digits */
+ || nonNum /* UTF16 with high-order bytes non-zero */
+ ){
/* zNum is empty or contains non-numeric text or is longer
** than 19 digits (thus guaranteeing that it is too large) */
return 1;
@@ -25845,7 +28114,6 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
#ifndef SQLITE_OMIT_HEX_INTEGER
if( z[0]=='0'
&& (z[1]=='x' || z[1]=='X')
- && sqlite3Isxdigit(z[2])
){
u64 u = 0;
int i, k;
@@ -26315,7 +28583,7 @@ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
*/
SQLITE_PRIVATE int sqlite3VarintLen(u64 v){
int i;
- for(i=1; (v >>= 7)!=0; i++){ assert( i<9 ); }
+ for(i=1; (v >>= 7)!=0; i++){ assert( i<10 ); }
return i;
}
@@ -26346,10 +28614,12 @@ SQLITE_PRIVATE u32 sqlite3Get4byte(const u8 *p){
SQLITE_PRIVATE void sqlite3Put4byte(unsigned char *p, u32 v){
#if SQLITE_BYTEORDER==4321
memcpy(p,&v,4);
-#elif SQLITE_BYTEORDER==1234 && defined(__GNUC__) && GCC_VERSION>=4003000
+#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
+ && defined(__GNUC__) && GCC_VERSION>=4003000
u32 x = __builtin_bswap32(v);
memcpy(p,&x,4);
-#elif SQLITE_BYTEORDER==1234 && defined(_MSC_VER) && _MSC_VER>=1300
+#elif SQLITE_BYTEORDER==1234 && !defined(SQLITE_DISABLE_INTRINSIC) \
+ && defined(_MSC_VER) && _MSC_VER>=1300
u32 x = _byteswap_ulong(v);
memcpy(p,&x,4);
#else
@@ -26491,36 +28761,21 @@ SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
return sqlite3AddInt64(pA, -iB);
}
}
-#define TWOPOWER32 (((i64)1)<<32)
-#define TWOPOWER31 (((i64)1)<<31)
SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
i64 iA = *pA;
- i64 iA1, iA0, iB1, iB0, r;
-
- iA1 = iA/TWOPOWER32;
- iA0 = iA % TWOPOWER32;
- iB1 = iB/TWOPOWER32;
- iB0 = iB % TWOPOWER32;
- if( iA1==0 ){
- if( iB1==0 ){
- *pA *= iB;
- return 0;
- }
- r = iA0*iB1;
- }else if( iB1==0 ){
- r = iA1*iB0;
- }else{
- /* If both iA1 and iB1 are non-zero, overflow will result */
- return 1;
- }
- testcase( r==(-TWOPOWER31)-1 );
- testcase( r==(-TWOPOWER31) );
- testcase( r==TWOPOWER31 );
- testcase( r==TWOPOWER31-1 );
- if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
- r *= TWOPOWER32;
- if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
- *pA = r;
+ if( iB>0 ){
+ if( iA>LARGEST_INT64/iB ) return 1;
+ if( iA<SMALLEST_INT64/iB ) return 1;
+ }else if( iB<0 ){
+ if( iA>0 ){
+ if( iB<SMALLEST_INT64/iA ) return 1;
+ }else if( iA<0 ){
+ if( iB==SMALLEST_INT64 ) return 1;
+ if( iA==SMALLEST_INT64 ) return 1;
+ if( -iA>LARGEST_INT64/-iB ) return 1;
+ }
+ }
+ *pA = iA*iB;
return 0;
}
@@ -26605,7 +28860,7 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){
if( x<2 ) return 0;
while( x<8 ){ y -= 10; x <<= 1; }
}else{
- while( x>255 ){ y += 40; x >>= 4; }
+ while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/
while( x>15 ){ y += 10; x >>= 1; }
}
return a[x&7] + y - 10;
@@ -26628,20 +28883,134 @@ SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
+ defined(SQLITE_ENABLE_STAT3_OR_STAT4) || \
+ defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
/*
** Convert a LogEst into an integer.
+**
+** Note that this routine is only used when one or more of various
+** non-standard compile-time options is enabled.
*/
SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
u64 n;
- if( x<10 ) return 1;
n = x%10;
x /= 10;
if( n>=5 ) n -= 2;
else if( n>=1 ) n -= 1;
- if( x>=3 ){
- return x>60 ? (u64)LARGEST_INT64 : (n+8)<<(x-3);
- }
- return (n+8)>>(3-x);
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
+ defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
+ if( x>60 ) return (u64)LARGEST_INT64;
+#else
+ /* If only SQLITE_ENABLE_STAT3_OR_STAT4 is on, then the largest input
+ ** possible to this routine is 310, resulting in a maximum x of 31 */
+ assert( x<=60 );
+#endif
+ return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x);
+}
+#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */
+
+/*
+** Add a new name/number pair to a VList. This might require that the
+** VList object be reallocated, so return the new VList. If an OOM
+** error occurs, the original VList returned and the
+** db->mallocFailed flag is set.
+**
+** A VList is really just an array of integers. To destroy a VList,
+** simply pass it to sqlite3DbFree().
+**
+** The first integer is the number of integers allocated for the whole
+** VList. The second integer is the number of integers actually used.
+** Each name/number pair is encoded by subsequent groups of 3 or more
+** integers.
+**
+** Each name/number pair starts with two integers which are the numeric
+** value for the pair and the size of the name/number pair, respectively.
+** The text name overlays one or more following integers. The text name
+** is always zero-terminated.
+**
+** Conceptually:
+**
+** struct VList {
+** int nAlloc; // Number of allocated slots
+** int nUsed; // Number of used slots
+** struct VListEntry {
+** int iValue; // Value for this entry
+** int nSlot; // Slots used by this entry
+** // ... variable name goes here
+** } a[0];
+** }
+**
+** During code generation, pointers to the variable names within the
+** VList are taken. When that happens, nAlloc is set to zero as an
+** indication that the VList may never again be enlarged, since the
+** accompanying realloc() would invalidate the pointers.
+*/
+SQLITE_PRIVATE VList *sqlite3VListAdd(
+ sqlite3 *db, /* The database connection used for malloc() */
+ VList *pIn, /* The input VList. Might be NULL */
+ const char *zName, /* Name of symbol to add */
+ int nName, /* Bytes of text in zName */
+ int iVal /* Value to associate with zName */
+){
+ int nInt; /* number of sizeof(int) objects needed for zName */
+ char *z; /* Pointer to where zName will be stored */
+ int i; /* Index in pIn[] where zName is stored */
+
+ nInt = nName/4 + 3;
+ assert( pIn==0 || pIn[0]>=3 ); /* Verify ok to add new elements */
+ if( pIn==0 || pIn[1]+nInt > pIn[0] ){
+ /* Enlarge the allocation */
+ int nAlloc = (pIn ? pIn[0]*2 : 10) + nInt;
+ VList *pOut = sqlite3DbRealloc(db, pIn, nAlloc*sizeof(int));
+ if( pOut==0 ) return pIn;
+ if( pIn==0 ) pOut[1] = 2;
+ pIn = pOut;
+ pIn[0] = nAlloc;
+ }
+ i = pIn[1];
+ pIn[i] = iVal;
+ pIn[i+1] = nInt;
+ z = (char*)&pIn[i+2];
+ pIn[1] = i+nInt;
+ assert( pIn[1]<=pIn[0] );
+ memcpy(z, zName, nName);
+ z[nName] = 0;
+ return pIn;
+}
+
+/*
+** Return a pointer to the name of a variable in the given VList that
+** has the value iVal. Or return a NULL if there is no such variable in
+** the list
+*/
+SQLITE_PRIVATE const char *sqlite3VListNumToName(VList *pIn, int iVal){
+ int i, mx;
+ if( pIn==0 ) return 0;
+ mx = pIn[1];
+ i = 2;
+ do{
+ if( pIn[i]==iVal ) return (char*)&pIn[i+2];
+ i += pIn[i+1];
+ }while( i<mx );
+ return 0;
+}
+
+/*
+** Return the number of the variable named zName, if it is in VList.
+** or return 0 if there is no such variable.
+*/
+SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nName){
+ int i, mx;
+ if( pIn==0 ) return 0;
+ mx = pIn[1];
+ i = 2;
+ do{
+ const char *z = (const char*)&pIn[i+2];
+ if( strncmp(z,zName,nName)==0 && z[nName]==0 ) return pIn[i];
+ i += pIn[i+1];
+ }while( i<mx );
+ return 0;
}
/************** End of util.c ************************************************/
@@ -26703,8 +29072,12 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash *pH){
static unsigned int strHash(const char *z){
unsigned int h = 0;
unsigned char c;
- while( (c = (unsigned char)*z++)!=0 ){
- h = (h<<3) ^ h ^ sqlite3UpperToLower[c];
+ while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/
+ /* Knuth multiplicative hashing. (Sorting & Searching, p. 510).
+ ** 0x9e3779b1 is 2654435761 which is the closest prime number to
+ ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */
+ h += sqlite3UpperToLower[c];
+ h *= 0x9e3779b1;
}
return h;
}
@@ -26796,7 +29169,7 @@ static HashElem *findElementWithHash(
int count; /* Number of elements left to test */
unsigned int h; /* The computed hash */
- if( pH->ht ){
+ if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
struct _ht *pEntry;
h = strHash(pKey) % pH->htsize;
pEntry = &pH->ht[h];
@@ -26943,150 +29316,150 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 12 */ "VUpdate" OpHelp("data=r[P3@P2]"),
/* 13 */ "Goto" OpHelp(""),
/* 14 */ "Gosub" OpHelp(""),
- /* 15 */ "Return" OpHelp(""),
- /* 16 */ "InitCoroutine" OpHelp(""),
- /* 17 */ "EndCoroutine" OpHelp(""),
- /* 18 */ "Yield" OpHelp(""),
+ /* 15 */ "InitCoroutine" OpHelp(""),
+ /* 16 */ "Yield" OpHelp(""),
+ /* 17 */ "MustBeInt" OpHelp(""),
+ /* 18 */ "Jump" OpHelp(""),
/* 19 */ "Not" OpHelp("r[P2]= !r[P1]"),
- /* 20 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
- /* 21 */ "Halt" OpHelp(""),
- /* 22 */ "Integer" OpHelp("r[P2]=P1"),
- /* 23 */ "Int64" OpHelp("r[P2]=P4"),
- /* 24 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
- /* 25 */ "Null" OpHelp("r[P2..P3]=NULL"),
- /* 26 */ "SoftNull" OpHelp("r[P1]=NULL"),
- /* 27 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
- /* 28 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
- /* 29 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
- /* 30 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
- /* 31 */ "SCopy" OpHelp("r[P2]=r[P1]"),
- /* 32 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
- /* 33 */ "ResultRow" OpHelp("output=r[P1@P2]"),
- /* 34 */ "CollSeq" OpHelp(""),
- /* 35 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"),
- /* 36 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"),
- /* 37 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
- /* 38 */ "MustBeInt" OpHelp(""),
- /* 39 */ "RealAffinity" OpHelp(""),
- /* 40 */ "Cast" OpHelp("affinity(r[P1])"),
- /* 41 */ "Permutation" OpHelp(""),
- /* 42 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
- /* 43 */ "Jump" OpHelp(""),
- /* 44 */ "Once" OpHelp(""),
- /* 45 */ "If" OpHelp(""),
- /* 46 */ "IfNot" OpHelp(""),
- /* 47 */ "Column" OpHelp("r[P3]=PX"),
- /* 48 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
- /* 49 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
- /* 50 */ "Count" OpHelp("r[P2]=count()"),
- /* 51 */ "ReadCookie" OpHelp(""),
- /* 52 */ "SetCookie" OpHelp(""),
- /* 53 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
- /* 54 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
- /* 55 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
- /* 56 */ "OpenAutoindex" OpHelp("nColumn=P2"),
- /* 57 */ "OpenEphemeral" OpHelp("nColumn=P2"),
- /* 58 */ "SorterOpen" OpHelp(""),
- /* 59 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
- /* 60 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
- /* 61 */ "Close" OpHelp(""),
- /* 62 */ "ColumnsUsed" OpHelp(""),
- /* 63 */ "SeekLT" OpHelp("key=r[P3@P4]"),
- /* 64 */ "SeekLE" OpHelp("key=r[P3@P4]"),
- /* 65 */ "SeekGE" OpHelp("key=r[P3@P4]"),
- /* 66 */ "SeekGT" OpHelp("key=r[P3@P4]"),
- /* 67 */ "NoConflict" OpHelp("key=r[P3@P4]"),
- /* 68 */ "NotFound" OpHelp("key=r[P3@P4]"),
- /* 69 */ "Found" OpHelp("key=r[P3@P4]"),
- /* 70 */ "NotExists" OpHelp("intkey=r[P3]"),
- /* 71 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
- /* 72 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
- /* 73 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
- /* 74 */ "NewRowid" OpHelp("r[P2]=rowid"),
- /* 75 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
- /* 76 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
- /* 77 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
- /* 78 */ "Ne" OpHelp("if r[P1]!=r[P3] goto P2"),
- /* 79 */ "Eq" OpHelp("if r[P1]==r[P3] goto P2"),
- /* 80 */ "Gt" OpHelp("if r[P1]>r[P3] goto P2"),
- /* 81 */ "Le" OpHelp("if r[P1]<=r[P3] goto P2"),
- /* 82 */ "Lt" OpHelp("if r[P1]<r[P3] goto P2"),
- /* 83 */ "Ge" OpHelp("if r[P1]>=r[P3] goto P2"),
- /* 84 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
- /* 85 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
- /* 86 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
- /* 87 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
- /* 88 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
- /* 89 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
- /* 90 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
- /* 91 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
- /* 92 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
- /* 93 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
- /* 94 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
- /* 95 */ "Delete" OpHelp(""),
- /* 96 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
+ /* 20 */ "Once" OpHelp(""),
+ /* 21 */ "If" OpHelp(""),
+ /* 22 */ "IfNot" OpHelp(""),
+ /* 23 */ "SeekLT" OpHelp("key=r[P3@P4]"),
+ /* 24 */ "SeekLE" OpHelp("key=r[P3@P4]"),
+ /* 25 */ "SeekGE" OpHelp("key=r[P3@P4]"),
+ /* 26 */ "SeekGT" OpHelp("key=r[P3@P4]"),
+ /* 27 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
+ /* 28 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
+ /* 29 */ "NoConflict" OpHelp("key=r[P3@P4]"),
+ /* 30 */ "NotFound" OpHelp("key=r[P3@P4]"),
+ /* 31 */ "Found" OpHelp("key=r[P3@P4]"),
+ /* 32 */ "SeekRowid" OpHelp("intkey=r[P3]"),
+ /* 33 */ "NotExists" OpHelp("intkey=r[P3]"),
+ /* 34 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
+ /* 35 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
+ /* 36 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
+ /* 37 */ "Eq" OpHelp("IF r[P3]==r[P1]"),
+ /* 38 */ "Gt" OpHelp("IF r[P3]>r[P1]"),
+ /* 39 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
+ /* 40 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
+ /* 41 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
+ /* 42 */ "ElseNotEq" OpHelp(""),
+ /* 43 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
+ /* 44 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
+ /* 45 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
+ /* 46 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
+ /* 47 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
+ /* 48 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
+ /* 49 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
+ /* 50 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
+ /* 51 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
+ /* 52 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
+ /* 53 */ "Last" OpHelp(""),
+ /* 54 */ "BitNot" OpHelp("r[P1]= ~r[P1]"),
+ /* 55 */ "SorterSort" OpHelp(""),
+ /* 56 */ "Sort" OpHelp(""),
+ /* 57 */ "Rewind" OpHelp(""),
+ /* 58 */ "IdxLE" OpHelp("key=r[P3@P4]"),
+ /* 59 */ "IdxGT" OpHelp("key=r[P3@P4]"),
+ /* 60 */ "IdxLT" OpHelp("key=r[P3@P4]"),
+ /* 61 */ "IdxGE" OpHelp("key=r[P3@P4]"),
+ /* 62 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
+ /* 63 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
+ /* 64 */ "Program" OpHelp(""),
+ /* 65 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
+ /* 66 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
+ /* 67 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
+ /* 68 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
+ /* 69 */ "IncrVacuum" OpHelp(""),
+ /* 70 */ "VNext" OpHelp(""),
+ /* 71 */ "Init" OpHelp("Start at P2"),
+ /* 72 */ "Return" OpHelp(""),
+ /* 73 */ "EndCoroutine" OpHelp(""),
+ /* 74 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
+ /* 75 */ "Halt" OpHelp(""),
+ /* 76 */ "Integer" OpHelp("r[P2]=P1"),
+ /* 77 */ "Int64" OpHelp("r[P2]=P4"),
+ /* 78 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
+ /* 79 */ "Null" OpHelp("r[P2..P3]=NULL"),
+ /* 80 */ "SoftNull" OpHelp("r[P1]=NULL"),
+ /* 81 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
+ /* 82 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
+ /* 83 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
+ /* 84 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
+ /* 85 */ "SCopy" OpHelp("r[P2]=r[P1]"),
+ /* 86 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
+ /* 87 */ "ResultRow" OpHelp("output=r[P1@P2]"),
+ /* 88 */ "CollSeq" OpHelp(""),
+ /* 89 */ "Function0" OpHelp("r[P3]=func(r[P2@P5])"),
+ /* 90 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"),
+ /* 91 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
+ /* 92 */ "RealAffinity" OpHelp(""),
+ /* 93 */ "Cast" OpHelp("affinity(r[P1])"),
+ /* 94 */ "Permutation" OpHelp(""),
+ /* 95 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
+ /* 96 */ "Column" OpHelp("r[P3]=PX"),
/* 97 */ "String8" OpHelp("r[P2]='P4'"),
- /* 98 */ "ResetCount" OpHelp(""),
- /* 99 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
- /* 100 */ "SorterData" OpHelp("r[P2]=data"),
- /* 101 */ "RowKey" OpHelp("r[P2]=key"),
- /* 102 */ "RowData" OpHelp("r[P2]=data"),
- /* 103 */ "Rowid" OpHelp("r[P2]=rowid"),
- /* 104 */ "NullRow" OpHelp(""),
- /* 105 */ "Last" OpHelp(""),
- /* 106 */ "SorterSort" OpHelp(""),
- /* 107 */ "Sort" OpHelp(""),
- /* 108 */ "Rewind" OpHelp(""),
- /* 109 */ "SorterInsert" OpHelp(""),
- /* 110 */ "IdxInsert" OpHelp("key=r[P2]"),
- /* 111 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
- /* 112 */ "Seek" OpHelp("Move P3 to P1.rowid"),
- /* 113 */ "IdxRowid" OpHelp("r[P2]=rowid"),
- /* 114 */ "IdxLE" OpHelp("key=r[P3@P4]"),
- /* 115 */ "IdxGT" OpHelp("key=r[P3@P4]"),
- /* 116 */ "IdxLT" OpHelp("key=r[P3@P4]"),
- /* 117 */ "IdxGE" OpHelp("key=r[P3@P4]"),
- /* 118 */ "Destroy" OpHelp(""),
- /* 119 */ "Clear" OpHelp(""),
- /* 120 */ "ResetSorter" OpHelp(""),
- /* 121 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
- /* 122 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
- /* 123 */ "ParseSchema" OpHelp(""),
- /* 124 */ "LoadAnalysis" OpHelp(""),
- /* 125 */ "DropTable" OpHelp(""),
- /* 126 */ "DropIndex" OpHelp(""),
- /* 127 */ "DropTrigger" OpHelp(""),
- /* 128 */ "IntegrityCk" OpHelp(""),
- /* 129 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
- /* 130 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
- /* 131 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
- /* 132 */ "Program" OpHelp(""),
- /* 133 */ "Real" OpHelp("r[P2]=P4"),
- /* 134 */ "Param" OpHelp(""),
- /* 135 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
- /* 136 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
- /* 137 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
- /* 138 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
- /* 139 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
- /* 140 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]-=P3, goto P2"),
- /* 141 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
- /* 142 */ "JumpZeroIncr" OpHelp("if (r[P1]++)==0 ) goto P2"),
- /* 143 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"),
- /* 144 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
- /* 145 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
- /* 146 */ "IncrVacuum" OpHelp(""),
- /* 147 */ "Expire" OpHelp(""),
- /* 148 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
- /* 149 */ "VBegin" OpHelp(""),
- /* 150 */ "VCreate" OpHelp(""),
- /* 151 */ "VDestroy" OpHelp(""),
- /* 152 */ "VOpen" OpHelp(""),
- /* 153 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 154 */ "VNext" OpHelp(""),
- /* 155 */ "VRename" OpHelp(""),
- /* 156 */ "Pagecount" OpHelp(""),
- /* 157 */ "MaxPgcnt" OpHelp(""),
- /* 158 */ "Init" OpHelp("Start at P2"),
+ /* 98 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
+ /* 99 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
+ /* 100 */ "Count" OpHelp("r[P2]=count()"),
+ /* 101 */ "ReadCookie" OpHelp(""),
+ /* 102 */ "SetCookie" OpHelp(""),
+ /* 103 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
+ /* 104 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
+ /* 105 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
+ /* 106 */ "OpenAutoindex" OpHelp("nColumn=P2"),
+ /* 107 */ "OpenEphemeral" OpHelp("nColumn=P2"),
+ /* 108 */ "SorterOpen" OpHelp(""),
+ /* 109 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
+ /* 110 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
+ /* 111 */ "Close" OpHelp(""),
+ /* 112 */ "ColumnsUsed" OpHelp(""),
+ /* 113 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
+ /* 114 */ "NewRowid" OpHelp("r[P2]=rowid"),
+ /* 115 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
+ /* 116 */ "InsertInt" OpHelp("intkey=P3 data=r[P2]"),
+ /* 117 */ "Delete" OpHelp(""),
+ /* 118 */ "ResetCount" OpHelp(""),
+ /* 119 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
+ /* 120 */ "SorterData" OpHelp("r[P2]=data"),
+ /* 121 */ "RowData" OpHelp("r[P2]=data"),
+ /* 122 */ "Rowid" OpHelp("r[P2]=rowid"),
+ /* 123 */ "NullRow" OpHelp(""),
+ /* 124 */ "SorterInsert" OpHelp("key=r[P2]"),
+ /* 125 */ "IdxInsert" OpHelp("key=r[P2]"),
+ /* 126 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
+ /* 127 */ "Seek" OpHelp("Move P3 to P1.rowid"),
+ /* 128 */ "IdxRowid" OpHelp("r[P2]=rowid"),
+ /* 129 */ "Destroy" OpHelp(""),
+ /* 130 */ "Clear" OpHelp(""),
+ /* 131 */ "ResetSorter" OpHelp(""),
+ /* 132 */ "Real" OpHelp("r[P2]=P4"),
+ /* 133 */ "CreateIndex" OpHelp("r[P2]=root iDb=P1"),
+ /* 134 */ "CreateTable" OpHelp("r[P2]=root iDb=P1"),
+ /* 135 */ "ParseSchema" OpHelp(""),
+ /* 136 */ "LoadAnalysis" OpHelp(""),
+ /* 137 */ "DropTable" OpHelp(""),
+ /* 138 */ "DropIndex" OpHelp(""),
+ /* 139 */ "DropTrigger" OpHelp(""),
+ /* 140 */ "IntegrityCk" OpHelp(""),
+ /* 141 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
+ /* 142 */ "Param" OpHelp(""),
+ /* 143 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
+ /* 144 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
+ /* 145 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
+ /* 146 */ "AggStep0" OpHelp("accum=r[P3] step(r[P2@P5])"),
+ /* 147 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
+ /* 148 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
+ /* 149 */ "Expire" OpHelp(""),
+ /* 150 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
+ /* 151 */ "VBegin" OpHelp(""),
+ /* 152 */ "VCreate" OpHelp(""),
+ /* 153 */ "VDestroy" OpHelp(""),
+ /* 154 */ "VOpen" OpHelp(""),
+ /* 155 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 156 */ "VRename" OpHelp(""),
+ /* 157 */ "Pagecount" OpHelp(""),
+ /* 158 */ "MaxPgcnt" OpHelp(""),
/* 159 */ "CursorHint" OpHelp(""),
/* 160 */ "Noop" OpHelp(""),
/* 161 */ "Explain" OpHelp(""),
@@ -27170,6 +29543,19 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
# endif
#endif
+/* Use pread() and pwrite() if they are available */
+#if defined(__APPLE__)
+# define HAVE_PREAD 1
+# define HAVE_PWRITE 1
+#endif
+#if defined(HAVE_PREAD64) && defined(HAVE_PWRITE64)
+# undef USE_PREAD
+# define USE_PREAD64 1
+#elif defined(HAVE_PREAD) && defined(HAVE_PWRITE)
+# undef USE_PREAD64
+# define USE_PREAD 1
+#endif
+
/*
** standard include files.
*/
@@ -27426,8 +29812,8 @@ static pid_t randomnessPid = 0;
** This file contains inline asm code for retrieving "high-performance"
** counters for x86 class CPUs.
*/
-#ifndef _HWTIME_H_
-#define _HWTIME_H_
+#ifndef SQLITE_HWTIME_H
+#define SQLITE_HWTIME_H
/*
** The following routine only works on pentium-class (or newer) processors.
@@ -27495,7 +29881,7 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
#endif
-#endif /* !defined(_HWTIME_H_) */
+#endif /* !defined(SQLITE_HWTIME_H) */
/************** End of hwtime.h **********************************************/
/************** Continuing where we left off in os_common.h ******************/
@@ -27689,7 +30075,7 @@ static struct unix_syscall {
#else
{ "pread64", (sqlite3_syscall_ptr)0, 0 },
#endif
-#define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent)
+#define osPread64 ((ssize_t(*)(int,void*,size_t,off64_t))aSyscall[10].pCurrent)
{ "write", (sqlite3_syscall_ptr)write, 0 },
#define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent)
@@ -27707,7 +30093,7 @@ static struct unix_syscall {
#else
{ "pwrite64", (sqlite3_syscall_ptr)0, 0 },
#endif
-#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
+#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\
aSyscall[13].pCurrent)
{ "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
@@ -28345,7 +30731,14 @@ struct unixFileId {
#if OS_VXWORKS
struct vxworksFileId *pId; /* Unique file ID for vxworks. */
#else
- ino_t ino; /* Inode number */
+ /* We are told that some versions of Android contain a bug that
+ ** sizes ino_t at only 32-bits instead of 64-bits. (See
+ ** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c)
+ ** To work around this, always allocate 64-bits for the inode number.
+ ** On small machines that only have 32-bit inodes, this wastes 4 bytes,
+ ** but that should not be a big deal. */
+ /* WAS: ino_t ino; */
+ u64 ino; /* Inode number */
#endif
};
@@ -28590,7 +30983,7 @@ static int findInodeInfo(
#if OS_VXWORKS
fileId.pId = pFile->pId;
#else
- fileId.ino = statbuf.st_ino;
+ fileId.ino = (u64)statbuf.st_ino;
#endif
pInode = inodeList;
while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){
@@ -28599,7 +30992,7 @@ static int findInodeInfo(
if( pInode==0 ){
pInode = sqlite3_malloc64( sizeof(*pInode) );
if( pInode==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memset(pInode, 0, sizeof(*pInode));
memcpy(&pInode->fileId, &fileId, sizeof(fileId));
@@ -28624,7 +31017,8 @@ static int fileHasMoved(unixFile *pFile){
#else
struct stat buf;
return pFile->pInode!=0 &&
- (osStat(pFile->zPath, &buf)!=0 || buf.st_ino!=pFile->pInode->fileId.ino);
+ (osStat(pFile->zPath, &buf)!=0
+ || (u64)buf.st_ino!=pFile->pInode->fileId.ino);
#endif
}
@@ -28641,12 +31035,16 @@ static int fileHasMoved(unixFile *pFile){
static void verifyDbFile(unixFile *pFile){
struct stat buf;
int rc;
+
+ /* These verifications occurs for the main database only */
+ if( pFile->ctrlFlags & UNIXFILE_NOLOCK ) return;
+
rc = osFstat(pFile->h, &buf);
if( rc!=0 ){
sqlite3_log(SQLITE_WARNING, "cannot fstat db file %s", pFile->zPath);
return;
}
- if( buf.st_nlink==0 && (pFile->ctrlFlags & UNIXFILE_DELETE)==0 ){
+ if( buf.st_nlink==0 ){
sqlite3_log(SQLITE_WARNING, "file unlinked while open: %s", pFile->zPath);
return;
}
@@ -28782,7 +31180,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** lock transitions in terms of the POSIX advisory shared and exclusive
** lock primitives (called read-locks and write-locks below, to avoid
** confusion with SQLite lock names). The algorithms are complicated
- ** slightly in order to be compatible with windows systems simultaneously
+ ** slightly in order to be compatible with Windows95 systems simultaneously
** accessing the same database file, in case that is ever required.
**
** Symbols defined in os.h indentify the 'pending byte' and the 'reserved
@@ -28790,8 +31188,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** range', a range of 510 bytes at a well known offset.
**
** To obtain a SHARED lock, a read-lock is obtained on the 'pending
- ** byte'. If this is successful, a random byte from the 'shared byte
- ** range' is read-locked and the lock on the 'pending byte' released.
+ ** byte'. If this is successful, 'shared byte range' is read-locked
+ ** and the lock on the 'pending byte' released. (Legacy note: When
+ ** SQLite was first developed, Windows95 systems were still very common,
+ ** and Widnows95 lacks a shared-lock capability. So on Windows95, a
+ ** single randomly selected by from the 'shared byte range' is locked.
+ ** Windows95 is now pretty much extinct, but this work-around for the
+ ** lack of shared-locks on Windows95 lives on, for backwards
+ ** compatibility.)
**
** A process may only obtain a RESERVED lock after it has a SHARED lock.
** A RESERVED lock is implemented by grabbing a write-lock on the
@@ -28810,11 +31214,6 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** range'. Since all other locks require a read-lock on one of the bytes
** within this range, this ensures that no other locks are held on the
** database.
- **
- ** The reason a single byte cannot be used instead of the 'shared byte
- ** range' is that some versions of windows do not support read-locks. By
- ** locking a random byte from a range, concurrent SHARED locks may exist
- ** even if the locking primitive used is always a write-lock.
*/
int rc = SQLITE_OK;
unixFile *pFile = (unixFile*)id;
@@ -31519,7 +33918,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
/* Allocate space for the new unixShm object. */
p = sqlite3_malloc64( sizeof(*p) );
- if( p==0 ) return SQLITE_NOMEM;
+ if( p==0 ) return SQLITE_NOMEM_BKPT;
memset(p, 0, sizeof(*p));
assert( pDbFd->pShm==0 );
@@ -31551,7 +33950,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
#endif
pShmNode = sqlite3_malloc64( sizeof(*pShmNode) + nShmFilename );
if( pShmNode==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
}
memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
@@ -31567,10 +33966,12 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
pShmNode->h = -1;
pDbFd->pInode->pShmNode = pShmNode;
pShmNode->pInode = pDbFd->pInode;
- pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
- if( pShmNode->mutex==0 ){
- rc = SQLITE_NOMEM;
- goto shm_open_err;
+ if( sqlite3GlobalConfig.bCoreMutex ){
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->mutex==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ goto shm_open_err;
+ }
}
if( pInode->bProcessLock==0 ){
@@ -31742,7 +34143,7 @@ static int unixShmMap(
pShmNode->apRegion, nReqRegion*sizeof(char *)
);
if( !apNew ){
- rc = SQLITE_IOERR_NOMEM;
+ rc = SQLITE_IOERR_NOMEM_BKPT;
goto shmpage_out;
}
pShmNode->apRegion = apNew;
@@ -31762,7 +34163,7 @@ static int unixShmMap(
}else{
pMem = sqlite3_malloc64(szRegion);
if( pMem==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto shmpage_out;
}
memset(pMem, 0, szRegion);
@@ -32540,7 +34941,7 @@ static int fillInUnixFile(
pNew->pId = vxworksFindFileId(zFilename);
if( pNew->pId==0 ){
ctrlFlags |= UNIXFILE_NOLOCK;
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
#endif
@@ -32596,7 +34997,7 @@ static int fillInUnixFile(
afpLockingContext *pCtx;
pNew->lockingContext = pCtx = sqlite3_malloc64( sizeof(*pCtx) );
if( pCtx==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
/* NB: zFilename exists and remains valid until the file is closed
** according to requirement F11141. So we do not need to make a
@@ -32626,7 +35027,7 @@ static int fillInUnixFile(
nFilename = (int)strlen(zFilename) + 6;
zLockFile = (char *)sqlite3_malloc64(nFilename);
if( zLockFile==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
sqlite3_snprintf(nFilename, zLockFile, "%s" DOTLOCK_SUFFIX, zFilename);
}
@@ -32649,7 +35050,7 @@ static int fillInUnixFile(
if( zSemName[n]=='/' ) zSemName[n] = '_';
pNew->pInode->pSem = sem_open(zSemName, O_CREAT, 0666, 1);
if( pNew->pInode->pSem == SEM_FAILED ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
pNew->pInode->aSemName[0] = '\0';
}
}
@@ -32689,20 +35090,24 @@ static const char *unixTempFileDir(void){
"/tmp",
"."
};
- unsigned int i;
+ unsigned int i = 0;
struct stat buf;
const char *zDir = sqlite3_temp_directory;
if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
- for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
- if( zDir==0 ) continue;
- if( osStat(zDir, &buf) ) continue;
- if( !S_ISDIR(buf.st_mode) ) continue;
- if( osAccess(zDir, 07) ) continue;
- break;
+ while(1){
+ if( zDir!=0
+ && osStat(zDir, &buf)==0
+ && S_ISDIR(buf.st_mode)
+ && osAccess(zDir, 03)==0
+ ){
+ return zDir;
+ }
+ if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break;
+ zDir = azDirs[i++];
}
- return zDir;
+ return 0;
}
/*
@@ -32718,9 +35123,11 @@ static int unixGetTempname(int nBuf, char *zBuf){
** using the io-error infrastructure to test that SQLite handles this
** function failing.
*/
+ zBuf[0] = 0;
SimulateIOError( return SQLITE_IOERR );
zDir = unixTempFileDir();
+ if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
do{
u64 r;
sqlite3_randomness(sizeof(r), &r);
@@ -32783,7 +35190,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
unixEnterMutex();
pInode = inodeList;
while( pInode && (pInode->fileId.dev!=sStat.st_dev
- || pInode->fileId.ino!=sStat.st_ino) ){
+ || pInode->fileId.ino!=(u64)sStat.st_ino) ){
pInode = pInode->pNext;
}
if( pInode ){
@@ -32801,6 +35208,27 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
}
/*
+** Find the mode, uid and gid of file zFile.
+*/
+static int getFileMode(
+ const char *zFile, /* File name */
+ mode_t *pMode, /* OUT: Permissions of zFile */
+ uid_t *pUid, /* OUT: uid of zFile. */
+ gid_t *pGid /* OUT: gid of zFile. */
+){
+ struct stat sStat; /* Output of stat() on database file */
+ int rc = SQLITE_OK;
+ if( 0==osStat(zFile, &sStat) ){
+ *pMode = sStat.st_mode & 0777;
+ *pUid = sStat.st_uid;
+ *pGid = sStat.st_gid;
+ }else{
+ rc = SQLITE_IOERR_FSTAT;
+ }
+ return rc;
+}
+
+/*
** This function is called by unixOpen() to determine the unix permissions
** to create new files with. If no error occurs, then SQLITE_OK is returned
** and a value suitable for passing as the third argument to open(2) is
@@ -32835,7 +35263,6 @@ static int findCreateFileMode(
if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){
char zDb[MAX_PATHNAME+1]; /* Database file path */
int nDb; /* Number of valid bytes in zDb */
- struct stat sStat; /* Output of stat() on database file */
/* zPath is a path to a WAL or journal file. The following block derives
** the path to the associated database file from zPath. This block handles
@@ -32866,15 +35293,18 @@ static int findCreateFileMode(
memcpy(zDb, zPath, nDb);
zDb[nDb] = '\0';
- if( 0==osStat(zDb, &sStat) ){
- *pMode = sStat.st_mode & 0777;
- *pUid = sStat.st_uid;
- *pGid = sStat.st_gid;
- }else{
- rc = SQLITE_IOERR_FSTAT;
- }
+ rc = getFileMode(zDb, pMode, pUid, pGid);
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
*pMode = 0600;
+ }else if( flags & SQLITE_OPEN_URI ){
+ /* If this is a main database file and the file was opened using a URI
+ ** filename, check for the "modeof" parameter. If present, interpret
+ ** its value as a filename and try to copy the mode, uid and gid from
+ ** that file. */
+ const char *z = sqlite3_uri_parameter(zPath, "modeof");
+ if( z ){
+ rc = getFileMode(z, pMode, pUid, pGid);
+ }
}
return rc;
}
@@ -32990,7 +35420,7 @@ static int unixOpen(
}else{
pUnused = sqlite3_malloc64(sizeof(*pUnused));
if( !pUnused ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
}
p->pUnused = pUnused;
@@ -33076,7 +35506,7 @@ static int unixOpen(
zPath = sqlite3_mprintf("%s", zName);
if( zPath==0 ){
robust_close(p, fd, __LINE__);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
#else
osUnlink(zName);
@@ -33087,9 +35517,6 @@ static int unixOpen(
p->openFlags = openFlags;
}
#endif
-
- noLock = eType!=SQLITE_OPEN_MAIN_DB;
-
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
if( fstatfs(fd, &fsInfo) == -1 ){
@@ -33108,6 +35535,7 @@ static int unixOpen(
/* Set up appropriate ctrlFlags */
if( isDelete ) ctrlFlags |= UNIXFILE_DELETE;
if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
+ noLock = eType!=SQLITE_OPEN_MAIN_DB;
if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
@@ -33308,7 +35736,7 @@ static int unixFullPathname(
if( bLink ){
if( zDel==0 ){
zDel = sqlite3_malloc(nOut);
- if( zDel==0 ) rc = SQLITE_NOMEM;
+ if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
}else if( ++nLink>SQLITE_MAX_SYMLINKS ){
rc = SQLITE_CANTOPEN_BKPT;
}
@@ -33546,23 +35974,18 @@ static int unixCurrentTime(sqlite3_vfs *NotUsed, double *prNow){
# define unixCurrentTime 0
#endif
-#ifndef SQLITE_OMIT_DEPRECATED
/*
-** We added the xGetLastError() method with the intention of providing
-** better low-level error messages when operating-system problems come up
-** during SQLite operation. But so far, none of that has been implemented
-** in the core. So this routine is never called. For now, it is merely
-** a place-holder.
+** The xGetLastError() method is designed to return a better
+** low-level error message when operating-system problems come up
+** during SQLite operation. Only the integer return code is currently
+** used.
*/
static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
UNUSED_PARAMETER(NotUsed);
UNUSED_PARAMETER(NotUsed2);
UNUSED_PARAMETER(NotUsed3);
- return 0;
+ return errno;
}
-#else
-# define unixGetLastError 0
-#endif
/*
@@ -33852,7 +36275,7 @@ static int proxyCreateUnixFile(
}else{
pUnused = sqlite3_malloc64(sizeof(*pUnused));
if( !pUnused ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
}
if( fd<0 ){
@@ -33885,7 +36308,7 @@ static int proxyCreateUnixFile(
pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
if( pNew==NULL ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto end_create_proxy;
}
memset(pNew, 0, sizeof(unixFile));
@@ -34298,7 +36721,7 @@ static int proxyTakeConch(unixFile *pFile){
if( tempLockPath ){
pCtx->lockProxyPath = sqlite3DbStrDup(0, tempLockPath);
if( !pCtx->lockProxyPath ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
}
}
@@ -34363,7 +36786,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
** the name of the original database file. */
*pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
if( conchPath==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memcpy(conchPath, dbPath, len+1);
@@ -34479,7 +36902,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
pCtx = sqlite3_malloc64( sizeof(*pCtx) );
if( pCtx==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memset(pCtx, 0, sizeof(*pCtx));
@@ -34515,7 +36938,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
if( rc==SQLITE_OK ){
pCtx->dbPath = sqlite3DbStrDup(0, dbPath);
if( pCtx->dbPath==NULL ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
}
if( rc==SQLITE_OK ){
@@ -34762,7 +37185,7 @@ static int proxyClose(sqlite3_file *id) {
** necessarily been initialized when this routine is called, and so they
** should not be used.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
+SQLITE_API int sqlite3_os_init(void){
/*
** The following macro defines an initializer for an sqlite3_vfs object.
** The name of the VFS is NAME. The pAppData is a pointer to a pointer
@@ -34861,7 +37284,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
** to release dynamically allocated objects. But not on unix.
** This routine is a no-op for unix.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
+SQLITE_API int sqlite3_os_end(void){
return SQLITE_OK;
}
@@ -34949,8 +37372,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
** This file contains inline asm code for retrieving "high-performance"
** counters for x86 class CPUs.
*/
-#ifndef _HWTIME_H_
-#define _HWTIME_H_
+#ifndef SQLITE_HWTIME_H
+#define SQLITE_HWTIME_H
/*
** The following routine only works on pentium-class (or newer) processors.
@@ -35018,7 +37441,7 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
#endif
-#endif /* !defined(_HWTIME_H_) */
+#endif /* !defined(SQLITE_HWTIME_H) */
/************** End of hwtime.h **********************************************/
/************** Continuing where we left off in os_common.h ******************/
@@ -35360,6 +37783,17 @@ struct winFile {
};
/*
+** The winVfsAppData structure is used for the pAppData member for all of the
+** Win32 VFS variants.
+*/
+typedef struct winVfsAppData winVfsAppData;
+struct winVfsAppData {
+ const sqlite3_io_methods *pMethod; /* The file I/O methods to use. */
+ void *pAppData; /* The extra pAppData, if any. */
+ BOOL bNoLock; /* Non-zero if locking is disabled. */
+};
+
+/*
** Allowed values for winFile.ctrlFlags
*/
#define WINFILE_RDONLY 0x02 /* Connection is read only */
@@ -35414,10 +37848,22 @@ struct winFile {
#endif
/*
+ * This is cache size used in the calculation of the initial size of the
+ * Win32-specific heap. It cannot be negative.
+ */
+#ifndef SQLITE_WIN32_CACHE_SIZE
+# if SQLITE_DEFAULT_CACHE_SIZE>=0
+# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE)
+# else
+# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE))
+# endif
+#endif
+
+/*
* The initial size of the Win32-specific heap. This value may be zero.
*/
#ifndef SQLITE_WIN32_HEAP_INIT_SIZE
-# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_DEFAULT_CACHE_SIZE) * \
+# define SQLITE_WIN32_HEAP_INIT_SIZE ((SQLITE_WIN32_CACHE_SIZE) * \
(SQLITE_DEFAULT_PAGE_SIZE) + 4194304)
#endif
@@ -36273,7 +38719,7 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
** "pnLargest" argument, if non-zero, will be used to return the size of the
** largest committed free block in the heap, in bytes.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
+SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){
int rc = SQLITE_OK;
UINT nLargest = 0;
HANDLE hHeap;
@@ -36291,7 +38737,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
if( lastErrno==NO_ERROR ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p",
(void*)hHeap);
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
osGetLastError(), (void*)hHeap);
@@ -36313,12 +38759,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_compact_heap(LPUINT pnLargest){
** the sqlite3_memory_used() function does not return zero, SQLITE_BUSY will
** be returned and no changes will be made to the Win32 native heap.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
+SQLITE_API int sqlite3_win32_reset_heap(){
int rc;
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
- MUTEX_LOGIC( pMaster = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); )
- MUTEX_LOGIC( pMem = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MEM); )
+ MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
+ MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
sqlite3_mutex_enter(pMaster);
sqlite3_mutex_enter(pMem);
winMemAssertMagic();
@@ -36358,11 +38804,17 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_reset_heap(){
** (if available).
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int nBuf){
+SQLITE_API void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */
if( nMin<-1 ) nMin = -1; /* all negative values become -1. */
assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !zBuf ){
+ (void)SQLITE_MISUSE_BKPT;
+ return;
+ }
+#endif
#if defined(SQLITE_WIN32_HAS_ANSI)
if( nMin>0 ){
memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
@@ -36398,7 +38850,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_win32_write_debug(const char *zBuf, int n
static HANDLE sleepObj = NULL;
#endif
-SQLITE_API void SQLITE_STDCALL sqlite3_win32_sleep(DWORD milliseconds){
+SQLITE_API void sqlite3_win32_sleep(DWORD milliseconds){
#if SQLITE_OS_WINRT
if ( sleepObj==NULL ){
sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
@@ -36447,7 +38899,7 @@ SQLITE_PRIVATE DWORD sqlite3Win32Wait(HANDLE hObject){
** This function determines if the machine is running a version of Windows
** based on the NT kernel.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_win32_is_nt(void){
+SQLITE_API int sqlite3_win32_is_nt(void){
#if SQLITE_OS_WINRT
/*
** NOTE: The WinRT sub-platform is always assumed to be based on the NT
@@ -36611,7 +39063,7 @@ static int winMemInit(void *pAppData){
"failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
dwMaximumSize);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pWinMemData->bOwned = TRUE;
assert( pWinMemData->bOwned );
@@ -36621,7 +39073,7 @@ static int winMemInit(void *pAppData){
if( !pWinMemData->hHeap ){
sqlite3_log(SQLITE_NOMEM,
"failed to GetProcessHeap (%lu)", osGetLastError());
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pWinMemData->bOwned = FALSE;
assert( !pWinMemData->bOwned );
@@ -36688,147 +39140,244 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
#endif /* SQLITE_WIN32_MALLOC */
/*
-** Convert a UTF-8 string to Microsoft Unicode (UTF-16?).
+** Convert a UTF-8 string to Microsoft Unicode.
**
-** Space to hold the returned string is obtained from malloc.
+** Space to hold the returned string is obtained from sqlite3_malloc().
*/
-static LPWSTR winUtf8ToUnicode(const char *zFilename){
+static LPWSTR winUtf8ToUnicode(const char *zText){
int nChar;
- LPWSTR zWideFilename;
+ LPWSTR zWideText;
- nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, NULL, 0);
if( nChar==0 ){
return 0;
}
- zWideFilename = sqlite3MallocZero( nChar*sizeof(zWideFilename[0]) );
- if( zWideFilename==0 ){
+ zWideText = sqlite3MallocZero( nChar*sizeof(WCHAR) );
+ if( zWideText==0 ){
return 0;
}
- nChar = osMultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename,
+ nChar = osMultiByteToWideChar(CP_UTF8, 0, zText, -1, zWideText,
nChar);
if( nChar==0 ){
- sqlite3_free(zWideFilename);
- zWideFilename = 0;
+ sqlite3_free(zWideText);
+ zWideText = 0;
}
- return zWideFilename;
+ return zWideText;
}
/*
-** Convert Microsoft Unicode to UTF-8. Space to hold the returned string is
-** obtained from sqlite3_malloc().
+** Convert a Microsoft Unicode string to UTF-8.
+**
+** Space to hold the returned string is obtained from sqlite3_malloc().
*/
-static char *winUnicodeToUtf8(LPCWSTR zWideFilename){
+static char *winUnicodeToUtf8(LPCWSTR zWideText){
int nByte;
- char *zFilename;
+ char *zText;
- nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
+ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, 0, 0, 0, 0);
if( nByte == 0 ){
return 0;
}
- zFilename = sqlite3MallocZero( nByte );
- if( zFilename==0 ){
+ zText = sqlite3MallocZero( nByte );
+ if( zText==0 ){
return 0;
}
- nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
+ nByte = osWideCharToMultiByte(CP_UTF8, 0, zWideText, -1, zText, nByte,
0, 0);
if( nByte == 0 ){
- sqlite3_free(zFilename);
- zFilename = 0;
+ sqlite3_free(zText);
+ zText = 0;
}
- return zFilename;
+ return zText;
}
/*
-** Convert an ANSI string to Microsoft Unicode, based on the
-** current codepage settings for file apis.
+** Convert an ANSI string to Microsoft Unicode, using the ANSI or OEM
+** code page.
**
-** Space to hold the returned string is obtained
-** from sqlite3_malloc.
+** Space to hold the returned string is obtained from sqlite3_malloc().
*/
-static LPWSTR winMbcsToUnicode(const char *zFilename){
+static LPWSTR winMbcsToUnicode(const char *zText, int useAnsi){
int nByte;
- LPWSTR zMbcsFilename;
- int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
+ LPWSTR zMbcsText;
+ int codepage = useAnsi ? CP_ACP : CP_OEMCP;
- nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, NULL,
+ nByte = osMultiByteToWideChar(codepage, 0, zText, -1, NULL,
0)*sizeof(WCHAR);
if( nByte==0 ){
return 0;
}
- zMbcsFilename = sqlite3MallocZero( nByte*sizeof(zMbcsFilename[0]) );
- if( zMbcsFilename==0 ){
+ zMbcsText = sqlite3MallocZero( nByte*sizeof(WCHAR) );
+ if( zMbcsText==0 ){
return 0;
}
- nByte = osMultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename,
+ nByte = osMultiByteToWideChar(codepage, 0, zText, -1, zMbcsText,
nByte);
if( nByte==0 ){
- sqlite3_free(zMbcsFilename);
- zMbcsFilename = 0;
+ sqlite3_free(zMbcsText);
+ zMbcsText = 0;
}
- return zMbcsFilename;
+ return zMbcsText;
}
/*
-** Convert Microsoft Unicode to multi-byte character string, based on the
-** user's ANSI codepage.
+** Convert a Microsoft Unicode string to a multi-byte character string,
+** using the ANSI or OEM code page.
**
-** Space to hold the returned string is obtained from
-** sqlite3_malloc().
+** Space to hold the returned string is obtained from sqlite3_malloc().
*/
-static char *winUnicodeToMbcs(LPCWSTR zWideFilename){
+static char *winUnicodeToMbcs(LPCWSTR zWideText, int useAnsi){
int nByte;
- char *zFilename;
- int codepage = osAreFileApisANSI() ? CP_ACP : CP_OEMCP;
+ char *zText;
+ int codepage = useAnsi ? CP_ACP : CP_OEMCP;
- nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
+ nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, 0, 0, 0, 0);
if( nByte == 0 ){
return 0;
}
- zFilename = sqlite3MallocZero( nByte );
- if( zFilename==0 ){
+ zText = sqlite3MallocZero( nByte );
+ if( zText==0 ){
return 0;
}
- nByte = osWideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename,
+ nByte = osWideCharToMultiByte(codepage, 0, zWideText, -1, zText,
nByte, 0, 0);
if( nByte == 0 ){
- sqlite3_free(zFilename);
- zFilename = 0;
+ sqlite3_free(zText);
+ zText = 0;
}
- return zFilename;
+ return zText;
}
/*
-** Convert multibyte character string to UTF-8. Space to hold the
-** returned string is obtained from sqlite3_malloc().
+** Convert a multi-byte character string to UTF-8.
+**
+** Space to hold the returned string is obtained from sqlite3_malloc().
*/
-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_mbcs_to_utf8(const char *zFilename){
- char *zFilenameUtf8;
+static char *winMbcsToUtf8(const char *zText, int useAnsi){
+ char *zTextUtf8;
LPWSTR zTmpWide;
- zTmpWide = winMbcsToUnicode(zFilename);
+ zTmpWide = winMbcsToUnicode(zText, useAnsi);
if( zTmpWide==0 ){
return 0;
}
- zFilenameUtf8 = winUnicodeToUtf8(zTmpWide);
+ zTextUtf8 = winUnicodeToUtf8(zTmpWide);
sqlite3_free(zTmpWide);
- return zFilenameUtf8;
+ return zTextUtf8;
}
/*
-** Convert UTF-8 to multibyte character string. Space to hold the
-** returned string is obtained from sqlite3_malloc().
+** Convert a UTF-8 string to a multi-byte character string.
+**
+** Space to hold the returned string is obtained from sqlite3_malloc().
*/
-SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename){
- char *zFilenameMbcs;
+static char *winUtf8ToMbcs(const char *zText, int useAnsi){
+ char *zTextMbcs;
LPWSTR zTmpWide;
- zTmpWide = winUtf8ToUnicode(zFilename);
+ zTmpWide = winUtf8ToUnicode(zText);
if( zTmpWide==0 ){
return 0;
}
- zFilenameMbcs = winUnicodeToMbcs(zTmpWide);
+ zTextMbcs = winUnicodeToMbcs(zTmpWide, useAnsi);
sqlite3_free(zTmpWide);
- return zFilenameMbcs;
+ return zTextMbcs;
+}
+
+/*
+** This is a public wrapper for the winUtf8ToUnicode() function.
+*/
+SQLITE_API LPWSTR sqlite3_win32_utf8_to_unicode(const char *zText){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !zText ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return 0;
+#endif
+ return winUtf8ToUnicode(zText);
+}
+
+/*
+** This is a public wrapper for the winUnicodeToUtf8() function.
+*/
+SQLITE_API char *sqlite3_win32_unicode_to_utf8(LPCWSTR zWideText){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !zWideText ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return 0;
+#endif
+ return winUnicodeToUtf8(zWideText);
+}
+
+/*
+** This is a public wrapper for the winMbcsToUtf8() function.
+*/
+SQLITE_API char *sqlite3_win32_mbcs_to_utf8(const char *zText){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !zText ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return 0;
+#endif
+ return winMbcsToUtf8(zText, osAreFileApisANSI());
+}
+
+/*
+** This is a public wrapper for the winMbcsToUtf8() function.
+*/
+SQLITE_API char *sqlite3_win32_mbcs_to_utf8_v2(const char *zText, int useAnsi){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !zText ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return 0;
+#endif
+ return winMbcsToUtf8(zText, useAnsi);
+}
+
+/*
+** This is a public wrapper for the winUtf8ToMbcs() function.
+*/
+SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zText){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !zText ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return 0;
+#endif
+ return winUtf8ToMbcs(zText, osAreFileApisANSI());
+}
+
+/*
+** This is a public wrapper for the winUtf8ToMbcs() function.
+*/
+SQLITE_API char *sqlite3_win32_utf8_to_mbcs_v2(const char *zText, int useAnsi){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !zText ){
+ (void)SQLITE_MISUSE_BKPT;
+ return 0;
+ }
+#endif
+#ifndef SQLITE_OMIT_AUTOINIT
+ if( sqlite3_initialize() ) return 0;
+#endif
+ return winUtf8ToMbcs(zText, useAnsi);
}
/*
@@ -36838,7 +39387,7 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_win32_utf8_to_mbcs(const char *zFilename
** argument is the name of the directory to use. The return value will be
** SQLITE_OK if successful.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
+SQLITE_API int sqlite3_win32_set_directory(DWORD type, LPCWSTR zValue){
char **ppDirectory = 0;
#ifndef SQLITE_OMIT_AUTOINIT
int rc = sqlite3_initialize();
@@ -36858,7 +39407,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_win32_set_directory(DWORD type, LPCWSTR zV
if( zValue && zValue[0] ){
zValueUtf8 = winUnicodeToUtf8(zValue);
if ( zValueUtf8==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
}
sqlite3_free(*ppDirectory);
@@ -36930,7 +39479,7 @@ static int winGetLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){
if( dwLen > 0 ){
/* allocate a buffer and convert to UTF8 */
sqlite3BeginBenignMalloc();
- zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
+ zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
sqlite3EndBenignMalloc();
/* free the system buffer allocated by FormatMessage */
osLocalFree(zTemp);
@@ -37072,16 +39621,17 @@ static void winLogIoerr(int nRetry, int lineno){
}
}
-#if SQLITE_OS_WINCE
-/*************************************************************************
-** This section contains code for WinCE only.
+/*
+** This #if does not rely on the SQLITE_OS_WINCE define because the
+** corresponding section in "date.c" cannot use it.
*/
-#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
+#if !defined(SQLITE_OMIT_LOCALTIME) && defined(_WIN32_WCE) && \
+ (!defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API)
/*
-** The MSVC CRT on Windows CE may not have a localtime() function. So
-** create a substitute.
+** The MSVC CRT on Windows CE may not have a localtime() function.
+** So define a substitute.
*/
-/* #include <time.h> */
+/* # include <time.h> */
struct tm *__cdecl localtime(const time_t *t)
{
static struct tm y;
@@ -37105,6 +39655,10 @@ struct tm *__cdecl localtime(const time_t *t)
}
#endif
+#if SQLITE_OS_WINCE
+/*************************************************************************
+** This section contains code for WinCE only.
+*/
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
/*
@@ -37135,7 +39689,7 @@ static int winceCreateLock(const char *zFilename, winFile *pFile){
zName = winUtf8ToUnicode(zFilename);
if( zName==0 ){
/* out of memory */
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
/* Initialize the local lockdata */
@@ -37560,7 +40114,12 @@ static int winClose(sqlite3_file *id){
}while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) );
#if SQLITE_OS_WINCE
#define WINCE_DELETION_ATTEMPTS 3
- winceDestroyLock(pFile);
+ {
+ winVfsAppData *pAppData = (winVfsAppData*)pFile->pVfs->pAppData;
+ if( pAppData==NULL || !pAppData->bNoLock ){
+ winceDestroyLock(pFile);
+ }
+ }
if( pFile->zDeleteOnClose ){
int cnt = 0;
while(
@@ -38118,9 +40677,8 @@ static int winLock(sqlite3_file *id, int locktype){
** the PENDING_LOCK byte is temporary.
*/
newLocktype = pFile->locktype;
- if( (pFile->locktype==NO_LOCK)
- || ( (locktype==EXCLUSIVE_LOCK)
- && (pFile->locktype==RESERVED_LOCK))
+ if( pFile->locktype==NO_LOCK
+ || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK)
){
int cnt = 3;
while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
@@ -38293,6 +40851,44 @@ static int winUnlock(sqlite3_file *id, int locktype){
return rc;
}
+/******************************************************************************
+****************************** No-op Locking **********************************
+**
+** Of the various locking implementations available, this is by far the
+** simplest: locking is ignored. No attempt is made to lock the database
+** file for reading or writing.
+**
+** This locking mode is appropriate for use on read-only databases
+** (ex: databases that are burned into CD-ROM, for example.) It can
+** also be used if the application employs some external mechanism to
+** prevent simultaneous access of the same database by two or more
+** database connections. But there is a serious risk of database
+** corruption if this locking mode is used in situations where multiple
+** database connections are accessing the same database file at the same
+** time and one or more of those connections are writing.
+*/
+
+static int winNolockLock(sqlite3_file *id, int locktype){
+ UNUSED_PARAMETER(id);
+ UNUSED_PARAMETER(locktype);
+ return SQLITE_OK;
+}
+
+static int winNolockCheckReservedLock(sqlite3_file *id, int *pResOut){
+ UNUSED_PARAMETER(id);
+ UNUSED_PARAMETER(pResOut);
+ return SQLITE_OK;
+}
+
+static int winNolockUnlock(sqlite3_file *id, int locktype){
+ UNUSED_PARAMETER(id);
+ UNUSED_PARAMETER(locktype);
+ return SQLITE_OK;
+}
+
+/******************* End of the no-op lock implementation *********************
+******************************************************************************/
+
/*
** If *pArg is initially negative then this is a query. Set *pArg to
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
@@ -38326,7 +40922,7 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}
- case SQLITE_LAST_ERRNO: {
+ case SQLITE_FCNTL_LAST_ERRNO: {
*(int*)pArg = (int)pFile->lastErrno;
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
@@ -38384,6 +40980,12 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
return SQLITE_OK;
}
+ case SQLITE_FCNTL_WIN32_GET_HANDLE: {
+ LPHANDLE phFile = (LPHANDLE)pArg;
+ *phFile = pFile->h;
+ OSTRACE(("FCNTL file=%p, rc=SQLITE_OK\n", pFile->h));
+ return SQLITE_OK;
+ }
#ifdef SQLITE_TEST
case SQLITE_FCNTL_WIN32_SET_HANDLE: {
LPHANDLE phFile = (LPHANDLE)pArg;
@@ -38571,12 +41173,12 @@ struct winShm {
/*
** Apply advisory locks for all n bytes beginning at ofst.
*/
-#define _SHM_UNLCK 1
-#define _SHM_RDLCK 2
-#define _SHM_WRLCK 3
+#define WINSHM_UNLCK 1
+#define WINSHM_RDLCK 2
+#define WINSHM_WRLCK 3
static int winShmSystemLock(
winShmNode *pFile, /* Apply locks to this open shared-memory segment */
- int lockType, /* _SHM_UNLCK, _SHM_RDLCK, or _SHM_WRLCK */
+ int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
int ofst, /* Offset to first byte to be locked/unlocked */
int nByte /* Number of bytes to lock or unlock */
){
@@ -38589,12 +41191,12 @@ static int winShmSystemLock(
pFile->hFile.h, lockType, ofst, nByte));
/* Release/Acquire the system-level lock */
- if( lockType==_SHM_UNLCK ){
+ if( lockType==WINSHM_UNLCK ){
rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
}else{
/* Initialize the locking parameters */
DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
- if( lockType == _SHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
+ if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
}
@@ -38606,7 +41208,7 @@ static int winShmSystemLock(
}
OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
- pFile->hFile.h, (lockType == _SHM_UNLCK) ? "winUnlockFile" :
+ pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
"winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
return rc;
@@ -38684,12 +41286,12 @@ static int winOpenSharedMemory(winFile *pDbFd){
** allocate space for a new winShmNode and filename.
*/
p = sqlite3MallocZero( sizeof(*p) );
- if( p==0 ) return SQLITE_IOERR_NOMEM;
+ if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT;
nName = sqlite3Strlen30(pDbFd->zPath);
pNew = sqlite3MallocZero( sizeof(*pShmNode) + nName + 17 );
if( pNew==0 ){
sqlite3_free(p);
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
pNew->zFilename = (char*)&pNew[1];
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
@@ -38714,10 +41316,12 @@ static int winOpenSharedMemory(winFile *pDbFd){
pShmNode->pNext = winShmNodeList;
winShmNodeList = pShmNode;
- pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
- if( pShmNode->mutex==0 ){
- rc = SQLITE_IOERR_NOMEM;
- goto shm_open_err;
+ if( sqlite3GlobalConfig.bCoreMutex ){
+ pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->mutex==0 ){
+ rc = SQLITE_IOERR_NOMEM_BKPT;
+ goto shm_open_err;
+ }
}
rc = winOpen(pDbFd->pVfs,
@@ -38732,7 +41336,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
/* Check to see if another process is holding the dead-man switch.
** If not, truncate the file to zero length.
*/
- if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
+ if( winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){
rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0);
if( rc!=SQLITE_OK ){
rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
@@ -38740,8 +41344,8 @@ static int winOpenSharedMemory(winFile *pDbFd){
}
}
if( rc==SQLITE_OK ){
- winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
- rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1);
+ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
+ rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
}
if( rc ) goto shm_open_err;
}
@@ -38770,7 +41374,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
/* Jump here on any error */
shm_open_err:
- winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1);
+ winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
winShmPurge(pDbFd->pVfs, 0); /* This call frees pShmNode if required */
sqlite3_free(p);
sqlite3_free(pNew);
@@ -38859,7 +41463,7 @@ static int winShmLock(
/* Unlock the system-level locks */
if( (mask & allMask)==0 ){
- rc = winShmSystemLock(pShmNode, _SHM_UNLCK, ofst+WIN_SHM_BASE, n);
+ rc = winShmSystemLock(pShmNode, WINSHM_UNLCK, ofst+WIN_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
@@ -38887,7 +41491,7 @@ static int winShmLock(
/* Get shared locks at the system level, if necessary */
if( rc==SQLITE_OK ){
if( (allShared & mask)==0 ){
- rc = winShmSystemLock(pShmNode, _SHM_RDLCK, ofst+WIN_SHM_BASE, n);
+ rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, ofst+WIN_SHM_BASE, n);
}else{
rc = SQLITE_OK;
}
@@ -38912,7 +41516,7 @@ static int winShmLock(
** also mark the local connection as being locked.
*/
if( rc==SQLITE_OK ){
- rc = winShmSystemLock(pShmNode, _SHM_WRLCK, ofst+WIN_SHM_BASE, n);
+ rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, ofst+WIN_SHM_BASE, n);
if( rc==SQLITE_OK ){
assert( (p->sharedMask & mask)==0 );
p->exclMask |= mask;
@@ -39021,7 +41625,7 @@ static int winShmMap(
pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
);
if( !apNew ){
- rc = SQLITE_IOERR_NOMEM;
+ rc = SQLITE_IOERR_NOMEM_BKPT;
goto shmpage_out;
}
pShmNode->aRegion = apNew;
@@ -39355,6 +41959,44 @@ static const sqlite3_io_methods winIoMethod = {
winUnfetch /* xUnfetch */
};
+/*
+** This vector defines all the methods that can operate on an
+** sqlite3_file for win32 without performing any locking.
+*/
+static const sqlite3_io_methods winIoNolockMethod = {
+ 3, /* iVersion */
+ winClose, /* xClose */
+ winRead, /* xRead */
+ winWrite, /* xWrite */
+ winTruncate, /* xTruncate */
+ winSync, /* xSync */
+ winFileSize, /* xFileSize */
+ winNolockLock, /* xLock */
+ winNolockUnlock, /* xUnlock */
+ winNolockCheckReservedLock, /* xCheckReservedLock */
+ winFileControl, /* xFileControl */
+ winSectorSize, /* xSectorSize */
+ winDeviceCharacteristics, /* xDeviceCharacteristics */
+ winShmMap, /* xShmMap */
+ winShmLock, /* xShmLock */
+ winShmBarrier, /* xShmBarrier */
+ winShmUnmap, /* xShmUnmap */
+ winFetch, /* xFetch */
+ winUnfetch /* xUnfetch */
+};
+
+static winVfsAppData winAppData = {
+ &winIoMethod, /* pMethod */
+ 0, /* pAppData */
+ 0 /* bNoLock */
+};
+
+static winVfsAppData winNolockAppData = {
+ &winIoNolockMethod, /* pMethod */
+ 0, /* pAppData */
+ 1 /* bNoLock */
+};
+
/****************************************************************************
**************************** sqlite3_vfs methods ****************************
**
@@ -39375,7 +42017,7 @@ static char *winConvertToUtf8Filename(const void *zFilename){
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
- zConverted = sqlite3_win32_mbcs_to_utf8(zFilename);
+ zConverted = winMbcsToUtf8(zFilename, osAreFileApisANSI());
}
#endif
/* caller will handle out of memory */
@@ -39396,7 +42038,7 @@ static void *winConvertFromUtf8Filename(const char *zFilename){
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
- zConverted = sqlite3_win32_utf8_to_mbcs(zFilename);
+ zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
}
#endif
/* caller will handle out of memory */
@@ -39451,7 +42093,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
zBuf = sqlite3MallocZero( nBuf );
if( !zBuf ){
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
/* Figure out the effective temporary directory. First, check if one
@@ -39509,7 +42151,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
if( !zConverted ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( winIsDir(zConverted) ){
sqlite3_snprintf(nMax, zBuf, "%s", zDir);
@@ -39522,7 +42164,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
if( !zConverted ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( cygwin_conv_path(
osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A, zDir,
@@ -39543,7 +42185,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
sqlite3_free(zConverted);
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
sqlite3_free(zUtf8);
@@ -39561,7 +42203,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
if( !zWidePath ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( osGetTempPathW(nMax, zWidePath)==0 ){
sqlite3_free(zWidePath);
@@ -39579,7 +42221,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
sqlite3_free(zWidePath);
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
}
#ifdef SQLITE_WIN32_HAS_ANSI
@@ -39589,7 +42231,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
if( !zMbcsPath ){
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( osGetTempPathA(nMax, zMbcsPath)==0 ){
sqlite3_free(zBuf);
@@ -39597,14 +42239,14 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
return winLogError(SQLITE_IOERR_GETTEMPPATH, osGetLastError(),
"winGetTempname3", 0);
}
- zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
+ zUtf8 = winMbcsToUtf8(zMbcsPath, osAreFileApisANSI());
if( zUtf8 ){
sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
sqlite3_free(zUtf8);
}else{
sqlite3_free(zBuf);
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
}
#endif /* SQLITE_WIN32_HAS_ANSI */
@@ -39687,7 +42329,7 @@ static int winIsDir(const void *zConverted){
** Open a file.
*/
static int winOpen(
- sqlite3_vfs *pVfs, /* Used to get maximum path name length */
+ sqlite3_vfs *pVfs, /* Used to get maximum path length and AppData */
const char *zName, /* Name of the file (UTF-8) */
sqlite3_file *id, /* Write the SQLite file handle here */
int flags, /* Open mode flags */
@@ -39702,6 +42344,7 @@ static int winOpen(
#if SQLITE_OS_WINCE
int isTemp = 0;
#endif
+ winVfsAppData *pAppData;
winFile *pFile = (winFile*)id;
void *zConverted; /* Filename in OS encoding */
const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */
@@ -39796,7 +42439,7 @@ static int winOpen(
if( zConverted==0 ){
sqlite3_free(zTmpname);
OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8Name));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( winIsDir(zConverted) ){
@@ -39923,15 +42566,20 @@ static int winOpen(
"rc=%s\n", h, zUtf8Name, dwDesiredAccess, pOutFlags, pOutFlags ?
*pOutFlags : 0, (h==INVALID_HANDLE_VALUE) ? "failed" : "ok"));
+ pAppData = (winVfsAppData*)pVfs->pAppData;
+
#if SQLITE_OS_WINCE
- if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
- && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
- ){
- osCloseHandle(h);
- sqlite3_free(zConverted);
- sqlite3_free(zTmpname);
- OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
- return rc;
+ {
+ if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
+ && ((pAppData==NULL) || !pAppData->bNoLock)
+ && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
+ ){
+ osCloseHandle(h);
+ sqlite3_free(zConverted);
+ sqlite3_free(zTmpname);
+ OSTRACE(("OPEN-CE-LOCK name=%s, rc=%s\n", zName, sqlite3ErrName(rc)));
+ return rc;
+ }
}
if( isTemp ){
pFile->zDeleteOnClose = zConverted;
@@ -39942,7 +42590,7 @@ static int winOpen(
}
sqlite3_free(zTmpname);
- pFile->pMethod = &winIoMethod;
+ pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
pFile->pVfs = pVfs;
pFile->h = h;
if( isReadonly ){
@@ -39996,7 +42644,7 @@ static int winDelete(
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("DELETE name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( osIsNT() ){
do {
@@ -40104,7 +42752,7 @@ static int winAccess(
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( osIsNT() ){
int cnt = 0;
@@ -40217,6 +42865,18 @@ static int winFullPathname(
int nFull, /* Size of output buffer in bytes */
char *zFull /* Output buffer */
){
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
+ DWORD nByte;
+ void *zConverted;
+ char *zOut;
+#endif
+
+ /* If this path name begins with "/X:", where "X" is any alphabetic
+ ** character, discard the initial "/" from the pathname.
+ */
+ if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
+ zRelative++;
+ }
#if defined(__CYGWIN__)
SimulateIOError( return SQLITE_ERROR );
@@ -40231,7 +42891,7 @@ static int winFullPathname(
*/
char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
if( !zOut ){
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( cygwin_conv_path(
(osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
@@ -40243,7 +42903,7 @@ static int winFullPathname(
char *zUtf8 = winConvertToUtf8Filename(zOut);
if( !zUtf8 ){
sqlite3_free(zOut);
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
sqlite3_data_directory, winGetDirSep(), zUtf8);
@@ -40253,7 +42913,7 @@ static int winFullPathname(
}else{
char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
if( !zOut ){
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( cygwin_conv_path(
(osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
@@ -40265,7 +42925,7 @@ static int winFullPathname(
char *zUtf8 = winConvertToUtf8Filename(zOut);
if( !zUtf8 ){
sqlite3_free(zOut);
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
sqlite3_free(zUtf8);
@@ -40295,17 +42955,6 @@ static int winFullPathname(
#endif
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__)
- DWORD nByte;
- void *zConverted;
- char *zOut;
-
- /* If this path name begins with "/X:", where "X" is any alphabetic
- ** character, discard the initial "/" from the pathname.
- */
- if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
- zRelative++;
- }
-
/* It's odd to simulate an io-error here, but really this is just
** using the io-error infrastructure to test that SQLite handles this
** function failing. This function could fail if, for example, the
@@ -40325,7 +42974,7 @@ static int winFullPathname(
}
zConverted = winConvertFromUtf8Filename(zRelative);
if( zConverted==0 ){
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
if( osIsNT() ){
LPWSTR zTemp;
@@ -40339,7 +42988,7 @@ static int winFullPathname(
zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
sqlite3_free(zConverted);
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
nByte = osGetFullPathNameW((LPCWSTR)zConverted, nByte, zTemp, 0);
if( nByte==0 ){
@@ -40365,7 +43014,7 @@ static int winFullPathname(
zTemp = sqlite3MallocZero( nByte*sizeof(zTemp[0]) );
if( zTemp==0 ){
sqlite3_free(zConverted);
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
nByte = osGetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
if( nByte==0 ){
@@ -40375,7 +43024,7 @@ static int winFullPathname(
"winFullPathname4", zRelative);
}
sqlite3_free(zConverted);
- zOut = sqlite3_win32_mbcs_to_utf8(zTemp);
+ zOut = winMbcsToUtf8(zTemp, osAreFileApisANSI());
sqlite3_free(zTemp);
}
#endif
@@ -40384,7 +43033,7 @@ static int winFullPathname(
sqlite3_free(zOut);
return SQLITE_OK;
}else{
- return SQLITE_IOERR_NOMEM;
+ return SQLITE_IOERR_NOMEM_BKPT;
}
#endif
}
@@ -40459,65 +43108,85 @@ static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
#define winDlClose 0
#endif
+/* State information for the randomness gatherer. */
+typedef struct EntropyGatherer EntropyGatherer;
+struct EntropyGatherer {
+ unsigned char *a; /* Gather entropy into this buffer */
+ int na; /* Size of a[] in bytes */
+ int i; /* XOR next input into a[i] */
+ int nXor; /* Number of XOR operations done */
+};
+
+#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
+/* Mix sz bytes of entropy into p. */
+static void xorMemory(EntropyGatherer *p, unsigned char *x, int sz){
+ int j, k;
+ for(j=0, k=p->i; j<sz; j++){
+ p->a[k++] ^= x[j];
+ if( k>=p->na ) k = 0;
+ }
+ p->i = k;
+ p->nXor += sz;
+}
+#endif /* !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS) */
/*
** Write up to nBuf bytes of randomness into zBuf.
*/
static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
- int n = 0;
- UNUSED_PARAMETER(pVfs);
#if defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS)
- n = nBuf;
+ UNUSED_PARAMETER(pVfs);
memset(zBuf, 0, nBuf);
+ return nBuf;
#else
- if( sizeof(SYSTEMTIME)<=nBuf-n ){
+ EntropyGatherer e;
+ UNUSED_PARAMETER(pVfs);
+ memset(zBuf, 0, nBuf);
+#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE
+ rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */
+#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */
+ e.a = (unsigned char*)zBuf;
+ e.na = nBuf;
+ e.nXor = 0;
+ e.i = 0;
+ {
SYSTEMTIME x;
osGetSystemTime(&x);
- memcpy(&zBuf[n], &x, sizeof(x));
- n += sizeof(x);
+ xorMemory(&e, (unsigned char*)&x, sizeof(SYSTEMTIME));
}
- if( sizeof(DWORD)<=nBuf-n ){
+ {
DWORD pid = osGetCurrentProcessId();
- memcpy(&zBuf[n], &pid, sizeof(pid));
- n += sizeof(pid);
+ xorMemory(&e, (unsigned char*)&pid, sizeof(DWORD));
}
#if SQLITE_OS_WINRT
- if( sizeof(ULONGLONG)<=nBuf-n ){
+ {
ULONGLONG cnt = osGetTickCount64();
- memcpy(&zBuf[n], &cnt, sizeof(cnt));
- n += sizeof(cnt);
+ xorMemory(&e, (unsigned char*)&cnt, sizeof(ULONGLONG));
}
#else
- if( sizeof(DWORD)<=nBuf-n ){
+ {
DWORD cnt = osGetTickCount();
- memcpy(&zBuf[n], &cnt, sizeof(cnt));
- n += sizeof(cnt);
+ xorMemory(&e, (unsigned char*)&cnt, sizeof(DWORD));
}
-#endif
- if( sizeof(LARGE_INTEGER)<=nBuf-n ){
+#endif /* SQLITE_OS_WINRT */
+ {
LARGE_INTEGER i;
osQueryPerformanceCounter(&i);
- memcpy(&zBuf[n], &i, sizeof(i));
- n += sizeof(i);
+ xorMemory(&e, (unsigned char*)&i, sizeof(LARGE_INTEGER));
}
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID
- if( sizeof(UUID)<=nBuf-n ){
+ {
UUID id;
memset(&id, 0, sizeof(UUID));
osUuidCreate(&id);
- memcpy(&zBuf[n], &id, sizeof(UUID));
- n += sizeof(UUID);
- }
- if( sizeof(UUID)<=nBuf-n ){
- UUID id;
+ xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
memset(&id, 0, sizeof(UUID));
osUuidCreateSequential(&id);
- memcpy(&zBuf[n], &id, sizeof(UUID));
- n += sizeof(UUID);
+ xorMemory(&e, (unsigned char*)&id, sizeof(UUID));
}
-#endif
-#endif /* defined(SQLITE_TEST) || defined(SQLITE_ZERO_PRNG_SEED) */
- return n;
+#endif /* !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_WIN32_USE_UUID */
+ return e.nXor>nBuf ? nBuf : e.nXor;
+#endif /* defined(SQLITE_TEST) || defined(SQLITE_OMIT_RANDOMNESS) */
}
@@ -40633,62 +43302,114 @@ static int winCurrentTime(sqlite3_vfs *pVfs, double *prNow){
** sqlite3_errmsg(), possibly making IO errors easier to debug.
*/
static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
+ DWORD e = osGetLastError();
UNUSED_PARAMETER(pVfs);
- return winGetLastErrorMsg(osGetLastError(), nBuf, zBuf);
+ if( nBuf>0 ) winGetLastErrorMsg(e, nBuf, zBuf);
+ return e;
}
/*
** Initialize and deinitialize the operating system interface.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
+SQLITE_API int sqlite3_os_init(void){
static sqlite3_vfs winVfs = {
- 3, /* iVersion */
- sizeof(winFile), /* szOsFile */
+ 3, /* iVersion */
+ sizeof(winFile), /* szOsFile */
SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
- 0, /* pNext */
- "win32", /* zName */
- 0, /* pAppData */
- winOpen, /* xOpen */
- winDelete, /* xDelete */
- winAccess, /* xAccess */
- winFullPathname, /* xFullPathname */
- winDlOpen, /* xDlOpen */
- winDlError, /* xDlError */
- winDlSym, /* xDlSym */
- winDlClose, /* xDlClose */
- winRandomness, /* xRandomness */
- winSleep, /* xSleep */
- winCurrentTime, /* xCurrentTime */
- winGetLastError, /* xGetLastError */
- winCurrentTimeInt64, /* xCurrentTimeInt64 */
- winSetSystemCall, /* xSetSystemCall */
- winGetSystemCall, /* xGetSystemCall */
- winNextSystemCall, /* xNextSystemCall */
+ 0, /* pNext */
+ "win32", /* zName */
+ &winAppData, /* pAppData */
+ winOpen, /* xOpen */
+ winDelete, /* xDelete */
+ winAccess, /* xAccess */
+ winFullPathname, /* xFullPathname */
+ winDlOpen, /* xDlOpen */
+ winDlError, /* xDlError */
+ winDlSym, /* xDlSym */
+ winDlClose, /* xDlClose */
+ winRandomness, /* xRandomness */
+ winSleep, /* xSleep */
+ winCurrentTime, /* xCurrentTime */
+ winGetLastError, /* xGetLastError */
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */
+ winSetSystemCall, /* xSetSystemCall */
+ winGetSystemCall, /* xGetSystemCall */
+ winNextSystemCall, /* xNextSystemCall */
};
#if defined(SQLITE_WIN32_HAS_WIDE)
static sqlite3_vfs winLongPathVfs = {
- 3, /* iVersion */
- sizeof(winFile), /* szOsFile */
+ 3, /* iVersion */
+ sizeof(winFile), /* szOsFile */
SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
- 0, /* pNext */
- "win32-longpath", /* zName */
- 0, /* pAppData */
- winOpen, /* xOpen */
- winDelete, /* xDelete */
- winAccess, /* xAccess */
- winFullPathname, /* xFullPathname */
- winDlOpen, /* xDlOpen */
- winDlError, /* xDlError */
- winDlSym, /* xDlSym */
- winDlClose, /* xDlClose */
- winRandomness, /* xRandomness */
- winSleep, /* xSleep */
- winCurrentTime, /* xCurrentTime */
- winGetLastError, /* xGetLastError */
- winCurrentTimeInt64, /* xCurrentTimeInt64 */
- winSetSystemCall, /* xSetSystemCall */
- winGetSystemCall, /* xGetSystemCall */
- winNextSystemCall, /* xNextSystemCall */
+ 0, /* pNext */
+ "win32-longpath", /* zName */
+ &winAppData, /* pAppData */
+ winOpen, /* xOpen */
+ winDelete, /* xDelete */
+ winAccess, /* xAccess */
+ winFullPathname, /* xFullPathname */
+ winDlOpen, /* xDlOpen */
+ winDlError, /* xDlError */
+ winDlSym, /* xDlSym */
+ winDlClose, /* xDlClose */
+ winRandomness, /* xRandomness */
+ winSleep, /* xSleep */
+ winCurrentTime, /* xCurrentTime */
+ winGetLastError, /* xGetLastError */
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */
+ winSetSystemCall, /* xSetSystemCall */
+ winGetSystemCall, /* xGetSystemCall */
+ winNextSystemCall, /* xNextSystemCall */
+ };
+#endif
+ static sqlite3_vfs winNolockVfs = {
+ 3, /* iVersion */
+ sizeof(winFile), /* szOsFile */
+ SQLITE_WIN32_MAX_PATH_BYTES, /* mxPathname */
+ 0, /* pNext */
+ "win32-none", /* zName */
+ &winNolockAppData, /* pAppData */
+ winOpen, /* xOpen */
+ winDelete, /* xDelete */
+ winAccess, /* xAccess */
+ winFullPathname, /* xFullPathname */
+ winDlOpen, /* xDlOpen */
+ winDlError, /* xDlError */
+ winDlSym, /* xDlSym */
+ winDlClose, /* xDlClose */
+ winRandomness, /* xRandomness */
+ winSleep, /* xSleep */
+ winCurrentTime, /* xCurrentTime */
+ winGetLastError, /* xGetLastError */
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */
+ winSetSystemCall, /* xSetSystemCall */
+ winGetSystemCall, /* xGetSystemCall */
+ winNextSystemCall, /* xNextSystemCall */
+ };
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ static sqlite3_vfs winLongPathNolockVfs = {
+ 3, /* iVersion */
+ sizeof(winFile), /* szOsFile */
+ SQLITE_WINNT_MAX_PATH_BYTES, /* mxPathname */
+ 0, /* pNext */
+ "win32-longpath-none", /* zName */
+ &winNolockAppData, /* pAppData */
+ winOpen, /* xOpen */
+ winDelete, /* xDelete */
+ winAccess, /* xAccess */
+ winFullPathname, /* xFullPathname */
+ winDlOpen, /* xDlOpen */
+ winDlError, /* xDlError */
+ winDlSym, /* xDlSym */
+ winDlClose, /* xDlClose */
+ winRandomness, /* xRandomness */
+ winSleep, /* xSleep */
+ winCurrentTime, /* xCurrentTime */
+ winGetLastError, /* xGetLastError */
+ winCurrentTimeInt64, /* xCurrentTimeInt64 */
+ winSetSystemCall, /* xSetSystemCall */
+ winGetSystemCall, /* xGetSystemCall */
+ winNextSystemCall, /* xNextSystemCall */
};
#endif
@@ -40712,10 +43433,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void){
sqlite3_vfs_register(&winLongPathVfs, 0);
#endif
+ sqlite3_vfs_register(&winNolockVfs, 0);
+
+#if defined(SQLITE_WIN32_HAS_WIDE)
+ sqlite3_vfs_register(&winLongPathNolockVfs, 0);
+#endif
+
return SQLITE_OK;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void){
+SQLITE_API int sqlite3_os_end(void){
#if SQLITE_OS_WINRT
if( sleepObj!=NULL ){
osCloseHandle(sleepObj);
@@ -40908,7 +43635,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
i = i%p->iDivisor;
if( p->u.apSub[bin]==0 ){
p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor );
- if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM;
+ if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM_BKPT;
}
p = p->u.apSub[bin];
}
@@ -40943,7 +43670,7 @@ bitvec_set_rehash:
int rc;
u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash));
if( aiValues==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}else{
memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
memset(p->u.apSub, 0, sizeof(p->u.apSub));
@@ -41024,7 +43751,7 @@ SQLITE_PRIVATE u32 sqlite3BitvecSize(Bitvec *p){
return p->iSize;
}
-#ifndef SQLITE_OMIT_BUILTIN_TEST
+#ifndef SQLITE_UNTESTABLE
/*
** Let V[] be an array of unsigned characters sufficient to hold
** up to N bits. Let I be an integer between 0 and N. 0<=I<N.
@@ -41139,7 +43866,7 @@ bitvec_end:
sqlite3BitvecDestroy(pBitvec);
return rc;
}
-#endif /* SQLITE_OMIT_BUILTIN_TEST */
+#endif /* SQLITE_UNTESTABLE */
/************** End of bitvec.c **********************************************/
/************** Begin file pcache.c ******************************************/
@@ -41159,7 +43886,29 @@ bitvec_end:
/* #include "sqliteInt.h" */
/*
-** A complete page cache is an instance of this structure.
+** A complete page cache is an instance of this structure. Every
+** entry in the cache holds a single page of the database file. The
+** btree layer only operates on the cached copy of the database pages.
+**
+** A page cache entry is "clean" if it exactly matches what is currently
+** on disk. A page is "dirty" if it has been modified and needs to be
+** persisted to disk.
+**
+** pDirty, pDirtyTail, pSynced:
+** All dirty pages are linked into the doubly linked list using
+** PgHdr.pDirtyNext and pDirtyPrev. The list is maintained in LRU order
+** such that p was added to the list more recently than p->pDirtyNext.
+** PCache.pDirty points to the first (newest) element in the list and
+** pDirtyTail to the last (oldest).
+**
+** The PCache.pSynced variable is used to optimize searching for a dirty
+** page to eject from the cache mid-transaction. It is better to eject
+** a page that does not require a journal sync than one that does.
+** Therefore, pSynced is maintained to that it *almost* always points
+** to either the oldest page in the pDirty/pDirtyTail list that has a
+** clear PGHDR_NEED_SYNC flag or to a page that is older than this one
+** (so that the right page to eject can be found by following pDirtyPrev
+** pointers).
*/
struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
@@ -41176,6 +43925,95 @@ struct PCache {
sqlite3_pcache *pCache; /* Pluggable cache module */
};
+/********************************** Test and Debug Logic **********************/
+/*
+** Debug tracing macros. Enable by by changing the "0" to "1" and
+** recompiling.
+**
+** When sqlite3PcacheTrace is 1, single line trace messages are issued.
+** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries
+** is displayed for many operations, resulting in a lot of output.
+*/
+#if defined(SQLITE_DEBUG) && 0
+ int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
+ int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
+# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
+ void pcacheDump(PCache *pCache){
+ int N;
+ int i, j;
+ sqlite3_pcache_page *pLower;
+ PgHdr *pPg;
+ unsigned char *a;
+
+ if( sqlite3PcacheTrace<2 ) return;
+ if( pCache->pCache==0 ) return;
+ N = sqlite3PcachePagecount(pCache);
+ if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
+ for(i=1; i<=N; i++){
+ pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
+ if( pLower==0 ) continue;
+ pPg = (PgHdr*)pLower->pExtra;
+ printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
+ a = (unsigned char *)pLower->pBuf;
+ for(j=0; j<12; j++) printf("%02x", a[j]);
+ printf("\n");
+ if( pPg->pPage==0 ){
+ sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
+ }
+ }
+ }
+ #else
+# define pcacheTrace(X)
+# define pcacheDump(X)
+#endif
+
+/*
+** Check invariants on a PgHdr entry. Return true if everything is OK.
+** Return false if any invariant is violated.
+**
+** This routine is for use inside of assert() statements only. For
+** example:
+**
+** assert( sqlite3PcachePageSanity(pPg) );
+*/
+#if SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
+ PCache *pCache;
+ assert( pPg!=0 );
+ assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */
+ pCache = pPg->pCache;
+ assert( pCache!=0 ); /* Every page has an associated PCache */
+ if( pPg->flags & PGHDR_CLEAN ){
+ assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */
+ assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */
+ assert( pCache->pDirtyTail!=pPg );
+ }
+ /* WRITEABLE pages must also be DIRTY */
+ if( pPg->flags & PGHDR_WRITEABLE ){
+ assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */
+ }
+ /* NEED_SYNC can be set independently of WRITEABLE. This can happen,
+ ** for example, when using the sqlite3PagerDontWrite() optimization:
+ ** (1) Page X is journalled, and gets WRITEABLE and NEED_SEEK.
+ ** (2) Page X moved to freelist, WRITEABLE is cleared
+ ** (3) Page X reused, WRITEABLE is set again
+ ** If NEED_SYNC had been cleared in step 2, then it would not be reset
+ ** in step 3, and page might be written into the database without first
+ ** syncing the rollback journal, which might cause corruption on a power
+ ** loss.
+ **
+ ** Another example is when the database page size is smaller than the
+ ** disk sector size. When any page of a sector is journalled, all pages
+ ** in that sector are marked NEED_SYNC even if they are still CLEAN, just
+ ** in case they are later modified, since all pages in the same sector
+ ** must be journalled and synced before any of those pages can be safely
+ ** written.
+ */
+ return 1;
+}
+#endif /* SQLITE_DEBUG */
+
+
/********************************** Linked List Management ********************/
/* Allowed values for second argument to pcacheManageDirtyList() */
@@ -41192,17 +44030,16 @@ struct PCache {
static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
PCache *p = pPage->pCache;
+ pcacheTrace(("%p.DIRTYLIST.%s %d\n", p,
+ addRemove==1 ? "REMOVE" : addRemove==2 ? "ADD" : "FRONT",
+ pPage->pgno));
if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
assert( pPage->pDirtyPrev || pPage==p->pDirty );
/* Update the PCache1.pSynced variable if necessary. */
if( p->pSynced==pPage ){
- PgHdr *pSynced = pPage->pDirtyPrev;
- while( pSynced && (pSynced->flags&PGHDR_NEED_SYNC) ){
- pSynced = pSynced->pDirtyPrev;
- }
- p->pSynced = pSynced;
+ p->pSynced = pPage->pDirtyPrev;
}
if( pPage->pDirtyNext ){
@@ -41214,10 +44051,15 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
if( pPage->pDirtyPrev ){
pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
}else{
+ /* If there are now no dirty pages in the cache, set eCreate to 2.
+ ** This is an optimization that allows sqlite3PcacheFetch() to skip
+ ** searching for a dirty page to eject from the cache when it might
+ ** otherwise have to. */
assert( pPage==p->pDirty );
p->pDirty = pPage->pDirtyNext;
- if( p->pDirty==0 && p->bPurgeable ){
- assert( p->eCreate==1 );
+ assert( p->bPurgeable || p->eCreate==2 );
+ if( p->pDirty==0 ){ /*OPTIMIZATION-IF-TRUE*/
+ assert( p->bPurgeable==0 || p->eCreate==1 );
p->eCreate = 2;
}
}
@@ -41239,10 +44081,19 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
}
}
p->pDirty = pPage;
- if( !p->pSynced && 0==(pPage->flags&PGHDR_NEED_SYNC) ){
+
+ /* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
+ ** pSynced to point to it. Checking the NEED_SYNC flag is an
+ ** optimization, as if pSynced points to a page with the NEED_SYNC
+ ** flag set sqlite3PcacheFetchStress() searches through all newer
+ ** entries of the dirty-list for a page with NEED_SYNC clear anyway. */
+ if( !p->pSynced
+ && 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/
+ ){
p->pSynced = pPage;
}
}
+ pcacheDump(p);
}
/*
@@ -41251,7 +44102,9 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
*/
static void pcacheUnpin(PgHdr *p){
if( p->pCache->bPurgeable ){
+ pcacheTrace(("%p.UNPIN %d\n", p->pCache, p->pgno));
sqlite3GlobalConfig.pcache2.xUnpin(p->pCache->pCache, p->pPage, 0);
+ pcacheDump(p->pCache);
}
}
@@ -41303,6 +44156,12 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
** has already been allocated and is passed in as the p pointer.
** The caller discovers how much space needs to be allocated by
** calling sqlite3PcacheSize().
+**
+** szExtra is some extra space allocated for each page. The first
+** 8 bytes of the extra space will be zeroed as the page is allocated,
+** but remaining content will be uninitialized. Though it is opaque
+** to this module, the extra space really ends up being the MemPage
+** structure in the pager.
*/
SQLITE_PRIVATE int sqlite3PcacheOpen(
int szPage, /* Size of every page */
@@ -41315,12 +44174,14 @@ SQLITE_PRIVATE int sqlite3PcacheOpen(
memset(p, 0, sizeof(PCache));
p->szPage = 1;
p->szExtra = szExtra;
+ assert( szExtra>=8 ); /* First 8 bytes will be zeroed */
p->bPurgeable = bPurgeable;
p->eCreate = 2;
p->xStress = xStress;
p->pStress = pStress;
p->szCache = 100;
p->szSpill = 1;
+ pcacheTrace(("%p.OPEN szPage %d bPurgeable %d\n",p,szPage,bPurgeable));
return sqlite3PcacheSetPageSize(p, szPage);
}
@@ -41336,13 +44197,14 @@ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *pCache, int szPage){
szPage, pCache->szExtra + ROUND8(sizeof(PgHdr)),
pCache->bPurgeable
);
- if( pNew==0 ) return SQLITE_NOMEM;
+ if( pNew==0 ) return SQLITE_NOMEM_BKPT;
sqlite3GlobalConfig.pcache2.xCachesize(pNew, numberOfCachePages(pCache));
if( pCache->pCache ){
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
}
pCache->pCache = pNew;
pCache->szPage = szPage;
+ pcacheTrace(("%p.PAGESIZE %d\n",pCache,szPage));
}
return SQLITE_OK;
}
@@ -41377,11 +44239,12 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
int createFlag /* If true, create page if it does not exist already */
){
int eCreate;
+ sqlite3_pcache_page *pRes;
assert( pCache!=0 );
assert( pCache->pCache!=0 );
assert( createFlag==3 || createFlag==0 );
- assert( pgno>0 );
+ assert( pCache->eCreate==((pCache->bPurgeable && pCache->pDirty) ? 1 : 2) );
/* eCreate defines what to do if the page does not exist.
** 0 Do not allocate a new page. (createFlag==0)
@@ -41394,12 +44257,15 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
assert( eCreate==0 || eCreate==1 || eCreate==2 );
assert( createFlag==0 || pCache->eCreate==eCreate );
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
- return sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
+ pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
+ pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
+ createFlag?" create":"",pRes));
+ return pRes;
}
/*
** If the sqlite3PcacheFetch() routine is unable to allocate a new
-** page because new clean pages are available for reuse and the cache
+** page because no clean pages are available for reuse and the cache
** size limit has been reached, then this routine can be invoked to
** try harder to allocate a page. This routine might invoke the stress
** callback to spill dirty pages to the journal. It will then try to
@@ -41421,7 +44287,11 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress(
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
** cleared), but if that is not possible settle for any other
** unreferenced dirty page.
- */
+ **
+ ** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
+ ** flag is currently referenced, then the following may leave pSynced
+ ** set incorrectly (pointing to other than the LRU page with NEED_SYNC
+ ** cleared). This is Ok, as pSynced is just an optimization. */
for(pPg=pCache->pSynced;
pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
pPg=pPg->pDirtyPrev
@@ -41439,14 +44309,16 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress(
sqlite3GlobalConfig.pcache.xPagecount(pCache->pCache),
numberOfCachePages(pCache));
#endif
+ pcacheTrace(("%p.SPILL %d\n",pCache,pPg->pgno));
rc = pCache->xStress(pCache->pStress, pPg);
+ pcacheDump(pCache);
if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
return rc;
}
}
}
*ppPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, 2);
- return *ppPage==0 ? SQLITE_NOMEM : SQLITE_OK;
+ return *ppPage==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
}
/*
@@ -41467,11 +44339,11 @@ static SQLITE_NOINLINE PgHdr *pcacheFetchFinishWithInit(
assert( pPage!=0 );
pPgHdr = (PgHdr*)pPage->pExtra;
assert( pPgHdr->pPage==0 );
- memset(pPgHdr, 0, sizeof(PgHdr));
+ memset(&pPgHdr->pDirty, 0, sizeof(PgHdr) - offsetof(PgHdr,pDirty));
pPgHdr->pPage = pPage;
pPgHdr->pData = pPage->pBuf;
pPgHdr->pExtra = (void *)&pPgHdr[1];
- memset(pPgHdr->pExtra, 0, pCache->szExtra);
+ memset(pPgHdr->pExtra, 0, 8);
pPgHdr->pCache = pCache;
pPgHdr->pgno = pgno;
pPgHdr->flags = PGHDR_CLEAN;
@@ -41499,6 +44371,7 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheFetchFinish(
}
pCache->nRefSum++;
pPgHdr->nRef++;
+ assert( sqlite3PcachePageSanity(pPgHdr) );
return pPgHdr;
}
@@ -41512,8 +44385,11 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
if( (--p->nRef)==0 ){
if( p->flags&PGHDR_CLEAN ){
pcacheUnpin(p);
- }else if( p->pDirtyPrev!=0 ){
- /* Move the page to the head of the dirty list. */
+ }else if( p->pDirtyPrev!=0 ){ /*OPTIMIZATION-IF-FALSE*/
+ /* Move the page to the head of the dirty list. If p->pDirtyPrev==0,
+ ** then page p is already at the head of the dirty list and the
+ ** following call would be a no-op. Hence the OPTIMIZATION-IF-FALSE
+ ** tag above. */
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
}
}
@@ -41524,6 +44400,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
*/
SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
assert(p->nRef>0);
+ assert( sqlite3PcachePageSanity(p) );
p->nRef++;
p->pCache->nRefSum++;
}
@@ -41535,6 +44412,7 @@ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr *p){
*/
SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
assert( p->nRef==1 );
+ assert( sqlite3PcachePageSanity(p) );
if( p->flags&PGHDR_DIRTY ){
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
}
@@ -41548,13 +44426,16 @@ SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr *p){
*/
SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
assert( p->nRef>0 );
- if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){
+ assert( sqlite3PcachePageSanity(p) );
+ if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/
p->flags &= ~PGHDR_DONT_WRITE;
if( p->flags & PGHDR_CLEAN ){
p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN);
+ pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
}
+ assert( sqlite3PcachePageSanity(p) );
}
}
@@ -41563,11 +44444,14 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
** make it so.
*/
SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
- if( (p->flags & PGHDR_DIRTY) ){
+ assert( sqlite3PcachePageSanity(p) );
+ if( ALWAYS((p->flags & PGHDR_DIRTY)!=0) ){
assert( (p->flags & PGHDR_CLEAN)==0 );
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_REMOVE);
p->flags &= ~(PGHDR_DIRTY|PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
p->flags |= PGHDR_CLEAN;
+ pcacheTrace(("%p.CLEAN %d\n",p->pCache,p->pgno));
+ assert( sqlite3PcachePageSanity(p) );
if( p->nRef==0 ){
pcacheUnpin(p);
}
@@ -41579,12 +44463,25 @@ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr *p){
*/
SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache *pCache){
PgHdr *p;
+ pcacheTrace(("%p.CLEAN-ALL\n",pCache));
while( (p = pCache->pDirty)!=0 ){
sqlite3PcacheMakeClean(p);
}
}
/*
+** Clear the PGHDR_NEED_SYNC and PGHDR_WRITEABLE flag from all dirty pages.
+*/
+SQLITE_PRIVATE void sqlite3PcacheClearWritable(PCache *pCache){
+ PgHdr *p;
+ pcacheTrace(("%p.CLEAR-WRITEABLE\n",pCache));
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){
+ p->flags &= ~(PGHDR_NEED_SYNC|PGHDR_WRITEABLE);
+ }
+ pCache->pSynced = pCache->pDirtyTail;
+}
+
+/*
** Clear the PGHDR_NEED_SYNC flag from all dirty pages.
*/
SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
@@ -41602,6 +44499,8 @@ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
PCache *pCache = p->pCache;
assert( p->nRef>0 );
assert( newPgno>0 );
+ assert( sqlite3PcachePageSanity(p) );
+ pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
p->pgno = newPgno;
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
@@ -41622,6 +44521,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
if( pCache->pCache ){
PgHdr *p;
PgHdr *pNext;
+ pcacheTrace(("%p.TRUNCATE %d\n",pCache,pgno));
for(p=pCache->pDirty; p; p=pNext){
pNext = p->pDirtyNext;
/* This routine never gets call with a positive pgno except right
@@ -41629,7 +44529,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
** it must be that pgno==0.
*/
assert( p->pgno>0 );
- if( ALWAYS(p->pgno>pgno) ){
+ if( p->pgno>pgno ){
assert( p->flags&PGHDR_DIRTY );
sqlite3PcacheMakeClean(p);
}
@@ -41652,6 +44552,7 @@ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
*/
SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
assert( pCache->pCache!=0 );
+ pcacheTrace(("%p.CLOSE\n",pCache));
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
}
@@ -41664,29 +44565,31 @@ SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
/*
** Merge two lists of pages connected by pDirty and in pgno order.
-** Do not both fixing the pDirtyPrev pointers.
+** Do not bother fixing the pDirtyPrev pointers.
*/
static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
PgHdr result, *pTail;
pTail = &result;
- while( pA && pB ){
+ assert( pA!=0 && pB!=0 );
+ for(;;){
if( pA->pgno<pB->pgno ){
pTail->pDirty = pA;
pTail = pA;
pA = pA->pDirty;
+ if( pA==0 ){
+ pTail->pDirty = pB;
+ break;
+ }
}else{
pTail->pDirty = pB;
pTail = pB;
pB = pB->pDirty;
+ if( pB==0 ){
+ pTail->pDirty = pA;
+ break;
+ }
}
}
- if( pA ){
- pTail->pDirty = pA;
- }else if( pB ){
- pTail->pDirty = pB;
- }else{
- pTail->pDirty = 0;
- }
return result.pDirty;
}
@@ -41727,7 +44630,8 @@ static PgHdr *pcacheSortDirtyList(PgHdr *pIn){
}
p = a[0];
for(i=1; i<N_SORT_BUCKET; i++){
- p = pcacheMergeDirtyList(p, a[i]);
+ if( a[i]==0 ) continue;
+ p = p ? pcacheMergeDirtyList(p, a[i]) : a[i];
}
return p;
}
@@ -41820,6 +44724,17 @@ SQLITE_PRIVATE void sqlite3PcacheShrink(PCache *pCache){
*/
SQLITE_PRIVATE int sqlite3HeaderSizePcache(void){ return ROUND8(sizeof(PgHdr)); }
+/*
+** Return the number of dirty pages currently in the cache, as a percentage
+** of the configured cache size.
+*/
+SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){
+ PgHdr *pDirty;
+ int nDirty = 0;
+ int nCache = numberOfCachePages(pCache);
+ for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext) nDirty++;
+ return nCache ? (int)(((i64)nDirty * 100) / nCache) : 0;
+}
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
/*
@@ -42118,7 +45033,7 @@ static int pcache1InitBulk(PCache1 *pCache){
szBulk = -1024 * (i64)pcache1.nInitPage;
}
if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){
- szBulk = pCache->szAlloc*pCache->nMax;
+ szBulk = pCache->szAlloc*(i64)pCache->nMax;
}
zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
sqlite3EndBenignMalloc();
@@ -42187,7 +45102,6 @@ static void *pcache1Alloc(int nByte){
** Free an allocated buffer obtained from pcache1Alloc().
*/
static void pcache1Free(void *p){
- int nFreed = 0;
if( p==0 ) return;
if( SQLITE_WITHIN(p, pcache1.pStart, pcache1.pEnd) ){
PgFreeslot *pSlot;
@@ -42204,10 +45118,13 @@ static void pcache1Free(void *p){
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
- nFreed = sqlite3MallocSize(p);
- sqlite3_mutex_enter(pcache1.mutex);
- sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
- sqlite3_mutex_leave(pcache1.mutex);
+ {
+ int nFreed = 0;
+ nFreed = sqlite3MallocSize(p);
+ sqlite3_mutex_enter(pcache1.mutex);
+ sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
+ sqlite3_mutex_leave(pcache1.mutex);
+ }
#endif
sqlite3_free(p);
}
@@ -42469,12 +45386,30 @@ static void pcache1TruncateUnsafe(
PCache1 *pCache, /* The cache to truncate */
unsigned int iLimit /* Drop pages with this pgno or larger */
){
- TESTONLY( unsigned int nPage = 0; ) /* To assert pCache->nPage is correct */
- unsigned int h;
+ TESTONLY( int nPage = 0; ) /* To assert pCache->nPage is correct */
+ unsigned int h, iStop;
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
- for(h=0; h<pCache->nHash; h++){
- PgHdr1 **pp = &pCache->apHash[h];
+ assert( pCache->iMaxKey >= iLimit );
+ assert( pCache->nHash > 0 );
+ if( pCache->iMaxKey - iLimit < pCache->nHash ){
+ /* If we are just shaving the last few pages off the end of the
+ ** cache, then there is no point in scanning the entire hash table.
+ ** Only scan those hash slots that might contain pages that need to
+ ** be removed. */
+ h = iLimit % pCache->nHash;
+ iStop = pCache->iMaxKey % pCache->nHash;
+ TESTONLY( nPage = -10; ) /* Disable the pCache->nPage validity check */
+ }else{
+ /* This is the general case where many pages are being removed.
+ ** It is necessary to scan the entire hash table */
+ h = pCache->nHash/2;
+ iStop = h - 1;
+ }
+ for(;;){
+ PgHdr1 **pp;
PgHdr1 *pPage;
+ assert( h<pCache->nHash );
+ pp = &pCache->apHash[h];
while( (pPage = *pp)!=0 ){
if( pPage->iKey>=iLimit ){
pCache->nPage--;
@@ -42483,11 +45418,13 @@ static void pcache1TruncateUnsafe(
pcache1FreePage(pPage);
}else{
pp = &pPage->pNext;
- TESTONLY( nPage++; )
+ TESTONLY( if( nPage>=0 ) nPage++; )
}
}
+ if( h==iStop ) break;
+ h = (h+1) % pCache->nHash;
}
- assert( pCache->nPage==nPage );
+ assert( nPage<0 || pCache->nPage==(unsigned)nPage );
}
/******************************************************************************/
@@ -42527,8 +45464,8 @@ static int pcache1Init(void *NotUsed){
#if SQLITE_THREADSAFE
if( sqlite3GlobalConfig.bCoreMutex ){
- pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
- pcache1.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PMEM);
+ pcache1.grp.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_LRU);
+ pcache1.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PMEM);
}
#endif
if( pcache1.separateCache
@@ -42964,7 +45901,7 @@ static void pcache1Destroy(sqlite3_pcache *p){
PGroup *pGroup = pCache->pGroup;
assert( pCache->bPurgeable || (pCache->nMax==0 && pCache->nMin==0) );
pcache1EnterMutex(pGroup);
- pcache1TruncateUnsafe(pCache, 0);
+ if( pCache->nPage ) pcache1TruncateUnsafe(pCache, 0);
assert( pGroup->nMaxPage >= pCache->nMax );
pGroup->nMaxPage -= pCache->nMax;
assert( pGroup->nMinPage >= pCache->nMin );
@@ -43134,8 +46071,9 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST
** primitives are constant time. The cost of DESTROY is O(N).
**
-** There is an added cost of O(N) when switching between TEST and
-** SMALLEST primitives.
+** TEST and SMALLEST may not be used by the same RowSet. This used to
+** be possible, but the feature was not used, so it was removed in order
+** to simplify the code.
*/
/* #include "sqliteInt.h" */
@@ -43256,7 +46194,9 @@ SQLITE_PRIVATE void sqlite3RowSetClear(RowSet *p){
*/
static struct RowSetEntry *rowSetEntryAlloc(RowSet *p){
assert( p!=0 );
- if( p->nFresh==0 ){
+ if( p->nFresh==0 ){ /*OPTIMIZATION-IF-FALSE*/
+ /* We could allocate a fresh RowSetEntry each time one is needed, but it
+ ** is more efficient to pull a preallocated entry from the pool */
struct RowSetChunk *pNew;
pNew = sqlite3DbMallocRawNN(p->db, sizeof(*pNew));
if( pNew==0 ){
@@ -43290,7 +46230,9 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
pEntry->pRight = 0;
pLast = p->pLast;
if( pLast ){
- if( (p->rsFlags & ROWSET_SORTED)!=0 && rowid<=pLast->v ){
+ if( rowid<=pLast->v ){ /*OPTIMIZATION-IF-FALSE*/
+ /* Avoid unnecessary sorts by preserving the ROWSET_SORTED flags
+ ** where possible */
p->rsFlags &= ~ROWSET_SORTED;
}
pLast->pRight = pEntry;
@@ -43314,28 +46256,26 @@ static struct RowSetEntry *rowSetEntryMerge(
struct RowSetEntry *pTail;
pTail = &head;
- while( pA && pB ){
+ assert( pA!=0 && pB!=0 );
+ for(;;){
assert( pA->pRight==0 || pA->v<=pA->pRight->v );
assert( pB->pRight==0 || pB->v<=pB->pRight->v );
- if( pA->v<pB->v ){
- pTail->pRight = pA;
+ if( pA->v<=pB->v ){
+ if( pA->v<pB->v ) pTail = pTail->pRight = pA;
pA = pA->pRight;
- pTail = pTail->pRight;
- }else if( pB->v<pA->v ){
- pTail->pRight = pB;
- pB = pB->pRight;
- pTail = pTail->pRight;
+ if( pA==0 ){
+ pTail->pRight = pB;
+ break;
+ }
}else{
- pA = pA->pRight;
+ pTail = pTail->pRight = pB;
+ pB = pB->pRight;
+ if( pB==0 ){
+ pTail->pRight = pA;
+ break;
+ }
}
}
- if( pA ){
- assert( pA->pRight==0 || pA->v<=pA->pRight->v );
- pTail->pRight = pA;
- }else{
- assert( pB==0 || pB->pRight==0 || pB->v<=pB->pRight->v );
- pTail->pRight = pB;
- }
return head.pRight;
}
@@ -43358,9 +46298,10 @@ static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
aBucket[i] = pIn;
pIn = pNext;
}
- pIn = 0;
- for(i=0; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
- pIn = rowSetEntryMerge(pIn, aBucket[i]);
+ pIn = aBucket[0];
+ for(i=1; i<sizeof(aBucket)/sizeof(aBucket[0]); i++){
+ if( aBucket[i]==0 ) continue;
+ pIn = pIn ? rowSetEntryMerge(pIn, aBucket[i]) : aBucket[i];
}
return pIn;
}
@@ -43412,23 +46353,29 @@ static struct RowSetEntry *rowSetNDeepTree(
){
struct RowSetEntry *p; /* Root of the new tree */
struct RowSetEntry *pLeft; /* Left subtree */
- if( *ppList==0 ){
- return 0;
- }
- if( iDepth==1 ){
+ if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/
+ /* Prevent unnecessary deep recursion when we run out of entries */
+ return 0;
+ }
+ if( iDepth>1 ){ /*OPTIMIZATION-IF-TRUE*/
+ /* This branch causes a *balanced* tree to be generated. A valid tree
+ ** is still generated without this branch, but the tree is wildly
+ ** unbalanced and inefficient. */
+ pLeft = rowSetNDeepTree(ppList, iDepth-1);
+ p = *ppList;
+ if( p==0 ){ /*OPTIMIZATION-IF-FALSE*/
+ /* It is safe to always return here, but the resulting tree
+ ** would be unbalanced */
+ return pLeft;
+ }
+ p->pLeft = pLeft;
+ *ppList = p->pRight;
+ p->pRight = rowSetNDeepTree(ppList, iDepth-1);
+ }else{
p = *ppList;
*ppList = p->pRight;
p->pLeft = p->pRight = 0;
- return p;
- }
- pLeft = rowSetNDeepTree(ppList, iDepth-1);
- p = *ppList;
- if( p==0 ){
- return pLeft;
}
- p->pLeft = pLeft;
- *ppList = p->pRight;
- p->pRight = rowSetNDeepTree(ppList, iDepth-1);
return p;
}
@@ -43456,58 +46403,36 @@ static struct RowSetEntry *rowSetListToTree(struct RowSetEntry *pList){
}
/*
-** Take all the entries on p->pEntry and on the trees in p->pForest and
-** sort them all together into one big ordered list on p->pEntry.
-**
-** This routine should only be called once in the life of a RowSet.
-*/
-static void rowSetToList(RowSet *p){
-
- /* This routine is called only once */
- assert( p!=0 && (p->rsFlags & ROWSET_NEXT)==0 );
-
- if( (p->rsFlags & ROWSET_SORTED)==0 ){
- p->pEntry = rowSetEntrySort(p->pEntry);
- }
-
- /* While this module could theoretically support it, sqlite3RowSetNext()
- ** is never called after sqlite3RowSetText() for the same RowSet. So
- ** there is never a forest to deal with. Should this change, simply
- ** remove the assert() and the #if 0. */
- assert( p->pForest==0 );
-#if 0
- while( p->pForest ){
- struct RowSetEntry *pTree = p->pForest->pLeft;
- if( pTree ){
- struct RowSetEntry *pHead, *pTail;
- rowSetTreeToList(pTree, &pHead, &pTail);
- p->pEntry = rowSetEntryMerge(p->pEntry, pHead);
- }
- p->pForest = p->pForest->pRight;
- }
-#endif
- p->rsFlags |= ROWSET_NEXT; /* Verify this routine is never called again */
-}
-
-/*
** Extract the smallest element from the RowSet.
** Write the element into *pRowid. Return 1 on success. Return
** 0 if the RowSet is already empty.
**
** After this routine has been called, the sqlite3RowSetInsert()
-** routine may not be called again.
+** routine may not be called again.
+**
+** This routine may not be called after sqlite3RowSetTest() has
+** been used. Older versions of RowSet allowed that, but as the
+** capability was not used by the code generator, it was removed
+** for code economy.
*/
SQLITE_PRIVATE int sqlite3RowSetNext(RowSet *p, i64 *pRowid){
assert( p!=0 );
+ assert( p->pForest==0 ); /* Cannot be used with sqlite3RowSetText() */
/* Merge the forest into a single sorted list on first call */
- if( (p->rsFlags & ROWSET_NEXT)==0 ) rowSetToList(p);
+ if( (p->rsFlags & ROWSET_NEXT)==0 ){ /*OPTIMIZATION-IF-FALSE*/
+ if( (p->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
+ p->pEntry = rowSetEntrySort(p->pEntry);
+ }
+ p->rsFlags |= ROWSET_SORTED|ROWSET_NEXT;
+ }
/* Return the next entry on the list */
if( p->pEntry ){
*pRowid = p->pEntry->v;
p->pEntry = p->pEntry->pRight;
- if( p->pEntry==0 ){
+ if( p->pEntry==0 ){ /*OPTIMIZATION-IF-TRUE*/
+ /* Free memory immediately, rather than waiting on sqlite3_finalize() */
sqlite3RowSetClear(p);
}
return 1;
@@ -43530,13 +46455,15 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
/* This routine is never called after sqlite3RowSetNext() */
assert( pRowSet!=0 && (pRowSet->rsFlags & ROWSET_NEXT)==0 );
- /* Sort entries into the forest on the first test of a new batch
+ /* Sort entries into the forest on the first test of a new batch.
+ ** To save unnecessary work, only do this when the batch number changes.
*/
- if( iBatch!=pRowSet->iBatch ){
+ if( iBatch!=pRowSet->iBatch ){ /*OPTIMIZATION-IF-FALSE*/
p = pRowSet->pEntry;
if( p ){
struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
- if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){
+ if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
+ /* Only sort the current set of entiries if they need it */
p = rowSetEntrySort(p);
}
for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
@@ -43626,8 +46553,8 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
** the implementation of each function in log.c for further details.
*/
-#ifndef _WAL_H_
-#define _WAL_H_
+#ifndef SQLITE_WAL_H
+#define SQLITE_WAL_H
/* #include "sqliteInt.h" */
@@ -43640,7 +46567,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
#ifdef SQLITE_OMIT_WAL
# define sqlite3WalOpen(x,y,z) 0
# define sqlite3WalLimit(x,y)
-# define sqlite3WalClose(w,x,y,z) 0
+# define sqlite3WalClose(v,w,x,y,z) 0
# define sqlite3WalBeginReadTransaction(y,z) 0
# define sqlite3WalEndReadTransaction(z)
# define sqlite3WalDbsize(y) 0
@@ -43650,7 +46577,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
# define sqlite3WalSavepoint(y,z)
# define sqlite3WalSavepointUndo(y,z) 0
# define sqlite3WalFrames(u,v,w,x,y,z) 0
-# define sqlite3WalCheckpoint(r,s,t,u,v,w,x,y,z) 0
+# define sqlite3WalCheckpoint(q,r,s,t,u,v,w,x,y,z) 0
# define sqlite3WalCallback(z) 0
# define sqlite3WalExclusiveMode(y,z) 0
# define sqlite3WalHeapMemory(z) 0
@@ -43668,7 +46595,7 @@ typedef struct Wal Wal;
/* Open and close a connection to a write-ahead log. */
SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**);
-SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
+SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8 *);
/* Set the limiting size of a WAL file. */
SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
@@ -43711,6 +46638,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
/* Copy pages from the log to the database file */
SQLITE_PRIVATE int sqlite3WalCheckpoint(
Wal *pWal, /* Write-ahead log connection */
+ sqlite3 *db, /* Check this handle's interrupt flag */
int eMode, /* One of PASSIVE, FULL and RESTART */
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
@@ -43742,6 +46670,7 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
#ifdef SQLITE_ENABLE_SNAPSHOT
SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot);
+SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal);
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
@@ -43755,7 +46684,7 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
#endif /* ifndef SQLITE_OMIT_WAL */
-#endif /* _WAL_H_ */
+#endif /* SQLITE_WAL_H */
/************** End of wal.h *************************************************/
/************** Continuing where we left off in pager.c **********************/
@@ -44166,19 +47095,6 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
*/
#define MAX_SECTOR_SIZE 0x10000
-/*
-** If the option SQLITE_EXTRA_DURABLE option is set at compile-time, then
-** SQLite will do extra fsync() operations when synchronous==FULL to help
-** ensure that transactions are durable across a power failure. Most
-** applications are happy as long as transactions are consistent across
-** a power failure, and are perfectly willing to lose the last transaction
-** in exchange for the extra performance of avoiding directory syncs.
-** And so the default SQLITE_EXTRA_DURABLE setting is off.
-*/
-#ifndef SQLITE_EXTRA_DURABLE
-# define SQLITE_EXTRA_DURABLE 0
-#endif
-
/*
** An instance of the following structure is allocated for each active
@@ -44444,6 +47360,7 @@ struct Pager {
int nRead; /* Database pages read */
#endif
void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
+ int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
#ifdef SQLITE_HAS_CODEC
void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
@@ -44568,9 +47485,10 @@ static const unsigned char aJournalMagic[] = {
** rollback journal. Otherwise false.
*/
#ifndef SQLITE_OMIT_WAL
-static int pagerUseWal(Pager *pPager){
+SQLITE_PRIVATE int sqlite3PagerUseWal(Pager *pPager){
return (pPager->pWal!=0);
}
+# define pagerUseWal(x) sqlite3PagerUseWal(x)
#else
# define pagerUseWal(x) 0
# define pagerRollbackWal(x) 0
@@ -44623,6 +47541,7 @@ static int assert_pager_state(Pager *p){
** state.
*/
if( MEMDB ){
+ assert( !isOpen(p->fd) );
assert( p->noSync );
assert( p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_MEMORY
@@ -44709,7 +47628,7 @@ static int assert_pager_state(Pager *p){
** back to OPEN state.
*/
assert( pPager->errCode!=SQLITE_OK );
- assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
+ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 || pPager->tempFile );
break;
}
@@ -44768,6 +47687,33 @@ static char *print_pager_state(Pager *p){
}
#endif
+/* Forward references to the various page getters */
+static int getPageNormal(Pager*,Pgno,DbPage**,int);
+static int getPageError(Pager*,Pgno,DbPage**,int);
+#if SQLITE_MAX_MMAP_SIZE>0
+static int getPageMMap(Pager*,Pgno,DbPage**,int);
+#endif
+
+/*
+** Set the Pager.xGet method for the appropriate routine used to fetch
+** content from the pager.
+*/
+static void setGetterMethod(Pager *pPager){
+ if( pPager->errCode ){
+ pPager->xGet = getPageError;
+#if SQLITE_MAX_MMAP_SIZE>0
+ }else if( USEFETCH(pPager)
+#ifdef SQLITE_HAS_CODEC
+ && pPager->xCodec==0
+#endif
+ ){
+ pPager->xGet = getPageMMap;
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+ }else{
+ pPager->xGet = getPageNormal;
+ }
+}
+
/*
** Return true if it is necessary to write page *pPg into the sub-journal.
** A page needs to be written into the sub-journal if there exists one
@@ -44921,6 +47867,8 @@ static int jrnlBufferSize(Pager *pPager){
return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
}
+#else
+# define jrnlBufferSize(x) 0
#endif
/*
@@ -45081,6 +48029,7 @@ static i64 journalHdrOffset(Pager *pPager){
static int zeroJournalHdr(Pager *pPager, int doTruncate){
int rc = SQLITE_OK; /* Return code */
assert( isOpen(pPager->jfd) );
+ assert( !sqlite3JournalIsInMemory(pPager->jfd) );
if( pPager->journalOff ){
const i64 iLimit = pPager->journalSizeLimit; /* Local cache of jsl */
@@ -45462,7 +48411,7 @@ static void releaseAllSavepoints(Pager *pPager){
for(ii=0; ii<pPager->nSavepoint; ii++){
sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint);
}
- if( !pPager->exclusiveMode || sqlite3IsMemJournal(pPager->sjfd) ){
+ if( !pPager->exclusiveMode || sqlite3JournalIsInMemory(pPager->sjfd) ){
sqlite3OsClose(pPager->sjfd);
}
sqlite3_free(pPager->aSavepoint);
@@ -45568,13 +48517,18 @@ static void pager_unlock(Pager *pPager){
** it can safely move back to PAGER_OPEN state. This happens in both
** normal and exclusive-locking mode.
*/
+ assert( pPager->errCode==SQLITE_OK || !MEMDB );
if( pPager->errCode ){
- assert( !MEMDB );
- pager_reset(pPager);
- pPager->changeCountDone = pPager->tempFile;
- pPager->eState = PAGER_OPEN;
- pPager->errCode = SQLITE_OK;
+ if( pPager->tempFile==0 ){
+ pager_reset(pPager);
+ pPager->changeCountDone = 0;
+ pPager->eState = PAGER_OPEN;
+ }else{
+ pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER);
+ }
if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
+ pPager->errCode = SQLITE_OK;
+ setGetterMethod(pPager);
}
pPager->journalOff = 0;
@@ -45612,6 +48566,7 @@ static int pager_error(Pager *pPager, int rc){
if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){
pPager->errCode = rc;
pPager->eState = PAGER_ERROR;
+ setGetterMethod(pPager);
}
return rc;
}
@@ -45619,6 +48574,29 @@ static int pager_error(Pager *pPager, int rc){
static int pager_truncate(Pager *pPager, Pgno nPage);
/*
+** The write transaction open on pPager is being committed (bCommit==1)
+** or rolled back (bCommit==0).
+**
+** Return TRUE if and only if all dirty pages should be flushed to disk.
+**
+** Rules:
+**
+** * For non-TEMP databases, always sync to disk. This is necessary
+** for transactions to be durable.
+**
+** * Sync TEMP database only on a COMMIT (not a ROLLBACK) when the backing
+** file has been created already (via a spill on pagerStress()) and
+** when the number of dirty pages in memory exceeds 25% of the total
+** cache size.
+*/
+static int pagerFlushOnCommit(Pager *pPager, int bCommit){
+ if( pPager->tempFile==0 ) return 1;
+ if( !bCommit ) return 0;
+ if( !isOpen(pPager->fd) ) return 0;
+ return (sqlite3PCachePercentDirty(pPager->pPCache)>=25);
+}
+
+/*
** This routine ends a transaction. A transaction is usually ended by
** either a COMMIT or a ROLLBACK operation. This routine may be called
** after rollback of a hot-journal, or if an error occurs while opening
@@ -45700,8 +48678,8 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
assert( !pagerUseWal(pPager) );
/* Finalize the journal file. */
- if( sqlite3IsMemJournal(pPager->jfd) ){
- assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY );
+ if( sqlite3JournalIsInMemory(pPager->jfd) ){
+ /* assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); */
sqlite3OsClose(pPager->jfd);
}else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){
if( pPager->journalOff==0 ){
@@ -45721,15 +48699,16 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|| (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
){
- rc = zeroJournalHdr(pPager, hasMaster);
+ rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
pPager->journalOff = 0;
}else{
/* This branch may be executed with Pager.journalMode==MEMORY if
** a hot-journal was just rolled back. In this case the journal
** file should be closed and deleted. If this connection writes to
- ** the database file, it will do so using an in-memory journal.
+ ** the database file, it will do so using an in-memory journal.
*/
- int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd));
+ int bDelete = !pPager->tempFile;
+ assert( sqlite3JournalIsInMemory(pPager->jfd)==0 );
assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
@@ -45755,8 +48734,14 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
pPager->nRec = 0;
- sqlite3PcacheCleanAll(pPager->pPCache);
- sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
+ if( rc==SQLITE_OK ){
+ if( MEMDB || pagerFlushOnCommit(pPager, bCommit) ){
+ sqlite3PcacheCleanAll(pPager->pPCache);
+ }else{
+ sqlite3PcacheClearWritable(pPager->pPCache);
+ }
+ sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize);
+ }
if( pagerUseWal(pPager) ){
/* Drop the WAL write-lock, if any. Also, if the connection was in
@@ -46040,7 +49025,7 @@ static int pager_playback_one_page(
pPg = sqlite3PagerLookup(pPager, pgno);
}
assert( pPg || !MEMDB );
- assert( pPager->eState!=PAGER_OPEN || pPg==0 );
+ assert( pPager->eState!=PAGER_OPEN || pPg==0 || pPager->tempFile );
PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
(isMainJrnl?"main-journal":"sub-journal")
@@ -46062,9 +49047,9 @@ static int pager_playback_one_page(
pPager->dbFileSize = pgno;
}
if( pPager->pBackup ){
- CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM);
+ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
- CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM, aData);
+ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
}
}else if( !isMainJrnl && pPg==0 ){
/* If this is a rollback of a savepoint and data was not written to
@@ -46090,7 +49075,6 @@ static int pager_playback_one_page(
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
if( rc!=SQLITE_OK ) return rc;
- pPg->flags &= ~PGHDR_NEED_READ;
sqlite3PcacheMakeDirty(pPg);
}
if( pPg ){
@@ -46104,29 +49088,10 @@ static int pager_playback_one_page(
pData = pPg->pData;
memcpy(pData, (u8*)aData, pPager->pageSize);
pPager->xReiniter(pPg);
- if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){
- /* If the contents of this page were just restored from the main
- ** journal file, then its content must be as they were when the
- ** transaction was first opened. In this case we can mark the page
- ** as clean, since there will be no need to write it out to the
- ** database.
- **
- ** There is one exception to this rule. If the page is being rolled
- ** back as part of a savepoint (or statement) rollback from an
- ** unsynced portion of the main journal file, then it is not safe
- ** to mark the page as clean. This is because marking the page as
- ** clean will clear the PGHDR_NEED_SYNC flag. Since the page is
- ** already in the journal file (recorded in Pager.pInJournal) and
- ** the PGHDR_NEED_SYNC flag is cleared, if the page is written to
- ** again within this transaction, it will be marked as dirty but
- ** the PGHDR_NEED_SYNC flag will not be set. It could then potentially
- ** be written out into the database file before its journal file
- ** segment is synced. If a crash occurs during or following this,
- ** database corruption may ensue.
- */
- assert( !pagerUseWal(pPager) );
- sqlite3PcacheMakeClean(pPg);
- }
+ /* It used to be that sqlite3PcacheMakeClean(pPg) was called here. But
+ ** that call was dangerous and had no detectable benefit since the cache
+ ** is normally cleaned by sqlite3PcacheCleanAll() after rollback and so
+ ** has been removed. */
pager_set_pagehash(pPg);
/* If this was page 1, then restore the value of Pager.dbFileVers.
@@ -46136,7 +49101,7 @@ static int pager_playback_one_page(
}
/* Decode the page just read from disk */
- CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM);
+ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
sqlite3PcacheRelease(pPg);
}
return rc;
@@ -46202,7 +49167,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
if( !pMaster ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
@@ -46219,7 +49184,7 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
nMasterPtr = pVfs->mxPathname+1;
zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1);
if( !zMasterJournal ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto delmaster_out;
}
zMasterPtr = &zMasterJournal[nMasterJournal+1];
@@ -46467,7 +49432,7 @@ static int pager_playback(Pager *pPager, int isHot){
** TODO: Technically the following is an error because it assumes that
** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that
** (pPager->pageSize >= pPager->pVfs->mxPathname+1). Using os_unix.c,
- ** mxPathname is 512, which is the same as the minimum allowable value
+ ** mxPathname is 512, which is the same as the minimum allowable value
** for pageSize.
*/
zMaster = pPager->pTmpSpace;
@@ -46689,7 +49654,7 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
}
}
- CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM);
+ CODEC1(pPager, pPg->pData, pgno, 3, rc = SQLITE_NOMEM_BKPT);
PAGER_INCR(sqlite3_pager_readdb_count);
PAGER_INCR(pPager->nRead);
@@ -46917,6 +49882,8 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
*/
assert( pPager->eState==PAGER_OPEN );
assert( pPager->eLock>=SHARED_LOCK );
+ assert( isOpen(pPager->fd) );
+ assert( pPager->tempFile==0 );
nPage = sqlite3WalDbsize(pPager->pWal);
/* If the number of pages in the database is not available from the
@@ -46924,14 +49891,11 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
** the database file. If the size of the database file is not an
** integer multiple of the page-size, round up the result.
*/
- if( nPage==0 ){
+ if( nPage==0 && ALWAYS(isOpen(pPager->fd)) ){
i64 n = 0; /* Size of db file in bytes */
- assert( isOpen(pPager->fd) || pPager->tempFile );
- if( isOpen(pPager->fd) ){
- int rc = sqlite3OsFileSize(pPager->fd, &n);
- if( rc!=SQLITE_OK ){
- return rc;
- }
+ int rc = sqlite3OsFileSize(pPager->fd, &n);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
nPage = (Pgno)((n+pPager->pageSize-1) / pPager->pageSize);
}
@@ -47049,7 +50013,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
if( pSavepoint ){
pDone = sqlite3BitvecCreate(pSavepoint->nOrig);
if( !pDone ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
}
@@ -47170,6 +50134,7 @@ static void pagerFixMaplimit(Pager *pPager){
sqlite3_int64 sz;
sz = pPager->szMmap;
pPager->bUseFetch = (sz>0);
+ setGetterMethod(pPager);
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz);
}
#endif
@@ -47196,7 +50161,7 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
** of the database to damage due to OS crashes or power failures by
** changing the number of syncs()s when writing the journals.
-** There are three levels:
+** There are four levels:
**
** OFF sqlite3OsSync() is never called. This is the default
** for temporary and transient files.
@@ -47216,6 +50181,10 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
** assurance that the journal will not be corrupted to the
** point of causing damage to the database during rollback.
**
+** EXTRA This is like FULL except that is also syncs the directory
+** that contains the rollback journal after the rollback
+** journal is unlinked.
+**
** The above is for a rollback-journal mode. For WAL mode, OFF continues
** to mean that no syncs ever occur. NORMAL means that the WAL is synced
** prior to the start of checkpoint and that the database file is synced
@@ -47223,7 +50192,8 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
** was written back into the database. But no sync operations occur for
** an ordinary commit in NORMAL mode with WAL. FULL means that the WAL
** file is synced following each commit operation, in addition to the
-** syncs associated with NORMAL.
+** syncs associated with NORMAL. There is no difference between FULL
+** and EXTRA for WAL mode.
**
** Do not confuse synchronous=FULL with SQLITE_SYNC_FULL. The
** SQLITE_SYNC_FULL macro means to use the MacOSX-style full-fsync
@@ -47412,7 +50382,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
}
if( rc==SQLITE_OK ){
pNew = (char *)sqlite3PageMalloc(pageSize);
- if( !pNew ) rc = SQLITE_NOMEM;
+ if( !pNew ) rc = SQLITE_NOMEM_BKPT;
}
if( rc==SQLITE_OK ){
@@ -47661,6 +50631,7 @@ static int pagerSyncHotJournal(Pager *pPager){
return rc;
}
+#if SQLITE_MAX_MMAP_SIZE>0
/*
** Obtain a reference to a memory mapped page object for page number pgno.
** The new object will use the pointer pData, obtained from xFetch().
@@ -47683,12 +50654,13 @@ static int pagerAcquireMapPage(
*ppPage = p = pPager->pMmapFreelist;
pPager->pMmapFreelist = p->pDirty;
p->pDirty = 0;
- memset(p->pExtra, 0, pPager->nExtra);
+ assert( pPager->nExtra>=8 );
+ memset(p->pExtra, 0, 8);
}else{
*ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
if( p==0 ){
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
p->pExtra = (void *)&p[1];
p->flags = PGHDR_MMAP;
@@ -47708,6 +50680,7 @@ static int pagerAcquireMapPage(
return SQLITE_OK;
}
+#endif
/*
** Release a reference to page pPg. pPg must have been returned by an
@@ -47750,9 +50723,10 @@ static void pagerFreeMapHdrs(Pager *pPager){
** a hot journal may be left in the filesystem but no error is returned
** to the caller.
*/
-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
+SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
u8 *pTmp = (u8 *)pPager->pTmpSpace;
+ assert( db || pagerUseWal(pPager)==0 );
assert( assert_pager_state(pPager) );
disable_simulated_io_errors();
sqlite3BeginBenignMalloc();
@@ -47760,7 +50734,10 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager){
/* pPager->errCode = 0; */
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
- sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
+ assert( db || pPager->pWal==0 );
+ sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags, pPager->pageSize,
+ (db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp)
+ );
pPager->pWal = 0;
#endif
pager_reset(pPager);
@@ -48002,8 +50979,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
/* This function is only called for rollback pagers in WRITER_DBMOD state. */
assert( !pagerUseWal(pPager) );
- assert( pPager->eState==PAGER_WRITER_DBMOD );
+ assert( pPager->tempFile || pPager->eState==PAGER_WRITER_DBMOD );
assert( pPager->eLock==EXCLUSIVE_LOCK );
+ assert( isOpen(pPager->fd) || pList->pDirty==0 );
/* If the file is a temp-file has not yet been opened, open it now. It
** is not possible for rc to be other than SQLITE_OK if this branch
@@ -48046,7 +51024,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
if( pList->pgno==1 ) pager_write_changecounter(pList);
/* Encode the database */
- CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
+ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData);
/* Write out the page data. */
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
@@ -48091,11 +51069,14 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
static int openSubJournal(Pager *pPager){
int rc = SQLITE_OK;
if( !isOpen(pPager->sjfd) ){
+ const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE
+ | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE
+ | SQLITE_OPEN_DELETEONCLOSE;
+ int nStmtSpill = sqlite3Config.nStmtSpill;
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
- sqlite3MemJournalOpen(pPager->sjfd);
- }else{
- rc = pagerOpentemp(pPager, pPager->sjfd, SQLITE_OPEN_SUBJOURNAL);
+ nStmtSpill = -1;
}
+ rc = sqlite3JournalOpen(pPager->pVfs, 0, pPager->sjfd, flags, nStmtSpill);
}
return rc;
}
@@ -48133,7 +51114,7 @@ static int subjournalPage(PgHdr *pPg){
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
char *pData2;
- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
+ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
rc = write32bits(pPager->sjfd, offset, pPg->pgno);
if( rc==SQLITE_OK ){
@@ -48275,7 +51256,9 @@ SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){
**
** The nExtra parameter specifies the number of bytes of space allocated
** along with each page reference. This space is available to the user
-** via the sqlite3PagerGetExtra() API.
+** via the sqlite3PagerGetExtra() API. When a new page is allocated, the
+** first 8 bytes of this space are zeroed but the remainder is uninitialized.
+** (The extra space is used by btree as the MemPage object.)
**
** The flags argument is used to specify properties that affect the
** operation of the pager. It should be passed some bitwise combination
@@ -48316,18 +51299,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int nUri = 0; /* Number of bytes of URI args at *zUri */
/* Figure out how much space is required for each journal file-handle
- ** (there are two of them, the main journal and the sub-journal). This
- ** is the maximum space required for an in-memory journal file handle
- ** and a regular journal file-handle. Note that a "regular journal-handle"
- ** may be a wrapper capable of caching the first portion of the journal
- ** file in memory to implement the atomic-write optimization (see
- ** source file journal.c).
- */
- if( sqlite3JournalSize(pVfs)>sqlite3MemJournalSize() ){
- journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
- }else{
- journalFileSize = ROUND8(sqlite3MemJournalSize());
- }
+ ** (there are two of them, the main journal and the sub-journal). */
+ journalFileSize = ROUND8(sqlite3JournalSize(pVfs));
/* Set the output variable to NULL in case an error occurs. */
*ppPager = 0;
@@ -48337,7 +51310,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
memDb = 1;
if( zFilename && zFilename[0] ){
zPathname = sqlite3DbStrDup(0, zFilename);
- if( zPathname==0 ) return SQLITE_NOMEM;
+ if( zPathname==0 ) return SQLITE_NOMEM_BKPT;
nPathname = sqlite3Strlen30(zPathname);
zFilename = 0;
}
@@ -48353,7 +51326,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
nPathname = pVfs->mxPathname+1;
zPathname = sqlite3DbMallocRaw(0, nPathname*2);
if( zPathname==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */
rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
@@ -48406,7 +51379,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) );
if( !pPtr ){
sqlite3DbFree(0, zPathname);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pPager = (Pager*)(pPtr);
pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager)));
@@ -48515,8 +51488,8 @@ act_like_temp_file:
/* Initialize the PCache object. */
if( rc==SQLITE_OK ){
- assert( nExtra<1000 );
nExtra = ROUND8(nExtra);
+ assert( nExtra>=8 && nExtra<1000 );
rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb,
!memDb?pagerStress:0, (void *)pPager, pPager->pPCache);
}
@@ -48561,11 +51534,7 @@ act_like_temp_file:
assert( pPager->ckptSyncFlags==0 );
}else{
pPager->fullSync = 1;
-#if SQLITE_EXTRA_DURABLE
- pPager->extraSync = 1;
-#else
pPager->extraSync = 0;
-#endif
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->walSyncFlags = SQLITE_SYNC_NORMAL | WAL_SYNC_TRANSACTIONS;
pPager->ckptSyncFlags = SQLITE_SYNC_NORMAL;
@@ -48585,6 +51554,7 @@ act_like_temp_file:
/* pPager->xBusyHandler = 0; */
/* pPager->pBusyHandlerArg = 0; */
pPager->xReiniter = xReinit;
+ setGetterMethod(pPager);
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
/* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */
@@ -48682,6 +51652,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
if( rc==SQLITE_OK && !locked ){
Pgno nPage; /* Number of pages in database file */
+ assert( pPager->tempFile==0 );
rc = pagerPagecount(pPager, &nPage);
if( rc==SQLITE_OK ){
/* If the database is zero pages in size, that means that either (1) the
@@ -48774,17 +51745,17 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
/* This routine is only called from b-tree and only when there are no
** outstanding pages. This implies that the pager state should either
** be OPEN or READER. READER is only possible if the pager is or was in
- ** exclusive access mode.
- */
+ ** exclusive access mode. */
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
assert( assert_pager_state(pPager) );
assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
- if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }
+ assert( pPager->errCode==SQLITE_OK );
if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
int bHotJournal = 1; /* True if there exists a hot journal-file */
assert( !MEMDB );
+ assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK );
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
if( rc!=SQLITE_OK ){
@@ -48870,7 +51841,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
assert( rc==SQLITE_OK );
rc = pagerSyncHotJournal(pPager);
if( rc==SQLITE_OK ){
- rc = pager_playback(pPager, 1);
+ rc = pager_playback(pPager, !pPager->tempFile);
pPager->eState = PAGER_OPEN;
}
}else if( !pPager->exclusiveMode ){
@@ -48966,7 +51937,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
rc = pagerBeginReadTransaction(pPager);
}
- if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
+ if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
rc = pagerPagecount(pPager, &pPager->dbSize);
}
@@ -48997,10 +51968,17 @@ static void pagerUnlockIfUnused(Pager *pPager){
}
/*
-** Acquire a reference to page number pgno in pager pPager (a page
-** reference has type DbPage*). If the requested reference is
+** The page getter methods each try to acquire a reference to a
+** page with page number pgno. If the requested reference is
** successfully obtained, it is copied to *ppPage and SQLITE_OK returned.
**
+** There are different implementations of the getter method depending
+** on the current state of the pager.
+**
+** getPageNormal() -- The normal getter
+** getPageError() -- Used if the pager is in an error state
+** getPageMmap() -- Used if memory-mapped I/O is enabled
+**
** If the requested page is already in the cache, it is returned.
** Otherwise, a new page object is allocated and populated with data
** read from the database file. In some cases, the pcache module may
@@ -49012,14 +51990,14 @@ static void pagerUnlockIfUnused(Pager *pPager){
** already in the cache when this function is called, then the extra
** data is left as it was when the page object was last used.
**
-** If the database image is smaller than the requested page or if a
-** non-zero value is passed as the noContent parameter and the
+** If the database image is smaller than the requested page or if
+** the flags parameter contains the PAGER_GET_NOCONTENT bit and the
** requested page is not already stored in the cache, then no
** actual disk read occurs. In this case the memory image of the
** page is initialized to all zeros.
**
-** If noContent is true, it means that we do not care about the contents
-** of the page. This occurs in two scenarios:
+** If PAGER_GET_NOCONTENT is true, it means that we do not care about
+** the contents of the page. This occurs in two scenarios:
**
** a) When reading a free-list leaf page from the database, and
**
@@ -49027,8 +52005,8 @@ static void pagerUnlockIfUnused(Pager *pPager){
** a new page into the cache to be filled with the data read
** from the savepoint journal.
**
-** If noContent is true, then the data returned is zeroed instead of
-** being read from the database. Additionally, the bits corresponding
+** If PAGER_GET_NOCONTENT is true, then the data returned is zeroed instead
+** of being read from the database. Additionally, the bits corresponding
** to pgno in Pager.pInJournal (bitvec of pages already written to the
** journal file) and the PagerSavepoint.pInSavepoint bitvecs of any open
** savepoints are set. This means if the page is made writable at any
@@ -49046,106 +52024,39 @@ static void pagerUnlockIfUnused(Pager *pPager){
** Since Lookup() never goes to disk, it never has to deal with locks
** or journal files.
*/
-SQLITE_PRIVATE int sqlite3PagerGet(
+static int getPageNormal(
Pager *pPager, /* The pager open on the database file */
Pgno pgno, /* Page number to fetch */
DbPage **ppPage, /* Write a pointer to the page here */
int flags /* PAGER_GET_XXX flags */
){
int rc = SQLITE_OK;
- PgHdr *pPg = 0;
- u32 iFrame = 0; /* Frame to read from WAL file */
- const int noContent = (flags & PAGER_GET_NOCONTENT);
-
- /* It is acceptable to use a read-only (mmap) page for any page except
- ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
- ** flag was specified by the caller. And so long as the db is not a
- ** temporary or in-memory database. */
- const int bMmapOk = (pgno>1 && USEFETCH(pPager)
- && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
-#ifdef SQLITE_HAS_CODEC
- && pPager->xCodec==0
-#endif
- );
+ PgHdr *pPg;
+ u8 noContent; /* True if PAGER_GET_NOCONTENT is set */
+ sqlite3_pcache_page *pBase;
- /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here
- ** allows the compiler optimizer to reuse the results of the "pgno>1"
- ** test in the previous statement, and avoid testing pgno==0 in the
- ** common case where pgno is large. */
- if( pgno<=1 && pgno==0 ){
- return SQLITE_CORRUPT_BKPT;
- }
+ assert( pPager->errCode==SQLITE_OK );
assert( pPager->eState>=PAGER_READER );
assert( assert_pager_state(pPager) );
- assert( noContent==0 || bMmapOk==0 );
-
assert( pPager->hasHeldSharedLock==1 );
- /* If the pager is in the error state, return an error immediately.
- ** Otherwise, request the page from the PCache layer. */
- if( pPager->errCode!=SQLITE_OK ){
- rc = pPager->errCode;
- }else{
- if( bMmapOk && pagerUseWal(pPager) ){
- rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
- if( rc!=SQLITE_OK ) goto pager_acquire_err;
- }
-
- if( bMmapOk && iFrame==0 ){
- void *pData = 0;
-
- rc = sqlite3OsFetch(pPager->fd,
- (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
- );
-
- if( rc==SQLITE_OK && pData ){
- if( pPager->eState>PAGER_READER ){
- pPg = sqlite3PagerLookup(pPager, pgno);
- }
- if( pPg==0 ){
- rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
- }else{
- sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
- }
- if( pPg ){
- assert( rc==SQLITE_OK );
- *ppPage = pPg;
- return SQLITE_OK;
- }
- }
- if( rc!=SQLITE_OK ){
- goto pager_acquire_err;
- }
- }
-
- {
- sqlite3_pcache_page *pBase;
- pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
- if( pBase==0 ){
- rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
- if( rc!=SQLITE_OK ) goto pager_acquire_err;
- if( pBase==0 ){
- pPg = *ppPage = 0;
- rc = SQLITE_NOMEM;
- goto pager_acquire_err;
- }
- }
- pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
- assert( pPg!=0 );
- }
- }
-
- if( rc!=SQLITE_OK ){
- /* Either the call to sqlite3PcacheFetch() returned an error or the
- ** pager was already in the error-state when this function was called.
- ** Set pPg to 0 and jump to the exception handler. */
+ if( pgno==0 ) return SQLITE_CORRUPT_BKPT;
+ pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
+ if( pBase==0 ){
pPg = 0;
- goto pager_acquire_err;
+ rc = sqlite3PcacheFetchStress(pPager->pPCache, pgno, &pBase);
+ if( rc!=SQLITE_OK ) goto pager_acquire_err;
+ if( pBase==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ goto pager_acquire_err;
+ }
}
+ pPg = *ppPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pBase);
assert( pPg==(*ppPage) );
assert( pPg->pgno==pgno );
assert( pPg->pPager==pPager || pPg->pPager==0 );
+ noContent = (flags & PAGER_GET_NOCONTENT)!=0;
if( pPg->pPager && !noContent ){
/* In this case the pcache already contains an initialized copy of
** the page. Return without further ado. */
@@ -49155,18 +52066,20 @@ SQLITE_PRIVATE int sqlite3PagerGet(
}else{
/* The pager cache has created a new page. Its content needs to
- ** be initialized. */
-
- pPg->pPager = pPager;
-
- /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
- ** number greater than this, or the unused locking-page, is requested. */
+ ** be initialized. But first some error checks:
+ **
+ ** (1) The maximum page number is 2^31
+ ** (2) Never try to fetch the locking page
+ */
if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
rc = SQLITE_CORRUPT_BKPT;
goto pager_acquire_err;
}
- if( MEMDB || pPager->dbSize<pgno || noContent || !isOpen(pPager->fd) ){
+ pPg->pPager = pPager;
+
+ assert( !isOpen(pPager->fd) || !MEMDB );
+ if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
if( pgno>pPager->mxPgno ){
rc = SQLITE_FULL;
goto pager_acquire_err;
@@ -49190,7 +52103,8 @@ SQLITE_PRIVATE int sqlite3PagerGet(
memset(pPg->pData, 0, pPager->pageSize);
IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
- if( pagerUseWal(pPager) && bMmapOk==0 ){
+ u32 iFrame = 0; /* Frame to read from WAL file */
+ if( pagerUseWal(pPager) ){
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
}
@@ -49203,7 +52117,6 @@ SQLITE_PRIVATE int sqlite3PagerGet(
}
pager_set_pagehash(pPg);
}
-
return SQLITE_OK;
pager_acquire_err:
@@ -49212,11 +52125,109 @@ pager_acquire_err:
sqlite3PcacheDrop(pPg);
}
pagerUnlockIfUnused(pPager);
-
*ppPage = 0;
return rc;
}
+#if SQLITE_MAX_MMAP_SIZE>0
+/* The page getter for when memory-mapped I/O is enabled */
+static int getPageMMap(
+ Pager *pPager, /* The pager open on the database file */
+ Pgno pgno, /* Page number to fetch */
+ DbPage **ppPage, /* Write a pointer to the page here */
+ int flags /* PAGER_GET_XXX flags */
+){
+ int rc = SQLITE_OK;
+ PgHdr *pPg = 0;
+ u32 iFrame = 0; /* Frame to read from WAL file */
+
+ /* It is acceptable to use a read-only (mmap) page for any page except
+ ** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
+ ** flag was specified by the caller. And so long as the db is not a
+ ** temporary or in-memory database. */
+ const int bMmapOk = (pgno>1
+ && (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
+ );
+
+ assert( USEFETCH(pPager) );
+#ifdef SQLITE_HAS_CODEC
+ assert( pPager->xCodec==0 );
+#endif
+
+ /* Optimization note: Adding the "pgno<=1" term before "pgno==0" here
+ ** allows the compiler optimizer to reuse the results of the "pgno>1"
+ ** test in the previous statement, and avoid testing pgno==0 in the
+ ** common case where pgno is large. */
+ if( pgno<=1 && pgno==0 ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ assert( pPager->eState>=PAGER_READER );
+ assert( assert_pager_state(pPager) );
+ assert( pPager->hasHeldSharedLock==1 );
+ assert( pPager->errCode==SQLITE_OK );
+
+ if( bMmapOk && pagerUseWal(pPager) ){
+ rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
+ if( rc!=SQLITE_OK ){
+ *ppPage = 0;
+ return rc;
+ }
+ }
+ if( bMmapOk && iFrame==0 ){
+ void *pData = 0;
+ rc = sqlite3OsFetch(pPager->fd,
+ (i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
+ );
+ if( rc==SQLITE_OK && pData ){
+ if( pPager->eState>PAGER_READER || pPager->tempFile ){
+ pPg = sqlite3PagerLookup(pPager, pgno);
+ }
+ if( pPg==0 ){
+ rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
+ }else{
+ sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
+ }
+ if( pPg ){
+ assert( rc==SQLITE_OK );
+ *ppPage = pPg;
+ return SQLITE_OK;
+ }
+ }
+ if( rc!=SQLITE_OK ){
+ *ppPage = 0;
+ return rc;
+ }
+ }
+ return getPageNormal(pPager, pgno, ppPage, flags);
+}
+#endif /* SQLITE_MAX_MMAP_SIZE>0 */
+
+/* The page getter method for when the pager is an error state */
+static int getPageError(
+ Pager *pPager, /* The pager open on the database file */
+ Pgno pgno, /* Page number to fetch */
+ DbPage **ppPage, /* Write a pointer to the page here */
+ int flags /* PAGER_GET_XXX flags */
+){
+ UNUSED_PARAMETER(pgno);
+ UNUSED_PARAMETER(flags);
+ assert( pPager->errCode!=SQLITE_OK );
+ *ppPage = 0;
+ return pPager->errCode;
+}
+
+
+/* Dispatch all page fetch requests to the appropriate getter method.
+*/
+SQLITE_PRIVATE int sqlite3PagerGet(
+ Pager *pPager, /* The pager open on the database file */
+ Pgno pgno, /* Page number to fetch */
+ DbPage **ppPage, /* Write a pointer to the page here */
+ int flags /* PAGER_GET_XXX flags */
+){
+ return pPager->xGet(pPager, pgno, ppPage, flags);
+}
+
/*
** Acquire a page if it is already in the in-memory cache. Do
** not read the page from disk. Return a pointer to the page,
@@ -49300,7 +52311,7 @@ static int pager_open_journal(Pager *pPager){
if( !pagerUseWal(pPager) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
pPager->pInJournal = sqlite3BitvecCreate(pPager->dbSize);
if( pPager->pInJournal==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
/* Open the journal file if it is not already open. */
@@ -49308,24 +52319,24 @@ static int pager_open_journal(Pager *pPager){
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
sqlite3MemJournalOpen(pPager->jfd);
}else{
- const int flags = /* VFS flags to open journal file */
- SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
- (pPager->tempFile ?
- (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL):
- (SQLITE_OPEN_MAIN_JOURNAL)
- );
+ int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
+ int nSpill;
+ if( pPager->tempFile ){
+ flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
+ nSpill = sqlite3Config.nStmtSpill;
+ }else{
+ flags |= SQLITE_OPEN_MAIN_JOURNAL;
+ nSpill = jrnlBufferSize(pPager);
+ }
+
/* Verify that the database still has the same name as it did when
** it was originally opened. */
rc = databaseIsUnmoved(pPager);
if( rc==SQLITE_OK ){
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
- rc = sqlite3JournalOpen(
- pVfs, pPager->zJournal, pPager->jfd, flags, jrnlBufferSize(pPager)
+ rc = sqlite3JournalOpen (
+ pVfs, pPager->zJournal, pPager->jfd, flags, nSpill
);
-#else
- rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
-#endif
}
}
assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
@@ -49455,7 +52466,7 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
assert( pPager->journalHdr<=pPager->journalOff );
- CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM, pData2);
+ CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
cksum = pager_cksum(pPager, (u8*)pData2);
/* Even if an IO or diskfull error occurs while journalling the
@@ -49690,12 +52701,13 @@ SQLITE_PRIVATE int sqlite3PagerWrite(PgHdr *pPg){
assert( (pPg->flags & PGHDR_MMAP)==0 );
assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( assert_pager_state(pPager) );
- if( pPager->errCode ){
- return pPager->errCode;
- }else if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){
+ if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){
if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg);
return SQLITE_OK;
+ }else if( pPager->errCode ){
+ return pPager->errCode;
}else if( pPager->sectorSize > (u32)pPager->pageSize ){
+ assert( pPager->tempFile==0 );
return pagerWriteLargeSector(pPg);
}else{
return pager_write(pPg);
@@ -49726,14 +52738,21 @@ SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
**
** Tests show that this optimization can quadruple the speed of large
** DELETE operations.
+**
+** This optimization cannot be used with a temp-file, as the page may
+** have been dirty at the start of the transaction. In that case, if
+** memory pressure forces page pPg out of the cache, the data does need
+** to be written out to disk so that it may be read back in if the
+** current transaction is rolled back.
*/
SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
Pager *pPager = pPg->pPager;
- if( (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
+ if( !pPager->tempFile && (pPg->flags&PGHDR_DIRTY) && pPager->nSavepoint==0 ){
PAGERTRACE(("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager)));
IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
pPg->flags |= PGHDR_DONT_WRITE;
pPg->flags &= ~PGHDR_WRITEABLE;
+ testcase( pPg->flags & PGHDR_NEED_SYNC );
pager_set_pagehash(pPg);
}
}
@@ -49812,7 +52831,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
if( DIRECT_MODE ){
const void *zBuf;
assert( pPager->dbFileSize>0 );
- CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
+ CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
pPager->aStat[PAGER_STAT_WRITE]++;
@@ -49928,17 +52947,21 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
/* If a prior error occurred, report that error again. */
if( NEVER(pPager->errCode) ) return pPager->errCode;
+ /* Provide the ability to easily simulate an I/O error during testing */
+ if( sqlite3FaultSim(400) ) return SQLITE_IOERR;
+
PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
pPager->zFilename, zMaster, pPager->dbSize));
/* If no database changes have been made, return early. */
if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
- if( MEMDB ){
+ assert( MEMDB==0 || pPager->tempFile );
+ assert( isOpen(pPager->fd) || pPager->tempFile );
+ if( 0==pagerFlushOnCommit(pPager, 1) ){
/* If this is an in-memory db, or no pages have been written to, or this
** function has already been called, it is mostly a no-op. However, any
- ** backup in progress needs to be restarted.
- */
+ ** backup in progress needs to be restarted. */
sqlite3BackupRestart(pPager->pBackup);
}else{
if( pagerUseWal(pPager) ){
@@ -50177,6 +53200,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
*/
pPager->errCode = SQLITE_ABORT;
pPager->eState = PAGER_ERROR;
+ setGetterMethod(pPager);
return rc;
}
}else{
@@ -50277,10 +53301,10 @@ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, i
}
/*
-** Return true if this is an in-memory pager.
+** Return true if this is an in-memory or temp-file backed pager.
*/
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
- return MEMDB;
+ return pPager->tempFile;
}
/*
@@ -50311,7 +53335,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
pPager->aSavepoint, sizeof(PagerSavepoint)*nSavepoint
);
if( !aNew ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memset(&aNew[nCurrent], 0, (nSavepoint-nCurrent) * sizeof(PagerSavepoint));
pPager->aSavepoint = aNew;
@@ -50327,7 +53351,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
aNew[ii].iSubRec = pPager->nSubRec;
aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
if( !aNew[ii].pInSavepoint ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
if( pagerUseWal(pPager) ){
sqlite3WalSavepoint(pPager->pWal, aNew[ii].aWalData);
@@ -50381,7 +53405,11 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
** savepoint. If no errors occur, SQLITE_OK is returned.
*/
SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
- int rc = pPager->errCode; /* Return code */
+ int rc = pPager->errCode;
+
+#ifdef SQLITE_ENABLE_ZIPVFS
+ if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK;
+#endif
assert( op==SAVEPOINT_RELEASE || op==SAVEPOINT_ROLLBACK );
assert( iSavepoint>=0 || op==SAVEPOINT_ROLLBACK );
@@ -50405,7 +53433,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
if( op==SAVEPOINT_RELEASE ){
if( nNew==0 && isOpen(pPager->sjfd) ){
/* Only truncate if it is an in-memory sub-journal. */
- if( sqlite3IsMemJournal(pPager->sjfd) ){
+ if( sqlite3JournalIsInMemory(pPager->sjfd) ){
rc = sqlite3OsTruncate(pPager->sjfd, 0);
assert( rc==SQLITE_OK );
}
@@ -50422,6 +53450,21 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
rc = pagerPlaybackSavepoint(pPager, pSavepoint);
assert(rc!=SQLITE_DONE);
}
+
+#ifdef SQLITE_ENABLE_ZIPVFS
+ /* If the cache has been modified but the savepoint cannot be rolled
+ ** back journal_mode=off, put the pager in the error state. This way,
+ ** if the VFS used by this pager includes ZipVFS, the entire transaction
+ ** can be rolled back at the ZipVFS level. */
+ else if(
+ pPager->journalMode==PAGER_JOURNALMODE_OFF
+ && pPager->eState>=PAGER_WRITER_CACHEMOD
+ ){
+ pPager->errCode = SQLITE_ABORT;
+ pPager->eState = PAGER_ERROR;
+ setGetterMethod(pPager);
+ }
+#endif
}
return rc;
@@ -50476,14 +53519,6 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
return pPager->zJournal;
}
-/*
-** Return true if fsync() calls are disabled for this pager. Return FALSE
-** if fsync()s are executed normally.
-*/
-SQLITE_PRIVATE int sqlite3PagerNosync(Pager *pPager){
- return pPager->noSync;
-}
-
#ifdef SQLITE_HAS_CODEC
/*
** Set or retrieve the codec for this pager
@@ -50500,6 +53535,7 @@ SQLITE_PRIVATE void sqlite3PagerSetCodec(
pPager->xCodecSizeChng = xCodecSizeChng;
pPager->xCodecFree = xCodecFree;
pPager->pCodec = pCodec;
+ setGetterMethod(pPager);
pagerReportSize(pPager);
}
SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
@@ -50568,7 +53604,8 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
/* In order to be able to rollback, an in-memory database must journal
** the page we are moving from.
*/
- if( MEMDB ){
+ assert( pPager->tempFile || !MEMDB );
+ if( pPager->tempFile ){
rc = sqlite3PagerWrite(pPg);
if( rc ) return rc;
}
@@ -50625,7 +53662,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
assert( !pPgOld || pPgOld->nRef==1 );
if( pPgOld ){
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
- if( MEMDB ){
+ if( pPager->tempFile ){
/* Do not discard pages from an in-memory database since we might
** need to rollback later. Just move the page out of the way. */
sqlite3PcacheMove(pPgOld, pPager->dbSize+1);
@@ -50642,8 +53679,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
** to exist, in case the transaction needs to roll back. Use pPgOld
** as the original page since it has already been allocated.
*/
- if( MEMDB ){
- assert( pPgOld );
+ if( pPager->tempFile && pPgOld ){
sqlite3PcacheMove(pPgOld, origPgno);
sqlite3PagerUnrefNotNull(pPgOld);
}
@@ -50895,10 +53931,12 @@ SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager *pPager){
** Unless this is an in-memory or temporary database, clear the pager cache.
*/
SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
- if( !MEMDB && pPager->tempFile==0 ) pager_reset(pPager);
+ assert( MEMDB==0 || pPager->tempFile );
+ if( pPager->tempFile==0 ) pager_reset(pPager);
}
#endif
+
#ifndef SQLITE_OMIT_WAL
/*
** This function is called when the user invokes "PRAGMA wal_checkpoint",
@@ -50907,10 +53945,16 @@ SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *pPager){
**
** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
*/
-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(
+ Pager *pPager, /* Checkpoint on this pager */
+ sqlite3 *db, /* Db handle used to check for interrupts */
+ int eMode, /* Type of checkpoint */
+ int *pnLog, /* OUT: Final number of frames in log */
+ int *pnCkpt /* OUT: Final number of checkpointed frames */
+){
int rc = SQLITE_OK;
if( pPager->pWal ){
- rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
+ rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
pPager->pBusyHandlerArg,
pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
@@ -50930,6 +53974,7 @@ SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager){
*/
SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
const sqlite3_io_methods *pMethods = pPager->fd->pMethods;
+ if( pPager->noLock ) return 0;
return pPager->exclusiveMode || (pMethods->iVersion>=2 && pMethods->xShmMap);
}
@@ -51041,7 +54086,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal(
** error (SQLITE_BUSY) is returned and the log connection is not closed.
** If successful, the EXCLUSIVE lock is not released before returning.
*/
-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
int rc = SQLITE_OK;
assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );
@@ -51069,10 +54114,11 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager){
if( rc==SQLITE_OK && pPager->pWal ){
rc = pagerExclusiveLock(pPager);
if( rc==SQLITE_OK ){
- rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
+ rc = sqlite3WalClose(pPager->pWal, db, pPager->ckptSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0;
pagerFixMaplimit(pPager);
+ if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
}
}
return rc;
@@ -51105,6 +54151,20 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSn
}
return rc;
}
+
+/*
+** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this
+** is not a WAL database, return an error.
+*/
+SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){
+ int rc;
+ if( pPager->pWal ){
+ rc = sqlite3WalSnapshotRecover(pPager->pWal);
+ }else{
+ rc = SQLITE_ERROR;
+ }
+ return rc;
+}
#endif /* SQLITE_ENABLE_SNAPSHOT */
#endif /* !SQLITE_OMIT_WAL */
@@ -51122,7 +54182,6 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
}
#endif
-
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
@@ -51675,7 +54734,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
if( !apNew ){
*ppPage = 0;
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memset((void*)&apNew[pWal->nWiData], 0,
sizeof(u32*)*(iPage+1-pWal->nWiData));
@@ -51687,7 +54746,7 @@ static int walIndexPage(Wal *pWal, int iPage, volatile u32 **ppPage){
if( pWal->apWiData[iPage]==0 ){
if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
- if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
+ if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT;
}else{
rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
@@ -52302,7 +55361,7 @@ static int walIndexRecover(Wal *pWal){
szFrame = szPage + WAL_FRAME_HDRSIZE;
aFrame = (u8 *)sqlite3_malloc64(szFrame);
if( !aFrame ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto recovery_error;
}
aData = &aFrame[WAL_FRAME_HDRSIZE];
@@ -52440,7 +55499,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
*ppWal = 0;
pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
if( !pRet ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pRet->pVfs = pVfs;
@@ -52704,7 +55763,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
+ iLast*sizeof(ht_slot);
p = (WalIterator *)sqlite3_malloc64(nByte);
if( !p ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memset(p, 0, nByte);
p->nSegment = nSegment;
@@ -52716,7 +55775,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
);
if( !aTmp ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
for(i=0; rc==SQLITE_OK && i<nSegment; i++){
@@ -52852,6 +55911,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
*/
static int walCheckpoint(
Wal *pWal, /* Wal connection */
+ sqlite3 *db, /* Check for interrupts on this handle */
int eMode, /* One of PASSIVE, FULL or RESTART */
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
@@ -52946,6 +56006,10 @@ static int walCheckpoint(
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
i64 iOffset;
assert( walFramePgno(pWal, iFrame)==iDbpage );
+ if( db->u1.isInterrupted ){
+ rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
+ break;
+ }
if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
continue;
}
@@ -53050,6 +56114,7 @@ static void walLimitSize(Wal *pWal, i64 nMax){
*/
SQLITE_PRIVATE int sqlite3WalClose(
Wal *pWal, /* Wal to close */
+ sqlite3 *db, /* For interrupt flag */
int sync_flags, /* Flags to pass to OsSync() (or 0) */
int nBuf,
u8 *zBuf /* Buffer of at least nBuf bytes */
@@ -53066,13 +56131,14 @@ SQLITE_PRIVATE int sqlite3WalClose(
**
** The EXCLUSIVE lock is not released before returning.
*/
- rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
- if( rc==SQLITE_OK ){
+ if( zBuf!=0
+ && SQLITE_OK==(rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE))
+ ){
if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
}
- rc = sqlite3WalCheckpoint(
- pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
+ rc = sqlite3WalCheckpoint(pWal, db,
+ SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
);
if( rc==SQLITE_OK ){
int bPersist = -1;
@@ -53501,6 +56567,84 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
return rc;
}
+#ifdef SQLITE_ENABLE_SNAPSHOT
+/*
+** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted
+** variable so that older snapshots can be accessed. To do this, loop
+** through all wal frames from nBackfillAttempted to (nBackfill+1),
+** comparing their content to the corresponding page with the database
+** file, if any. Set nBackfillAttempted to the frame number of the
+** first frame for which the wal file content matches the db file.
+**
+** This is only really safe if the file-system is such that any page
+** writes made by earlier checkpointers were atomic operations, which
+** is not always true. It is also possible that nBackfillAttempted
+** may be left set to a value larger than expected, if a wal frame
+** contains content that duplicate of an earlier version of the same
+** page.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code if an
+** error occurs. It is not an error if nBackfillAttempted cannot be
+** decreased at all.
+*/
+SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
+ int rc;
+
+ assert( pWal->readLock>=0 );
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ int szPage = (int)pWal->szPage;
+ i64 szDb; /* Size of db file in bytes */
+
+ rc = sqlite3OsFileSize(pWal->pDbFd, &szDb);
+ if( rc==SQLITE_OK ){
+ void *pBuf1 = sqlite3_malloc(szPage);
+ void *pBuf2 = sqlite3_malloc(szPage);
+ if( pBuf1==0 || pBuf2==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ u32 i = pInfo->nBackfillAttempted;
+ for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){
+ volatile ht_slot *dummy;
+ volatile u32 *aPgno; /* Array of page numbers */
+ u32 iZero; /* Frame corresponding to aPgno[0] */
+ u32 pgno; /* Page number in db file */
+ i64 iDbOff; /* Offset of db file entry */
+ i64 iWalOff; /* Offset of wal file entry */
+
+ rc = walHashGet(pWal, walFramePage(i), &dummy, &aPgno, &iZero);
+ if( rc!=SQLITE_OK ) break;
+ pgno = aPgno[i-iZero];
+ iDbOff = (i64)(pgno-1) * szPage;
+
+ if( iDbOff+szPage<=szDb ){
+ iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
+ rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
+ }
+
+ if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
+ break;
+ }
+ }
+
+ pInfo->nBackfillAttempted = i-1;
+ }
+ }
+
+ sqlite3_free(pBuf1);
+ sqlite3_free(pBuf2);
+ }
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ }
+
+ return rc;
+}
+#endif /* SQLITE_ENABLE_SNAPSHOT */
+
/*
** Begin a read transaction on the database.
**
@@ -53563,7 +56707,11 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
** has not yet set the pInfo->nBackfillAttempted variable to indicate
** its intent. To avoid the race condition this leads to, ensure that
** there is no checkpointer process by taking a shared CKPT lock
- ** before checking pInfo->nBackfillAttempted. */
+ ** before checking pInfo->nBackfillAttempted.
+ **
+ ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing
+ ** this already?
+ */
rc = walLockShared(pWal, WAL_CKPT_LOCK);
if( rc==SQLITE_OK ){
@@ -54009,7 +57157,7 @@ static int walWriteOneFrame(
void *pData; /* Data actually written */
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
#if defined(SQLITE_HAS_CODEC)
- if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
+ if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
#else
pData = pPage->pData;
#endif
@@ -54038,7 +57186,7 @@ static int walRewriteChecksums(Wal *pWal, u32 iLast){
i64 iCksumOff;
aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE);
- if( aBuf==0 ) return SQLITE_NOMEM;
+ if( aBuf==0 ) return SQLITE_NOMEM_BKPT;
/* Find the checksum values to use as input for the recalculating the
** first checksum. If the first frame is frame 1 (implying that the current
@@ -54238,16 +57386,21 @@ SQLITE_PRIVATE int sqlite3WalFrames(
** past the sector boundary is written after the sync.
*/
if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
+ int bSync = 1;
if( pWal->padToSectorBoundary ){
int sectorSize = sqlite3SectorSize(pWal->pWalFd);
w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
+ bSync = (w.iSyncPoint==iOffset);
+ testcase( bSync );
while( iOffset<w.iSyncPoint ){
rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
if( rc ) return rc;
iOffset += szFrame;
nExtra++;
}
- }else{
+ }
+ if( bSync ){
+ assert( rc==SQLITE_OK );
rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
}
}
@@ -54315,6 +57468,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
*/
SQLITE_PRIVATE int sqlite3WalCheckpoint(
Wal *pWal, /* Wal connection */
+ sqlite3 *db, /* Check this handle's interrupt flag */
int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */
int (*xBusy)(void*), /* Function to call when busy */
void *pBusyArg, /* Context argument for xBusyHandler */
@@ -54389,7 +57543,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
rc = SQLITE_CORRUPT_BKPT;
}else{
- rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
+ rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
}
/* If no error occurred, set the output variables. */
@@ -54509,12 +57663,17 @@ SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){
int rc = SQLITE_OK;
WalIndexHdr *pRet;
+ static const u32 aZero[4] = { 0, 0, 0, 0 };
assert( pWal->readLock>=0 && pWal->writeLock==0 );
+ if( memcmp(&pWal->hdr.aFrameCksum[0],aZero,16)==0 ){
+ *ppSnapshot = 0;
+ return SQLITE_ERROR;
+ }
pRet = (WalIndexHdr*)sqlite3_malloc(sizeof(WalIndexHdr));
if( pRet==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
memcpy(pRet, &pWal->hdr, sizeof(WalIndexHdr));
*ppSnapshot = (sqlite3_snapshot*)pRet;
@@ -54528,6 +57687,23 @@ SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapsho
SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
}
+
+/*
+** Return a +ve value if snapshot p1 is newer than p2. A -ve value if
+** p1 is older than p2 and zero if p1 and p2 are the same snapshot.
+*/
+SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
+ WalIndexHdr *pHdr1 = (WalIndexHdr*)p1;
+ WalIndexHdr *pHdr2 = (WalIndexHdr*)p2;
+
+ /* aSalt[0] is a copy of the value stored in the wal file header. It
+ ** is incremented each time the wal file is restarted. */
+ if( pHdr1->aSalt[0]<pHdr2->aSalt[0] ) return -1;
+ if( pHdr1->aSalt[0]>pHdr2->aSalt[0] ) return +1;
+ if( pHdr1->mxFrame<pHdr2->mxFrame ) return -1;
+ if( pHdr1->mxFrame>pHdr2->mxFrame ) return +1;
+ return 0;
+}
#endif /* SQLITE_ENABLE_SNAPSHOT */
#ifdef SQLITE_ENABLE_ZIPVFS
@@ -54832,37 +58008,39 @@ typedef struct CellInfo CellInfo;
#define PTF_LEAF 0x08
/*
-** As each page of the file is loaded into memory, an instance of the following
-** structure is appended and initialized to zero. This structure stores
-** information about the page that is decoded from the raw file page.
+** An instance of this object stores information about each a single database
+** page that has been loaded into memory. The information in this object
+** is derived from the raw on-disk page content.
**
-** The pParent field points back to the parent page. This allows us to
-** walk up the BTree from any leaf to the root. Care must be taken to
-** unref() the parent page pointer when this page is no longer referenced.
-** The pageDestructor() routine handles that chore.
+** As each database page is loaded into memory, the pager allocats an
+** instance of this object and zeros the first 8 bytes. (This is the
+** "extra" information associated with each page of the pager.)
**
** Access to all fields of this structure is controlled by the mutex
** stored in MemPage.pBt->mutex.
*/
struct MemPage {
u8 isInit; /* True if previously initialized. MUST BE FIRST! */
- u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
+ u8 bBusy; /* Prevent endless loops on corrupt database files */
u8 intKey; /* True if table b-trees. False for index b-trees */
u8 intKeyLeaf; /* True if the leaf of an intKey table */
+ Pgno pgno; /* Page number for this page */
+ /* Only the first 8 bytes (above) are zeroed by pager.c when a new page
+ ** is allocated. All fields that follow must be initialized before use */
u8 leaf; /* True if a leaf page */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
u8 max1bytePayload; /* min(maxLocal,127) */
- u8 bBusy; /* Prevent endless loops on corrupt database files */
+ u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */
u16 nFree; /* Number of free bytes on the page */
u16 nCell; /* Number of cells on this page, local and ovfl */
u16 maskPage; /* Mask for page offset */
- u16 aiOvfl[5]; /* Insert the i-th overflow cell before the aiOvfl-th
+ u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th
** non-overflow cell */
- u8 *apOvfl[5]; /* Pointers to the body of overflow cells */
+ u8 *apOvfl[4]; /* Pointers to the body of overflow cells */
BtShared *pBt; /* Pointer to BtShared that this page is part of */
u8 *aData; /* Pointer to disk image of the page data */
u8 *aDataEnd; /* One byte past the end of usable data */
@@ -54871,17 +58049,9 @@ struct MemPage {
DbPage *pDbPage; /* Pager page handle */
u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */
void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */
- Pgno pgno; /* Page number for this page */
};
/*
-** The in-memory image of a disk page has the auxiliary information appended
-** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
-** that extra information.
-*/
-#define EXTRA_SIZE sizeof(MemPage)
-
-/*
** A linked list of the following structures is stored at BtShared.pLock.
** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
** is opened on the table with root page BtShared.iTable. Locks are removed
@@ -55653,7 +58823,7 @@ static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
** The shared cache setting effects only future calls to
** sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2().
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int enable){
+SQLITE_API int sqlite3_enable_shared_cache(int enable){
sqlite3GlobalConfig.sharedCacheEnabled = enable;
return SQLITE_OK;
}
@@ -55917,7 +59087,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
if( !pLock ){
pLock = (BtLock *)sqlite3MallocZero(sizeof(BtLock));
if( !pLock ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pLock->iTable = iTable;
pLock->pBtree = p;
@@ -56017,6 +59187,15 @@ static void releasePage(MemPage *pPage); /* Forward reference */
static int cursorHoldsMutex(BtCursor *p){
return sqlite3_mutex_held(p->pBt->mutex);
}
+
+/* Verify that the cursor and the BtShared agree about what is the current
+** database connetion. This is important in shared-cache mode. If the database
+** connection pointers get out-of-sync, it is possible for routines like
+** btreeInitPage() to reference an stale connection pointer that references a
+** a connection that has already closed. This routine is used inside assert()
+** statements only and for the purpose of double-checking that the btree code
+** does keep the database connection pointers up-to-date.
+*/
static int cursorOwnsBtShared(BtCursor *p){
assert( cursorHoldsMutex(p) );
return (p->pBtree->db==p->pBt->db);
@@ -56120,7 +59299,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
assert( pgno<=pBt->nPage );
pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
if( !pBt->pHasContent ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
}
if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){
@@ -56176,30 +59355,28 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
** the key.
*/
static int saveCursorKey(BtCursor *pCur){
- int rc;
+ int rc = SQLITE_OK;
assert( CURSOR_VALID==pCur->eState );
assert( 0==pCur->pKey );
assert( cursorHoldsMutex(pCur) );
- rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);
- assert( rc==SQLITE_OK ); /* KeySize() cannot fail */
-
- /* If this is an intKey table, then the above call to BtreeKeySize()
- ** stores the integer key in pCur->nKey. In this case this value is
- ** all that is required. Otherwise, if pCur is not open on an intKey
- ** table, then malloc space for and store the pCur->nKey bytes of key
- ** data. */
- if( 0==pCur->curIntKey ){
- void *pKey = sqlite3Malloc( pCur->nKey );
+ if( pCur->curIntKey ){
+ /* Only the rowid is required for a table btree */
+ pCur->nKey = sqlite3BtreeIntegerKey(pCur);
+ }else{
+ /* For an index btree, save the complete key content */
+ void *pKey;
+ pCur->nKey = sqlite3BtreePayloadSize(pCur);
+ pKey = sqlite3Malloc( pCur->nKey );
if( pKey ){
- rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey);
+ rc = sqlite3BtreePayload(pCur, 0, (int)pCur->nKey, pKey);
if( rc==SQLITE_OK ){
pCur->pKey = pKey;
}else{
sqlite3_free(pKey);
}
}else{
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
}
assert( !pCur->curIntKey || !pCur->pKey );
@@ -56323,26 +59500,23 @@ static int btreeMoveto(
){
int rc; /* Status code */
UnpackedRecord *pIdxKey; /* Unpacked index key */
- char aSpace[200]; /* Temp space for pIdxKey - to avoid a malloc */
- char *pFree = 0;
if( pKey ){
assert( nKey==(i64)(int)nKey );
- pIdxKey = sqlite3VdbeAllocUnpackedRecord(
- pCur->pKeyInfo, aSpace, sizeof(aSpace), &pFree
- );
- if( pIdxKey==0 ) return SQLITE_NOMEM;
+ pIdxKey = sqlite3VdbeAllocUnpackedRecord(pCur->pKeyInfo);
+ if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 ){
- sqlite3DbFree(pCur->pKeyInfo->db, pFree);
- return SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_BKPT;
+ goto moveto_done;
}
}else{
pIdxKey = 0;
}
rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
- if( pFree ){
- sqlite3DbFree(pCur->pKeyInfo->db, pFree);
+moveto_done:
+ if( pIdxKey ){
+ sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
}
return rc;
}
@@ -57165,8 +60339,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
if( data[iPtr+1]==0 && data[iPtr]==0 ){
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
}else{
- while( (iFreeBlk = get2byte(&data[iPtr]))>0 && iFreeBlk<iStart ){
- if( iFreeBlk<iPtr+4 ) return SQLITE_CORRUPT_BKPT;
+ while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
+ if( iFreeBlk<iPtr+4 ){
+ if( iFreeBlk==0 ) break;
+ return SQLITE_CORRUPT_BKPT;
+ }
iPtr = iFreeBlk;
}
if( iFreeBlk>iLast ) return SQLITE_CORRUPT_BKPT;
@@ -57243,11 +60420,11 @@ static int decodeFlags(MemPage *pPage, int flagByte){
pPage->xCellSize = cellSizePtr;
pBt = pPage->pBt;
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
- /* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior
- ** table b-tree page. */
+ /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
+ ** interior table b-tree page. */
assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
- /* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf
- ** table b-tree page. */
+ /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
+ ** leaf table b-tree page. */
assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
pPage->intKey = 1;
if( pPage->leaf ){
@@ -57261,11 +60438,11 @@ static int decodeFlags(MemPage *pPage, int flagByte){
pPage->maxLocal = pBt->maxLeaf;
pPage->minLocal = pBt->minLeaf;
}else if( flagByte==PTF_ZERODATA ){
- /* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior
- ** index b-tree page. */
+ /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
+ ** interior index b-tree page. */
assert( (PTF_ZERODATA)==2 );
- /* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
- ** index b-tree page. */
+ /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
+ ** leaf index b-tree page. */
assert( (PTF_ZERODATA|PTF_LEAF)==10 );
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
@@ -57300,7 +60477,7 @@ static int btreeInitPage(MemPage *pPage){
assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
if( !pPage->isInit ){
- u16 pc; /* Address of a freeblock within pPage->aData[] */
+ int pc; /* Address of a freeblock within pPage->aData[] */
u8 hdr; /* Offset to beginning of page header */
u8 *data; /* Equal to pPage->aData */
BtShared *pBt; /* The main btree structure */
@@ -57380,25 +60557,30 @@ static int btreeInitPage(MemPage *pPage){
** freeblocks. */
pc = get2byte(&data[hdr+1]);
nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
- while( pc>0 ){
- u16 next, size;
- if( pc<iCellFirst || pc>iCellLast ){
+ if( pc>0 ){
+ u32 next, size;
+ if( pc<iCellFirst ){
/* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
** always be at least one cell before the first freeblock.
- **
- ** Or, the freeblock is off the end of the page
*/
return SQLITE_CORRUPT_BKPT;
}
- next = get2byte(&data[pc]);
- size = get2byte(&data[pc+2]);
- if( (next>0 && next<=pc+size+3) || pc+size>usableSize ){
- /* Free blocks must be in ascending order. And the last byte of
- ** the free-block must lie on the database page. */
- return SQLITE_CORRUPT_BKPT;
+ while( 1 ){
+ if( pc>iCellLast ){
+ return SQLITE_CORRUPT_BKPT; /* Freeblock off the end of the page */
+ }
+ next = get2byte(&data[pc]);
+ size = get2byte(&data[pc+2]);
+ nFree = nFree + size;
+ if( next<=pc+size+3 ) break;
+ pc = next;
+ }
+ if( next>0 ){
+ return SQLITE_CORRUPT_BKPT; /* Freeblock not in ascending order */
+ }
+ if( pc+size>(unsigned int)usableSize ){
+ return SQLITE_CORRUPT_BKPT; /* Last freeblock extends past page end */
}
- nFree = nFree + size;
- pc = next;
}
/* At this point, nFree contains the sum of the offset to the start
@@ -57743,7 +60925,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
}
p = sqlite3MallocZero(sizeof(Btree));
if( !p ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
p->inTrans = TRANS_NONE;
p->db = db;
@@ -57767,7 +60949,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
p->sharable = 1;
if( !zFullPathname ){
sqlite3_free(p);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
if( isMemdb ){
memcpy(zFullPathname, zFilename, nFilename);
@@ -57835,11 +61017,11 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
pBt = sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto btree_open_out;
}
rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
- EXTRA_SIZE, flags, vfsFlags, pageReinit);
+ sizeof(MemPage), flags, vfsFlags, pageReinit);
if( rc==SQLITE_OK ){
sqlite3PagerSetMmapLimit(pBt->pPager, db->szMmap);
rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
@@ -57897,14 +61079,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
/* Add the new BtShared object to the linked list sharable BtShareds.
*/
+ pBt->nRef = 1;
if( p->sharable ){
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
- pBt->nRef = 1;
MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
if( pBt->mutex==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto btree_open_out;
}
}
@@ -57927,12 +61109,12 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
for(i=0; i<db->nDb; i++){
if( (pSib = db->aDb[i].pBt)!=0 && pSib->sharable ){
while( pSib->pPrev ){ pSib = pSib->pPrev; }
- if( p->pBt<pSib->pBt ){
+ if( (uptr)p->pBt<(uptr)pSib->pBt ){
p->pNext = pSib;
p->pPrev = 0;
pSib->pPrev = p;
}else{
- while( pSib->pNext && pSib->pNext->pBt<p->pBt ){
+ while( pSib->pNext && (uptr)pSib->pNext->pBt<(uptr)p->pBt ){
pSib = pSib->pNext;
}
p->pNext = pSib->pNext;
@@ -57952,12 +61134,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
btree_open_out:
if( rc!=SQLITE_OK ){
if( pBt && pBt->pPager ){
- sqlite3PagerClose(pBt->pPager);
+ sqlite3PagerClose(pBt->pPager, 0);
}
sqlite3_free(pBt);
sqlite3_free(p);
*ppBtree = 0;
}else{
+ sqlite3_file *pFile;
+
/* If the B-Tree was successfully opened, set the pager-cache size to the
** default value. Except, when opening on an existing shared pager-cache,
** do not change the pager-cache size.
@@ -57965,11 +61149,17 @@ btree_open_out:
if( sqlite3BtreeSchema(p, 0, 0)==0 ){
sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
}
+
+ pFile = sqlite3PagerFile(pBt->pPager);
+ if( pFile->pMethods ){
+ sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db);
+ }
}
if( mutexOpen ){
assert( sqlite3_mutex_held(mutexOpen) );
sqlite3_mutex_leave(mutexOpen);
}
+ assert( rc!=SQLITE_OK || sqlite3BtreeConnectionCount(*ppBtree)>0 );
return rc;
}
@@ -58093,7 +61283,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
** Clean out and delete the BtShared object.
*/
assert( !pBt->pCursor );
- sqlite3PagerClose(pBt->pPager);
+ sqlite3PagerClose(pBt->pPager, p->db);
if( pBt->xFreeSchema && pBt->pSchema ){
pBt->xFreeSchema(pBt->pSchema);
}
@@ -58187,21 +61377,6 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(
#endif
/*
-** Return TRUE if the given btree is set to safety level 1. In other
-** words, return TRUE if no sync() occurs on the disk files.
-*/
-SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree *p){
- BtShared *pBt = p->pBt;
- int rc;
- assert( sqlite3_mutex_held(p->db->mutex) );
- sqlite3BtreeEnter(p);
- assert( pBt && pBt->pPager );
- rc = sqlite3PagerNosync(pBt->pPager);
- sqlite3BtreeLeave(p);
- return rc;
-}
-
-/*
** Change the default pages size and the number of reserved bytes per page.
** Or, if the page size has already been fixed, return SQLITE_READONLY
** without changing anything.
@@ -58446,9 +61621,25 @@ static int lockBtree(BtShared *pBt){
rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
if( rc!=SQLITE_OK ){
goto page1_init_failed;
- }else if( isOpen==0 ){
- releasePage(pPage1);
- return SQLITE_OK;
+ }else{
+#if SQLITE_DEFAULT_SYNCHRONOUS!=SQLITE_DEFAULT_WAL_SYNCHRONOUS
+ sqlite3 *db;
+ Db *pDb;
+ if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
+ while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
+ if( pDb->bSyncSet==0
+ && pDb->safety_level==SQLITE_DEFAULT_SYNCHRONOUS+1
+ ){
+ pDb->safety_level = SQLITE_DEFAULT_WAL_SYNCHRONOUS+1;
+ sqlite3PagerSetFlags(pBt->pPager,
+ pDb->safety_level | (db->flags & PAGER_FLAGS_MASK));
+ }
+ }
+#endif
+ if( isOpen==0 ){
+ releasePage(pPage1);
+ return SQLITE_OK;
+ }
}
rc = SQLITE_NOTADB;
}
@@ -58839,14 +62030,11 @@ static int setChildPtrmaps(MemPage *pPage){
int nCell; /* Number of cells in page pPage */
int rc; /* Return code */
BtShared *pBt = pPage->pBt;
- u8 isInitOrig = pPage->isInit;
Pgno pgno = pPage->pgno;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
rc = btreeInitPage(pPage);
- if( rc!=SQLITE_OK ){
- goto set_child_ptrmaps_out;
- }
+ if( rc!=SQLITE_OK ) return rc;
nCell = pPage->nCell;
for(i=0; i<nCell; i++){
@@ -58865,8 +62053,6 @@ static int setChildPtrmaps(MemPage *pPage){
ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc);
}
-set_child_ptrmaps_out:
- pPage->isInit = isInitOrig;
return rc;
}
@@ -58894,7 +62080,6 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
}
put4byte(pPage->aData, iTo);
}else{
- u8 isInitOrig = pPage->isInit;
int i;
int nCell;
int rc;
@@ -58930,8 +62115,6 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
}
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
}
-
- pPage->isInit = isInitOrig;
}
return SQLITE_OK;
}
@@ -59681,7 +62864,7 @@ static int btreeCursor(
if( wrFlag ){
allocateTempSpace(pBt);
- if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM;
+ if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
}
if( iTable==1 && btreePagecount(pBt)==0 ){
assert( wrFlag==0 );
@@ -59826,48 +63009,39 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){
return pCur && pCur->eState==CURSOR_VALID;
}
#endif /* NDEBUG */
+SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor *pCur){
+ assert( pCur!=0 );
+ return pCur->eState==CURSOR_VALID;
+}
/*
-** Set *pSize to the size of the buffer needed to hold the value of
-** the key for the current entry. If the cursor is not pointing
-** to a valid entry, *pSize is set to 0.
-**
-** For a table with the INTKEY flag set, this routine returns the key
-** itself, not the number of bytes in the key.
-**
-** The caller must position the cursor prior to invoking this routine.
-**
-** This routine cannot fail. It always returns SQLITE_OK.
+** Return the value of the integer key or "rowid" for a table btree.
+** This routine is only valid for a cursor that is pointing into a
+** ordinary table btree. If the cursor points to an index btree or
+** is invalid, the result of this routine is undefined.
*/
-SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
+SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor *pCur){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
+ assert( pCur->curIntKey );
getCellInfo(pCur);
- *pSize = pCur->info.nKey;
- return SQLITE_OK;
+ return pCur->info.nKey;
}
/*
-** Set *pSize to the number of bytes of data in the entry the
-** cursor currently points to.
+** Return the number of bytes of payload for the entry that pCur is
+** currently pointing to. For table btrees, this will be the amount
+** of data. For index btrees, this will be the size of the key.
**
** The caller must guarantee that the cursor is pointing to a non-NULL
** valid entry. In other words, the calling procedure must guarantee
** that the cursor has Cursor.eState==CURSOR_VALID.
-**
-** Failure is not possible. This function always returns SQLITE_OK.
-** It might just as well be a procedure (returning void) but we continue
-** to return an integer result code for historical reasons.
*/
-SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
- assert( cursorOwnsBtShared(pCur) );
+SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){
+ assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
- assert( pCur->iPage>=0 );
- assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
- assert( pCur->apPage[pCur->iPage]->intKeyLeaf==1 );
getCellInfo(pCur);
- *pSize = pCur->info.nPayload;
- return SQLITE_OK;
+ return pCur->info.nPayload;
}
/*
@@ -60038,8 +63212,13 @@ static int accessPayload(
#endif
assert( offset+amt <= pCur->info.nPayload );
- if( &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){
- /* Trying to read or write past the end of the data is an error */
+ assert( aPayload > pPage->aData );
+ if( (uptr)(aPayload - pPage->aData) > (pBt->usableSize - pCur->info.nLocal) ){
+ /* Trying to read or write past the end of the data is an error. The
+ ** conditional above is really:
+ ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
+ ** but is recast into its current form to avoid integer overflow problems
+ */
return SQLITE_CORRUPT_BKPT;
}
@@ -60079,7 +63258,7 @@ static int accessPayload(
pCur->aOverflow, nOvfl*2*sizeof(Pgno)
);
if( aNew==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
pCur->nOvflAlloc = nOvfl*2;
pCur->aOverflow = aNew;
@@ -60164,7 +63343,7 @@ static int accessPayload(
&& (bEnd || a==ovflSize) /* (6) */
&& pBt->inTransaction==TRANS_READ /* (4) */
&& (fd = sqlite3PagerFile(pBt->pPager))->pMethods /* (3) */
- && pBt->pPage1->aData[19]==0x01 /* (5) */
+ && 0==sqlite3PagerUseWal(pBt->pPager) /* (5) */
&& &pBuf[-4]>=pBufStart /* (7) */
){
u8 aSave[4];
@@ -60203,43 +63382,35 @@ static int accessPayload(
}
/*
-** Read part of the key associated with cursor pCur. Exactly
-** "amt" bytes will be transferred into pBuf[]. The transfer
+** Read part of the payload for the row at which that cursor pCur is currently
+** pointing. "amt" bytes will be transferred into pBuf[]. The transfer
** begins at "offset".
**
-** The caller must ensure that pCur is pointing to a valid row
-** in the table.
+** pCur can be pointing to either a table or an index b-tree.
+** If pointing to a table btree, then the content section is read. If
+** pCur is pointing to an index b-tree then the key section is read.
+**
+** For sqlite3BtreePayload(), the caller must ensure that pCur is pointing
+** to a valid row in the table. For sqlite3BtreePayloadChecked(), the
+** cursor might be invalid or might need to be restored before being read.
**
** Return SQLITE_OK on success or an error code if anything goes
** wrong. An error is returned if "offset+amt" is larger than
** the available payload.
*/
-SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
+SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
}
-
-/*
-** Read part of the data associated with cursor pCur. Exactly
-** "amt" bytes will be transfered into pBuf[]. The transfer
-** begins at "offset".
-**
-** Return SQLITE_OK on success or an error code if anything goes
-** wrong. An error is returned if "offset+amt" is larger than
-** the available payload.
-*/
-SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- int rc;
-
#ifndef SQLITE_OMIT_INCRBLOB
+SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
+ int rc;
if ( pCur->eState==CURSOR_INVALID ){
return SQLITE_ABORT;
}
-#endif
-
assert( cursorOwnsBtShared(pCur) );
rc = restoreCursorPosition(pCur);
if( rc==SQLITE_OK ){
@@ -60250,6 +63421,7 @@ SQLITE_PRIVATE int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *p
}
return rc;
}
+#endif /* SQLITE_OMIT_INCRBLOB */
/*
** Return a pointer to payload information from the entry that the
@@ -60304,10 +63476,7 @@ static const void *fetchPayload(
** These routines is used to get quick access to key and data
** in the common case where no overflow pages are used.
*/
-SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){
- return fetchPayload(pCur, pAmt);
-}
-SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
+SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
return fetchPayload(pCur, pAmt);
}
@@ -60423,9 +63592,12 @@ static int moveToRoot(BtCursor *pCur){
}
if( pCur->iPage>=0 ){
- while( pCur->iPage ){
- assert( pCur->apPage[pCur->iPage]!=0 );
- releasePageNotNull(pCur->apPage[pCur->iPage--]);
+ if( pCur->iPage ){
+ do{
+ assert( pCur->apPage[pCur->iPage]!=0 );
+ releasePageNotNull(pCur->apPage[pCur->iPage--]);
+ }while( pCur->iPage);
+ goto skip_init;
}
}else if( pCur->pgnoRoot==0 ){
pCur->eState = CURSOR_INVALID;
@@ -60436,7 +63608,7 @@ static int moveToRoot(BtCursor *pCur){
0, pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
- return rc;
+ return rc;
}
pCur->iPage = 0;
pCur->curIntKey = pCur->apPage[0]->intKey;
@@ -60459,10 +63631,12 @@ static int moveToRoot(BtCursor *pCur){
return SQLITE_CORRUPT_BKPT;
}
+skip_init:
pCur->aiIdx[0] = 0;
pCur->info.nSize = 0;
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
+ pRoot = pCur->apPage[0];
if( pRoot->nCell>0 ){
pCur->eState = CURSOR_VALID;
}else if( !pRoot->leaf ){
@@ -60640,11 +63814,12 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( pRes );
assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
+ assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) );
/* If the cursor is already positioned at the point we are trying
** to move to, then just return without doing any work */
- if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
- && pCur->curIntKey
+ if( pIdxKey==0
+ && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
){
if( pCur->info.nKey==intKey ){
*pRes = 0;
@@ -60718,16 +63893,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
if( lwr>upr ){ c = +1; break; }
}else{
assert( nCellKey==intKey );
- pCur->curFlags |= BTCF_ValidNKey;
- pCur->info.nKey = nCellKey;
pCur->aiIdx[pCur->iPage] = (u16)idx;
if( !pPage->leaf ){
lwr = idx;
goto moveto_next_layer;
}else{
+ pCur->curFlags |= BTCF_ValidNKey;
+ pCur->info.nKey = nCellKey;
+ pCur->info.nSize = 0;
*pRes = 0;
- rc = SQLITE_OK;
- goto moveto_finish;
+ return SQLITE_OK;
}
}
assert( lwr+upr>=0 );
@@ -60784,7 +63959,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
}
pCellKey = sqlite3Malloc( nCell+18 );
if( pCellKey==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto moveto_finish;
}
pCur->aiIdx[pCur->iPage] = (u16)idx;
@@ -60838,7 +64013,7 @@ moveto_next_layer:
}
moveto_finish:
pCur->info.nSize = 0;
- pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
+ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
return rc;
}
@@ -61036,7 +64211,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
moveToParent(pCur);
}
assert( pCur->info.nSize==0 );
- assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 );
+ assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
pCur->aiIdx[pCur->iPage]--;
pPage = pCur->apPage[pCur->iPage];
@@ -61552,30 +64727,28 @@ static void freePage(MemPage *pPage, int *pRC){
static int clearCell(
MemPage *pPage, /* The page that contains the Cell */
unsigned char *pCell, /* First byte of the Cell */
- u16 *pnSize /* Write the size of the Cell here */
+ CellInfo *pInfo /* Size information about the cell */
){
BtShared *pBt = pPage->pBt;
- CellInfo info;
Pgno ovflPgno;
int rc;
int nOvfl;
u32 ovflPageSize;
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
- pPage->xParseCell(pPage, pCell, &info);
- *pnSize = info.nSize;
- if( info.nLocal==info.nPayload ){
+ pPage->xParseCell(pPage, pCell, pInfo);
+ if( pInfo->nLocal==pInfo->nPayload ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
- if( pCell+info.nSize-1 > pPage->aData+pPage->maskPage ){
+ if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){
return SQLITE_CORRUPT_BKPT; /* Cell extends past end of page */
}
- ovflPgno = get4byte(pCell + info.nSize - 4);
+ ovflPgno = get4byte(pCell + pInfo->nSize - 4);
assert( pBt->usableSize > 4 );
ovflPageSize = pBt->usableSize - 4;
- nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize;
+ nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
assert( nOvfl>0 ||
- (CORRUPT_DB && (info.nPayload + ovflPageSize)<ovflPageSize)
+ (CORRUPT_DB && (pInfo->nPayload + ovflPageSize)<ovflPageSize)
);
while( nOvfl-- ){
Pgno iNext = 0;
@@ -61633,9 +64806,7 @@ static int clearCell(
static int fillInCell(
MemPage *pPage, /* The page that contains the cell */
unsigned char *pCell, /* Complete text of the cell */
- const void *pKey, i64 nKey, /* The key */
- const void *pData,int nData, /* The data */
- int nZero, /* Extra zero bytes to append to pData */
+ const BtreePayload *pX, /* Payload with which to construct the cell */
int *pnSize /* Write cell size here */
){
int nPayload;
@@ -61659,26 +64830,21 @@ static int fillInCell(
/* Fill in the header. */
nHeader = pPage->childPtrSize;
- nPayload = nData + nZero;
- if( pPage->intKeyLeaf ){
+ if( pPage->intKey ){
+ nPayload = pX->nData + pX->nZero;
+ pSrc = pX->pData;
+ nSrc = pX->nData;
+ assert( pPage->intKeyLeaf ); /* fillInCell() only called for leaves */
nHeader += putVarint32(&pCell[nHeader], nPayload);
+ nHeader += putVarint(&pCell[nHeader], *(u64*)&pX->nKey);
}else{
- assert( nData==0 );
- assert( nZero==0 );
+ assert( pX->nKey<=0x7fffffff && pX->pKey!=0 );
+ nSrc = nPayload = (int)pX->nKey;
+ pSrc = pX->pKey;
+ nHeader += putVarint32(&pCell[nHeader], nPayload);
}
- nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey);
- /* Fill in the payload size */
- if( pPage->intKey ){
- pSrc = pData;
- nSrc = nData;
- nData = 0;
- }else{
- assert( nKey<=0x7fffffff && pKey!=0 );
- nPayload = (int)nKey;
- pSrc = pKey;
- nSrc = (int)nKey;
- }
+ /* Fill in the payload */
if( nPayload<=pPage->maxLocal ){
n = nHeader + nPayload;
testcase( n==3 );
@@ -61716,7 +64882,7 @@ static int fillInCell(
CellInfo info;
pPage->xParseCell(pPage, pCell, &info);
assert( nHeader==(int)(info.pPayload - pCell) );
- assert( info.nKey==nKey );
+ assert( info.nKey==pX->nKey );
assert( *pnSize == info.nSize );
assert( spaceLeft == info.nLocal );
}
@@ -61801,10 +64967,6 @@ static int fillInCell(
pSrc += n;
nSrc -= n;
spaceLeft -= n;
- if( nSrc==0 ){
- nSrc = nData;
- pSrc = pData;
- }
}
releasePage(pToRelease);
return SQLITE_OK;
@@ -61826,7 +64988,6 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */
if( *pRC ) return;
-
assert( idx>=0 && idx<pPage->nCell );
assert( CORRUPT_DB || sz==cellSize(pPage, idx) );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
@@ -61871,6 +65032,8 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** in pTemp or the original pCell) and also record its index.
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
+**
+** *pRC must be SQLITE_OK when this routine is called.
*/
static void insertCell(
MemPage *pPage, /* Page into which we are copying */
@@ -61886,8 +65049,7 @@ static void insertCell(
u8 *data; /* The content of the whole page */
u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
- if( *pRC ) return;
-
+ assert( *pRC==SQLITE_OK );
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( MX_CELL(pPage->pBt)<=10921 );
assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
@@ -61909,7 +65071,10 @@ static void insertCell(
put4byte(pCell, iChild);
}
j = pPage->nOverflow++;
- assert( j<(int)(sizeof(pPage->apOvfl)/sizeof(pPage->apOvfl[0])) );
+ /* Comparison against ArraySize-1 since we hold back one extra slot
+ ** as a contingency. In other words, never need more than 3 overflow
+ ** slots but 4 are allocated, just to be safe. */
+ assert( j < ArraySize(pPage->apOvfl)-1 );
pPage->apOvfl[j] = pCell;
pPage->aiOvfl[j] = (u16)i;
@@ -61961,7 +65126,7 @@ static void insertCell(
/*
** A CellArray object contains a cache of pointers and sizes for a
-** consecutive sequence of cells that might be held multiple pages.
+** consecutive sequence of cells that might be held on multiple pages.
*/
typedef struct CellArray CellArray;
struct CellArray {
@@ -62106,8 +65271,8 @@ static int pageInsertArray(
u8 *pSlot;
sz = cachedCellSize(pCArray, i);
if( (aData[1]==0 && aData[2]==0) || (pSlot = pageFindSlot(pPg,sz,&rc))==0 ){
+ if( (pData - pBegin)<sz ) return 1;
pData -= sz;
- if( pData<pBegin ) return 1;
pSlot = pData;
}
/* pSlot and pCArray->apCell[i] will never overlap on a well-formed
@@ -62269,7 +65434,7 @@ static int editPage(
for(i=0; i<nNew && !CORRUPT_DB; i++){
u8 *pCell = pCArray->apCell[i+iNew];
int iOff = get2byteAligned(&pPg->aCellIdx[i*2]);
- if( pCell>=aData && pCell<&aData[pPg->pBt->usableSize] ){
+ if( SQLITE_WITHIN(pCell, aData, &aData[pPg->pBt->usableSize]) ){
pCell = &pTmp[pCell - aData];
}
assert( 0==memcmp(pCell, &aData[iOff],
@@ -62393,8 +65558,10 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop );
/* Insert the new divider cell into pParent. */
- insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
- 0, pPage->pgno, &rc);
+ if( rc==SQLITE_OK ){
+ insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
+ 0, pPage->pgno, &rc);
+ }
/* Set the right-child pointer of pParent to point to the new page. */
put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
@@ -62603,7 +65770,7 @@ static int balance_nonroot(
assert( pParent->nOverflow==0 || pParent->aiOvfl[0]==iParentIdx );
if( !aOvflSpace ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
/* Find the sibling pages to balance. Also locate the cells in pParent
@@ -62647,7 +65814,7 @@ static int balance_nonroot(
nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow;
if( (i--)==0 ) break;
- if( i+nxDiv==pParent->aiOvfl[0] && pParent->nOverflow ){
+ if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){
apDiv[i] = pParent->apOvfl[0];
pgno = get4byte(apDiv[i]);
szNew[i] = pParent->xCellSize(pParent, apDiv[i]);
@@ -62703,7 +65870,7 @@ static int balance_nonroot(
assert( szScratch<=6*(int)pBt->pageSize );
b.apCell = sqlite3ScratchMalloc( szScratch );
if( b.apCell==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto balance_cleanup;
}
b.szCell = (u16*)&b.apCell[nMaxCells];
@@ -62914,7 +66081,7 @@ static int balance_nonroot(
assert( r<nMaxCells );
(void)cachedCellSize(&b, r);
if( szRight!=0
- && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+2)) ){
+ && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){
break;
}
szRight += b.szCell[d] + 2;
@@ -63138,9 +66305,9 @@ static int balance_nonroot(
** any cell). But it is important to pass the correct size to
** insertCell(), so reparse the cell now.
**
- ** Note that this can never happen in an SQLite data file, as all
- ** cells are at least 4 bytes. It only happens in b-trees used
- ** to evaluate "IN (SELECT ...)" and similar clauses.
+ ** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
+ ** and WITHOUT ROWID tables with exactly one column which is the
+ ** primary key.
*/
if( b.szCell[j]==4 ){
assert(leafCorrection==4);
@@ -63486,32 +66653,38 @@ static int balance(BtCursor *pCur){
/*
-** Insert a new record into the BTree. The key is given by (pKey,nKey)
-** and the data is given by (pData,nData). The cursor is used only to
-** define what table the record should be inserted into. The cursor
-** is left pointing at a random location.
+** Insert a new record into the BTree. The content of the new record
+** is described by the pX object. The pCur cursor is used only to
+** define what table the record should be inserted into, and is left
+** pointing at a random location.
+**
+** For a table btree (used for rowid tables), only the pX.nKey value of
+** the key is used. The pX.pKey value must be NULL. The pX.nKey is the
+** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields
+** hold the content of the row.
**
-** For an INTKEY table, only the nKey value of the key is used. pKey is
-** ignored. For a ZERODATA table, the pData and nData are both ignored.
+** For an index btree (used for indexes and WITHOUT ROWID tables), the
+** key is an arbitrary byte sequence stored in pX.pKey,nKey. The
+** pX.pData,nData,nZero fields must be zero.
**
** If the seekResult parameter is non-zero, then a successful call to
-** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already
-** been performed. seekResult is the search result returned (a negative
-** number if pCur points at an entry that is smaller than (pKey, nKey), or
-** a positive value if pCur points at an entry that is larger than
-** (pKey, nKey)).
-**
-** If the seekResult parameter is non-zero, then the caller guarantees that
-** cursor pCur is pointing at the existing copy of a row that is to be
-** overwritten. If the seekResult parameter is 0, then cursor pCur may
-** point to any entry or to no entry at all and so this function has to seek
-** the cursor before the new key can be inserted.
+** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already
+** been performed. In other words, if seekResult!=0 then the cursor
+** is currently pointing to a cell that will be adjacent to the cell
+** to be inserted. If seekResult<0 then pCur points to a cell that is
+** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell
+** that is larger than (pKey,nKey).
+**
+** If seekResult==0, that means pCur is pointing at some unknown location.
+** In that case, this routine must seek the cursor to the correct insertion
+** point for (pKey,nKey) before doing the insertion. For index btrees,
+** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked
+** key values and pX->aMem can be used instead of pX->pKey to avoid having
+** to decode the key.
*/
SQLITE_PRIVATE int sqlite3BtreeInsert(
BtCursor *pCur, /* Insert data into the table of this cursor */
- const void *pKey, i64 nKey, /* The key of the new record */
- const void *pData, int nData, /* The data of the new record */
- int nZero, /* Number of extra 0 bytes to append to data */
+ const BtreePayload *pX, /* Content of the row to be inserted */
int appendBias, /* True if this is likely an append */
int seekResult /* Result of prior MovetoUnpacked() call */
){
@@ -63541,7 +66714,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** keys with no associated data. If the cursor was opened expecting an
** intkey table, the caller should be inserting integer keys with a
** blob of associated data. */
- assert( (pKey==0)==(pCur->pKeyInfo==0) );
+ assert( (pX->pKey==0)==(pCur->pKeyInfo==0) );
/* Save the positions of any other cursors open on this table.
**
@@ -63560,44 +66733,59 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}
if( pCur->pKeyInfo==0 ){
- assert( pKey==0 );
+ assert( pX->pKey==0 );
/* If this is an insert into a table b-tree, invalidate any incrblob
** cursors open on the row being replaced */
- invalidateIncrblobCursors(p, nKey, 0);
+ invalidateIncrblobCursors(p, pX->nKey, 0);
/* If the cursor is currently on the last row and we are appending a
** new row onto the end, set the "loc" to avoid an unnecessary
** btreeMoveto() call */
- if( (pCur->curFlags&BTCF_ValidNKey)!=0 && nKey>0
- && pCur->info.nKey==nKey-1 ){
- loc = -1;
+ if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){
+ loc = 0;
+ }else if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0
+ && pCur->info.nKey==pX->nKey-1 ){
+ loc = -1;
}else if( loc==0 ){
- rc = sqlite3BtreeMovetoUnpacked(pCur, 0, nKey, appendBias, &loc);
+ rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, appendBias, &loc);
if( rc ) return rc;
}
}else if( loc==0 ){
- rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc);
+ if( pX->nMem ){
+ UnpackedRecord r;
+ r.pKeyInfo = pCur->pKeyInfo;
+ r.aMem = pX->aMem;
+ r.nField = pX->nMem;
+ r.default_rc = 0;
+ r.errCode = 0;
+ r.r1 = 0;
+ r.r2 = 0;
+ r.eqSeen = 0;
+ rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, appendBias, &loc);
+ }else{
+ rc = btreeMoveto(pCur, pX->pKey, pX->nKey, appendBias, &loc);
+ }
if( rc ) return rc;
}
assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
pPage = pCur->apPage[pCur->iPage];
- assert( pPage->intKey || nKey>=0 );
+ assert( pPage->intKey || pX->nKey>=0 );
assert( pPage->leaf || !pPage->intKey );
TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
- pCur->pgnoRoot, nKey, nData, pPage->pgno,
+ pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit );
newCell = pBt->pTmpSpace;
assert( newCell!=0 );
- rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew);
+ rc = fillInCell(pPage, newCell, pX, &szNew);
if( rc ) goto end_insert;
assert( szNew==pPage->xCellSize(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(pBt) );
idx = pCur->aiIdx[pCur->iPage];
if( loc==0 ){
- u16 szOld;
+ CellInfo info;
assert( idx<pPage->nCell );
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ){
@@ -63607,8 +66795,19 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( !pPage->leaf ){
memcpy(newCell, oldCell, 4);
}
- rc = clearCell(pPage, oldCell, &szOld);
- dropCell(pPage, idx, szOld, &rc);
+ rc = clearCell(pPage, oldCell, &info);
+ if( info.nSize==szNew && info.nLocal==info.nPayload ){
+ /* Overwrite the old cell with the new if they are the same size.
+ ** We could also try to do this if the old cell is smaller, then add
+ ** the leftover space to the free list. But experiments show that
+ ** doing that is no faster then skipping this optimization and just
+ ** calling dropCell() and insertCell(). */
+ assert( rc==SQLITE_OK ); /* clearCell never fails when nLocal==nPayload */
+ if( oldCell+szNew > pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
+ memcpy(oldCell, newCell, szNew);
+ return SQLITE_OK;
+ }
+ dropCell(pPage, idx, info.nSize, &rc);
if( rc ) goto end_insert;
}else if( loc<0 && pPage->nCell>0 ){
assert( pPage->leaf );
@@ -63617,6 +66816,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
assert( pPage->leaf );
}
insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
+ assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
/* If no error has occurred and pPage has an overflow cell, call balance()
@@ -63640,7 +66840,8 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** row without seeking the cursor. This can be a big performance boost.
*/
pCur->info.nSize = 0;
- if( rc==SQLITE_OK && pPage->nOverflow ){
+ if( pPage->nOverflow ){
+ assert( rc==SQLITE_OK );
pCur->curFlags &= ~(BTCF_ValidNKey);
rc = balance(pCur);
@@ -63682,7 +66883,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
unsigned char *pCell; /* Pointer to cell to delete */
int iCellIdx; /* Index of cell to delete */
int iCellDepth; /* Depth of node containing pCell */
- u16 szCell; /* Size of the cell being deleted */
+ CellInfo info; /* Size of the cell being deleted */
int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */
@@ -63701,6 +66902,28 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
pPage = pCur->apPage[iCellDepth];
pCell = findCell(pPage, iCellIdx);
+ /* If the bPreserve flag is set to true, then the cursor position must
+ ** be preserved following this delete operation. If the current delete
+ ** will cause a b-tree rebalance, then this is done by saving the cursor
+ ** key and leaving the cursor in CURSOR_REQUIRESEEK state before
+ ** returning.
+ **
+ ** Or, if the current delete will not cause a rebalance, then the cursor
+ ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
+ ** before or after the deleted entry. In this case set bSkipnext to true. */
+ if( bPreserve ){
+ if( !pPage->leaf
+ || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
+ ){
+ /* A b-tree rebalance will be required after deleting this entry.
+ ** Save the cursor key. */
+ rc = saveCursorKey(pCur);
+ if( rc ) return rc;
+ }else{
+ bSkipnext = 1;
+ }
+ }
+
/* If the page containing the entry to delete is not a leaf page, move
** the cursor to the largest entry in the tree that is smaller than
** the entry being deleted. This cell will replace the cell being deleted
@@ -63727,35 +66950,13 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
invalidateIncrblobCursors(p, pCur->info.nKey, 0);
}
- /* If the bPreserve flag is set to true, then the cursor position must
- ** be preserved following this delete operation. If the current delete
- ** will cause a b-tree rebalance, then this is done by saving the cursor
- ** key and leaving the cursor in CURSOR_REQUIRESEEK state before
- ** returning.
- **
- ** Or, if the current delete will not cause a rebalance, then the cursor
- ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
- ** before or after the deleted entry. In this case set bSkipnext to true. */
- if( bPreserve ){
- if( !pPage->leaf
- || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
- ){
- /* A b-tree rebalance will be required after deleting this entry.
- ** Save the cursor key. */
- rc = saveCursorKey(pCur);
- if( rc ) return rc;
- }else{
- bSkipnext = 1;
- }
- }
-
/* Make the page containing the entry to be deleted writable. Then free any
** overflow pages associated with the entry and finally remove the cell
** itself from within the page. */
rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
- rc = clearCell(pPage, pCell, &szCell);
- dropCell(pPage, iCellIdx, szCell, &rc);
+ rc = clearCell(pPage, pCell, &info);
+ dropCell(pPage, iCellIdx, info.nSize, &rc);
if( rc ) return rc;
/* If the cell deleted was not located on a leaf page, then the cursor
@@ -63776,7 +66977,9 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
pTmp = pBt->pTmpSpace;
assert( pTmp!=0 );
rc = sqlite3PagerWrite(pLeaf->pDbPage);
- insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
+ if( rc==SQLITE_OK ){
+ insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
+ }
dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
if( rc ) return rc;
}
@@ -64003,7 +67206,7 @@ static int clearDatabasePage(
unsigned char *pCell;
int i;
int hdr;
- u16 szCell;
+ CellInfo info;
assert( sqlite3_mutex_held(pBt->mutex) );
if( pgno>btreePagecount(pBt) ){
@@ -64023,7 +67226,7 @@ static int clearDatabasePage(
rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange);
if( rc ) goto cleardatabasepage_out;
}
- rc = clearCell(pPage, pCell, &szCell);
+ rc = clearCell(pPage, pCell, &info);
if( rc ) goto cleardatabasepage_out;
}
if( !pPage->leaf ){
@@ -64114,27 +67317,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
assert( sqlite3BtreeHoldsMutex(p) );
assert( p->inTrans==TRANS_WRITE );
-
- /* It is illegal to drop a table if any cursors are open on the
- ** database. This is because in auto-vacuum mode the backend may
- ** need to move another root-page to fill a gap left by the deleted
- ** root page. If an open cursor was using this page a problem would
- ** occur.
- **
- ** This error is caught long before control reaches this point.
- */
- if( NEVER(pBt->pCursor) ){
- sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db);
- return SQLITE_LOCKED_SHAREDCACHE;
- }
-
- /*
- ** It is illegal to drop the sqlite_master table on page 1. But again,
- ** this error is caught long before reaching this point.
- */
- if( NEVER(iTable<2) ){
- return SQLITE_CORRUPT_BKPT;
- }
+ assert( iTable>=2 );
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
if( rc ) return rc;
@@ -65042,7 +68225,7 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *
if( pBt->inTransaction!=TRANS_NONE ){
rc = SQLITE_LOCKED;
}else{
- rc = sqlite3PagerCheckpoint(pBt->pPager, eMode, pnLog, pnCkpt);
+ rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt);
}
sqlite3BtreeLeave(p);
}
@@ -65265,6 +68448,16 @@ SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage));
SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
return p->sharable;
}
+
+/*
+** Return the number of connections to the BtShared object accessed by
+** the Btree handle passed as the only argument. For private caches
+** this is always 1. For shared caches it may be 1 or greater.
+*/
+SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){
+ testcase( p->sharable );
+ return p->pBt->nRef;
+}
#endif
/************** End of btree.c ***********************************************/
@@ -65354,22 +68547,16 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
int i = sqlite3FindDbName(pDb, zDb);
if( i==1 ){
- Parse *pParse;
+ Parse sParse;
int rc = 0;
- pParse = sqlite3StackAllocZero(pErrorDb, sizeof(*pParse));
- if( pParse==0 ){
- sqlite3ErrorWithMsg(pErrorDb, SQLITE_NOMEM, "out of memory");
- rc = SQLITE_NOMEM;
- }else{
- pParse->db = pDb;
- if( sqlite3OpenTempDatabase(pParse) ){
- sqlite3ErrorWithMsg(pErrorDb, pParse->rc, "%s", pParse->zErrMsg);
- rc = SQLITE_ERROR;
- }
- sqlite3DbFree(pErrorDb, pParse->zErrMsg);
- sqlite3ParserReset(pParse);
- sqlite3StackFree(pErrorDb, pParse);
+ memset(&sParse, 0, sizeof(sParse));
+ sParse.db = pDb;
+ if( sqlite3OpenTempDatabase(&sParse) ){
+ sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);
+ rc = SQLITE_ERROR;
}
+ sqlite3DbFree(pErrorDb, sParse.zErrMsg);
+ sqlite3ParserReset(&sParse);
if( rc ){
return 0;
}
@@ -65415,7 +68602,7 @@ static int checkReadTransaction(sqlite3 *db, Btree *p){
** If an error occurs, NULL is returned and an error code and error message
** stored in database handle pDestDb.
*/
-SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
+SQLITE_API sqlite3_backup *sqlite3_backup_init(
sqlite3* pDestDb, /* Database to write to */
const char *zDestDb, /* Name of database within pDestDb */
sqlite3* pSrcDb, /* Database connection to read from */
@@ -65453,7 +68640,7 @@ SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
** sqlite3_backup_finish(). */
p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
if( !p ){
- sqlite3Error(pDestDb, SQLITE_NOMEM);
+ sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT);
}
}
@@ -65467,7 +68654,6 @@ SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
p->isAttached = 0;
if( 0==p->pSrc || 0==p->pDest
- || setDestPgsz(p)==SQLITE_NOMEM
|| checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
){
/* One (or both) of the named databases did not exist or an OOM
@@ -65623,7 +68809,7 @@ static void attachBackupObject(sqlite3_backup *p){
/*
** Copy nPage pages from the source b-tree to the destination.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
+SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int rc;
int destMode; /* Destination journal mode */
int pgszSrc = 0; /* Source page size */
@@ -65655,14 +68841,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
rc = SQLITE_OK;
}
- /* Lock the destination database, if it is not locked already. */
- if( SQLITE_OK==rc && p->bDestLocked==0
- && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2))
- ){
- p->bDestLocked = 1;
- sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
- }
-
/* If there is no open read-transaction on the source database, open
** one now. If a transaction is opened here, then it will be closed
** before this function exits.
@@ -65672,6 +68850,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
bCloseTrans = 1;
}
+ /* If the destination database has not yet been locked (i.e. if this
+ ** is the first call to backup_step() for the current backup operation),
+ ** try to set its page size to the same as the source database. This
+ ** is especially important on ZipVFS systems, as in that case it is
+ ** not possible to create a database file that uses one page size by
+ ** writing to it with another. */
+ if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){
+ rc = SQLITE_NOMEM;
+ }
+
+ /* Lock the destination database, if it is not locked already. */
+ if( SQLITE_OK==rc && p->bDestLocked==0
+ && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2))
+ ){
+ p->bDestLocked = 1;
+ sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema);
+ }
+
/* Do not allow backup if the destination database is in WAL mode
** and the page sizes are different between source and destination */
pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
@@ -65852,7 +69048,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
}
if( rc==SQLITE_IOERR_NOMEM ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
p->rc = rc;
}
@@ -65867,7 +69063,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage){
/*
** Release all resources associated with an sqlite3_backup* handle.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){
+SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
sqlite3_backup **pp; /* Ptr to head of pagers backup list */
sqlite3 *pSrcDb; /* Source database connection */
int rc; /* Value to return */
@@ -65919,7 +69115,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p){
** Return the number of pages still to be backed up as of the most recent
** call to sqlite3_backup_step().
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){
+SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
#ifdef SQLITE_ENABLE_API_ARMOR
if( p==0 ){
(void)SQLITE_MISUSE_BKPT;
@@ -65933,7 +69129,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p){
** Return the total number of pages in the source database as of the most
** recent call to sqlite3_backup_step().
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p){
+SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
#ifdef SQLITE_ENABLE_API_ARMOR
if( p==0 ){
(void)SQLITE_MISUSE_BKPT;
@@ -66048,10 +69244,10 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
** sqlite3_backup_step(), we can guarantee that the copy finishes
** within a single call (unless an error occurs). The assert() statement
** checks this assumption - (p->rc) should be set to either SQLITE_DONE
- ** or an error code.
- */
+ ** or an error code. */
sqlite3_backup_step(&b, 0x7FFFFFFF);
assert( b.rc!=SQLITE_OK );
+
rc = sqlite3_backup_finish(&b);
if( rc==SQLITE_OK ){
pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
@@ -66209,7 +69405,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre
sqlite3VdbeMemSetNull(pMem);
pMem->z = 0;
pMem->szMalloc = 0;
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}else{
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}
@@ -66260,18 +69456,18 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
- int f;
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
assert( (pMem->flags&MEM_RowSet)==0 );
- ExpandBlob(pMem);
- f = pMem->flags;
- if( (f&(MEM_Str|MEM_Blob)) && (pMem->szMalloc==0 || pMem->z!=pMem->zMalloc) ){
- if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
- return SQLITE_NOMEM;
+ if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
+ if( ExpandBlob(pMem) ) return SQLITE_NOMEM;
+ if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){
+ if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){
+ return SQLITE_NOMEM_BKPT;
+ }
+ pMem->z[pMem->n] = 0;
+ pMem->z[pMem->n+1] = 0;
+ pMem->flags |= MEM_Term;
}
- pMem->z[pMem->n] = 0;
- pMem->z[pMem->n+1] = 0;
- pMem->flags |= MEM_Term;
}
pMem->flags &= ~MEM_Ephem;
#ifdef SQLITE_DEBUG
@@ -66287,25 +69483,24 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
*/
#ifndef SQLITE_OMIT_INCRBLOB
SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
- if( pMem->flags & MEM_Zero ){
- int nByte;
- assert( pMem->flags&MEM_Blob );
- assert( (pMem->flags&MEM_RowSet)==0 );
- assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
-
- /* Set nByte to the number of bytes required to store the expanded blob. */
- nByte = pMem->n + pMem->u.nZero;
- if( nByte<=0 ){
- nByte = 1;
- }
- if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
- return SQLITE_NOMEM;
- }
+ int nByte;
+ assert( pMem->flags & MEM_Zero );
+ assert( pMem->flags&MEM_Blob );
+ assert( (pMem->flags&MEM_RowSet)==0 );
+ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
- memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
- pMem->n += pMem->u.nZero;
- pMem->flags &= ~(MEM_Zero|MEM_Term);
+ /* Set nByte to the number of bytes required to store the expanded blob. */
+ nByte = pMem->n + pMem->u.nZero;
+ if( nByte<=0 ){
+ nByte = 1;
+ }
+ if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
+ return SQLITE_NOMEM_BKPT;
}
+
+ memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
+ pMem->n += pMem->u.nZero;
+ pMem->flags &= ~(MEM_Zero|MEM_Term);
return SQLITE_OK;
}
#endif
@@ -66316,7 +69511,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
*/
static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pMem->z[pMem->n] = 0;
pMem->z[pMem->n+1] = 0;
@@ -66365,7 +69560,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){
- return SQLITE_NOMEM;
+ pMem->enc = 0;
+ return SQLITE_NOMEM_BKPT;
}
/* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8
@@ -66646,7 +69842,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
}
}
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
- pMem->flags &= ~(MEM_Str|MEM_Blob);
+ pMem->flags &= ~(MEM_Str|MEM_Blob|MEM_Zero);
return SQLITE_OK;
}
@@ -66664,7 +69860,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
if( (pMem->flags & MEM_Blob)==0 ){
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, encoding);
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
- MemSetTypeFlag(pMem, MEM_Blob);
+ if( pMem->flags & MEM_Str ) MemSetTypeFlag(pMem, MEM_Blob);
}else{
pMem->flags &= ~(MEM_TypeMask&~MEM_Blob);
}
@@ -66832,7 +70028,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
int i;
Mem *pX;
- for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
+ for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){
if( pX->pScopyFrom==pMem ){
pX->flags |= MEM_Undefined;
pX->pScopyFrom = 0;
@@ -66873,10 +70069,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int sr
SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
int rc = SQLITE_OK;
- /* The pFrom==0 case in the following assert() is when an sqlite3_value
- ** from sqlite3_value_dup() is used as the argument
- ** to sqlite3_result_value(). */
- assert( pTo->db==pFrom->db || pFrom->db==0 );
assert( (pFrom->flags & MEM_RowSet)==0 );
if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
@@ -66976,7 +70168,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
testcase( nAlloc==31 );
testcase( nAlloc==32 );
if( sqlite3VdbeMemClearAndResize(pMem, MAX(nAlloc,32)) ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memcpy(pMem->z, z, nAlloc);
}else if( xDel==SQLITE_DYNAMIC ){
@@ -66996,7 +70188,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
#ifndef SQLITE_OMIT_UTF16
if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
#endif
@@ -67009,10 +70201,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
/*
** Move data out of a btree key or data field and into a Mem structure.
-** The data or key is taken from the entry that pCur is currently pointing
+** The data is payload from the entry that pCur is currently pointing
** to. offset and amt determine what portion of the data or key to retrieve.
-** key is true to get the key or false to get data. The result is written
-** into the pMem element.
+** The result is written into the pMem element.
**
** The pMem object must have been initialized. This routine will use
** pMem->zMalloc to hold the content from the btree, if possible. New
@@ -67027,17 +70218,12 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
u32 offset, /* Offset from the start of data to return bytes from. */
u32 amt, /* Number of bytes to return. */
- int key, /* If true, retrieve from the btree key, not data. */
Mem *pMem /* OUT: Return data in this Mem structure. */
){
int rc;
pMem->flags = MEM_Null;
if( SQLITE_OK==(rc = sqlite3VdbeMemClearAndResize(pMem, amt+2)) ){
- if( key ){
- rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
- }else{
- rc = sqlite3BtreeData(pCur, offset, amt, pMem->z);
- }
+ rc = sqlite3BtreePayload(pCur, offset, amt, pMem->z);
if( rc==SQLITE_OK ){
pMem->z[amt] = 0;
pMem->z[amt+1] = 0;
@@ -67053,7 +70239,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
u32 offset, /* Offset from the start of data to return bytes from. */
u32 amt, /* Number of bytes to return. */
- int key, /* If true, retrieve from the btree key, not data. */
Mem *pMem /* OUT: Return data in this Mem structure. */
){
char *zData; /* Data from the btree layer */
@@ -67066,11 +70251,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
/* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
** that both the BtShared and database handle mutexes are held. */
assert( (pMem->flags & MEM_RowSet)==0 );
- if( key ){
- zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
- }else{
- zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
- }
+ zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
assert( zData!=0 );
if( offset+amt<=available ){
@@ -67078,7 +70259,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
pMem->flags = MEM_Blob|MEM_Ephem;
pMem->n = (int)amt;
}else{
- rc = vdbeMemFromBtreeResize(pCur, offset, amt, key, pMem);
+ rc = vdbeMemFromBtreeResize(pCur, offset, amt, pMem);
}
return rc;
@@ -67097,9 +70278,6 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){
assert( (pVal->flags & (MEM_Null))==0 );
if( pVal->flags & (MEM_Blob|MEM_Str) ){
pVal->flags |= MEM_Str;
- if( pVal->flags & MEM_Zero ){
- sqlite3VdbeMemExpandBlob(pVal);
- }
if( pVal->enc != (enc & ~SQLITE_UTF16_ALIGNED) ){
sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
}
@@ -67257,7 +70435,6 @@ static int valueFromFunction(
FuncDef *pFunc = 0; /* Function definition */
sqlite3_value *pVal = 0; /* New value */
int rc = SQLITE_OK; /* Return code */
- int nName; /* Size of function name in bytes */
ExprList *pList = 0; /* Function arguments */
int i; /* Iterator variable */
@@ -67265,8 +70442,7 @@ static int valueFromFunction(
assert( (p->flags & EP_TokenOnly)==0 );
pList = p->x.pList;
if( pList ) nVal = pList->nExpr;
- nName = sqlite3Strlen30(p->u.zToken);
- pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
+ pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
assert( pFunc );
if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|| (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
@@ -67277,7 +70453,7 @@ static int valueFromFunction(
if( pList ){
apVal = (sqlite3_value**)sqlite3DbMallocZero(db, sizeof(apVal[0]) * nVal);
if( apVal==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto value_from_function_out;
}
for(i=0; i<nVal; i++){
@@ -67288,7 +70464,7 @@ static int valueFromFunction(
pVal = valueNew(db, pCtx);
if( pVal==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto value_from_function_out;
}
@@ -67354,11 +70530,8 @@ static int valueFromExpr(
const char *zNeg = "";
int rc = SQLITE_OK;
- if( !pExpr ){
- *ppVal = 0;
- return SQLITE_OK;
- }
- while( (op = pExpr->op)==TK_UPLUS ) pExpr = pExpr->pLeft;
+ assert( pExpr!=0 );
+ while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
/* Compressed expressions only appear when parsing the DEFAULT clause
@@ -67427,6 +70600,7 @@ static int valueFromExpr(
}else if( op==TK_NULL ){
pVal = valueNew(db, pCtx);
if( pVal==0 ) goto no_mem;
+ sqlite3VdbeMemNumerify(pVal);
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
else if( op==TK_BLOB ){
@@ -67461,7 +70635,7 @@ no_mem:
#else
assert( pCtx==0 ); sqlite3ValueFree(pVal);
#endif
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
/*
@@ -67481,7 +70655,7 @@ SQLITE_PRIVATE int sqlite3ValueFromExpr(
u8 affinity, /* Affinity to use */
sqlite3_value **ppVal /* Write the new value here */
){
- return valueFromExpr(db, pExpr, enc, affinity, ppVal, 0);
+ return pExpr ? valueFromExpr(db, pExpr, enc, affinity, ppVal, 0) : 0;
}
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
@@ -67528,15 +70702,10 @@ static void recordFunc(
** Register built-in functions used to help read ANALYZE data.
*/
SQLITE_PRIVATE void sqlite3AnalyzeFunctions(void){
- static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
+ static FuncDef aAnalyzeTableFuncs[] = {
FUNCTION(sqlite_record, 1, 0, 0, recordFunc),
};
- int i;
- FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
- FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
- for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
- sqlite3FuncDefInsert(pHash, &aFunc[i]);
- }
+ sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs));
}
/*
@@ -67606,9 +70775,9 @@ static int stat4ValueFromExpr(
** structures intended to be compared against sample index keys stored
** in the sqlite_stat4 table.
**
-** A single call to this function attempts to populates field iVal (leftmost
-** is 0 etc.) of the unpacked record with a value extracted from expression
-** pExpr. Extraction of values is possible if:
+** A single call to this function populates zero or more fields of the
+** record starting with field iVal (fields are numbered from left to
+** right starting with 0). A single field is populated if:
**
** * (pExpr==0). In this case the value is assumed to be an SQL NULL,
**
@@ -67617,10 +70786,14 @@ static int stat4ValueFromExpr(
** * The sqlite3ValueFromExpr() function is able to extract a value
** from the expression (i.e. the expression is a literal value).
**
-** If a value can be extracted, the affinity passed as the 5th argument
-** is applied to it before it is copied into the UnpackedRecord. Output
-** parameter *pbOk is set to true if a value is extracted, or false
-** otherwise.
+** Or, if pExpr is a TK_VECTOR, one field is populated for each of the
+** vector components that match either of the two latter criteria listed
+** above.
+**
+** Before any value is appended to the record, the affinity of the
+** corresponding column within index pIdx is applied to it. Before
+** this function returns, output parameter *pnExtract is set to the
+** number of values appended to the record.
**
** When this function is called, *ppRec must either point to an object
** allocated by an earlier call to this function, or must be NULL. If it
@@ -67636,22 +70809,33 @@ SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(
Index *pIdx, /* Index being probed */
UnpackedRecord **ppRec, /* IN/OUT: Probe record */
Expr *pExpr, /* The expression to extract a value from */
- u8 affinity, /* Affinity to use */
+ int nElem, /* Maximum number of values to append */
int iVal, /* Array element to populate */
- int *pbOk /* OUT: True if value was extracted */
+ int *pnExtract /* OUT: Values appended to the record */
){
- int rc;
- sqlite3_value *pVal = 0;
- struct ValueNewStat4Ctx alloc;
+ int rc = SQLITE_OK;
+ int nExtract = 0;
+
+ if( pExpr==0 || pExpr->op!=TK_SELECT ){
+ int i;
+ struct ValueNewStat4Ctx alloc;
+
+ alloc.pParse = pParse;
+ alloc.pIdx = pIdx;
+ alloc.ppRec = ppRec;
- alloc.pParse = pParse;
- alloc.pIdx = pIdx;
- alloc.ppRec = ppRec;
- alloc.iVal = iVal;
+ for(i=0; i<nElem; i++){
+ sqlite3_value *pVal = 0;
+ Expr *pElem = (pExpr ? sqlite3VectorFieldSubexpr(pExpr, i) : 0);
+ u8 aff = sqlite3IndexColumnAffinity(pParse->db, pIdx, iVal+i);
+ alloc.iVal = iVal+i;
+ rc = stat4ValueFromExpr(pParse, pElem, aff, &alloc, &pVal);
+ if( !pVal ) break;
+ nExtract++;
+ }
+ }
- rc = stat4ValueFromExpr(pParse, pExpr, affinity, &alloc, &pVal);
- assert( pVal==0 || pVal->db==pParse->db );
- *pbOk = (pVal!=0);
+ *pnExtract = nExtract;
return rc;
}
@@ -67715,7 +70899,7 @@ SQLITE_PRIVATE int sqlite3Stat4Column(
if( iField>nRec ) return SQLITE_CORRUPT_BKPT;
if( pMem==0 ){
pMem = *ppVal = sqlite3ValueNew(db);
- if( pMem==0 ) return SQLITE_NOMEM;
+ if( pMem==0 ) return SQLITE_NOMEM_BKPT;
}
sqlite3VdbeSerialGet(&a[iField-szField], t, pMem);
pMem->enc = ENC(db);
@@ -67814,8 +70998,9 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
sqlite3 *db = pParse->db;
Vdbe *p;
- p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
+ p = sqlite3DbMallocRawNN(db, sizeof(Vdbe) );
if( p==0 ) return 0;
+ memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp));
p->db = db;
if( db->pVdbe ){
db->pVdbe->pPrev = p;
@@ -67858,19 +71043,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepa
}
/*
-** Return the SQL associated with a prepared statement
-*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt){
- Vdbe *p = (Vdbe *)pStmt;
- return p ? p->zSql : 0;
-}
-
-/*
** Swap all content between two VDBE structures.
*/
SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
Vdbe tmp, *pTmp;
char *zTmp;
+ assert( pA->db==pB->db );
tmp = *pA;
*pA = *pB;
*pB = tmp;
@@ -67922,7 +71100,7 @@ static int growOpArray(Vdbe *v, int nOp){
p->nOpAlloc = p->szOpAlloc/sizeof(Op);
v->aOp = pNew;
}
- return (pNew ? SQLITE_OK : SQLITE_NOMEM);
+ return (pNew ? SQLITE_OK : SQLITE_NOMEM_BKPT);
}
#ifdef SQLITE_DEBUG
@@ -67984,9 +71162,8 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
if( p->db->flags & SQLITE_VdbeAddopTrace ){
int jj, kk;
Parse *pParse = p->pParse;
- for(jj=kk=0; jj<SQLITE_N_COLCACHE; jj++){
+ for(jj=kk=0; jj<pParse->nColCache; jj++){
struct yColCache *x = pParse->aColCache + jj;
- if( x->iLevel>pParse->iCacheLevel || x->iReg==0 ) continue;
printf(" r[%d]={%d:%d}", x->iReg, x->iTable, x->iColumn);
kk++;
}
@@ -68113,7 +71290,11 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
int p4 /* The P4 operand as an integer */
){
int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
- sqlite3VdbeChangeP4(p, addr, SQLITE_INT_TO_PTR(p4), P4_INT32);
+ if( p->db->mallocFailed==0 ){
+ VdbeOp *pOp = &p->aOp[addr];
+ pOp->p4type = P4_INT32;
+ pOp->p4.i = p4;
+ }
return addr;
}
@@ -68174,7 +71355,6 @@ SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
if( p->aLabel ){
p->aLabel[j] = v->nOp;
}
- p->iFixedOp = v->nOp - 1;
}
/*
@@ -68184,6 +71364,13 @@ SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){
p->runOnlyOnce = 1;
}
+/*
+** Mark the VDBE as one that can only be run multiple times.
+*/
+SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){
+ p->runOnlyOnce = 0;
+}
+
#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
/*
@@ -68330,73 +71517,84 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
** (4) Initialize the p4.xAdvance pointer on opcodes that use it.
**
** (5) Reclaim the memory allocated for storing labels.
+**
+** This routine will only function correctly if the mkopcodeh.tcl generator
+** script numbers the opcodes correctly. Changes to this routine must be
+** coordinated with changes to mkopcodeh.tcl.
*/
static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
- int i;
int nMaxArgs = *pMaxFuncArgs;
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
p->readOnly = 1;
p->bIsReader = 0;
- for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
- u8 opcode = pOp->opcode;
-
- /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
- ** cases from this switch! */
- switch( opcode ){
- case OP_Transaction: {
- if( pOp->p2!=0 ) p->readOnly = 0;
- /* fall thru */
- }
- case OP_AutoCommit:
- case OP_Savepoint: {
- p->bIsReader = 1;
- break;
- }
+ pOp = &p->aOp[p->nOp-1];
+ while(1){
+
+ /* Only JUMP opcodes and the short list of special opcodes in the switch
+ ** below need to be considered. The mkopcodeh.tcl generator script groups
+ ** all these opcodes together near the front of the opcode list. Skip
+ ** any opcode that does not need processing by virtual of the fact that
+ ** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization.
+ */
+ if( pOp->opcode<=SQLITE_MX_JUMP_OPCODE ){
+ /* NOTE: Be sure to update mkopcodeh.tcl when adding or removing
+ ** cases from this switch! */
+ switch( pOp->opcode ){
+ case OP_Transaction: {
+ if( pOp->p2!=0 ) p->readOnly = 0;
+ /* fall thru */
+ }
+ case OP_AutoCommit:
+ case OP_Savepoint: {
+ p->bIsReader = 1;
+ break;
+ }
#ifndef SQLITE_OMIT_WAL
- case OP_Checkpoint:
+ case OP_Checkpoint:
#endif
- case OP_Vacuum:
- case OP_JournalMode: {
- p->readOnly = 0;
- p->bIsReader = 1;
- break;
- }
+ case OP_Vacuum:
+ case OP_JournalMode: {
+ p->readOnly = 0;
+ p->bIsReader = 1;
+ break;
+ }
#ifndef SQLITE_OMIT_VIRTUALTABLE
- case OP_VUpdate: {
- if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
- break;
- }
- case OP_VFilter: {
- int n;
- assert( p->nOp - i >= 3 );
- assert( pOp[-1].opcode==OP_Integer );
- n = pOp[-1].p1;
- if( n>nMaxArgs ) nMaxArgs = n;
- break;
- }
+ case OP_VUpdate: {
+ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
+ break;
+ }
+ case OP_VFilter: {
+ int n;
+ assert( (pOp - p->aOp) >= 3 );
+ assert( pOp[-1].opcode==OP_Integer );
+ n = pOp[-1].p1;
+ if( n>nMaxArgs ) nMaxArgs = n;
+ break;
+ }
#endif
- case OP_Next:
- case OP_NextIfOpen:
- case OP_SorterNext: {
- pOp->p4.xAdvance = sqlite3BtreeNext;
- pOp->p4type = P4_ADVANCE;
- break;
+ case OP_Next:
+ case OP_NextIfOpen:
+ case OP_SorterNext: {
+ pOp->p4.xAdvance = sqlite3BtreeNext;
+ pOp->p4type = P4_ADVANCE;
+ break;
+ }
+ case OP_Prev:
+ case OP_PrevIfOpen: {
+ pOp->p4.xAdvance = sqlite3BtreePrevious;
+ pOp->p4type = P4_ADVANCE;
+ break;
+ }
}
- case OP_Prev:
- case OP_PrevIfOpen: {
- pOp->p4.xAdvance = sqlite3BtreePrevious;
- pOp->p4type = P4_ADVANCE;
- break;
+ if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 && pOp->p2<0 ){
+ assert( ADDR(pOp->p2)<pParse->nLabel );
+ pOp->p2 = aLabel[ADDR(pOp->p2)];
}
}
-
- pOp->opflags = sqlite3OpcodeProperty[opcode];
- if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){
- assert( ADDR(pOp->p2)<pParse->nLabel );
- pOp->p2 = aLabel[ADDR(pOp->p2)];
- }
+ if( pOp==p->aOp ) break;
+ pOp--;
}
sqlite3DbFree(p->db, pParse->aLabel);
pParse->aLabel = 0;
@@ -68547,7 +71745,8 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, u32 addr, int val){
sqlite3VdbeGetOp(p,addr)->p3 = val;
}
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
- if( !p->db->mallocFailed ) p->aOp[p->nOp-1].p5 = p5;
+ assert( p->nOp>0 || p->db->mallocFailed );
+ if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5;
}
/*
@@ -68555,7 +71754,6 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u8 p5){
** the address of the next instruction to be coded.
*/
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
- p->pParse->iFixedOp = p->nOp - 1;
sqlite3VdbeChangeP2(p, addr, p->nOp);
}
@@ -68565,7 +71763,7 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
- if( ALWAYS(pDef) && (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
+ if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
sqlite3DbFree(db, pDef);
}
}
@@ -68575,53 +71773,53 @@ static void vdbeFreeOpArray(sqlite3 *, Op *, int);
/*
** Delete a P4 value if necessary.
*/
+static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
+ if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
+ sqlite3DbFree(db, p);
+}
+static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
+ freeEphemeralFunction(db, p->pFunc);
+ sqlite3DbFree(db, p);
+}
static void freeP4(sqlite3 *db, int p4type, void *p4){
- if( p4 ){
- assert( db );
- switch( p4type ){
- case P4_FUNCCTX: {
- freeEphemeralFunction(db, ((sqlite3_context*)p4)->pFunc);
- /* Fall through into the next case */
- }
- case P4_REAL:
- case P4_INT64:
- case P4_DYNAMIC:
- case P4_INTARRAY: {
- sqlite3DbFree(db, p4);
- break;
- }
- case P4_KEYINFO: {
- if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
- break;
- }
+ assert( db );
+ switch( p4type ){
+ case P4_FUNCCTX: {
+ freeP4FuncCtx(db, (sqlite3_context*)p4);
+ break;
+ }
+ case P4_REAL:
+ case P4_INT64:
+ case P4_DYNAMIC:
+ case P4_INTARRAY: {
+ sqlite3DbFree(db, p4);
+ break;
+ }
+ case P4_KEYINFO: {
+ if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4);
+ break;
+ }
#ifdef SQLITE_ENABLE_CURSOR_HINTS
- case P4_EXPR: {
- sqlite3ExprDelete(db, (Expr*)p4);
- break;
- }
+ case P4_EXPR: {
+ sqlite3ExprDelete(db, (Expr*)p4);
+ break;
+ }
#endif
- case P4_MPRINTF: {
- if( db->pnBytesFreed==0 ) sqlite3_free(p4);
- break;
- }
- case P4_FUNCDEF: {
- freeEphemeralFunction(db, (FuncDef*)p4);
- break;
- }
- case P4_MEM: {
- if( db->pnBytesFreed==0 ){
- sqlite3ValueFree((sqlite3_value*)p4);
- }else{
- Mem *p = (Mem*)p4;
- if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
- sqlite3DbFree(db, p);
- }
- break;
- }
- case P4_VTAB : {
- if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
- break;
+ case P4_FUNCDEF: {
+ freeEphemeralFunction(db, (FuncDef*)p4);
+ break;
+ }
+ case P4_MEM: {
+ if( db->pnBytesFreed==0 ){
+ sqlite3ValueFree((sqlite3_value*)p4);
+ }else{
+ freeP4Mem(db, (Mem*)p4);
}
+ break;
+ }
+ case P4_VTAB : {
+ if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
+ break;
}
}
}
@@ -68674,7 +71872,7 @@ SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe *p, int addr){
** then remove it. Return true if and only if an opcode was removed.
*/
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){
- if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){
+ if( p->nOp>0 && p->aOp[p->nOp-1].opcode==op ){
return sqlite3VdbeChangeToNoop(p, p->nOp-1);
}else{
return 0;
@@ -68752,15 +71950,41 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
}
/*
+** Change the P4 operand of the most recently coded instruction
+** to the value defined by the arguments. This is a high-speed
+** version of sqlite3VdbeChangeP4().
+**
+** The P4 operand must not have been previously defined. And the new
+** P4 must not be P4_INT32. Use sqlite3VdbeChangeP4() in either of
+** those cases.
+*/
+SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){
+ VdbeOp *pOp;
+ assert( n!=P4_INT32 && n!=P4_VTAB );
+ assert( n<=0 );
+ if( p->db->mallocFailed ){
+ freeP4(p->db, n, pP4);
+ }else{
+ assert( pP4!=0 );
+ assert( p->nOp>0 );
+ pOp = &p->aOp[p->nOp-1];
+ assert( pOp->p4type==P4_NOTUSED );
+ pOp->p4type = n;
+ pOp->p4.p = pP4;
+ }
+}
+
+/*
** Set the P4 on the most recently added opcode to the KeyInfo for the
** index given.
*/
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){
Vdbe *v = pParse->pVdbe;
+ KeyInfo *pKeyInfo;
assert( v!=0 );
assert( pIdx!=0 );
- sqlite3VdbeChangeP4(v, -1, (char*)sqlite3KeyInfoOfIndex(pParse, pIdx),
- P4_KEYINFO);
+ pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pIdx);
+ if( pKeyInfo ) sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
}
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
@@ -68872,12 +72096,21 @@ static int displayComment(
const char *zSynopsis;
int nOpName;
int ii, jj;
+ char zAlt[50];
zOpName = sqlite3OpcodeName(pOp->opcode);
nOpName = sqlite3Strlen30(zOpName);
if( zOpName[nOpName+1] ){
int seenCom = 0;
char c;
zSynopsis = zOpName += nOpName + 1;
+ if( strncmp(zSynopsis,"IF ",3)==0 ){
+ if( pOp->p5 & SQLITE_STOREP2 ){
+ sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3);
+ }else{
+ sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3);
+ }
+ zSynopsis = zAlt;
+ }
for(ii=jj=0; jj<nTemp-1 && (c = zSynopsis[ii])!=0; ii++){
if( c=='P' ){
c = zSynopsis[++ii];
@@ -69041,7 +72274,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
break;
}
-#ifdef SQLITE_DEBUG
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
case P4_FUNCCTX: {
FuncDef *pDef = pOp->p4.pCtx->pFunc;
sqlite3XPrintf(&x, "%s(%d)", pDef->zName, pDef->nArg);
@@ -69103,6 +72336,10 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
zTemp[0] = 0;
break;
}
+ case P4_TABLE: {
+ sqlite3XPrintf(&x, "%s", pOp->p4.pTab->zName);
+ break;
+ }
default: {
zP4 = pOp->p4.z;
if( zP4==0 ){
@@ -69225,6 +72462,21 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
#endif
/*
+** Initialize an array of N Mem element.
+*/
+static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
+ while( (N--)>0 ){
+ p->db = db;
+ p->flags = flags;
+ p->szMalloc = 0;
+#ifdef SQLITE_DEBUG
+ p->pScopyFrom = 0;
+#endif
+ p++;
+ }
+}
+
+/*
** Release an array of N Mem elements
*/
static void releaseMemArray(Mem *p, int N){
@@ -69281,6 +72533,7 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
sqlite3VdbeFreeCursor(p->v, apCsr[i]);
}
releaseMemArray(aMem, p->nChildMem);
+ sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0);
sqlite3DbFree(p->v->db, p);
}
@@ -69323,7 +72576,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
releaseMemArray(pMem, 8);
p->pResultSet = 0;
- if( p->rc==SQLITE_NOMEM ){
+ if( p->rc==SQLITE_NOMEM_BKPT ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
sqlite3OomFault(db);
@@ -69434,6 +72687,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
pMem->flags = MEM_Str|MEM_Term;
zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
if( zP4!=pMem->z ){
+ pMem->n = 0;
sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
}else{
assert( pMem->z!=0 );
@@ -69576,7 +72830,7 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
int i;
#endif
assert( p!=0 );
- assert( p->magic==VDBE_MAGIC_INIT );
+ assert( p->magic==VDBE_MAGIC_INIT || p->magic==VDBE_MAGIC_RESET );
/* There should be at least one opcode.
*/
@@ -69586,7 +72840,7 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
p->magic = VDBE_MAGIC_RUN;
#ifdef SQLITE_DEBUG
- for(i=1; i<p->nMem; i++){
+ for(i=0; i<p->nMem; i++){
assert( p->aMem[i].db==p->db );
}
#endif
@@ -69633,7 +72887,6 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
int nMem; /* Number of VM memory registers */
int nCursor; /* Number of cursors required */
int nArg; /* Number of arguments in subprograms */
- int nOnce; /* Number of OP_Once instructions */
int n; /* Loop counter */
struct ReusableSpace x; /* Reusable bulk memory */
@@ -69648,19 +72901,14 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
nMem = pParse->nMem;
nCursor = pParse->nTab;
nArg = pParse->nMaxArg;
- nOnce = pParse->nOnce;
- if( nOnce==0 ) nOnce = 1; /* Ensure at least one byte in p->aOnceFlag[] */
- /* For each cursor required, also allocate a memory cell. Memory
- ** cells (nMem+1-nCursor)..nMem, inclusive, will never be used by
- ** the vdbe program. Instead they are used to allocate memory for
- ** VdbeCursor/BtCursor structures. The blob of memory associated with
- ** cursor 0 is stored in memory cell nMem. Memory cell (nMem-1)
- ** stores the blob of memory associated with cursor 1, etc.
- **
+ /* Each cursor uses a memory cell. The first cursor (cursor 0) can
+ ** use aMem[0] which is not otherwise used by the VDBE program. Allocate
+ ** space at the end of aMem[] for cursors 1 and greater.
** See also: allocateCursor().
*/
nMem += nCursor;
+ if( nCursor==0 && nMem>0 ) nMem++; /* Space for aMem[0] even if not used */
/* Figure out how much reusable memory is available at the end of the
** opcode array. This extra memory will be reallocated for other elements
@@ -69671,10 +72919,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */
assert( x.nFree>=0 );
- if( x.nFree>0 ){
- memset(x.pSpace, 0, x.nFree);
- assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) );
- }
+ assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) );
resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
@@ -69699,37 +72944,32 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
- p->aOnceFlag = allocSpace(&x, p->aOnceFlag, nOnce);
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
#endif
if( x.nNeeded==0 ) break;
- x.pSpace = p->pFree = sqlite3DbMallocZero(db, x.nNeeded);
+ x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded);
x.nFree = x.nNeeded;
}while( !db->mallocFailed );
- p->nCursor = nCursor;
- p->nOnceFlag = nOnce;
- if( p->aVar ){
+ p->pVList = pParse->pVList;
+ pParse->pVList = 0;
+ p->explain = pParse->explain;
+ if( db->mallocFailed ){
+ p->nVar = 0;
+ p->nCursor = 0;
+ p->nMem = 0;
+ }else{
+ p->nCursor = nCursor;
p->nVar = (ynVar)nVar;
- for(n=0; n<nVar; n++){
- p->aVar[n].flags = MEM_Null;
- p->aVar[n].db = db;
- }
- }
- p->nzVar = pParse->nzVar;
- p->azVar = pParse->azVar;
- pParse->nzVar = 0;
- pParse->azVar = 0;
- if( p->aMem ){
- p->aMem--; /* aMem[] goes from 1..nMem */
- p->nMem = nMem; /* not from 0..nMem-1 */
- for(n=1; n<=nMem; n++){
- p->aMem[n].flags = MEM_Undefined;
- p->aMem[n].db = db;
- }
+ initMemArray(p->aVar, nVar, db, MEM_Null);
+ p->nMem = nMem;
+ initMemArray(p->aMem, nMem, db, MEM_Undefined);
+ memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*));
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ memset(p->anExec, 0, p->nOp*sizeof(i64));
+#endif
}
- p->explain = pParse->explain;
sqlite3VdbeRewind(p);
}
@@ -69741,15 +72981,15 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx==0 ){
return;
}
- assert( pCx->pBt==0 || pCx->eCurType==CURTYPE_BTREE );
+ assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE );
switch( pCx->eCurType ){
case CURTYPE_SORTER: {
sqlite3VdbeSorterClose(p->db, pCx);
break;
}
case CURTYPE_BTREE: {
- if( pCx->pBt ){
- sqlite3BtreeClose(pCx->pBt);
+ if( pCx->pBtx ){
+ sqlite3BtreeClose(pCx->pBtx);
/* The pCx->pCursor will be close automatically, if it exists, by
** the call above. */
}else{
@@ -69798,8 +73038,6 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
v->anExec = pFrame->anExec;
#endif
- v->aOnceFlag = pFrame->aOnceFlag;
- v->nOnceFlag = pFrame->nOnceFlag;
v->aOp = pFrame->aOp;
v->nOp = pFrame->nOp;
v->aMem = pFrame->aMem;
@@ -69809,6 +73047,9 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
v->db->lastRowid = pFrame->lastRowid;
v->nChange = pFrame->nChange;
v->db->nChange = pFrame->nDbChange;
+ sqlite3VdbeDeleteAuxData(v->db, &v->pAuxData, -1, 0);
+ v->pAuxData = pFrame->pAuxData;
+ pFrame->pAuxData = 0;
return pFrame->pc;
}
@@ -69831,7 +73072,7 @@ static void closeAllCursors(Vdbe *p){
assert( p->nFrame==0 );
closeCursorsInFrame(p);
if( p->aMem ){
- releaseMemArray(&p->aMem[1], p->nMem);
+ releaseMemArray(p->aMem, p->nMem);
}
while( p->pDelFrame ){
VdbeFrame *pDel = p->pDelFrame;
@@ -69840,7 +73081,7 @@ static void closeAllCursors(Vdbe *p){
}
/* Delete any auxdata allocations made by the VM */
- if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p, -1, 0);
+ if( p->pAuxData ) sqlite3VdbeDeleteAuxData(p->db, &p->pAuxData, -1, 0);
assert( p->pAuxData==0 );
}
@@ -69856,7 +73097,7 @@ static void Cleanup(Vdbe *p){
int i;
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
if( p->aMem ){
- for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
+ for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
}
#endif
@@ -69880,13 +73121,9 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
sqlite3DbFree(db, p->aColName);
n = nResColumn*COLNAME_N;
p->nResColumn = (u16)nResColumn;
- p->aColName = pColName = (Mem*)sqlite3DbMallocZero(db, sizeof(Mem)*n );
+ p->aColName = pColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
- while( n-- > 0 ){
- pColName->flags = MEM_Null;
- pColName->db = p->db;
- pColName++;
- }
+ initMemArray(p->aColName, n, p->db, MEM_Null);
}
/*
@@ -69912,7 +73149,7 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
assert( var<COLNAME_N );
if( p->db->mallocFailed ){
assert( !zName || xDel!=SQLITE_DYNAMIC );
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
assert( p->aColName!=0 );
pColName = &(p->aColName[idx+var*p->nResColumn]);
@@ -69929,7 +73166,9 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
*/
static int vdbeCommit(sqlite3 *db, Vdbe *p){
int i;
- int nTrans = 0; /* Number of databases with an active write-transaction */
+ int nTrans = 0; /* Number of databases with an active write-transaction
+ ** that are candidates for a two-phase commit using a
+ ** master-journal */
int rc = SQLITE_OK;
int needXcommit = 0;
@@ -69957,10 +73196,28 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( sqlite3BtreeIsInTrans(pBt) ){
+ /* Whether or not a database might need a master journal depends upon
+ ** its journal mode (among other things). This matrix determines which
+ ** journal modes use a master journal and which do not */
+ static const u8 aMJNeeded[] = {
+ /* DELETE */ 1,
+ /* PERSIST */ 1,
+ /* OFF */ 0,
+ /* TRUNCATE */ 1,
+ /* MEMORY */ 0,
+ /* WAL */ 0
+ };
+ Pager *pPager; /* Pager associated with pBt */
needXcommit = 1;
- if( i!=1 ) nTrans++;
sqlite3BtreeEnter(pBt);
- rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
+ pPager = sqlite3BtreePager(pBt);
+ if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF
+ && aMJNeeded[sqlite3PagerGetJournalMode(pPager)]
+ ){
+ assert( i!=1 );
+ nTrans++;
+ }
+ rc = sqlite3PagerExclusiveLock(pPager);
sqlite3BtreeLeave(pBt);
}
}
@@ -70018,7 +73275,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
#ifndef SQLITE_OMIT_DISKIO
else{
sqlite3_vfs *pVfs = db->pVfs;
- int needSync = 0;
char *zMaster = 0; /* File-name for the master journal */
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
sqlite3_file *pMaster = 0;
@@ -70030,7 +73286,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* Select a master journal file name */
nMainFile = sqlite3Strlen30(zMainFile);
zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile);
- if( zMaster==0 ) return SQLITE_NOMEM;
+ if( zMaster==0 ) return SQLITE_NOMEM_BKPT;
do {
u32 iRandom;
if( retryCount ){
@@ -70078,9 +73334,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
continue; /* Ignore TEMP and :memory: databases */
}
assert( zFile[0]!=0 );
- if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){
- needSync = 1;
- }
rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset);
offset += sqlite3Strlen30(zFile)+1;
if( rc!=SQLITE_OK ){
@@ -70095,8 +73348,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
/* Sync the master journal file. If the IOCAP_SEQUENTIAL device
** flag is set this is not required.
*/
- if( needSync
- && 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
+ if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
&& SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))
){
sqlite3OsCloseFree(pMaster);
@@ -70132,7 +73384,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
** doing this the directory is synced again before any individual
** transaction files are deleted.
*/
- rc = sqlite3OsDelete(pVfs, zMaster, needSync);
+ rc = sqlite3OsDelete(pVfs, zMaster, 1);
sqlite3DbFree(db, zMaster);
zMaster = 0;
if( rc ){
@@ -70320,9 +73572,8 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
*/
if( db->mallocFailed ){
- p->rc = SQLITE_NOMEM;
+ p->rc = SQLITE_NOMEM_BKPT;
}
- if( p->aOnceFlag ) memset(p->aOnceFlag, 0, p->nOnceFlag);
closeAllCursors(p);
if( p->magic!=VDBE_MAGIC_RUN ){
return SQLITE_OK;
@@ -70481,7 +73732,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
p->magic = VDBE_MAGIC_HALT;
checkActiveVdbeCnt(db);
if( db->mallocFailed ){
- p->rc = SQLITE_NOMEM;
+ p->rc = SQLITE_NOMEM_BKPT;
}
/* If the auto-commit flag is set to true, then any locks that were held
@@ -70634,7 +73885,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
}
#endif
p->iCurrentTime = 0;
- p->magic = VDBE_MAGIC_INIT;
+ p->magic = VDBE_MAGIC_RESET;
return p->rc & db->errMask;
}
@@ -70668,8 +73919,7 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){
** * the corresponding bit in argument mask is clear (where the first
** function parameter corresponds to bit 0 etc.).
*/
-SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
- AuxData **pp = &pVdbe->pAuxData;
+SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp, int mask){
while( *pp ){
AuxData *pAux = *pp;
if( (iOp<0)
@@ -70680,7 +73930,7 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
pAux->xDelete(pAux->pAux);
}
*pp = pAux->pNext;
- sqlite3DbFree(pVdbe->db, pAux);
+ sqlite3DbFree(db, pAux);
}else{
pp= &pAux->pNext;
}
@@ -70697,26 +73947,29 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
*/
SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
SubProgram *pSub, *pNext;
- int i;
assert( p->db==0 || p->db==db );
- releaseMemArray(p->aVar, p->nVar);
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
for(pSub=p->pProgram; pSub; pSub=pNext){
pNext = pSub->pNext;
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
sqlite3DbFree(db, pSub);
}
- for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]);
- sqlite3DbFree(db, p->azVar);
+ if( p->magic!=VDBE_MAGIC_INIT ){
+ releaseMemArray(p->aVar, p->nVar);
+ sqlite3DbFree(db, p->pVList);
+ sqlite3DbFree(db, p->pFree);
+ }
vdbeFreeOpArray(db, p->aOp, p->nOp);
sqlite3DbFree(db, p->aColName);
sqlite3DbFree(db, p->zSql);
- sqlite3DbFree(db, p->pFree);
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
- for(i=0; i<p->nScan; i++){
- sqlite3DbFree(db, p->aScan[i].zName);
+ {
+ int i;
+ for(i=0; i<p->nScan; i++){
+ sqlite3DbFree(db, p->aScan[i].zName);
+ }
+ sqlite3DbFree(db, p->aScan);
}
- sqlite3DbFree(db, p->aScan);
#endif
}
@@ -71217,30 +74470,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
** If an OOM error occurs, NULL is returned.
*/
SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
- KeyInfo *pKeyInfo, /* Description of the record */
- char *pSpace, /* Unaligned space available */
- int szSpace, /* Size of pSpace[] in bytes */
- char **ppFree /* OUT: Caller should free this pointer */
+ KeyInfo *pKeyInfo /* Description of the record */
){
UnpackedRecord *p; /* Unpacked record to return */
- int nOff; /* Increment pSpace by nOff to align it */
int nByte; /* Number of bytes required for *p */
-
- /* We want to shift the pointer pSpace up such that it is 8-byte aligned.
- ** Thus, we need to calculate a value, nOff, between 0 and 7, to shift
- ** it by. If pSpace is already 8-byte aligned, nOff should be zero.
- */
- nOff = (8 - (SQLITE_PTR_TO_INT(pSpace) & 7)) & 7;
nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nField+1);
- if( nByte>szSpace+nOff ){
- p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
- *ppFree = (char *)p;
- if( !p ) return 0;
- }else{
- p = (UnpackedRecord*)&pSpace[nOff];
- *ppFree = 0;
- }
-
+ p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
+ if( !p ) return 0;
p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
assert( pKeyInfo->aSortOrder!=0 );
p->pKeyInfo = pKeyInfo;
@@ -71279,6 +74515,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
pMem->db = pKeyInfo->db;
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
pMem->szMalloc = 0;
+ pMem->z = 0;
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
pMem++;
if( (++u)>=p->nField ) break;
@@ -71459,7 +74696,7 @@ static int vdbeCompareMemString(
v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc);
n2 = v2==0 ? 0 : c2.n;
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
- if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
+ if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM_BKPT;
sqlite3VdbeMemRelease(&c1);
sqlite3VdbeMemRelease(&c2);
return rc;
@@ -71467,14 +74704,48 @@ static int vdbeCompareMemString(
}
/*
+** The input pBlob is guaranteed to be a Blob that is not marked
+** with MEM_Zero. Return true if it could be a zero-blob.
+*/
+static int isAllZero(const char *z, int n){
+ int i;
+ for(i=0; i<n; i++){
+ if( z[i] ) return 0;
+ }
+ return 1;
+}
+
+/*
** Compare two blobs. Return negative, zero, or positive if the first
** is less than, equal to, or greater than the second, respectively.
** If one blob is a prefix of the other, then the shorter is the lessor.
*/
static SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem *pB2){
- int c = memcmp(pB1->z, pB2->z, pB1->n>pB2->n ? pB2->n : pB1->n);
+ int c;
+ int n1 = pB1->n;
+ int n2 = pB2->n;
+
+ /* It is possible to have a Blob value that has some non-zero content
+ ** followed by zero content. But that only comes up for Blobs formed
+ ** by the OP_MakeRecord opcode, and such Blobs never get passed into
+ ** sqlite3MemCompare(). */
+ assert( (pB1->flags & MEM_Zero)==0 || n1==0 );
+ assert( (pB2->flags & MEM_Zero)==0 || n2==0 );
+
+ if( (pB1->flags|pB2->flags) & MEM_Zero ){
+ if( pB1->flags & pB2->flags & MEM_Zero ){
+ return pB1->u.nZero - pB2->u.nZero;
+ }else if( pB1->flags & MEM_Zero ){
+ if( !isAllZero(pB2->z, pB2->n) ) return -1;
+ return pB1->u.nZero - n2;
+ }else{
+ if( !isAllZero(pB1->z, pB1->n) ) return +1;
+ return n1 - pB2->u.nZero;
+ }
+ }
+ c = memcmp(pB1->z, pB2->z, n1>n2 ? n2 : n1);
if( c ) return c;
- return pB1->n - pB2->n;
+ return n1 - n2;
}
/*
@@ -71780,6 +75051,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* RHS is a blob */
else if( pRhs->flags & MEM_Blob ){
+ assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 );
getVarint32(&aKey1[idx1], serial_type);
testcase( serial_type==12 );
if( serial_type<12 || (serial_type & 0x01) ){
@@ -71791,6 +75063,12 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
if( (d1+nStr) > (unsigned)nKey1 ){
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
+ }else if( pRhs->flags & MEM_Zero ){
+ if( !isAllZero((const char*)&aKey1[d1],nStr) ){
+ rc = 1;
+ }else{
+ rc = nStr - pRhs->u.nZero;
+ }
}else{
int nCmp = MIN(nStr, pRhs->n);
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
@@ -71861,7 +75139,7 @@ static int vdbeRecordCompareInt(
int res;
u32 y;
u64 x;
- i64 v = pPKey2->aMem[0].u.i;
+ i64 v;
i64 lhs;
vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
@@ -71920,6 +75198,7 @@ static int vdbeRecordCompareInt(
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
}
+ v = pPKey2->aMem[0].u.i;
if( v>lhs ){
res = pPKey2->r1;
}else if( v<lhs ){
@@ -72066,13 +75345,12 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
** this code can safely assume that nCellKey is 32-bits
*/
assert( sqlite3BtreeCursorIsValid(pCur) );
- VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
- assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
+ nCellKey = sqlite3BtreePayloadSize(pCur);
assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey );
/* Read in the complete content of the index entry */
sqlite3VdbeMemInit(&m, db, 0);
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
+ rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
if( rc ){
return rc;
}
@@ -72144,8 +75422,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
assert( pC->eCurType==CURTYPE_BTREE );
pCur = pC->uc.pCursor;
assert( sqlite3BtreeCursorIsValid(pCur) );
- VVA_ONLY(rc =) sqlite3BtreeKeySize(pCur, &nCellKey);
- assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */
+ nCellKey = sqlite3BtreePayloadSize(pCur);
/* nCellKey will always be between 0 and 0xffffffff because of the way
** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
if( nCellKey<=0 || nCellKey>0x7fffffff ){
@@ -72153,7 +75430,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
return SQLITE_CORRUPT_BKPT;
}
sqlite3VdbeMemInit(&m, db, 0);
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
+ rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
if( rc ){
return rc;
}
@@ -72259,6 +75536,90 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+
+/*
+** If the second argument is not NULL, release any allocations associated
+** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord
+** structure itself, using sqlite3DbFree().
+**
+** This function is used to free UnpackedRecord structures allocated by
+** the vdbeUnpackRecord() function found in vdbeapi.c.
+*/
+static void vdbeFreeUnpacked(sqlite3 *db, UnpackedRecord *p){
+ if( p ){
+ int i;
+ for(i=0; i<p->nField; i++){
+ Mem *pMem = &p->aMem[i];
+ if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
+ }
+ sqlite3DbFree(db, p);
+ }
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call,
+** then cursor passed as the second argument should point to the row about
+** to be update or deleted. If the application calls sqlite3_preupdate_old(),
+** the required value will be read from the row the cursor points to.
+*/
+SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
+ Vdbe *v, /* Vdbe pre-update hook is invoked by */
+ VdbeCursor *pCsr, /* Cursor to grab old.* values from */
+ int op, /* SQLITE_INSERT, UPDATE or DELETE */
+ const char *zDb, /* Database name */
+ Table *pTab, /* Modified table */
+ i64 iKey1, /* Initial key value */
+ int iReg /* Register for new.* record */
+){
+ sqlite3 *db = v->db;
+ i64 iKey2;
+ PreUpdate preupdate;
+ const char *zTbl = pTab->zName;
+ static const u8 fakeSortOrder = 0;
+
+ assert( db->pPreUpdate==0 );
+ memset(&preupdate, 0, sizeof(PreUpdate));
+ if( op==SQLITE_UPDATE ){
+ iKey2 = v->aMem[iReg].u.i;
+ }else{
+ iKey2 = iKey1;
+ }
+
+ assert( pCsr->nField==pTab->nCol
+ || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
+ );
+
+ preupdate.v = v;
+ preupdate.pCsr = pCsr;
+ preupdate.op = op;
+ preupdate.iNewReg = iReg;
+ preupdate.keyinfo.db = db;
+ preupdate.keyinfo.enc = ENC(db);
+ preupdate.keyinfo.nField = pTab->nCol;
+ preupdate.keyinfo.aSortOrder = (u8*)&fakeSortOrder;
+ preupdate.iKey1 = iKey1;
+ preupdate.iKey2 = iKey2;
+ preupdate.pTab = pTab;
+
+ db->pPreUpdate = &preupdate;
+ db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
+ db->pPreUpdate = 0;
+ sqlite3DbFree(db, preupdate.aRecord);
+ vdbeFreeUnpacked(db, preupdate.pUnpacked);
+ vdbeFreeUnpacked(db, preupdate.pNewUnpacked);
+ if( preupdate.aNew ){
+ int i;
+ for(i=0; i<pCsr->nField; i++){
+ sqlite3VdbeMemRelease(&preupdate.aNew[i]);
+ }
+ sqlite3DbFree(db, preupdate.aNew);
+ }
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
/************** End of vdbeaux.c *********************************************/
/************** Begin file vdbeapi.c *****************************************/
/*
@@ -72288,7 +75649,7 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
** collating sequences are registered or if an authorizer function is
** added or changed.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
return p==0 || p->expired;
}
@@ -72323,12 +75684,19 @@ static int vdbeSafetyNotNull(Vdbe *p){
*/
static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
sqlite3_int64 iNow;
+ sqlite3_int64 iElapse;
assert( p->startTime>0 );
- assert( db->xProfile!=0 );
+ assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 );
assert( db->init.busy==0 );
assert( p->zSql!=0 );
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
- db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
+ iElapse = (iNow - p->startTime)*1000000;
+ if( db->xProfile ){
+ db->xProfile(db->pProfileArg, p->zSql, iElapse);
+ }
+ if( db->mTrace & SQLITE_TRACE_PROFILE ){
+ db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
+ }
p->startTime = 0;
}
/*
@@ -72350,7 +75718,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
** This routine sets the error code and string returned by
** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
int rc;
if( pStmt==0 ){
/* IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL
@@ -72377,7 +75745,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt){
** This routine sets the error code and string returned by
** sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16().
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt){
int rc;
if( pStmt==0 ){
rc = SQLITE_OK;
@@ -72398,7 +75766,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt){
/*
** Set all the parameters in the compiled SQL statement to NULL.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
int i;
int rc = SQLITE_OK;
Vdbe *p = (Vdbe*)pStmt;
@@ -72422,10 +75790,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt *pStmt){
** The following routines extract information from a Mem or sqlite3_value
** structure.
*/
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){
+SQLITE_API const void *sqlite3_value_blob(sqlite3_value *pVal){
Mem *p = (Mem*)pVal;
if( p->flags & (MEM_Blob|MEM_Str) ){
- if( sqlite3VdbeMemExpandBlob(p)!=SQLITE_OK ){
+ if( ExpandBlob(p)!=SQLITE_OK ){
assert( p->flags==MEM_Null && p->z==0 );
return 0;
}
@@ -72435,36 +75803,36 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value *pVal){
return sqlite3_value_text(pVal);
}
}
-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value *pVal){
+SQLITE_API int sqlite3_value_bytes(sqlite3_value *pVal){
return sqlite3ValueBytes(pVal, SQLITE_UTF8);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value *pVal){
+SQLITE_API int sqlite3_value_bytes16(sqlite3_value *pVal){
return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE);
}
-SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value *pVal){
+SQLITE_API double sqlite3_value_double(sqlite3_value *pVal){
return sqlite3VdbeRealValue((Mem*)pVal);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value *pVal){
+SQLITE_API int sqlite3_value_int(sqlite3_value *pVal){
return (int)sqlite3VdbeIntValue((Mem*)pVal);
}
-SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value *pVal){
+SQLITE_API sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){
return sqlite3VdbeIntValue((Mem*)pVal);
}
-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value *pVal){
+SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value *pVal){
Mem *pMem = (Mem*)pVal;
return ((pMem->flags & MEM_Subtype) ? pMem->eSubtype : 0);
}
-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value *pVal){
+SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value *pVal){
return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value* pVal){
+SQLITE_API const void *sqlite3_value_text16(sqlite3_value* pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
}
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value *pVal){
+SQLITE_API const void *sqlite3_value_text16be(sqlite3_value *pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16BE);
}
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal){
+SQLITE_API const void *sqlite3_value_text16le(sqlite3_value *pVal){
return sqlite3ValueText(pVal, SQLITE_UTF16LE);
}
#endif /* SQLITE_OMIT_UTF16 */
@@ -72472,7 +75840,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value *pVal
** fundamental datatypes: 64-bit signed integer 64-bit IEEE floating
** point number string BLOB NULL
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){
+SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
static const u8 aType[] = {
SQLITE_BLOB, /* 0x00 */
SQLITE_NULL, /* 0x01 */
@@ -72512,7 +75880,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value* pVal){
/* Make a copy of an sqlite3_value object
*/
-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value *pOrig){
+SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
sqlite3_value *pNew;
if( pOrig==0 ) return 0;
pNew = sqlite3_malloc( sizeof(*pNew) );
@@ -72535,7 +75903,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value *
/* Destroy an sqlite3_value object previously obtained from
** sqlite3_value_dup().
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value *pOld){
+SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){
sqlite3ValueFree(pOld);
}
@@ -72578,7 +75946,7 @@ static int invokeValueDestructor(
if( pCtx ) sqlite3_result_error_toobig(pCtx);
return SQLITE_TOOBIG;
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(
+SQLITE_API void sqlite3_result_blob(
sqlite3_context *pCtx,
const void *z,
int n,
@@ -72588,7 +75956,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, 0, xDel);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(
+SQLITE_API void sqlite3_result_blob64(
sqlite3_context *pCtx,
const void *z,
sqlite3_uint64 n,
@@ -72602,43 +75970,43 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(
setResultStrOrError(pCtx, z, (int)n, 0, xDel);
}
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context *pCtx, double rVal){
+SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
+SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
+SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
-SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context *pCtx, int iVal){
+SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
+SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context *pCtx){
+SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
+SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
Mem *pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
pOut->eSubtype = eSubtype & 0xff;
pOut->flags |= MEM_Subtype;
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
+SQLITE_API void sqlite3_result_text(
sqlite3_context *pCtx,
const char *z,
int n,
@@ -72647,7 +76015,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(
+SQLITE_API void sqlite3_result_text64(
sqlite3_context *pCtx,
const char *z,
sqlite3_uint64 n,
@@ -72664,7 +76032,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(
}
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(
+SQLITE_API void sqlite3_result_text16(
sqlite3_context *pCtx,
const void *z,
int n,
@@ -72673,7 +76041,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(
+SQLITE_API void sqlite3_result_text16be(
sqlite3_context *pCtx,
const void *z,
int n,
@@ -72682,7 +76050,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(
+SQLITE_API void sqlite3_result_text16le(
sqlite3_context *pCtx,
const void *z,
int n,
@@ -72692,15 +76060,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(
setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
+SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemCopy(pCtx->pOut, pValue);
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
+SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
+SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
Mem *pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
@@ -72709,7 +76077,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context *pCtx, u
sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n);
return SQLITE_OK;
}
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
+SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
pCtx->isError = errCode;
pCtx->fErrorOrAux = 1;
#ifdef SQLITE_DEBUG
@@ -72722,7 +76090,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context *pCtx,
}
/* Force an SQLITE_TOOBIG error. */
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx){
+SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
pCtx->fErrorOrAux = 1;
@@ -72731,10 +76099,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context *pCtx
}
/* An SQLITE_NOMEM error. */
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context *pCtx){
+SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
- pCtx->isError = SQLITE_NOMEM;
+ pCtx->isError = SQLITE_NOMEM_BKPT;
pCtx->fErrorOrAux = 1;
sqlite3OomFault(pCtx->pOut->db);
}
@@ -72755,7 +76123,7 @@ static int doWalCallbacks(sqlite3 *db){
nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
sqlite3BtreeLeave(pBt);
if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
- rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
+ rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zDbSName, nEntry);
}
}
}
@@ -72810,7 +76178,7 @@ static int sqlite3Step(Vdbe *p){
db = p->db;
if( db->mallocFailed ){
p->rc = SQLITE_NOMEM;
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
if( p->pc<=0 && p->expired ){
@@ -72832,7 +76200,8 @@ static int sqlite3Step(Vdbe *p){
);
#ifndef SQLITE_OMIT_TRACE
- if( db->xProfile && !db->init.busy && p->zSql ){
+ if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0)
+ && !db->init.busy && p->zSql ){
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}else{
assert( p->startTime==0 );
@@ -72873,7 +76242,7 @@ static int sqlite3Step(Vdbe *p){
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
- p->rc = SQLITE_NOMEM;
+ p->rc = SQLITE_NOMEM_BKPT;
}
end_of_step:
/* At this point local variable rc holds the value that should be
@@ -72902,7 +76271,7 @@ end_of_step:
** sqlite3Step() to do most of the work. If a schema error occurs,
** call sqlite3Reprepare() and try again.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
int rc = SQLITE_OK; /* Result from sqlite3Step() */
int rc2 = SQLITE_OK; /* Result from sqlite3Reprepare() */
Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */
@@ -72940,7 +76309,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
v->rc = rc2;
} else {
v->zErrMsg = 0;
- v->rc = rc = SQLITE_NOMEM;
+ v->rc = rc = SQLITE_NOMEM_BKPT;
}
}
rc = sqlite3ApiExit(db, rc);
@@ -72953,7 +76322,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt *pStmt){
** Extract the user data from a sqlite3_context structure and return a
** pointer to it.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
+SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
assert( p && p->pFunc );
return p->pFunc->pUserData;
}
@@ -72968,7 +76337,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context *p){
** sqlite3_create_function16() routines that originally registered the
** application defined function.
*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context *p){
+SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
assert( p && p->pOut );
return p->pOut->db;
}
@@ -73044,7 +76413,7 @@ static SQLITE_NOINLINE void *createAggContext(sqlite3_context *p, int nByte){
** context is allocated on the first call. Subsequent calls return the
** same context that was returned on prior calls.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, int nByte){
+SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
assert( p && p->pFunc && p->pFunc->xFinalize );
assert( sqlite3_mutex_held(p->pOut->db->mutex) );
testcase( nByte<0 );
@@ -73059,7 +76428,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context *p, in
** Return the auxiliary data pointer, if any, for the iArg'th argument to
** the user-function defined by pCtx.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
+SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
AuxData *pAuxData;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
@@ -73080,7 +76449,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context *pCtx, int i
** argument to the user-function defined by pCtx. Any previous value is
** deleted by calling the delete function specified when it was set.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(
+SQLITE_API void sqlite3_set_auxdata(
sqlite3_context *pCtx,
int iArg,
void *pAux,
@@ -73135,7 +76504,7 @@ failed:
** implementations should keep their own counts within their aggregate
** context.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
+SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){
assert( p && p->pMem && p->pFunc && p->pFunc->xFinalize );
return p->pMem->n;
}
@@ -73144,7 +76513,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context *p){
/*
** Return the number of columns in the result set for the statement pStmt.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
return pVm ? pVm->nResColumn : 0;
}
@@ -73153,7 +76522,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt){
** Return the number of values available from the current row of the
** currently executing statement pStmt.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
if( pVm==0 || pVm->pResultSet==0 ) return 0;
return pVm->nResColumn;
@@ -73207,14 +76576,13 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
Mem *pOut;
pVm = (Vdbe *)pStmt;
- if( pVm && pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
- sqlite3_mutex_enter(pVm->db->mutex);
+ if( pVm==0 ) return (Mem*)columnNullValue();
+ assert( pVm->db );
+ sqlite3_mutex_enter(pVm->db->mutex);
+ if( pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
pOut = &pVm->pResultSet[i];
}else{
- if( pVm && ALWAYS(pVm->db) ){
- sqlite3_mutex_enter(pVm->db->mutex);
- sqlite3Error(pVm->db, SQLITE_RANGE);
- }
+ sqlite3Error(pVm->db, SQLITE_RANGE);
pOut = (Mem*)columnNullValue();
}
return pOut;
@@ -73247,6 +76615,8 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
*/
Vdbe *p = (Vdbe *)pStmt;
if( p ){
+ assert( p->db!=0 );
+ assert( sqlite3_mutex_held(p->db->mutex) );
p->rc = sqlite3ApiExit(p->db, p->rc);
sqlite3_mutex_leave(p->db->mutex);
}
@@ -73256,7 +76626,7 @@ static void columnMallocFailure(sqlite3_stmt *pStmt)
** The following routines are used to access elements of the current row
** in the result set.
*/
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
+SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
const void *val;
val = sqlite3_value_blob( columnMem(pStmt,i) );
/* Even though there is no encoding conversion, value_blob() might
@@ -73266,37 +76636,37 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt *pStmt, i
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
+SQLITE_API int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
int val = sqlite3_value_bytes( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
+SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
int val = sqlite3_value_bytes16( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt *pStmt, int i){
+SQLITE_API double sqlite3_column_double(sqlite3_stmt *pStmt, int i){
double val = sqlite3_value_double( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt *pStmt, int i){
+SQLITE_API int sqlite3_column_int(sqlite3_stmt *pStmt, int i){
int val = sqlite3_value_int( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
+SQLITE_API sqlite_int64 sqlite3_column_int64(sqlite3_stmt *pStmt, int i){
sqlite_int64 val = sqlite3_value_int64( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt *pStmt, int i){
+SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){
const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStmt, int i){
+SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){
Mem *pOut = columnMem(pStmt, i);
if( pOut->flags&MEM_Static ){
pOut->flags &= ~MEM_Static;
@@ -73306,13 +76676,13 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt *pStm
return (sqlite3_value *)pOut;
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
+SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt *pStmt, int i){
const void *val = sqlite3_value_text16( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return val;
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt *pStmt, int i){
+SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
int iType = sqlite3_value_type( columnMem(pStmt,i) );
columnMallocFailure(pStmt);
return iType;
@@ -73376,12 +76746,12 @@ static const void *columnName(
** Return the name of the Nth column of the result set returned by SQL
** statement pStmt.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *sqlite3_column_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_NAME);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_NAME);
}
@@ -73401,12 +76771,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt *pStmt,
** Return the column declaration type (if applicable) of the 'i'th column
** of the result set of SQL statement pStmt.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DECLTYPE);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DECLTYPE);
}
@@ -73419,12 +76789,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt *pS
** NULL is returned if the result column is an expression or constant or
** anything else which is not an unambiguous reference to a database column.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_DATABASE);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_DATABASE);
}
@@ -73435,12 +76805,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stm
** NULL is returned if the result column is an expression or constant or
** anything else which is not an unambiguous reference to a database column.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_TABLE);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_TABLE);
}
@@ -73451,12 +76821,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt *
** NULL is returned if the result column is an expression or constant or
** anything else which is not an unambiguous reference to a database column.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
+SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text, COLNAME_COLUMN);
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
+SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
return columnName(
pStmt, N, (const void*(*)(Mem*))sqlite3_value_text16, COLNAME_COLUMN);
}
@@ -73557,16 +76927,19 @@ static int bindText(
/*
** Bind a blob value to an SQL statement variable.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(
+SQLITE_API int sqlite3_bind_blob(
sqlite3_stmt *pStmt,
int i,
const void *zData,
int nData,
void (*xDel)(void*)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( nData<0 ) return SQLITE_MISUSE_BKPT;
+#endif
return bindText(pStmt, i, zData, nData, xDel, 0);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(
+SQLITE_API int sqlite3_bind_blob64(
sqlite3_stmt *pStmt,
int i,
const void *zData,
@@ -73580,7 +76953,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(
return bindText(pStmt, i, zData, (int)nData, xDel, 0);
}
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
+SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
@@ -73590,10 +76963,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt *pStmt, int i, do
}
return rc;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
+SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
return sqlite3_bind_int64(p, i, (i64)iValue);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
+SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
@@ -73603,7 +76976,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sql
}
return rc;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
+SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
int rc;
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, i);
@@ -73612,7 +76985,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
}
return rc;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(
+SQLITE_API int sqlite3_bind_text(
sqlite3_stmt *pStmt,
int i,
const char *zData,
@@ -73621,7 +76994,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(
){
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(
+SQLITE_API int sqlite3_bind_text64(
sqlite3_stmt *pStmt,
int i,
const char *zData,
@@ -73638,7 +77011,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(
}
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(
+SQLITE_API int sqlite3_bind_text16(
sqlite3_stmt *pStmt,
int i,
const void *zData,
@@ -73648,7 +77021,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
}
#endif /* SQLITE_OMIT_UTF16 */
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
+SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
int rc;
switch( sqlite3_value_type((sqlite3_value*)pValue) ){
case SQLITE_INTEGER: {
@@ -73679,7 +77052,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt *pStmt, int i, con
}
return rc;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
+SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
rc = vdbeUnbind(p, i);
@@ -73689,7 +77062,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i,
}
return rc;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){
+SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
sqlite3_mutex_enter(p->db->mutex);
@@ -73708,7 +77081,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i
** Return the number of wildcards that can be potentially bound to.
** This routine is added to support DBD::SQLite.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
return p ? p->nVar : 0;
}
@@ -73719,12 +77092,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
**
** The result is always UTF-8.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
+SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt *pStmt, int i){
Vdbe *p = (Vdbe*)pStmt;
- if( p==0 || i<1 || i>p->nzVar ){
- return 0;
- }
- return p->azVar[i-1];
+ if( p==0 ) return 0;
+ return sqlite3VListNumToName(p->pVList, i);
}
/*
@@ -73733,21 +77104,10 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt *
** return 0.
*/
SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){
- int i;
- if( p==0 ){
- return 0;
- }
- if( zName ){
- for(i=0; i<p->nzVar; i++){
- const char *z = p->azVar[i];
- if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){
- return i+1;
- }
- }
- }
- return 0;
+ if( p==0 || zName==0 ) return 0;
+ return sqlite3VListNameToNum(p->pVList, zName, nName);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
+SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){
return sqlite3VdbeParameterIndex((Vdbe*)pStmt, zName, sqlite3Strlen30(zName));
}
@@ -73781,7 +77141,7 @@ SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *pFromStmt, sqlite3_stmt
** an SQLITE_ERROR is returned. Nothing else can go wrong, so otherwise
** SQLITE_OK is returned.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
+SQLITE_API int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
Vdbe *pFrom = (Vdbe*)pFromStmt;
Vdbe *pTo = (Vdbe*)pToStmt;
if( pFrom->nVar!=pTo->nVar ){
@@ -73803,7 +77163,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt,
** the first argument to the sqlite3_prepare() that was used to create
** the statement in the first place.
*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){
+SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt *pStmt){
return pStmt ? ((Vdbe*)pStmt)->db : 0;
}
@@ -73811,16 +77171,16 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt *pStmt){
** Return true if the prepared statement is guaranteed to not modify the
** database.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt){
return pStmt ? ((Vdbe*)pStmt)->readOnly : 1;
}
/*
** Return true if the prepared statement is in need of being reset.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt *pStmt){
+SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
Vdbe *v = (Vdbe*)pStmt;
- return v!=0 && v->pc>=0 && v->magic==VDBE_MAGIC_RUN;
+ return v!=0 && v->magic==VDBE_MAGIC_RUN && v->pc>=0;
}
/*
@@ -73829,7 +77189,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt *pStmt){
** prepared statement for the database connection. Return NULL if there
** are no more.
*/
-SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
+SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
sqlite3_stmt *pNext;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(pDb) ){
@@ -73850,7 +77210,7 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_
/*
** Return the value of a status counter for a prepared statement
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
+SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
Vdbe *pVdbe = (Vdbe*)pStmt;
u32 v;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -73864,11 +77224,228 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, i
return (int)v;
}
+/*
+** Return the SQL associated with a prepared statement
+*/
+SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt){
+ Vdbe *p = (Vdbe *)pStmt;
+ return p ? p->zSql : 0;
+}
+
+/*
+** Return the SQL associated with a prepared statement with
+** bound parameters expanded. Space to hold the returned string is
+** obtained from sqlite3_malloc(). The caller is responsible for
+** freeing the returned string by passing it to sqlite3_free().
+**
+** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of
+** expanded bound parameters.
+*/
+SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){
+#ifdef SQLITE_OMIT_TRACE
+ return 0;
+#else
+ char *z = 0;
+ const char *zSql = sqlite3_sql(pStmt);
+ if( zSql ){
+ Vdbe *p = (Vdbe *)pStmt;
+ sqlite3_mutex_enter(p->db->mutex);
+ z = sqlite3VdbeExpandSql(p, zSql);
+ sqlite3_mutex_leave(p->db->mutex);
+ }
+ return z;
+#endif
+}
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** Allocate and populate an UnpackedRecord structure based on the serialized
+** record in nKey/pKey. Return a pointer to the new UnpackedRecord structure
+** if successful, or a NULL pointer if an OOM error is encountered.
+*/
+static UnpackedRecord *vdbeUnpackRecord(
+ KeyInfo *pKeyInfo,
+ int nKey,
+ const void *pKey
+){
+ UnpackedRecord *pRet; /* Return value */
+
+ pRet = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
+ if( pRet ){
+ memset(pRet->aMem, 0, sizeof(Mem)*(pKeyInfo->nField+1));
+ sqlite3VdbeRecordUnpack(pKeyInfo, nKey, pKey, pRet);
+ }
+ return pRet;
+}
+
+/*
+** This function is called from within a pre-update callback to retrieve
+** a field of the row currently being updated or deleted.
+*/
+SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
+ PreUpdate *p = db->pPreUpdate;
+ int rc = SQLITE_OK;
+
+ /* Test that this call is being made from within an SQLITE_DELETE or
+ ** SQLITE_UPDATE pre-update callback, and that iIdx is within range. */
+ if( !p || p->op==SQLITE_INSERT ){
+ rc = SQLITE_MISUSE_BKPT;
+ goto preupdate_old_out;
+ }
+ if( iIdx>=p->pCsr->nField || iIdx<0 ){
+ rc = SQLITE_RANGE;
+ goto preupdate_old_out;
+ }
+
+ /* If the old.* record has not yet been loaded into memory, do so now. */
+ if( p->pUnpacked==0 ){
+ u32 nRec;
+ u8 *aRec;
+
+ nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
+ aRec = sqlite3DbMallocRaw(db, nRec);
+ if( !aRec ) goto preupdate_old_out;
+ rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
+ if( rc==SQLITE_OK ){
+ p->pUnpacked = vdbeUnpackRecord(&p->keyinfo, nRec, aRec);
+ if( !p->pUnpacked ) rc = SQLITE_NOMEM;
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3DbFree(db, aRec);
+ goto preupdate_old_out;
+ }
+ p->aRecord = aRec;
+ }
+
+ if( iIdx>=p->pUnpacked->nField ){
+ *ppValue = (sqlite3_value *)columnNullValue();
+ }else{
+ Mem *pMem = *ppValue = &p->pUnpacked->aMem[iIdx];
+ *ppValue = &p->pUnpacked->aMem[iIdx];
+ if( iIdx==p->pTab->iPKey ){
+ sqlite3VdbeMemSetInt64(pMem, p->iKey1);
+ }else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
+ if( pMem->flags & MEM_Int ){
+ sqlite3VdbeMemRealify(pMem);
+ }
+ }
+ }
+
+ preupdate_old_out:
+ sqlite3Error(db, rc);
+ return sqlite3ApiExit(db, rc);
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** This function is called from within a pre-update callback to retrieve
+** the number of columns in the row being updated, deleted or inserted.
+*/
+SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
+ PreUpdate *p = db->pPreUpdate;
+ return (p ? p->keyinfo.nField : 0);
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** This function is designed to be called from within a pre-update callback
+** only. It returns zero if the change that caused the callback was made
+** immediately by a user SQL statement. Or, if the change was made by a
+** trigger program, it returns the number of trigger programs currently
+** on the stack (1 for a top-level trigger, 2 for a trigger fired by a
+** top-level trigger etc.).
+**
+** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL
+** or SET DEFAULT action is considered a trigger.
+*/
+SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){
+ PreUpdate *p = db->pPreUpdate;
+ return (p ? p->v->nFrame : 0);
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** This function is called from within a pre-update callback to retrieve
+** a field of the row currently being updated or inserted.
+*/
+SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppValue){
+ PreUpdate *p = db->pPreUpdate;
+ int rc = SQLITE_OK;
+ Mem *pMem;
+
+ if( !p || p->op==SQLITE_DELETE ){
+ rc = SQLITE_MISUSE_BKPT;
+ goto preupdate_new_out;
+ }
+ if( iIdx>=p->pCsr->nField || iIdx<0 ){
+ rc = SQLITE_RANGE;
+ goto preupdate_new_out;
+ }
+
+ if( p->op==SQLITE_INSERT ){
+ /* For an INSERT, memory cell p->iNewReg contains the serialized record
+ ** that is being inserted. Deserialize it. */
+ UnpackedRecord *pUnpack = p->pNewUnpacked;
+ if( !pUnpack ){
+ Mem *pData = &p->v->aMem[p->iNewReg];
+ rc = ExpandBlob(pData);
+ if( rc!=SQLITE_OK ) goto preupdate_new_out;
+ pUnpack = vdbeUnpackRecord(&p->keyinfo, pData->n, pData->z);
+ if( !pUnpack ){
+ rc = SQLITE_NOMEM;
+ goto preupdate_new_out;
+ }
+ p->pNewUnpacked = pUnpack;
+ }
+ if( iIdx>=pUnpack->nField ){
+ pMem = (sqlite3_value *)columnNullValue();
+ }else{
+ pMem = &pUnpack->aMem[iIdx];
+ if( iIdx==p->pTab->iPKey ){
+ sqlite3VdbeMemSetInt64(pMem, p->iKey2);
+ }
+ }
+ }else{
+ /* For an UPDATE, memory cell (p->iNewReg+1+iIdx) contains the required
+ ** value. Make a copy of the cell contents and return a pointer to it.
+ ** It is not safe to return a pointer to the memory cell itself as the
+ ** caller may modify the value text encoding.
+ */
+ assert( p->op==SQLITE_UPDATE );
+ if( !p->aNew ){
+ p->aNew = (Mem *)sqlite3DbMallocZero(db, sizeof(Mem) * p->pCsr->nField);
+ if( !p->aNew ){
+ rc = SQLITE_NOMEM;
+ goto preupdate_new_out;
+ }
+ }
+ assert( iIdx>=0 && iIdx<p->pCsr->nField );
+ pMem = &p->aNew[iIdx];
+ if( pMem->flags==0 ){
+ if( iIdx==p->pTab->iPKey ){
+ sqlite3VdbeMemSetInt64(pMem, p->iKey2);
+ }else{
+ rc = sqlite3VdbeMemCopy(pMem, &p->v->aMem[p->iNewReg+1+iIdx]);
+ if( rc!=SQLITE_OK ) goto preupdate_new_out;
+ }
+ }
+ }
+ *ppValue = pMem;
+
+ preupdate_new_out:
+ sqlite3Error(db, rc);
+ return sqlite3ApiExit(db, rc);
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
/*
** Return status data for a single loop within query pStmt.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+SQLITE_API int sqlite3_stmt_scanstatus(
sqlite3_stmt *pStmt, /* Prepared statement being queried */
int idx, /* Index of loop to report on */
int iScanStatusOp, /* Which metric to return */
@@ -73927,7 +77504,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
/*
** Zero all counters associated with the sqlite3_stmt_scanstatus() data.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
+SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
memset(p->anExec, 0, p->nOp * sizeof(i64));
}
@@ -74018,10 +77595,13 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
int i; /* Loop counter */
Mem *pVar; /* Value of a host parameter */
StrAccum out; /* Accumulate the output here */
+#ifndef SQLITE_OMIT_UTF16
+ Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */
+#endif
char zBase[100]; /* Initial working space */
db = p->db;
- sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase),
+ sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase),
db->aLimit[SQLITE_LIMIT_LENGTH]);
if( db->nVdbeExec>1 ){
while( *zRawSql ){
@@ -74072,12 +77652,14 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
int nOut; /* Number of bytes of the string text to include in output */
#ifndef SQLITE_OMIT_UTF16
u8 enc = ENC(db);
- Mem utf8;
if( enc!=SQLITE_UTF8 ){
memset(&utf8, 0, sizeof(utf8));
utf8.db = db;
sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
- sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
+ if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){
+ out.accError = STRACCUM_NOMEM;
+ out.nAlloc = 0;
+ }
pVar = &utf8;
}
#endif
@@ -74119,6 +77701,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
}
}
}
+ if( out.accError ) sqlite3StrAccumReset(&out);
return sqlite3StrAccumFinish(&out);
}
@@ -74215,6 +77798,16 @@ static void updateMaxBlobsize(Mem *p){
#endif
/*
+** This macro evaluates to true if either the update hook or the preupdate
+** hook are enabled for database connect DB.
+*/
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+# define HAS_UPDATE_HOOK(DB) ((DB)->xPreUpdateCallback||(DB)->xUpdateCallback)
+#else
+# define HAS_UPDATE_HOOK(DB) ((DB)->xUpdateCallback)
+#endif
+
+/*
** The next global variable is incremented each time the OP_Found opcode
** is executed. This is used to test whether or not the foreign key
** operation implemented using OP_FkIsZero is working. This variable
@@ -74229,7 +77822,7 @@ SQLITE_API int sqlite3_found_count = 0;
** Test a register to see if it exceeds the current maximum blob size.
** If it does, record the new maximum blob size.
*/
-#if defined(SQLITE_TEST) && !defined(SQLITE_OMIT_BUILTIN_TEST)
+#if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE)
# define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P)
#else
# define UPDATE_MAX_BLOBSIZE(P)
@@ -74320,11 +77913,11 @@ static VdbeCursor *allocateCursor(
** be freed lazily via the sqlite3_release_memory() API. This
** minimizes the number of malloc calls made by the system.
**
- ** Memory cells for cursors are allocated at the top of the address
- ** space. Memory cell (p->nMem) corresponds to cursor 0. Space for
- ** cursor 1 is managed by memory cell (p->nMem-1), etc.
+ ** The memory cell for cursor 0 is aMem[0]. The rest are allocated from
+ ** the top of the register space. Cursor 1 is at Mem[p->nMem-1].
+ ** Cursor 2 is at Mem[p->nMem-2]. And so forth.
*/
- Mem *pMem = &p->aMem[p->nMem-iCur];
+ Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem;
int nByte;
VdbeCursor *pCx = 0;
@@ -74332,14 +77925,14 @@ static VdbeCursor *allocateCursor(
ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
(eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
- assert( iCur<p->nCursor );
- if( p->apCsr[iCur] ){
+ assert( iCur>=0 && iCur<p->nCursor );
+ if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
p->apCsr[iCur] = 0;
}
if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
- memset(pCx, 0, sizeof(VdbeCursor));
+ memset(pCx, 0, offsetof(VdbeCursor,pAltCursor));
pCx->eCurType = eCurType;
pCx->iDb = iDb;
pCx->nField = nField;
@@ -74410,7 +78003,7 @@ static void applyAffinity(
if( affinity>=SQLITE_AFF_NUMERIC ){
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|| affinity==SQLITE_AFF_NUMERIC );
- if( (pRec->flags & MEM_Int)==0 ){
+ if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/
if( (pRec->flags & MEM_Real)==0 ){
if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1);
}else{
@@ -74420,10 +78013,13 @@ static void applyAffinity(
}else if( affinity==SQLITE_AFF_TEXT ){
/* Only attempt the conversion to TEXT if there is an integer or real
** representation (blob and NULL do not get converted) but no string
- ** representation.
- */
- if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){
- sqlite3VdbeMemStringify(pRec, enc, 1);
+ ** representation. It would be harmless to repeat the conversion if
+ ** there is already a string rep, but it is pointless to waste those
+ ** CPU cycles. */
+ if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/
+ if( (pRec->flags&(MEM_Real|MEM_Int)) ){
+ sqlite3VdbeMemStringify(pRec, enc, 1);
+ }
}
pRec->flags &= ~(MEM_Real|MEM_Int);
}
@@ -74435,7 +78031,7 @@ static void applyAffinity(
** is appropriate. But only do the conversion if it is possible without
** loss of information and return the revised type of the argument.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value *pVal){
+SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){
int eType = sqlite3_value_type(pVal);
if( eType==SQLITE_TEXT ){
Mem *pMem = (Mem*)pVal;
@@ -74638,8 +78234,8 @@ static void registerTrace(int iReg, Mem *p){
** This file contains inline asm code for retrieving "high-performance"
** counters for x86 class CPUs.
*/
-#ifndef _HWTIME_H_
-#define _HWTIME_H_
+#ifndef SQLITE_HWTIME_H
+#define SQLITE_HWTIME_H
/*
** The following routine only works on pentium-class (or newer) processors.
@@ -74707,7 +78303,7 @@ SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
#endif
-#endif /* !defined(_HWTIME_H_) */
+#endif /* !defined(SQLITE_HWTIME_H) */
/************** End of hwtime.h **********************************************/
/************** Continuing where we left off in vdbe.c ***********************/
@@ -74746,10 +78342,10 @@ static SQLITE_NOINLINE Mem *out2PrereleaseWithClear(Mem *pOut){
static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
Mem *pOut;
assert( pOp->p2>0 );
- assert( pOp->p2<=(p->nMem-p->nCursor) );
+ assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
pOut = &p->aMem[pOp->p2];
memAboutToChange(p, pOut);
- if( VdbeMemDynamic(pOut) ){
+ if( VdbeMemDynamic(pOut) ){ /*OPTIMIZATION-IF-FALSE*/
return out2PrereleaseWithClear(pOut);
}else{
pOut->flags = MEM_Int;
@@ -74777,7 +78373,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
sqlite3 *db = p->db; /* The database */
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
u8 encoding = ENC(db); /* The database encoding */
- int iCompare = 0; /* Result of last OP_Compare operation */
+ int iCompare = 0; /* Result of last comparison */
unsigned nVmStep = 0; /* Number of virtual machine steps */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */
@@ -74844,7 +78440,11 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
}
sqlite3EndBenignMalloc();
#endif
- for(pOp=&aOp[p->pc]; rc==SQLITE_OK; pOp++){
+ for(pOp=&aOp[p->pc]; 1; pOp++){
+ /* Errors are detected by individual opcodes, with an immediate
+ ** jumps to abort_due_to_error. */
+ assert( rc==SQLITE_OK );
+
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
#ifdef VDBE_PROFILE
start = sqlite3Hwtime();
@@ -74877,37 +78477,39 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
/* Sanity checking on other operands */
#ifdef SQLITE_DEBUG
- assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
- if( (pOp->opflags & OPFLG_IN1)!=0 ){
- assert( pOp->p1>0 );
- assert( pOp->p1<=(p->nMem-p->nCursor) );
- assert( memIsValid(&aMem[pOp->p1]) );
- assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
- REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
- }
- if( (pOp->opflags & OPFLG_IN2)!=0 ){
- assert( pOp->p2>0 );
- assert( pOp->p2<=(p->nMem-p->nCursor) );
- assert( memIsValid(&aMem[pOp->p2]) );
- assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
- REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
- }
- if( (pOp->opflags & OPFLG_IN3)!=0 ){
- assert( pOp->p3>0 );
- assert( pOp->p3<=(p->nMem-p->nCursor) );
- assert( memIsValid(&aMem[pOp->p3]) );
- assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
- REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
- }
- if( (pOp->opflags & OPFLG_OUT2)!=0 ){
- assert( pOp->p2>0 );
- assert( pOp->p2<=(p->nMem-p->nCursor) );
- memAboutToChange(p, &aMem[pOp->p2]);
- }
- if( (pOp->opflags & OPFLG_OUT3)!=0 ){
- assert( pOp->p3>0 );
- assert( pOp->p3<=(p->nMem-p->nCursor) );
- memAboutToChange(p, &aMem[pOp->p3]);
+ {
+ u8 opProperty = sqlite3OpcodeProperty[pOp->opcode];
+ if( (opProperty & OPFLG_IN1)!=0 ){
+ assert( pOp->p1>0 );
+ assert( pOp->p1<=(p->nMem+1 - p->nCursor) );
+ assert( memIsValid(&aMem[pOp->p1]) );
+ assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) );
+ REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
+ }
+ if( (opProperty & OPFLG_IN2)!=0 ){
+ assert( pOp->p2>0 );
+ assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
+ assert( memIsValid(&aMem[pOp->p2]) );
+ assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) );
+ REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
+ }
+ if( (opProperty & OPFLG_IN3)!=0 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
+ assert( memIsValid(&aMem[pOp->p3]) );
+ assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) );
+ REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
+ }
+ if( (opProperty & OPFLG_OUT2)!=0 ){
+ assert( pOp->p2>0 );
+ assert( pOp->p2<=(p->nMem+1 - p->nCursor) );
+ memAboutToChange(p, &aMem[pOp->p2]);
+ }
+ if( (opProperty & OPFLG_OUT3)!=0 ){
+ assert( pOp->p3>0 );
+ assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
+ memAboutToChange(p, &aMem[pOp->p3]);
+ }
}
#endif
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
@@ -74991,7 +78593,7 @@ check_for_interrupt:
nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps);
if( db->xProgress(db->pProgressArg) ){
rc = SQLITE_INTERRUPT;
- goto vdbe_error_halt;
+ goto abort_due_to_error;
}
}
#endif
@@ -75005,7 +78607,7 @@ check_for_interrupt:
** and then jump to address P2.
*/
case OP_Gosub: { /* jump */
- assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
pIn1 = &aMem[pOp->p1];
assert( VdbeMemDynamic(pIn1)==0 );
memAboutToChange(p, pIn1);
@@ -75045,7 +78647,7 @@ case OP_Return: { /* in1 */
** See also: EndCoroutine
*/
case OP_InitCoroutine: { /* jump */
- assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
assert( pOp->p2>=0 && pOp->p2<p->nOp );
assert( pOp->p3>=0 && pOp->p3<p->nOp );
pOut = &aMem[pOp->p1];
@@ -75103,7 +78705,7 @@ case OP_Yield: { /* in1, jump */
}
/* Opcode: HaltIfNull P1 P2 P3 P4 P5
-** Synopsis: if r[P3]=null halt
+** Synopsis: if r[P3]=null halt
**
** Check the value in register P3. If it is NULL then Halt using
** parameter P1, P2, and P4 as if this were a Halt instruction. If the
@@ -75147,8 +78749,6 @@ case OP_HaltIfNull: { /* in3 */
** is the same as executing Halt.
*/
case OP_Halt: {
- const char *zType;
- const char *zLogFmt;
VdbeFrame *pFrame;
int pcx;
@@ -75177,34 +78777,28 @@ case OP_Halt: {
p->rc = pOp->p1;
p->errorAction = (u8)pOp->p2;
p->pc = pcx;
+ assert( pOp->p5<=4 );
if( p->rc ){
if( pOp->p5 ){
static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
"FOREIGN KEY" };
- assert( pOp->p5>=1 && pOp->p5<=4 );
testcase( pOp->p5==1 );
testcase( pOp->p5==2 );
testcase( pOp->p5==3 );
testcase( pOp->p5==4 );
- zType = azType[pOp->p5-1];
+ sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]);
+ if( pOp->p4.z ){
+ p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z);
+ }
}else{
- zType = 0;
- }
- assert( zType!=0 || pOp->p4.z!=0 );
- zLogFmt = "abort at %d in [%s]: %s";
- if( zType && pOp->p4.z ){
- sqlite3VdbeError(p, "%s constraint failed: %s", zType, pOp->p4.z);
- }else if( pOp->p4.z ){
sqlite3VdbeError(p, "%s", pOp->p4.z);
- }else{
- sqlite3VdbeError(p, "%s constraint failed", zType);
}
- sqlite3_log(pOp->p1, zLogFmt, pcx, p->zSql, p->zErrMsg);
+ sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
}
rc = sqlite3VdbeHalt(p);
assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR );
if( rc==SQLITE_BUSY ){
- p->rc = rc = SQLITE_BUSY;
+ p->rc = SQLITE_BUSY;
}else{
assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
assert( rc==SQLITE_OK || db->nDeferredCons>0 || db->nDeferredImmCons>0 );
@@ -75270,7 +78864,7 @@ case OP_String8: { /* same as TK_STRING, out2 */
#ifndef SQLITE_OMIT_UTF16
if( encoding!=SQLITE_UTF8 ){
rc = sqlite3VdbeMemSetStr(pOut, pOp->p4.z, -1, SQLITE_UTF8, SQLITE_STATIC);
- if( rc==SQLITE_TOOBIG ) goto too_big;
+ assert( rc==SQLITE_OK || rc==SQLITE_TOOBIG );
if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
assert( pOut->szMalloc>0 && pOut->zMalloc==pOut->z );
assert( VdbeMemDynamic(pOut)==0 );
@@ -75283,10 +78877,12 @@ case OP_String8: { /* same as TK_STRING, out2 */
pOp->p4.z = pOut->z;
pOp->p1 = pOut->n;
}
+ testcase( rc==SQLITE_TOOBIG );
#endif
if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
+ assert( rc==SQLITE_OK );
/* Fall through to the next case, OP_String */
}
@@ -75295,10 +78891,12 @@ case OP_String8: { /* same as TK_STRING, out2 */
**
** The string value P4 of length P1 (bytes) is stored in register P2.
**
-** If P5!=0 and the content of register P3 is greater than zero, then
+** If P3 is not zero and the content of register P3 is equal to P5, then
** the datatype of the register P2 is converted to BLOB. The content is
** the same sequence of bytes, it is merely interpreted as a BLOB instead
-** of a string, as if it had been CAST.
+** of a string, as if it had been CAST. In other words:
+**
+** if( P3!=0 and reg[P3]==P5 ) reg[P2] := CAST(reg[P2] as BLOB)
*/
case OP_String: { /* out2 */
assert( pOp->p4.z!=0 );
@@ -75309,19 +78907,18 @@ case OP_String: { /* out2 */
pOut->enc = encoding;
UPDATE_MAX_BLOBSIZE(pOut);
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- if( pOp->p5 ){
- assert( pOp->p3>0 );
- assert( pOp->p3<=(p->nMem-p->nCursor) );
+ if( pOp->p3>0 ){
+ assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int );
- if( pIn3->u.i ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
+ if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term;
}
#endif
break;
}
/* Opcode: Null P1 P2 P3 * *
-** Synopsis: r[P2..P3]=NULL
+** Synopsis: r[P2..P3]=NULL
**
** Write a NULL into registers P2. If P3 greater than P2, then also write
** NULL into register P3 and every register in between P2 and P3. If P3
@@ -75337,20 +78934,22 @@ case OP_Null: { /* out2 */
u16 nullFlag;
pOut = out2Prerelease(p, pOp);
cnt = pOp->p3-pOp->p2;
- assert( pOp->p3<=(p->nMem-p->nCursor) );
+ assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
+ pOut->n = 0;
while( cnt>0 ){
pOut++;
memAboutToChange(p, pOut);
sqlite3VdbeMemSetNull(pOut);
pOut->flags = nullFlag;
+ pOut->n = 0;
cnt--;
}
break;
}
/* Opcode: SoftNull P1 * * * *
-** Synopsis: r[P1]=NULL
+** Synopsis: r[P1]=NULL
**
** Set register P1 to have the value NULL as seen by the OP_MakeRecord
** instruction, but do not free any string or blob memory associated with
@@ -75358,7 +78957,7 @@ case OP_Null: { /* out2 */
** previously copied using OP_SCopy, the copies will continue to be valid.
*/
case OP_SoftNull: {
- assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
pOut = &aMem[pOp->p1];
pOut->flags = (pOut->flags|MEM_Null)&~MEM_Undefined;
break;
@@ -75391,7 +78990,7 @@ case OP_Variable: { /* out2 */
Mem *pVar; /* Value being transferred */
assert( pOp->p1>0 && pOp->p1<=p->nVar );
- assert( pOp->p4.z==0 || pOp->p4.z==p->azVar[pOp->p1-1] );
+ assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) );
pVar = &p->aVar[pOp->p1 - 1];
if( sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
@@ -75403,7 +79002,7 @@ case OP_Variable: { /* out2 */
}
/* Opcode: Move P1 P2 P3 * *
-** Synopsis: r[P2@P3]=r[P1@P3]
+** Synopsis: r[P2@P3]=r[P1@P3]
**
** Move the P3 values in register P1..P1+P3-1 over into
** registers P2..P2+P3-1. Registers P1..P1+P3-1 are
@@ -75425,8 +79024,8 @@ case OP_Move: {
pIn1 = &aMem[p1];
pOut = &aMem[p2];
do{
- assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
- assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
+ assert( pOut<=&aMem[(p->nMem+1 - p->nCursor)] );
+ assert( pIn1<=&aMem[(p->nMem+1 - p->nCursor)] );
assert( memIsValid(pIn1) );
memAboutToChange(p, pOut);
sqlite3VdbeMemMove(pOut, pIn1);
@@ -75513,7 +79112,7 @@ case OP_IntCopy: { /* out2 */
}
/* Opcode: ResultRow P1 P2 * * *
-** Synopsis: output=r[P1@P2]
+** Synopsis: output=r[P1@P2]
**
** The registers P1 through P1+P2-1 contain a single row of
** results. This opcode causes the sqlite3_step() call to terminate
@@ -75526,7 +79125,7 @@ case OP_ResultRow: {
int i;
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 );
- assert( pOp->p1+pOp->p2<=(p->nMem-p->nCursor)+1 );
+ assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
/* Run the progress counter just before returning.
@@ -75536,7 +79135,7 @@ case OP_ResultRow: {
&& db->xProgress(db->pProgressArg)!=0
){
rc = SQLITE_INTERRUPT;
- goto vdbe_error_halt;
+ goto abort_due_to_error;
}
#endif
@@ -75546,7 +79145,7 @@ case OP_ResultRow: {
if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){
assert( db->flags&SQLITE_CountRows );
assert( p->usesStmtJournal );
- break;
+ goto abort_due_to_error;
}
/* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then
@@ -75566,9 +79165,7 @@ case OP_ResultRow: {
*/
assert( p->iStatement==0 || db->flags&SQLITE_CountRows );
rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE);
- if( NEVER(rc!=SQLITE_OK) ){
- break;
- }
+ assert( rc==SQLITE_OK );
/* Invalidate all ephemeral cursor row caches */
p->cacheCtr = (p->cacheCtr + 2)|1;
@@ -75588,6 +79185,10 @@ case OP_ResultRow: {
}
if( db->mallocFailed ) goto no_mem;
+ if( db->mTrace & SQLITE_TRACE_ROW ){
+ db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
+ }
+
/* Return SQLITE_ROW
*/
p->pc = (int)(pOp - aOp) + 1;
@@ -75644,14 +79245,14 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
}
/* Opcode: Add P1 P2 P3 * *
-** Synopsis: r[P3]=r[P1]+r[P2]
+** Synopsis: r[P3]=r[P1]+r[P2]
**
** Add the value in register P1 to the value in register P2
** and store the result in register P3.
** If either input is NULL, the result is NULL.
*/
/* Opcode: Multiply P1 P2 P3 * *
-** Synopsis: r[P3]=r[P1]*r[P2]
+** Synopsis: r[P3]=r[P1]*r[P2]
**
**
** Multiply the value in register P1 by the value in register P2
@@ -75659,14 +79260,14 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
** If either input is NULL, the result is NULL.
*/
/* Opcode: Subtract P1 P2 P3 * *
-** Synopsis: r[P3]=r[P2]-r[P1]
+** Synopsis: r[P3]=r[P2]-r[P1]
**
** Subtract the value in register P1 from the value in register P2
** and store the result in register P3.
** If either input is NULL, the result is NULL.
*/
/* Opcode: Divide P1 P2 P3 * *
-** Synopsis: r[P3]=r[P2]/r[P1]
+** Synopsis: r[P3]=r[P2]/r[P1]
**
** Divide the value in register P1 by the value in register P2
** and store the result in register P3 (P3=P2/P1). If the value in
@@ -75674,7 +79275,7 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
** NULL, the result is NULL.
*/
/* Opcode: Remainder P1 P2 P3 * *
-** Synopsis: r[P3]=r[P2]%r[P1]
+** Synopsis: r[P3]=r[P2]%r[P1]
**
** Compute the remainder after integer register P2 is divided by
** register P1 and store the result in register P3.
@@ -75840,8 +79441,8 @@ case OP_Function0: {
assert( pOp->p4type==P4_FUNCDEF );
n = pOp->p5;
- assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
- assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
+ assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
if( pCtx==0 ) goto no_mem;
@@ -75891,7 +79492,8 @@ case OP_Function: {
sqlite3VdbeError(p, "%s", sqlite3_value_text(pCtx->pOut));
rc = pCtx->isError;
}
- sqlite3VdbeDeleteAuxData(p, pCtx->iOp, pOp->p1);
+ sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1);
+ if( rc ) goto abort_due_to_error;
}
/* Copy the result of the function into register P3 */
@@ -75906,21 +79508,21 @@ case OP_Function: {
}
/* Opcode: BitAnd P1 P2 P3 * *
-** Synopsis: r[P3]=r[P1]&r[P2]
+** Synopsis: r[P3]=r[P1]&r[P2]
**
** Take the bit-wise AND of the values in register P1 and P2 and
** store the result in register P3.
** If either input is NULL, the result is NULL.
*/
/* Opcode: BitOr P1 P2 P3 * *
-** Synopsis: r[P3]=r[P1]|r[P2]
+** Synopsis: r[P3]=r[P1]|r[P2]
**
** Take the bit-wise OR of the values in register P1 and P2 and
** store the result in register P3.
** If either input is NULL, the result is NULL.
*/
/* Opcode: ShiftLeft P1 P2 P3 * *
-** Synopsis: r[P3]=r[P2]<<r[P1]
+** Synopsis: r[P3]=r[P2]<<r[P1]
**
** Shift the integer value in register P2 to the left by the
** number of bits specified by the integer in register P1.
@@ -75928,7 +79530,7 @@ case OP_Function: {
** If either input is NULL, the result is NULL.
*/
/* Opcode: ShiftRight P1 P2 P3 * *
-** Synopsis: r[P3]=r[P2]>>r[P1]
+** Synopsis: r[P3]=r[P2]>>r[P1]
**
** Shift the integer value in register P2 to the right by the
** number of bits specified by the integer in register P1.
@@ -75988,7 +79590,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
}
/* Opcode: AddImm P1 P2 * * *
-** Synopsis: r[P1]=r[P1]+P2
+** Synopsis: r[P1]=r[P1]+P2
**
** Add the constant P2 to the value in register P1.
** The result is always an integer.
@@ -76075,19 +79677,17 @@ case OP_Cast: { /* in1 */
rc = ExpandBlob(pIn1);
sqlite3VdbeMemCast(pIn1, pOp->p2, encoding);
UPDATE_MAX_BLOBSIZE(pIn1);
+ if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_CAST */
-/* Opcode: Lt P1 P2 P3 P4 P5
-** Synopsis: if r[P1]<r[P3] goto P2
-**
-** Compare the values in register P1 and P3. If reg(P3)<reg(P1) then
-** jump to address P2.
+/* Opcode: Eq P1 P2 P3 P4 P5
+** Synopsis: IF r[P3]==r[P1]
**
-** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
-** reg(P3) is NULL then take the jump. If the SQLITE_JUMPIFNULL
-** bit is clear then fall through if either operand is NULL.
+** Compare the values in register P1 and P3. If reg(P3)==reg(P1) then
+** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5, then
+** store the result of comparison in register P2.
**
** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
@@ -76101,61 +79701,78 @@ case OP_Cast: { /* in1 */
** the values are compared. If both values are blobs then memcmp() is
** used to determine the results of the comparison. If both values
** are text, then the appropriate collating function specified in
-** P4 is used to do the comparison. If P4 is not specified then
+** P4 is used to do the comparison. If P4 is not specified then
** memcmp() is used to compare text string. If both values are
** numeric, then a numeric comparison is used. If the two values
** are of different types, then numbers are considered less than
** strings and strings are considered less than blobs.
**
-** If the SQLITE_STOREP2 bit of P5 is set, then do not jump. Instead,
-** store a boolean result (either 0, or 1, or NULL) in register P2.
+** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
+** true or false and is never NULL. If both operands are NULL then the result
+** of comparison is true. If either operand is NULL then the result is false.
+** If neither operand is NULL the result is the same as it would be if
+** the SQLITE_NULLEQ flag were omitted from P5.
**
-** If the SQLITE_NULLEQ bit is set in P5, then NULL values are considered
-** equal to one another, provided that they do not have their MEM_Cleared
-** bit set.
+** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
+** content of r[P2] is only changed if the new value is NULL or 0 (false).
+** In other words, a prior r[P2] value will not be overwritten by 1 (true).
*/
/* Opcode: Ne P1 P2 P3 P4 P5
-** Synopsis: if r[P1]!=r[P3] goto P2
+** Synopsis: IF r[P3]!=r[P1]
**
-** This works just like the Lt opcode except that the jump is taken if
-** the operands in registers P1 and P3 are not equal. See the Lt opcode for
+** This works just like the Eq opcode except that the jump is taken if
+** the operands in registers P1 and P3 are not equal. See the Eq opcode for
** additional information.
**
-** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
-** true or false and is never NULL. If both operands are NULL then the result
-** of comparison is false. If either operand is NULL then the result is true.
-** If neither operand is NULL the result is the same as it would be if
-** the SQLITE_NULLEQ flag were omitted from P5.
+** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
+** content of r[P2] is only changed if the new value is NULL or 1 (true).
+** In other words, a prior r[P2] value will not be overwritten by 0 (false).
*/
-/* Opcode: Eq P1 P2 P3 P4 P5
-** Synopsis: if r[P1]==r[P3] goto P2
+/* Opcode: Lt P1 P2 P3 P4 P5
+** Synopsis: IF r[P3]<r[P1]
**
-** This works just like the Lt opcode except that the jump is taken if
-** the operands in registers P1 and P3 are equal.
-** See the Lt opcode for additional information.
+** Compare the values in register P1 and P3. If reg(P3)<reg(P1) then
+** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5 store
+** the result of comparison (0 or 1 or NULL) into register P2.
**
-** If SQLITE_NULLEQ is set in P5 then the result of comparison is always either
-** true or false and is never NULL. If both operands are NULL then the result
-** of comparison is true. If either operand is NULL then the result is false.
-** If neither operand is NULL the result is the same as it would be if
-** the SQLITE_NULLEQ flag were omitted from P5.
+** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
+** reg(P3) is NULL then the take the jump. If the SQLITE_JUMPIFNULL
+** bit is clear then fall through if either operand is NULL.
+**
+** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
+** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
+** to coerce both inputs according to this affinity before the
+** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric
+** affinity is used. Note that the affinity conversions are stored
+** back into the input registers P1 and P3. So this opcode can cause
+** persistent changes to registers P1 and P3.
+**
+** Once any conversions have taken place, and neither value is NULL,
+** the values are compared. If both values are blobs then memcmp() is
+** used to determine the results of the comparison. If both values
+** are text, then the appropriate collating function specified in
+** P4 is used to do the comparison. If P4 is not specified then
+** memcmp() is used to compare text string. If both values are
+** numeric, then a numeric comparison is used. If the two values
+** are of different types, then numbers are considered less than
+** strings and strings are considered less than blobs.
*/
/* Opcode: Le P1 P2 P3 P4 P5
-** Synopsis: if r[P1]<=r[P3] goto P2
+** Synopsis: IF r[P3]<=r[P1]
**
** This works just like the Lt opcode except that the jump is taken if
** the content of register P3 is less than or equal to the content of
** register P1. See the Lt opcode for additional information.
*/
/* Opcode: Gt P1 P2 P3 P4 P5
-** Synopsis: if r[P1]>r[P3] goto P2
+** Synopsis: IF r[P3]>r[P1]
**
** This works just like the Lt opcode except that the jump is taken if
** the content of register P3 is greater than the content of
** register P1. See the Lt opcode for additional information.
*/
/* Opcode: Ge P1 P2 P3 P4 P5
-** Synopsis: if r[P1]>=r[P3] goto P2
+** Synopsis: IF r[P3]>=r[P1]
**
** This works just like the Lt opcode except that the jump is taken if
** the content of register P3 is greater than or equal to the content of
@@ -76167,7 +79784,7 @@ case OP_Lt: /* same as TK_LT, jump, in1, in3 */
case OP_Le: /* same as TK_LE, jump, in1, in3 */
case OP_Gt: /* same as TK_GT, jump, in1, in3 */
case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
- int res; /* Result of the comparison of pIn1 against pIn3 */
+ int res, res2; /* Result of the comparison of pIn1 against pIn3 */
char affinity; /* Affinity to use for comparison */
u16 flags1; /* Copy of initial value of pIn1->flags */
u16 flags3; /* Copy of initial value of pIn3->flags */
@@ -76186,13 +79803,12 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne );
assert( (flags1 & MEM_Cleared)==0 );
assert( (pOp->p5 & SQLITE_JUMPIFNULL)==0 );
- if( (flags1&MEM_Null)!=0
- && (flags3&MEM_Null)!=0
+ if( (flags1&flags3&MEM_Null)!=0
&& (flags3&MEM_Cleared)==0
){
- res = 0; /* Results are equal */
+ res = 0; /* Operands are equal */
}else{
- res = 1; /* Results are not equal */
+ res = 1; /* Operands are not equal */
}
}else{
/* SQLITE_NULLEQ is clear and at least one operand is NULL,
@@ -76201,6 +79817,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
*/
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
+ iCompare = 1; /* Operands are not equal */
memAboutToChange(p, pOut);
MemSetTypeFlag(pOut, MEM_Null);
REGISTER_TRACE(pOp->p2, pOut);
@@ -76216,11 +79833,23 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
/* Neither operand is NULL. Do a comparison. */
affinity = pOp->p5 & SQLITE_AFF_MASK;
if( affinity>=SQLITE_AFF_NUMERIC ){
- if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
- applyNumericAffinity(pIn1,0);
+ if( (flags1 | flags3)&MEM_Str ){
+ if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ applyNumericAffinity(pIn1,0);
+ testcase( flags3!=pIn3->flags ); /* Possible if pIn1==pIn3 */
+ flags3 = pIn3->flags;
+ }
+ if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
+ applyNumericAffinity(pIn3,0);
+ }
}
- if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){
- applyNumericAffinity(pIn3,0);
+ /* Handle the common case of integer comparison here, as an
+ ** optimization, to avoid a call to sqlite3MemCompare() */
+ if( (pIn1->flags & pIn3->flags & MEM_Int)!=0 ){
+ if( pIn3->u.i > pIn1->u.i ){ res = +1; goto compare_op; }
+ if( pIn3->u.i < pIn1->u.i ){ res = -1; goto compare_op; }
+ res = 0;
+ goto compare_op;
}
}else if( affinity==SQLITE_AFF_TEXT ){
if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){
@@ -76229,6 +79858,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
sqlite3VdbeMemStringify(pIn1, encoding, 1);
testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
+ assert( pIn1!=pIn3 );
}
if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){
testcase( pIn3->flags & MEM_Int );
@@ -76239,23 +79869,16 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}
}
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
- if( flags1 & MEM_Zero ){
- sqlite3VdbeMemExpandBlob(pIn1);
- flags1 &= ~MEM_Zero;
- }
- if( flags3 & MEM_Zero ){
- sqlite3VdbeMemExpandBlob(pIn3);
- flags3 &= ~MEM_Zero;
- }
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
}
+compare_op:
switch( pOp->opcode ){
- case OP_Eq: res = res==0; break;
- case OP_Ne: res = res!=0; break;
- case OP_Lt: res = res<0; break;
- case OP_Le: res = res<=0; break;
- case OP_Gt: res = res>0; break;
- default: res = res>=0; break;
+ case OP_Eq: res2 = res==0; break;
+ case OP_Ne: res2 = res; break;
+ case OP_Lt: res2 = res<0; break;
+ case OP_Le: res2 = res<=0; break;
+ case OP_Gt: res2 = res>0; break;
+ default: res2 = res>=0; break;
}
/* Undo any changes made by applyAffinity() to the input registers. */
@@ -76266,19 +79889,55 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
+ iCompare = res;
+ res2 = res2!=0; /* For this path res2 must be exactly 0 or 1 */
+ if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){
+ /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1
+ ** and prevents OP_Ne from overwriting NULL with 0. This flag
+ ** is only used in contexts where either:
+ ** (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
+ ** (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
+ ** Therefore it is not necessary to check the content of r[P2] for
+ ** NULL. */
+ assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq );
+ assert( res2==0 || res2==1 );
+ testcase( res2==0 && pOp->opcode==OP_Eq );
+ testcase( res2==1 && pOp->opcode==OP_Eq );
+ testcase( res2==0 && pOp->opcode==OP_Ne );
+ testcase( res2==1 && pOp->opcode==OP_Ne );
+ if( (pOp->opcode==OP_Eq)==res2 ) break;
+ }
memAboutToChange(p, pOut);
MemSetTypeFlag(pOut, MEM_Int);
- pOut->u.i = res;
+ pOut->u.i = res2;
REGISTER_TRACE(pOp->p2, pOut);
}else{
VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
- if( res ){
+ if( res2 ){
goto jump_to_p2;
}
}
break;
}
+/* Opcode: ElseNotEq * P2 * * *
+**
+** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator.
+** If result of an OP_Eq comparison on the same two operands
+** would have be NULL or false (0), then then jump to P2.
+** If the result of an OP_Eq comparison on the two previous operands
+** would have been true (1), then fall through.
+*/
+case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */
+ assert( pOp>aOp );
+ assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt );
+ assert( pOp[-1].p5 & SQLITE_STOREP2 );
+ VdbeBranchTaken(iCompare!=0, 2);
+ if( iCompare!=0 ) goto jump_to_p2;
+ break;
+}
+
+
/* Opcode: Permutation * * * P4 *
**
** Set the permutation used by the OP_Compare operator to be the array
@@ -76339,11 +79998,11 @@ case OP_Compare: {
if( aPermute ){
int k, mx = 0;
for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
- assert( p1>0 && p1+mx<=(p->nMem-p->nCursor)+1 );
- assert( p2>0 && p2+mx<=(p->nMem-p->nCursor)+1 );
+ assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
+ assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
}else{
- assert( p1>0 && p1+n<=(p->nMem-p->nCursor)+1 );
- assert( p2>0 && p2+n<=(p->nMem-p->nCursor)+1 );
+ assert( p1>0 && p1+n<=(p->nMem+1 - p->nCursor)+1 );
+ assert( p2>0 && p2+n<=(p->nMem+1 - p->nCursor)+1 );
}
#endif /* SQLITE_DEBUG */
for(i=0; i<n; i++){
@@ -76474,22 +80133,18 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
/* Opcode: Once P1 P2 * * *
**
-** Check the "once" flag number P1. If it is set, jump to instruction P2.
-** Otherwise, set the flag and fall through to the next instruction.
-** In other words, this opcode causes all following opcodes up through P2
-** (but not including P2) to run just once and to be skipped on subsequent
-** times through the loop.
-**
-** All "once" flags are initially cleared whenever a prepared statement
-** first begins to run.
+** If the P1 value is equal to the P1 value on the OP_Init opcode at
+** instruction 0, then jump to P2. If the two P1 values differ, then
+** set the P1 value on this opcode to equal the P1 value on the OP_Init
+** and fall through.
*/
case OP_Once: { /* jump */
- assert( pOp->p1<p->nOnceFlag );
- VdbeBranchTaken(p->aOnceFlag[pOp->p1]!=0, 2);
- if( p->aOnceFlag[pOp->p1] ){
+ assert( p->aOp[0].opcode==OP_Init );
+ VdbeBranchTaken(p->aOp[0].p1==pOp->p1, 2);
+ if( p->aOp[0].p1==pOp->p1 ){
goto jump_to_p2;
}else{
- p->aOnceFlag[pOp->p1] = 1;
+ pOp->p1 = p->aOp[0].p1;
}
break;
}
@@ -76528,7 +80183,7 @@ case OP_IfNot: { /* jump, in1 */
}
/* Opcode: IsNull P1 P2 * * *
-** Synopsis: if r[P1]==NULL goto P2
+** Synopsis: if r[P1]==NULL goto P2
**
** Jump to P2 if the value in register P1 is NULL.
*/
@@ -76556,7 +80211,7 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
}
/* Opcode: Column P1 P2 P3 P4 P5
-** Synopsis: r[P3]=PX
+** Synopsis: r[P3]=PX
**
** Interpret the data that cursor P1 points to as a structure built using
** the MakeRecord instruction. (See the MakeRecord opcode for additional
@@ -76581,7 +80236,6 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** skipped for length() and all content loading can be skipped for typeof().
*/
case OP_Column: {
- i64 payloadSize64; /* Number of bytes in the record */
int p2; /* column number to retrieve */
VdbeCursor *pC; /* The VDBE cursor */
BtCursor *pCrsr; /* The BTree cursor */
@@ -76604,8 +80258,9 @@ case OP_Column: {
/* If the cursor cache is stale, bring it up-to-date */
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
+ if( rc ) goto abort_due_to_error;
- assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
@@ -76615,10 +80270,8 @@ case OP_Column: {
assert( pC->eCurType!=CURTYPE_VTAB );
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
assert( pC->eCurType!=CURTYPE_SORTER );
- pCrsr = pC->uc.pCursor;
- if( rc ) goto abort_due_to_error;
- if( pC->cacheStatus!=p->cacheCtr ){
+ if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/
if( pC->nullRow ){
if( pC->eCurType==CURTYPE_PSEUDO ){
assert( pC->uc.pseudoTableReg>0 );
@@ -76632,24 +80285,12 @@ case OP_Column: {
goto op_column_out;
}
}else{
+ pCrsr = pC->uc.pCursor;
assert( pC->eCurType==CURTYPE_BTREE );
assert( pCrsr );
- if( pC->isTable==0 ){
- assert( sqlite3BtreeCursorIsValid(pCrsr) );
- VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
- assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
- /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
- ** payload size, so it is impossible for payloadSize64 to be
- ** larger than 32 bits. */
- assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
- pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail);
- pC->payloadSize = (u32)payloadSize64;
- }else{
- assert( sqlite3BtreeCursorIsValid(pCrsr) );
- VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize);
- assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
- pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail);
- }
+ assert( sqlite3BtreeCursorIsValid(pCrsr) );
+ pC->payloadSize = sqlite3BtreePayloadSize(pCrsr);
+ pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &avail);
assert( avail<=65536 ); /* Maximum page size is 64KiB */
if( pC->payloadSize <= (u32)avail ){
pC->szRow = pC->payloadSize;
@@ -76665,7 +80306,7 @@ case OP_Column: {
aOffset[0] = offset;
- if( avail<offset ){
+ if( avail<offset ){ /*OPTIMIZATION-IF-FALSE*/
/* pC->aRow does not have to hold the entire row, but it does at least
** need to cover the header of the record. If pC->aRow does not contain
** the complete header, then set it to zero, forcing the header to be
@@ -76684,16 +80325,17 @@ case OP_Column: {
*/
if( offset > 98307 || offset > pC->payloadSize ){
rc = SQLITE_CORRUPT_BKPT;
- goto op_column_error;
+ goto abort_due_to_error;
}
+ }else if( offset>0 ){ /*OPTIMIZATION-IF-TRUE*/
+ /* The following goto is an optimization. It can be omitted and
+ ** everything will still work. But OP_Column is measurably faster
+ ** by skipping the subsequent conditional, which is always true.
+ */
+ zData = pC->aRow;
+ assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */
+ goto op_column_read_header;
}
-
- /* The following goto is an optimization. It can be omitted and
- ** everything will still work. But OP_Column is measurably faster
- ** by skipping the subsequent conditional, which is always true.
- */
- assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */
- goto op_column_read_header;
}
/* Make sure at least the first p2+1 entries of the header have been
@@ -76703,24 +80345,23 @@ case OP_Column: {
/* If there is more header available for parsing in the record, try
** to extract additional fields up through the p2+1-th field
*/
- op_column_read_header:
if( pC->iHdrOffset<aOffset[0] ){
/* Make sure zData points to enough of the record to cover the header. */
if( pC->aRow==0 ){
memset(&sMem, 0, sizeof(sMem));
- rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0], !pC->isTable, &sMem);
- if( rc!=SQLITE_OK ) goto op_column_error;
+ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, 0, aOffset[0], &sMem);
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
zData = (u8*)sMem.z;
}else{
zData = pC->aRow;
}
/* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */
+ op_column_read_header:
i = pC->nHdrParsed;
offset64 = aOffset[i];
zHdr = zData + pC->iHdrOffset;
zEndHdr = zData + aOffset[0];
- assert( i<=p2 && zHdr<zEndHdr );
do{
if( (t = zHdr[0])<0x80 ){
zHdr++;
@@ -76732,10 +80373,7 @@ case OP_Column: {
pC->aType[i++] = t;
aOffset[i] = (u32)(offset64 & 0xffffffff);
}while( i<=p2 && zHdr<zEndHdr );
- pC->nHdrParsed = i;
- pC->iHdrOffset = (u32)(zHdr - zData);
- if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
-
+
/* The record is corrupt if any of the following are true:
** (1) the bytes of the header extend past the declared header size
** (2) the entire header was used but not all data was used
@@ -76744,9 +80382,14 @@ case OP_Column: {
if( (zHdr>=zEndHdr && (zHdr>zEndHdr || offset64!=pC->payloadSize))
|| (offset64 > pC->payloadSize)
){
+ if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
rc = SQLITE_CORRUPT_BKPT;
- goto op_column_error;
+ goto abort_due_to_error;
}
+
+ pC->nHdrParsed = i;
+ pC->iHdrOffset = (u32)(zHdr - zData);
+ if( pC->aRow==0 ) sqlite3VdbeMemRelease(&sMem);
}else{
t = 0;
}
@@ -76774,9 +80417,10 @@ case OP_Column: {
assert( p2<pC->nHdrParsed );
assert( rc==SQLITE_OK );
assert( sqlite3VdbeCheckMemInvariants(pDest) );
- if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest);
+ if( VdbeMemDynamic(pDest) ){
+ sqlite3VdbeMemSetNull(pDest);
+ }
assert( t==pC->aType[p2] );
- pDest->enc = encoding;
if( pC->szRow>=aOffset[p2+1] ){
/* This is the common case where the desired content fits on the original
** page - where the content is not on an overflow page */
@@ -76790,6 +80434,7 @@ case OP_Column: {
*/
static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term };
pDest->n = len = (t-12)/2;
+ pDest->enc = encoding;
if( pDest->szMalloc < len+2 ){
pDest->flags = MEM_Null;
if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem;
@@ -76802,6 +80447,7 @@ case OP_Column: {
pDest->flags = aFlag[t&1];
}
}else{
+ pDest->enc = encoding;
/* This branch happens only when content is on overflow pages */
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
@@ -76816,17 +80462,14 @@ case OP_Column: {
static u8 aZero[8]; /* This is the bogus content */
sqlite3VdbeSerialGet(aZero, t, pDest);
}else{
- rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
- pDest);
- if( rc==SQLITE_OK ){
- sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
- pDest->flags &= ~MEM_Ephem;
- }
+ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, aOffset[p2], len, pDest);
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
+ sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
+ pDest->flags &= ~MEM_Ephem;
}
}
op_column_out:
-op_column_error:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
break;
@@ -76850,7 +80493,7 @@ case OP_Affinity: {
assert( zAffinity[pOp->p2]==0 );
pIn1 = &aMem[pOp->p1];
while( (cAff = *(zAffinity++))!=0 ){
- assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] );
+ assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] );
assert( memIsValid(pIn1) );
applyAffinity(pIn1, cAff, encoding);
pIn1++;
@@ -76912,7 +80555,7 @@ case OP_MakeRecord: {
nZero = 0; /* Number of zero bytes at the end of the record */
nField = pOp->p1;
zAffinity = pOp->p4.z;
- assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem-p->nCursor)+1 );
+ assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 );
pData0 = &aMem[nField];
nField = pOp->p2;
pLast = &pData0[nField-1];
@@ -76953,7 +80596,9 @@ case OP_MakeRecord: {
testcase( serial_type==127 );
testcase( serial_type==128 );
nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
- }while( (--pRec)>=pData0 );
+ if( pRec==pData0 ) break;
+ pRec--;
+ }while(1);
/* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
** which determines the total number of bytes in the header. The varint
@@ -77002,7 +80647,7 @@ case OP_MakeRecord: {
assert( i==nHdr );
assert( j==nByte );
- assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pOut->n = (int)nByte;
pOut->flags = MEM_Blob;
if( nZero ){
@@ -77031,6 +80676,7 @@ case OP_Count: { /* out2 */
assert( pCrsr );
nEntry = 0; /* Not needed. Only used to silence a warning. */
rc = sqlite3BtreeCount(pCrsr, &nEntry);
+ if( rc ) goto abort_due_to_error;
pOut = out2Prerelease(p, pOp);
pOut->u.i = nEntry;
break;
@@ -77100,7 +80746,7 @@ case OP_Savepoint: {
}else{
db->nSavepoint++;
}
-
+
/* Link the new savepoint into the database handle's list. */
pNew->pNext = db->pSavepoint;
db->pSavepoint = pNew;
@@ -77208,6 +80854,7 @@ case OP_Savepoint: {
}
}
}
+ if( rc ) goto abort_due_to_error;
break;
}
@@ -77244,7 +80891,7 @@ case OP_AutoCommit: {
sqlite3VdbeError(p, "cannot commit transaction - "
"SQL statements in progress");
rc = SQLITE_BUSY;
- break;
+ goto abort_due_to_error;
}else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
goto vdbe_return;
}else{
@@ -77271,6 +80918,7 @@ case OP_AutoCommit: {
"cannot commit - no transaction is active"));
rc = SQLITE_ERROR;
+ goto abort_due_to_error;
}
break;
}
@@ -77328,12 +80976,12 @@ case OP_Transaction: {
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2);
testcase( rc==SQLITE_BUSY_SNAPSHOT );
testcase( rc==SQLITE_BUSY_RECOVERY );
- if( (rc&0xff)==SQLITE_BUSY ){
- p->pc = (int)(pOp - aOp);
- p->rc = rc;
- goto vdbe_return;
- }
if( rc!=SQLITE_OK ){
+ if( (rc&0xff)==SQLITE_BUSY ){
+ p->pc = (int)(pOp - aOp);
+ p->rc = rc;
+ goto vdbe_return;
+ }
goto abort_due_to_error;
}
@@ -77360,10 +81008,9 @@ case OP_Transaction: {
}
/* Gather the schema version number for checking:
- ** IMPLEMENTATION-OF: R-32195-19465 The schema version is used by SQLite
- ** each time a query is executed to ensure that the internal cache of the
- ** schema used when compiling the SQL query matches the schema of the
- ** database against which the compiled query is actually executed.
+ ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema
+ ** version is checked to ensure that the schema has not changed since the
+ ** SQL statement was prepared.
*/
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
@@ -77393,6 +81040,7 @@ case OP_Transaction: {
p->expired = 1;
rc = SQLITE_SCHEMA;
}
+ if( rc ) goto abort_due_to_error;
break;
}
@@ -77462,6 +81110,7 @@ case OP_SetCookie: {
sqlite3ExpirePreparedStatements(db);
p->expired = 0;
}
+ if( rc ) goto abort_due_to_error;
break;
}
@@ -77559,7 +81208,7 @@ case OP_OpenWrite:
if( p->expired ){
rc = SQLITE_ABORT_ROLLBACK;
- break;
+ goto abort_due_to_error;
}
nField = 0;
@@ -77583,7 +81232,7 @@ case OP_OpenWrite:
}
if( pOp->p5 & OPFLAG_P2ISREG ){
assert( p2>0 );
- assert( p2<=(p->nMem-p->nCursor) );
+ assert( p2<=(p->nMem+1 - p->nCursor) );
pIn2 = &aMem[p2];
assert( memIsValid(pIn2) );
assert( (pIn2->flags & MEM_Int)!=0 );
@@ -77593,10 +81242,7 @@ case OP_OpenWrite:
** that opcode will always set the p2 value to 2 or more or else fail.
** If there were a failure, the prepared statement would have halted
** before reaching this instruction. */
- if( NEVER(p2<2) ) {
- rc = SQLITE_CORRUPT_BKPT;
- goto abort_due_to_error;
- }
+ assert( p2>=2 );
}
if( pOp->p4type==P4_KEYINFO ){
pKeyInfo = pOp->p4.pKeyInfo;
@@ -77634,6 +81280,7 @@ open_cursor_set_hints:
#endif
sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
(pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
+ if( rc ) goto abort_due_to_error;
break;
}
@@ -77680,10 +81327,10 @@ case OP_OpenEphemeral: {
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->isEphemeral = 1;
- rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
+ rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx,
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
if( rc==SQLITE_OK ){
- rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
+ rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1);
}
if( rc==SQLITE_OK ){
/* If a transient index is required, create it by calling
@@ -77691,25 +81338,25 @@ case OP_OpenEphemeral: {
** opening it. If a transient table is required, just use the
** automatically created table with root-page 1 (an BLOB_INTKEY table).
*/
- if( (pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
+ if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
int pgno;
assert( pOp->p4type==P4_KEYINFO );
- rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5);
+ rc = sqlite3BtreeCreateTable(pCx->pBtx, &pgno, BTREE_BLOBKEY | pOp->p5);
if( rc==SQLITE_OK ){
assert( pgno==MASTER_ROOT+1 );
assert( pKeyInfo->db==db );
assert( pKeyInfo->enc==ENC(db) );
- pCx->pKeyInfo = pKeyInfo;
- rc = sqlite3BtreeCursor(pCx->pBt, pgno, BTREE_WRCSR,
+ rc = sqlite3BtreeCursor(pCx->pBtx, pgno, BTREE_WRCSR,
pKeyInfo, pCx->uc.pCursor);
}
pCx->isTable = 0;
}else{
- rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, BTREE_WRCSR,
+ rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR,
0, pCx->uc.pCursor);
pCx->isTable = 1;
}
}
+ if( rc ) goto abort_due_to_error;
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
break;
}
@@ -77735,6 +81382,7 @@ case OP_SorterOpen: {
assert( pCx->pKeyInfo->db==db );
assert( pCx->pKeyInfo->enc==ENC(db) );
rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx);
+ if( rc ) goto abort_due_to_error;
break;
}
@@ -77935,7 +81583,8 @@ case OP_SeekGT: { /* jump, in3 */
if( pC->isTable ){
/* The BTREE_SEEK_EQ flag is only set on index cursors */
- assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0 );
+ assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0
+ || CORRUPT_DB );
/* The input value in P3 might be of any type: integer, real, string,
** blob, or NULL. But it needs to be an integer before we can do
@@ -78022,7 +81671,6 @@ case OP_SeekGT: { /* jump, in3 */
#ifdef SQLITE_DEBUG
{ int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
#endif
- ExpandBlob(r.aMem);
r.eqSeen = 0;
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res);
if( rc!=SQLITE_OK ){
@@ -78070,7 +81718,6 @@ seek_not_found:
}
break;
}
-
/* Opcode: Found P1 P2 P3 P4 *
** Synopsis: key=r[P3@P4]
@@ -78139,10 +81786,9 @@ case OP_Found: { /* jump, in3 */
int ii;
VdbeCursor *pC;
int res;
- char *pFree;
+ UnpackedRecord *pFree;
UnpackedRecord *pIdxKey;
UnpackedRecord r;
- char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*4 + 7];
#ifdef SQLITE_TEST
if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++;
@@ -78159,26 +81805,24 @@ case OP_Found: { /* jump, in3 */
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
assert( pC->isTable==0 );
- pFree = 0;
if( pOp->p4.i>0 ){
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p4.i;
r.aMem = pIn3;
+#ifdef SQLITE_DEBUG
for(ii=0; ii<r.nField; ii++){
assert( memIsValid(&r.aMem[ii]) );
- ExpandBlob(&r.aMem[ii]);
-#ifdef SQLITE_DEBUG
+ assert( (r.aMem[ii].flags & MEM_Zero)==0 || r.aMem[ii].n==0 );
if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]);
-#endif
}
+#endif
pIdxKey = &r;
+ pFree = 0;
}else{
- pIdxKey = sqlite3VdbeAllocUnpackedRecord(
- pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
- );
+ pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
if( pIdxKey==0 ) goto no_mem;
assert( pIn3->flags & MEM_Blob );
- ExpandBlob(pIn3);
+ (void)ExpandBlob(pIn3);
sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
}
pIdxKey->default_rc = 0;
@@ -78195,9 +81839,9 @@ case OP_Found: { /* jump, in3 */
}
}
rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
- sqlite3DbFree(db, pFree);
+ if( pFree ) sqlite3DbFree(db, pFree);
if( rc!=SQLITE_OK ){
- break;
+ goto abort_due_to_error;
}
pC->seekResult = res;
alreadyExists = (res==0);
@@ -78214,6 +81858,30 @@ case OP_Found: { /* jump, in3 */
break;
}
+/* Opcode: SeekRowid P1 P2 P3 * *
+** Synopsis: intkey=r[P3]
+**
+** P1 is the index of a cursor open on an SQL table btree (with integer
+** keys). If register P3 does not contain an integer or if P1 does not
+** contain a record with rowid P3 then jump immediately to P2.
+** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain
+** a record with rowid P3 then
+** leave the cursor pointing at that record and fall through to the next
+** instruction.
+**
+** The OP_NotExists opcode performs the same operation, but with OP_NotExists
+** the P3 register must be guaranteed to contain an integer value. With this
+** opcode, register P3 might not contain an integer.
+**
+** The OP_NotFound opcode performs the same operation on index btrees
+** (with arbitrary multi-value keys).
+**
+** This opcode leaves the cursor in a state where it cannot be advanced
+** in either direction. In other words, the Next and Prev opcodes will
+** not work following this opcode.
+**
+** See also: Found, NotFound, NoConflict, SeekRowid
+*/
/* Opcode: NotExists P1 P2 P3 * *
** Synopsis: intkey=r[P3]
**
@@ -78224,6 +81892,10 @@ case OP_Found: { /* jump, in3 */
** leave the cursor pointing at that record and fall through to the next
** instruction.
**
+** The OP_SeekRowid opcode performs the same operation but also allows the
+** P3 register to contain a non-integer value, in which case the jump is
+** always taken. This opcode requires that P3 always contain an integer.
+**
** The OP_NotFound opcode performs the same operation on index btrees
** (with arbitrary multi-value keys).
**
@@ -78231,15 +81903,22 @@ case OP_Found: { /* jump, in3 */
** in either direction. In other words, the Next and Prev opcodes will
** not work following this opcode.
**
-** See also: Found, NotFound, NoConflict
+** See also: Found, NotFound, NoConflict, SeekRowid
*/
-case OP_NotExists: { /* jump, in3 */
+case OP_SeekRowid: { /* jump, in3 */
VdbeCursor *pC;
BtCursor *pCrsr;
int res;
u64 iKey;
pIn3 = &aMem[pOp->p3];
+ if( (pIn3->flags & MEM_Int)==0 ){
+ applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding);
+ if( (pIn3->flags & MEM_Int)==0 ) goto jump_to_p2;
+ }
+ /* Fall through into OP_NotExists */
+case OP_NotExists: /* jump, in3 */
+ pIn3 = &aMem[pOp->p3];
assert( pIn3->flags & MEM_Int );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
@@ -78269,6 +81948,7 @@ case OP_NotExists: { /* jump, in3 */
goto jump_to_p2;
}
}
+ if( rc ) goto abort_due_to_error;
break;
}
@@ -78356,8 +82036,7 @@ case OP_NewRowid: { /* out2 */
v = 1; /* IMP: R-61914-48074 */
}else{
assert( sqlite3BtreeCursorIsValid(pC->uc.pCursor) );
- rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
- assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */
+ v = sqlite3BtreeIntegerKey(pC->uc.pCursor);
if( v>=MAX_ROWID ){
pC->useRandomRowid = 1;
}else{
@@ -78377,7 +82056,7 @@ case OP_NewRowid: { /* out2 */
pMem = &pFrame->aMem[pOp->p3];
}else{
/* Assert that P3 is a valid memory cell. */
- assert( pOp->p3<=(p->nMem-p->nCursor) );
+ assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
pMem = &aMem[pOp->p3];
memAboutToChange(p, pMem);
}
@@ -78387,7 +82066,7 @@ case OP_NewRowid: { /* out2 */
sqlite3VdbeMemIntegerify(pMem);
assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */
if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
- rc = SQLITE_FULL; /* IMP: R-12275-61338 */
+ rc = SQLITE_FULL; /* IMP: R-17817-00630 */
goto abort_due_to_error;
}
if( v<pMem->u.i+1 ){
@@ -78411,7 +82090,8 @@ case OP_NewRowid: { /* out2 */
0, &res))==SQLITE_OK)
&& (res==0)
&& (++cnt<100));
- if( rc==SQLITE_OK && res==0 ){
+ if( rc ) goto abort_due_to_error;
+ if( res==0 ){
rc = SQLITE_FULL; /* IMP: R-38219-53002 */
goto abort_due_to_error;
}
@@ -78438,22 +82118,19 @@ case OP_NewRowid: { /* out2 */
** then rowid is stored for subsequent return by the
** sqlite3_last_insert_rowid() function (otherwise it is unmodified).
**
-** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of
-** the last seek operation (OP_NotExists) was a success, then this
-** operation will not attempt to find the appropriate row before doing
-** the insert but will instead overwrite the row that the cursor is
-** currently pointing to. Presumably, the prior OP_NotExists opcode
-** has already positioned the cursor correctly. This is an optimization
-** that boosts performance by avoiding redundant seeks.
+** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
+** run faster by avoiding an unnecessary seek on cursor P1. However,
+** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
+** seeks on the cursor or if the most recent seek used a key equal to P3.
**
** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an
** UPDATE operation. Otherwise (if the flag is clear) then this opcode
** is part of an INSERT operation. The difference is only important to
** the update hook.
**
-** Parameter P4 may point to a string containing the table-name, or
-** may be NULL. If it is not NULL, then the update-hook
-** (sqlite3.xUpdateCallback) is invoked following a successful insert.
+** Parameter P4 may point to a Table structure, or may be NULL. If it is
+** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked
+** following a successful insert.
**
** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
** allocated, then ownership of P2 is transferred to the pseudo-cursor
@@ -78465,7 +82142,7 @@ case OP_NewRowid: { /* out2 */
** for indices is OP_IdxInsert.
*/
/* Opcode: InsertInt P1 P2 P3 P4 P5
-** Synopsis: intkey=P3 data=r[P2]
+** Synopsis: intkey=P3 data=r[P2]
**
** This works exactly like OP_Insert except that the key is the
** integer value P3, not the value of the integer stored in register P3.
@@ -78474,14 +82151,14 @@ case OP_Insert:
case OP_InsertInt: {
Mem *pData; /* MEM cell holding data for the record to be inserted */
Mem *pKey; /* MEM cell holding key for the record */
- i64 iKey; /* The integer ROWID or key for the record to be inserted */
VdbeCursor *pC; /* Cursor to table into which insert is written */
- int nZero; /* Number of zero-bytes to append */
int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */
const char *zDb; /* database name - used by the update hook */
- const char *zTbl; /* Table name - used by the opdate hook */
+ Table *pTab; /* Table structure - used by update and pre-update hooks */
int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */
+ BtreePayload x; /* Payload to be inserted */
+ op = 0;
pData = &aMem[pOp->p2];
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( memIsValid(pData) );
@@ -78490,6 +82167,7 @@ case OP_InsertInt: {
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
assert( pC->isTable );
+ assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
REGISTER_TRACE(pOp->p2, pData);
if( pOp->opcode==OP_Insert ){
@@ -78497,46 +82175,66 @@ case OP_InsertInt: {
assert( pKey->flags & MEM_Int );
assert( memIsValid(pKey) );
REGISTER_TRACE(pOp->p3, pKey);
- iKey = pKey->u.i;
+ x.nKey = pKey->u.i;
}else{
assert( pOp->opcode==OP_InsertInt );
- iKey = pOp->p3;
+ x.nKey = pOp->p3;
+ }
+
+ if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
+ assert( pC->isTable );
+ assert( pC->iDb>=0 );
+ zDb = db->aDb[pC->iDb].zDbSName;
+ pTab = pOp->p4.pTab;
+ assert( HasRowid(pTab) );
+ op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
+ }else{
+ pTab = 0; /* Not needed. Silence a comiler warning. */
+ zDb = 0; /* Not needed. Silence a compiler warning. */
+ }
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ /* Invoke the pre-update hook, if any */
+ if( db->xPreUpdateCallback
+ && pOp->p4type==P4_TABLE
+ && !(pOp->p5 & OPFLAG_ISUPDATE)
+ ){
+ sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey, pOp->p2);
}
+#endif
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = iKey;
+ if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = x.nKey;
if( pData->flags & MEM_Null ){
- pData->z = 0;
- pData->n = 0;
+ x.pData = 0;
+ x.nData = 0;
}else{
assert( pData->flags & (MEM_Blob|MEM_Str) );
+ x.pData = pData->z;
+ x.nData = pData->n;
}
seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
if( pData->flags & MEM_Zero ){
- nZero = pData->u.nZero;
+ x.nZero = pData->u.nZero;
}else{
- nZero = 0;
+ x.nZero = 0;
}
- rc = sqlite3BtreeInsert(pC->uc.pCursor, 0, iKey,
- pData->z, pData->n, nZero,
+ x.pKey = 0;
+ rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
(pOp->p5 & OPFLAG_APPEND)!=0, seekResult
);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
/* Invoke the update-hook if required. */
- if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
- zDb = db->aDb[pC->iDb].zName;
- zTbl = pOp->p4.z;
- op = ((pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT);
- assert( pC->isTable );
- db->xUpdateCallback(db->pUpdateArg, op, zDb, zTbl, iKey);
- assert( pC->iDb>=0 );
+ if( rc ) goto abort_due_to_error;
+ if( db->xUpdateCallback && op ){
+ db->xUpdateCallback(db->pUpdateArg, op, zDb, pTab->zName, x.nKey);
}
break;
}
-/* Opcode: Delete P1 P2 * P4 P5
+/* Opcode: Delete P1 P2 P3 P4 P5
**
** Delete the record at which the P1 cursor is currently pointing.
**
@@ -78560,15 +82258,24 @@ case OP_InsertInt: {
** P1 must not be pseudo-table. It has to be a real table with
** multiple rows.
**
-** If P4 is not NULL, then it is the name of the table that P1 is
-** pointing to. The update hook will be invoked, if it exists.
-** If P4 is not NULL then the P1 cursor must have been positioned
-** using OP_NotFound prior to invoking this opcode.
+** If P4 is not NULL then it points to a Table object. In this case either
+** the update or pre-update hook, or both, may be invoked. The P1 cursor must
+** have been positioned using OP_NotFound prior to invoking this opcode in
+** this case. Specifically, if one is configured, the pre-update hook is
+** invoked if P4 is not NULL. The update-hook is invoked if one is configured,
+** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2.
+**
+** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address
+** of the memory cell that contains the value that the rowid of the row will
+** be set to by the update.
*/
case OP_Delete: {
VdbeCursor *pC;
- u8 hasUpdateCallback;
+ const char *zDb;
+ Table *pTab;
+ int opflags;
+ opflags = pOp->p2;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
@@ -78576,22 +82283,47 @@ case OP_Delete: {
assert( pC->uc.pCursor!=0 );
assert( pC->deferredMoveto==0 );
- hasUpdateCallback = db->xUpdateCallback && pOp->p4.z && pC->isTable;
- if( pOp->p5 && hasUpdateCallback ){
- sqlite3BtreeKeySize(pC->uc.pCursor, &pC->movetoTarget);
- }
-
#ifdef SQLITE_DEBUG
- /* The seek operation that positioned the cursor prior to OP_Delete will
- ** have also set the pC->movetoTarget field to the rowid of the row that
- ** is being deleted */
- if( pOp->p4.z && pC->isTable && pOp->p5==0 ){
- i64 iKey = 0;
- sqlite3BtreeKeySize(pC->uc.pCursor, &iKey);
- assert( pC->movetoTarget==iKey );
+ if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){
+ /* If p5 is zero, the seek operation that positioned the cursor prior to
+ ** OP_Delete will have also set the pC->movetoTarget field to the rowid of
+ ** the row that is being deleted */
+ i64 iKey = sqlite3BtreeIntegerKey(pC->uc.pCursor);
+ assert( pC->movetoTarget==iKey );
}
#endif
+ /* If the update-hook or pre-update-hook will be invoked, set zDb to
+ ** the name of the db to pass as to it. Also set local pTab to a copy
+ ** of p4.pTab. Finally, if p5 is true, indicating that this cursor was
+ ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set
+ ** VdbeCursor.movetoTarget to the current rowid. */
+ if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
+ assert( pC->iDb>=0 );
+ assert( pOp->p4.pTab!=0 );
+ zDb = db->aDb[pC->iDb].zDbSName;
+ pTab = pOp->p4.pTab;
+ if( (pOp->p5 & OPFLAG_SAVEPOSITION)!=0 && pC->isTable ){
+ pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor);
+ }
+ }else{
+ zDb = 0; /* Not needed. Silence a compiler warning. */
+ pTab = 0; /* Not needed. Silence a compiler warning. */
+ }
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ /* Invoke the pre-update-hook if required. */
+ if( db->xPreUpdateCallback && pOp->p4.pTab && HasRowid(pTab) ){
+ assert( !(opflags & OPFLAG_ISUPDATE) || (aMem[pOp->p3].flags & MEM_Int) );
+ sqlite3VdbePreUpdateHook(p, pC,
+ (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
+ zDb, pTab, pC->movetoTarget,
+ pOp->p3
+ );
+ }
+ if( opflags & OPFLAG_ISNOOP ) break;
+#endif
+
/* Only flags that can be set are SAVEPOISTION and AUXDELETE */
assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 );
assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION );
@@ -78613,14 +82345,19 @@ case OP_Delete: {
rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
pC->cacheStatus = CACHE_STALE;
+ pC->seekResult = 0;
+ if( rc ) goto abort_due_to_error;
/* Invoke the update-hook if required. */
- if( rc==SQLITE_OK && hasUpdateCallback ){
- db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE,
- db->aDb[pC->iDb].zName, pOp->p4.z, pC->movetoTarget);
- assert( pC->iDb>=0 );
+ if( opflags & OPFLAG_NCHANGE ){
+ p->nChange++;
+ if( db->xUpdateCallback && HasRowid(pTab) ){
+ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,
+ pC->movetoTarget);
+ assert( pC->iDb>=0 );
+ }
}
- if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
+
break;
}
/* Opcode: ResetCount * * * * *
@@ -78637,7 +82374,7 @@ case OP_ResetCount: {
}
/* Opcode: SorterCompare P1 P2 P3 P4
-** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2
+** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2
**
** P1 is a sorter cursor. This instruction compares a prefix of the
** record blob in register P3 against a prefix of the entry that
@@ -78664,6 +82401,7 @@ case OP_SorterCompare: {
res = 0;
rc = sqlite3VdbeSorterCompare(pC, pIn3, nKeyCol, &res);
VdbeBranchTaken(res!=0,2);
+ if( rc ) goto abort_due_to_error;
if( res ) goto jump_to_p2;
break;
};
@@ -78689,6 +82427,7 @@ case OP_SorterData: {
rc = sqlite3VdbeSorterRowkey(pC, pOut);
assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ if( rc ) goto abort_due_to_error;
p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE;
break;
}
@@ -78696,50 +82435,39 @@ case OP_SorterData: {
/* Opcode: RowData P1 P2 * * *
** Synopsis: r[P2]=data
**
-** Write into register P2 the complete row data for cursor P1.
+** Write into register P2 the complete row content for the row at
+** which cursor P1 is currently pointing.
** There is no interpretation of the data.
** It is just copied onto the P2 register exactly as
** it is found in the database file.
**
-** If the P1 cursor must be pointing to a valid row (not a NULL row)
-** of a real table, not a pseudo-table.
-*/
-/* Opcode: RowKey P1 P2 * * *
-** Synopsis: r[P2]=key
-**
-** Write into register P2 the complete row key for cursor P1.
-** There is no interpretation of the data.
-** The key is copied onto the P2 register exactly as
-** it is found in the database file.
+** If cursor P1 is an index, then the content is the key of the row.
+** If cursor P2 is a table, then the content extracted is the data.
**
** If the P1 cursor must be pointing to a valid row (not a NULL row)
** of a real table, not a pseudo-table.
*/
-case OP_RowKey:
case OP_RowData: {
VdbeCursor *pC;
BtCursor *pCrsr;
u32 n;
- i64 n64;
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
- /* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
assert( isSorter(pC)==0 );
- assert( pC->isTable || pOp->opcode!=OP_RowData );
- assert( pC->isTable==0 || pOp->opcode==OP_RowData );
assert( pC->nullRow==0 );
assert( pC->uc.pCursor!=0 );
pCrsr = pC->uc.pCursor;
- /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or
- ** OP_Rewind/Op_Next with no intervening instructions that might invalidate
- ** the cursor. If this where not the case, on of the following assert()s
+ /* The OP_RowData opcodes always follow OP_NotExists or
+ ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions
+ ** that might invalidate the cursor.
+ ** If this where not the case, on of the following assert()s
** would fail. Should this ever change (because of changes in the code
** generator) then the fix would be to insert a call to
** sqlite3VdbeCursorMoveto().
@@ -78751,20 +82479,9 @@ case OP_RowData: {
if( rc!=SQLITE_OK ) goto abort_due_to_error;
#endif
- if( pC->isTable==0 ){
- assert( !pC->isTable );
- VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
- assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
- if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){
- goto too_big;
- }
- n = (u32)n64;
- }else{
- VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &n);
- assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
- if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
- goto too_big;
- }
+ n = sqlite3BtreePayloadSize(pCrsr);
+ if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ goto too_big;
}
testcase( n==0 );
if( sqlite3VdbeMemClearAndResize(pOut, MAX(n,32)) ){
@@ -78772,11 +82489,8 @@ case OP_RowData: {
}
pOut->n = n;
MemSetTypeFlag(pOut, MEM_Blob);
- if( pC->isTable==0 ){
- rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
- }else{
- rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
- }
+ rc = sqlite3BtreePayload(pCrsr, 0, n, pOut->z);
+ if( rc ) goto abort_due_to_error;
pOut->enc = SQLITE_UTF8; /* In case the blob is ever cast to text */
UPDATE_MAX_BLOBSIZE(pOut);
REGISTER_TRACE(pOp->p2, pOut);
@@ -78817,6 +82531,7 @@ case OP_Rowid: { /* out2 */
assert( pModule->xRowid );
rc = pModule->xRowid(pC->uc.pVCur, &v);
sqlite3VtabImportErrmsg(p, pVtab);
+ if( rc ) goto abort_due_to_error;
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}else{
assert( pC->eCurType==CURTYPE_BTREE );
@@ -78827,8 +82542,7 @@ case OP_Rowid: { /* out2 */
pOut->flags = MEM_Null;
break;
}
- rc = sqlite3BtreeKeySize(pC->uc.pCursor, &v);
- assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */
+ v = sqlite3BtreeIntegerKey(pC->uc.pCursor);
}
pOut->u.i = v;
break;
@@ -78866,6 +82580,13 @@ case OP_NullRow: {
** This opcode leaves the cursor configured to move in reverse order,
** from the end toward the beginning. In other words, the cursor is
** configured to use Prev, not Next.
+**
+** If P3 is -1, then the cursor is positioned at the end of the btree
+** for the purpose of appending a new entry onto the btree. In that
+** case P2 must be 0. It is assumed that the cursor is used only for
+** appending and so if the cursor is valid, then the cursor must already
+** be pointing at the end of the btree and so no changes are made to
+** the cursor.
*/
case OP_Last: { /* jump */
VdbeCursor *pC;
@@ -78879,22 +82600,36 @@ case OP_Last: { /* jump */
pCrsr = pC->uc.pCursor;
res = 0;
assert( pCrsr!=0 );
- rc = sqlite3BtreeLast(pCrsr, &res);
- pC->nullRow = (u8)res;
- pC->deferredMoveto = 0;
- pC->cacheStatus = CACHE_STALE;
pC->seekResult = pOp->p3;
#ifdef SQLITE_DEBUG
pC->seekOp = OP_Last;
#endif
- if( pOp->p2>0 ){
- VdbeBranchTaken(res!=0,2);
- if( res ) goto jump_to_p2;
+ if( pOp->p3==0 || !sqlite3BtreeCursorIsValidNN(pCrsr) ){
+ rc = sqlite3BtreeLast(pCrsr, &res);
+ pC->nullRow = (u8)res;
+ pC->deferredMoveto = 0;
+ pC->cacheStatus = CACHE_STALE;
+ if( rc ) goto abort_due_to_error;
+ if( pOp->p2>0 ){
+ VdbeBranchTaken(res!=0,2);
+ if( res ) goto jump_to_p2;
+ }
+ }else{
+ assert( pOp->p2==0 );
}
break;
}
+/* Opcode: SorterSort P1 P2 * * *
+**
+** After all records have been inserted into the Sorter object
+** identified by P1, invoke this opcode to actually do the sorting.
+** Jump to P2 if there are no records to be sorted.
+**
+** This opcode is an alias for OP_Sort and OP_Rewind that is used
+** for Sorter objects.
+*/
/* Opcode: Sort P1 P2 * * *
**
** This opcode does exactly the same thing as OP_Rewind except that
@@ -78951,6 +82686,7 @@ case OP_Rewind: { /* jump */
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
}
+ if( rc ) goto abort_due_to_error;
pC->nullRow = (u8)res;
assert( pOp->p2>0 && pOp->p2<p->nOp );
VdbeBranchTaken(res!=0,2);
@@ -79021,6 +82757,13 @@ case OP_Rewind: { /* jump */
** This opcode works just like Prev except that if cursor P1 is not
** open it behaves a no-op.
*/
+/* Opcode: SorterNext P1 P2 * * P5
+**
+** This opcode works just like OP_Next except that P1 must be a
+** sorter object for which the OP_SorterSort opcode has been
+** invoked. This opcode advances the cursor to the next sorted
+** record, or jumps to P2 if there are no more sorted records.
+*/
case OP_SorterNext: { /* jump */
VdbeCursor *pC;
int res;
@@ -79063,6 +82806,7 @@ case OP_Next: /* jump */
next_tail:
pC->cacheStatus = CACHE_STALE;
VdbeBranchTaken(res==0,2);
+ if( rc ) goto abort_due_to_error;
if( res==0 ){
pC->nullRow = 0;
p->aCounter[pOp->p5]++;
@@ -79076,32 +82820,45 @@ next_tail:
goto check_for_interrupt;
}
-/* Opcode: IdxInsert P1 P2 P3 * P5
+/* Opcode: IdxInsert P1 P2 P3 P4 P5
** Synopsis: key=r[P2]
**
** Register P2 holds an SQL index key made using the
** MakeRecord instructions. This opcode writes that key
** into the index P1. Data for the entry is nil.
**
-** P3 is a flag that provides a hint to the b-tree layer that this
-** insert is likely to be an append.
+** If P4 is not zero, then it is the number of values in the unpacked
+** key of reg(P2). In that case, P3 is the index of the first register
+** for the unpacked key. The availability of the unpacked key can sometimes
+** be an optimization.
+**
+** If P5 has the OPFLAG_APPEND bit set, that is a hint to the b-tree layer
+** that this insert is likely to be an append.
**
** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is
** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear,
** then the change counter is unchanged.
**
-** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have
-** just done a seek to the spot where the new entry is to be inserted.
-** This flag avoids doing an extra seek.
+** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
+** run faster by avoiding an unnecessary seek on cursor P1. However,
+** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
+** seeks on the cursor or if the most recent seek used a key equivalent
+** to P2.
**
** This instruction only works for indices. The equivalent instruction
** for tables is OP_Insert.
*/
+/* Opcode: SorterInsert P1 P2 * * *
+** Synopsis: key=r[P2]
+**
+** Register P2 holds an SQL index key made using the
+** MakeRecord instructions. This opcode writes that key
+** into the sorter P1. Data for the entry is nil.
+*/
case OP_SorterInsert: /* in2 */
case OP_IdxInsert: { /* in2 */
VdbeCursor *pC;
- int nKey;
- const char *zKey;
+ BtreePayload x;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
@@ -79113,19 +82870,22 @@ case OP_IdxInsert: { /* in2 */
assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert );
assert( pC->isTable==0 );
rc = ExpandBlob(pIn2);
- if( rc==SQLITE_OK ){
- if( pOp->opcode==OP_SorterInsert ){
- rc = sqlite3VdbeSorterWrite(pC, pIn2);
- }else{
- nKey = pIn2->n;
- zKey = pIn2->z;
- rc = sqlite3BtreeInsert(pC->uc.pCursor, zKey, nKey, "", 0, 0, pOp->p3,
- ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
- );
- assert( pC->deferredMoveto==0 );
- pC->cacheStatus = CACHE_STALE;
- }
+ if( rc ) goto abort_due_to_error;
+ if( pOp->opcode==OP_SorterInsert ){
+ rc = sqlite3VdbeSorterWrite(pC, pIn2);
+ }else{
+ x.nKey = pIn2->n;
+ x.pKey = pIn2->z;
+ x.aMem = aMem + pOp->p3;
+ x.nMem = (u16)pOp->p4.i;
+ rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
+ (pOp->p5 & OPFLAG_APPEND)!=0,
+ ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
+ );
+ assert( pC->deferredMoveto==0 );
+ pC->cacheStatus = CACHE_STALE;
}
+ if( rc) goto abort_due_to_error;
break;
}
@@ -79143,7 +82903,7 @@ case OP_IdxDelete: {
UnpackedRecord r;
assert( pOp->p3>0 );
- assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem-p->nCursor)+1 );
+ assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem+1 - p->nCursor)+1 );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
@@ -79156,16 +82916,19 @@ case OP_IdxDelete: {
r.default_rc = 0;
r.aMem = &aMem[pOp->p2];
rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
- if( rc==SQLITE_OK && res==0 ){
+ if( rc ) goto abort_due_to_error;
+ if( res==0 ){
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
+ if( rc ) goto abort_due_to_error;
}
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
+ pC->seekResult = 0;
break;
}
/* Opcode: Seek P1 * P3 P4 *
-** Synopsis: Move P3 to P1.rowid
+** Synopsis: Move P3 to P1.rowid
**
** P1 is an open index cursor and P3 is a cursor on the corresponding
** table. This opcode does a deferred seek of the P3 table cursor
@@ -79332,6 +83095,7 @@ case OP_IdxGE: { /* jump */
res++;
}
VdbeBranchTaken(res>0,2);
+ if( rc ) goto abort_due_to_error;
if( res>0 ) goto jump_to_p2;
break;
}
@@ -79367,6 +83131,7 @@ case OP_Destroy: { /* out2 */
if( db->nVdbeRead > db->nVDestroy+1 ){
rc = SQLITE_LOCKED;
p->errorAction = OE_Abort;
+ goto abort_due_to_error;
}else{
iDb = pOp->p3;
assert( DbMaskTest(p->btreeMask, iDb) );
@@ -79374,8 +83139,9 @@ case OP_Destroy: { /* out2 */
rc = sqlite3BtreeDropTable(db->aDb[iDb].pBt, pOp->p1, &iMoved);
pOut->flags = MEM_Int;
pOut->u.i = iMoved;
+ if( rc ) goto abort_due_to_error;
#ifndef SQLITE_OMIT_AUTOVACUUM
- if( rc==SQLITE_OK && iMoved!=0 ){
+ if( iMoved!=0 ){
sqlite3RootPageMoved(db, iDb, iMoved, pOp->p1);
/* All OP_Destroy operations occur on the same btree */
assert( resetSchemaOnFault==0 || resetSchemaOnFault==iDb+1 );
@@ -79421,6 +83187,7 @@ case OP_Clear: {
aMem[pOp->p3].u.i += nChange;
}
}
+ if( rc ) goto abort_due_to_error;
break;
}
@@ -79444,6 +83211,7 @@ case OP_ResetSorter: {
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->isEphemeral );
rc = sqlite3BtreeClearTableOfCursor(pC->uc.pCursor);
+ if( rc ) goto abort_due_to_error;
}
break;
}
@@ -79492,6 +83260,7 @@ case OP_CreateTable: { /* out2 */
flags = BTREE_BLOBKEY;
}
rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
+ if( rc ) goto abort_due_to_error;
pOut->u.i = pgno;
break;
}
@@ -79524,15 +83293,15 @@ case OP_ParseSchema: {
assert( iDb>=0 && iDb<db->nDb );
assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
/* Used to be a conditional */ {
- zMaster = SCHEMA_TABLE(iDb);
+ zMaster = MASTER_NAME;
initData.db = db;
initData.iDb = pOp->p1;
initData.pzErrMsg = &p->zErrMsg;
zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM '%q'.%s WHERE %s ORDER BY rowid",
- db->aDb[iDb].zName, zMaster, pOp->p4.z);
+ db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
if( zSql==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
assert( db->init.busy==0 );
db->init.busy = 1;
@@ -79544,9 +83313,12 @@ case OP_ParseSchema: {
db->init.busy = 0;
}
}
- if( rc ) sqlite3ResetAllSchemasOfConnection(db);
- if( rc==SQLITE_NOMEM ){
- goto no_mem;
+ if( rc ){
+ sqlite3ResetAllSchemasOfConnection(db);
+ if( rc==SQLITE_NOMEM ){
+ goto no_mem;
+ }
+ goto abort_due_to_error;
}
break;
}
@@ -79561,6 +83333,7 @@ case OP_ParseSchema: {
case OP_LoadAnalysis: {
assert( pOp->p1>=0 && pOp->p1<db->nDb );
rc = sqlite3AnalysisLoad(db, pOp->p1);
+ if( rc ) goto abort_due_to_error;
break;
}
#endif /* !defined(SQLITE_OMIT_ANALYZE) */
@@ -79606,7 +83379,7 @@ case OP_DropTrigger: {
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
-/* Opcode: IntegrityCk P1 P2 P3 * P5
+/* Opcode: IntegrityCk P1 P2 P3 P4 P5
**
** Do an analysis of the currently open database. Store in
** register P1 the text of an error message describing any problems.
@@ -79617,9 +83390,8 @@ case OP_DropTrigger: {
** In other words, the analysis stops as soon as reg(P1) errors are
** seen. Reg(P1) is updated with the number of errors remaining.
**
-** The root page numbers of all tables in the database are integer
-** stored in reg(P1), reg(P1+1), reg(P1+2), .... There are P2 tables
-** total.
+** The root page numbers of all tables in the database are integers
+** stored in P4_INTARRAY argument.
**
** If P5 is not zero, the check is done on the auxiliary database
** file, not the main database file.
@@ -79629,30 +83401,24 @@ case OP_DropTrigger: {
case OP_IntegrityCk: {
int nRoot; /* Number of tables to check. (Number of root pages.) */
int *aRoot; /* Array of rootpage numbers for tables to be checked */
- int j; /* Loop counter */
int nErr; /* Number of errors reported */
char *z; /* Text of the error report */
Mem *pnErr; /* Register keeping track of errors remaining */
assert( p->bIsReader );
nRoot = pOp->p2;
+ aRoot = pOp->p4.ai;
assert( nRoot>0 );
- aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(nRoot+1) );
- if( aRoot==0 ) goto no_mem;
- assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
+ assert( aRoot[nRoot]==0 );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pnErr = &aMem[pOp->p3];
assert( (pnErr->flags & MEM_Int)!=0 );
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
pIn1 = &aMem[pOp->p1];
- for(j=0; j<nRoot; j++){
- aRoot[j] = (int)sqlite3VdbeIntValue(&pIn1[j]);
- }
- aRoot[j] = 0;
assert( pOp->p5<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p5) );
z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p5].pBt, aRoot, nRoot,
(int)pnErr->u.i, &nErr);
- sqlite3DbFree(db, aRoot);
pnErr->u.i -= nErr;
sqlite3VdbeMemSetNull(pIn1);
if( nErr==0 ){
@@ -79669,7 +83435,7 @@ case OP_IntegrityCk: {
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
/* Opcode: RowSetAdd P1 P2 * * *
-** Synopsis: rowset(P1)=r[P2]
+** Synopsis: rowset(P1)=r[P2]
**
** Insert the integer value held by register P2 into a boolean index
** held in register P1.
@@ -79689,7 +83455,7 @@ case OP_RowSetAdd: { /* in1, in2 */
}
/* Opcode: RowSetRead P1 P2 P3 * *
-** Synopsis: r[P3]=rowset(P1)
+** Synopsis: r[P3]=rowset(P1)
**
** Extract the smallest value from boolean index P1 and put that value into
** register P3. Or, if boolean index P1 is initially empty, leave P3
@@ -79820,7 +83586,7 @@ case OP_Program: { /* jump */
if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){
rc = SQLITE_ERROR;
sqlite3VdbeError(p, "too many levels of trigger recursion");
- break;
+ goto abort_due_to_error;
}
/* Register pRt is used to store the memory required to save the state
@@ -79834,10 +83600,11 @@ case OP_Program: { /* jump */
** variable nMem (and later, VdbeFrame.nChildMem) to this value.
*/
nMem = pProgram->nMem + pProgram->nCsr;
+ assert( nMem>0 );
+ if( pProgram->nCsr==0 ) nMem++;
nByte = ROUND8(sizeof(VdbeFrame))
+ nMem * sizeof(Mem)
- + pProgram->nCsr * sizeof(VdbeCursor *)
- + pProgram->nOnce * sizeof(u8);
+ + pProgram->nCsr * sizeof(VdbeCursor *);
pFrame = sqlite3DbMallocZero(db, nByte);
if( !pFrame ){
goto no_mem;
@@ -79857,8 +83624,6 @@ case OP_Program: { /* jump */
pFrame->aOp = p->aOp;
pFrame->nOp = p->nOp;
pFrame->token = pProgram->token;
- pFrame->aOnceFlag = p->aOnceFlag;
- pFrame->nOnceFlag = p->nOnceFlag;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
pFrame->anExec = p->anExec;
#endif
@@ -79870,7 +83635,8 @@ case OP_Program: { /* jump */
}
}else{
pFrame = pRt->u.pFrame;
- assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem );
+ assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem
+ || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) );
assert( pProgram->nCsr==pFrame->nChildCsr );
assert( (int)(pOp - aOp)==pFrame->pc );
}
@@ -79880,21 +83646,21 @@ case OP_Program: { /* jump */
pFrame->lastRowid = lastRowid;
pFrame->nChange = p->nChange;
pFrame->nDbChange = p->db->nChange;
+ assert( pFrame->pAuxData==0 );
+ pFrame->pAuxData = p->pAuxData;
+ p->pAuxData = 0;
p->nChange = 0;
p->pFrame = pFrame;
- p->aMem = aMem = &VdbeFrameMem(pFrame)[-1];
+ p->aMem = aMem = VdbeFrameMem(pFrame);
p->nMem = pFrame->nChildMem;
p->nCursor = (u16)pFrame->nChildCsr;
- p->apCsr = (VdbeCursor **)&aMem[p->nMem+1];
+ p->apCsr = (VdbeCursor **)&aMem[p->nMem];
p->aOp = aOp = pProgram->aOp;
p->nOp = pProgram->nOp;
- p->aOnceFlag = (u8 *)&p->apCsr[p->nCursor];
- p->nOnceFlag = pProgram->nOnce;
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
p->anExec = 0;
#endif
pOp = &aOp[-1];
- memset(p->aOnceFlag, 0, p->nOnceFlag);
break;
}
@@ -80038,29 +83804,42 @@ case OP_IfPos: { /* jump, in1 */
** Otherwise, r[P2] is set to the sum of r[P1] and r[P3].
*/
case OP_OffsetLimit: { /* in1, out2, in3 */
+ i64 x;
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
pOut = out2Prerelease(p, pOp);
assert( pIn1->flags & MEM_Int );
assert( pIn3->flags & MEM_Int );
- pOut->u.i = pIn1->u.i<=0 ? -1 : pIn1->u.i+(pIn3->u.i>0?pIn3->u.i:0);
+ x = pIn1->u.i;
+ if( x<=0 || sqlite3AddInt64(&x, pIn3->u.i>0?pIn3->u.i:0) ){
+ /* If the LIMIT is less than or equal to zero, loop forever. This
+ ** is documented. But also, if the LIMIT+OFFSET exceeds 2^63 then
+ ** also loop forever. This is undocumented. In fact, one could argue
+ ** that the loop should terminate. But assuming 1 billion iterations
+ ** per second (far exceeding the capabilities of any current hardware)
+ ** it would take nearly 300 years to actually reach the limit. So
+ ** looping forever is a reasonable approximation. */
+ pOut->u.i = -1;
+ }else{
+ pOut->u.i = x;
+ }
break;
}
-/* Opcode: IfNotZero P1 P2 P3 * *
-** Synopsis: if r[P1]!=0 then r[P1]-=P3, goto P2
+/* Opcode: IfNotZero P1 P2 * * *
+** Synopsis: if r[P1]!=0 then r[P1]--, goto P2
**
** Register P1 must contain an integer. If the content of register P1 is
-** initially nonzero, then subtract P3 from the value in register P1 and
-** jump to P2. If register P1 is initially zero, leave it unchanged
-** and fall through.
+** initially greater than zero, then decrement the value in register P1.
+** If it is non-zero (negative or positive) and then also jump to P2.
+** If register P1 is initially zero, leave it unchanged and fall through.
*/
case OP_IfNotZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
VdbeBranchTaken(pIn1->u.i<0, 2);
if( pIn1->u.i ){
- pIn1->u.i -= pOp->p3;
+ if( pIn1->u.i>0 ) pIn1->u.i--;
goto jump_to_p2;
}
break;
@@ -80069,34 +83848,19 @@ case OP_IfNotZero: { /* jump, in1 */
/* Opcode: DecrJumpZero P1 P2 * * *
** Synopsis: if (--r[P1])==0 goto P2
**
-** Register P1 must hold an integer. Decrement the value in register P1
-** then jump to P2 if the new value is exactly zero.
+** Register P1 must hold an integer. Decrement the value in P1
+** and jump to P2 if the new value is exactly zero.
*/
case OP_DecrJumpZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int );
- pIn1->u.i--;
+ if( pIn1->u.i>SMALLEST_INT64 ) pIn1->u.i--;
VdbeBranchTaken(pIn1->u.i==0, 2);
if( pIn1->u.i==0 ) goto jump_to_p2;
break;
}
-/* Opcode: JumpZeroIncr P1 P2 * * *
-** Synopsis: if (r[P1]++)==0 ) goto P2
-**
-** The register P1 must contain an integer. If register P1 is initially
-** zero, then jump to P2. Increment register P1 regardless of whether or
-** not the jump is taken.
-*/
-case OP_JumpZeroIncr: { /* jump, in1 */
- pIn1 = &aMem[pOp->p1];
- assert( pIn1->flags&MEM_Int );
- VdbeBranchTaken(pIn1->u.i==0, 2);
- if( (pIn1->u.i++)==0 ) goto jump_to_p2;
- break;
-}
-
/* Opcode: AggStep0 * P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5])
**
@@ -80131,8 +83895,8 @@ case OP_AggStep0: {
assert( pOp->p4type==P4_FUNCDEF );
n = pOp->p5;
- assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
- assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
+ assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*));
if( pCtx==0 ) goto no_mem;
@@ -80184,6 +83948,7 @@ case OP_AggStep: {
rc = pCtx->isError;
}
sqlite3VdbeMemRelease(&t);
+ if( rc ) goto abort_due_to_error;
}else{
assert( t.flags==MEM_Null );
}
@@ -80210,12 +83975,13 @@ case OP_AggStep: {
*/
case OP_AggFinal: {
Mem *pMem;
- assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
pMem = &aMem[pOp->p1];
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
if( rc ){
sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem));
+ goto abort_due_to_error;
}
sqlite3VdbeChangeEncoding(pMem, encoding);
UPDATE_MAX_BLOBSIZE(pMem);
@@ -80251,7 +84017,8 @@ case OP_Checkpoint: {
|| pOp->p2==SQLITE_CHECKPOINT_TRUNCATE
);
rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]);
- if( rc==SQLITE_BUSY ){
+ if( rc ){
+ if( rc!=SQLITE_BUSY ) goto abort_due_to_error;
rc = SQLITE_OK;
aRes[0] = 1;
}
@@ -80324,7 +84091,7 @@ case OP_JournalMode: { /* out2 */
"cannot change %s wal mode from within a transaction",
(eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
);
- break;
+ goto abort_due_to_error;
}else{
if( eOld==PAGER_JOURNALMODE_WAL ){
@@ -80333,7 +84100,7 @@ case OP_JournalMode: { /* out2 */
** file. An EXCLUSIVE lock may still be held on the database file
** after a successful return.
*/
- rc = sqlite3PagerCloseWal(pPager);
+ rc = sqlite3PagerCloseWal(pPager, db);
if( rc==SQLITE_OK ){
sqlite3PagerSetJournalMode(pPager, eNew);
}
@@ -80354,9 +84121,7 @@ case OP_JournalMode: { /* out2 */
}
#endif /* ifndef SQLITE_OMIT_WAL */
- if( rc ){
- eNew = eOld;
- }
+ if( rc ) eNew = eOld;
eNew = sqlite3PagerSetJournalMode(pPager, eNew);
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
@@ -80364,20 +84129,21 @@ case OP_JournalMode: { /* out2 */
pOut->n = sqlite3Strlen30(pOut->z);
pOut->enc = SQLITE_UTF8;
sqlite3VdbeChangeEncoding(pOut, encoding);
+ if( rc ) goto abort_due_to_error;
break;
};
#endif /* SQLITE_OMIT_PRAGMA */
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
-/* Opcode: Vacuum * * * * *
+/* Opcode: Vacuum P1 * * * *
**
-** Vacuum the entire database. This opcode will cause other virtual
-** machines to be created and run. It may not be called from within
-** a transaction.
+** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more
+** for an attached database. The "temp" database may not be vacuumed.
*/
case OP_Vacuum: {
assert( p->readOnly==0 );
- rc = sqlite3RunVacuum(&p->zErrMsg, db);
+ rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1);
+ if( rc ) goto abort_due_to_error;
break;
}
#endif
@@ -80398,7 +84164,8 @@ case OP_IncrVacuum: { /* jump */
pBt = db->aDb[pOp->p1].pBt;
rc = sqlite3BtreeIncrVacuum(pBt);
VdbeBranchTaken(rc==SQLITE_DONE,2);
- if( rc==SQLITE_DONE ){
+ if( rc ){
+ if( rc!=SQLITE_DONE ) goto abort_due_to_error;
rc = SQLITE_OK;
goto jump_to_p2;
}
@@ -80449,9 +84216,12 @@ case OP_TableLock: {
assert( DbMaskTest(p->btreeMask, p1) );
assert( isWriteLock==0 || isWriteLock==1 );
rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock);
- if( (rc&0xFF)==SQLITE_LOCKED ){
- const char *z = pOp->p4.z;
- sqlite3VdbeError(p, "database table is locked: %s", z);
+ if( rc ){
+ if( (rc&0xFF)==SQLITE_LOCKED ){
+ const char *z = pOp->p4.z;
+ sqlite3VdbeError(p, "database table is locked: %s", z);
+ }
+ goto abort_due_to_error;
}
}
break;
@@ -80473,6 +84243,7 @@ case OP_VBegin: {
pVTab = pOp->p4.pVtab;
rc = sqlite3VtabBegin(db, pVTab);
if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab);
+ if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -80501,6 +84272,7 @@ case OP_VCreate: {
rc = sqlite3VtabCallCreate(db, pOp->p1, zTab, &p->zErrMsg);
}
sqlite3VdbeMemRelease(&sMem);
+ if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -80515,6 +84287,7 @@ case OP_VDestroy: {
db->nVDestroy++;
rc = sqlite3VtabCallDestroy(db, pOp->p1, pOp->p4.z);
db->nVDestroy--;
+ if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -80538,25 +84311,25 @@ case OP_VOpen: {
pVtab = pOp->p4.pVtab->pVtab;
if( pVtab==0 || NEVER(pVtab->pModule==0) ){
rc = SQLITE_LOCKED;
- break;
+ goto abort_due_to_error;
}
pModule = pVtab->pModule;
rc = pModule->xOpen(pVtab, &pVCur);
sqlite3VtabImportErrmsg(p, pVtab);
- if( SQLITE_OK==rc ){
- /* Initialize sqlite3_vtab_cursor base class */
- pVCur->pVtab = pVtab;
+ if( rc ) goto abort_due_to_error;
- /* Initialize vdbe cursor object */
- pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB);
- if( pCur ){
- pCur->uc.pVCur = pVCur;
- pVtab->nRef++;
- }else{
- assert( db->mallocFailed );
- pModule->xClose(pVCur);
- goto no_mem;
- }
+ /* Initialize sqlite3_vtab_cursor base class */
+ pVCur->pVtab = pVtab;
+
+ /* Initialize vdbe cursor object */
+ pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB);
+ if( pCur ){
+ pCur->uc.pVCur = pVCur;
+ pVtab->nRef++;
+ }else{
+ assert( db->mallocFailed );
+ pModule->xClose(pVCur);
+ goto no_mem;
}
break;
}
@@ -80618,9 +84391,8 @@ case OP_VFilter: { /* jump */
}
rc = pModule->xFilter(pVCur, iQuery, pOp->p4.z, nArg, apArg);
sqlite3VtabImportErrmsg(p, pVtab);
- if( rc==SQLITE_OK ){
- res = pModule->xEof(pVCur);
- }
+ if( rc ) goto abort_due_to_error;
+ res = pModule->xEof(pVCur);
pCur->nullRow = 0;
VdbeBranchTaken(res!=0,2);
if( res ) goto jump_to_p2;
@@ -80644,7 +84416,7 @@ case OP_VColumn: {
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur->eCurType==CURTYPE_VTAB );
- assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
if( pCur->nullRow ){
@@ -80669,6 +84441,7 @@ case OP_VColumn: {
if( sqlite3VdbeMemTooBig(pDest) ){
goto too_big;
}
+ if( rc ) goto abort_due_to_error;
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -80704,9 +84477,8 @@ case OP_VNext: { /* jump */
*/
rc = pModule->xNext(pCur->uc.pVCur);
sqlite3VtabImportErrmsg(p, pVtab);
- if( rc==SQLITE_OK ){
- res = pModule->xEof(pCur->uc.pVCur);
- }
+ if( rc ) goto abort_due_to_error;
+ res = pModule->xEof(pCur->uc.pVCur);
VdbeBranchTaken(!res,2);
if( !res ){
/* If there is data, jump to P2 */
@@ -80738,11 +84510,11 @@ case OP_VRename: {
testcase( pName->enc==SQLITE_UTF16BE );
testcase( pName->enc==SQLITE_UTF16LE );
rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
- if( rc==SQLITE_OK ){
- rc = pVtab->pModule->xRename(pVtab, pName->z);
- sqlite3VtabImportErrmsg(p, pVtab);
- p->expired = 0;
- }
+ if( rc ) goto abort_due_to_error;
+ rc = pVtab->pModule->xRename(pVtab, pName->z);
+ sqlite3VtabImportErrmsg(p, pVtab);
+ p->expired = 0;
+ if( rc ) goto abort_due_to_error;
break;
}
#endif
@@ -80791,7 +84563,7 @@ case OP_VUpdate: {
pVtab = pOp->p4.pVtab->pVtab;
if( pVtab==0 || NEVER(pVtab->pModule==0) ){
rc = SQLITE_LOCKED;
- break;
+ goto abort_due_to_error;
}
pModule = pVtab->pModule;
nArg = pOp->p2;
@@ -80823,6 +84595,7 @@ case OP_VUpdate: {
}else{
p->nChange++;
}
+ if( rc ) goto abort_due_to_error;
}
break;
}
@@ -80867,8 +84640,8 @@ case OP_MaxPgcnt: { /* out2 */
#endif
-/* Opcode: Init * P2 * P4 *
-** Synopsis: Start at P2
+/* Opcode: Init P1 P2 * P4 *
+** Synopsis: Start at P2
**
** Programs contain a single instance of this opcode as the very first
** opcode.
@@ -80878,27 +84651,50 @@ case OP_MaxPgcnt: { /* out2 */
** Or if P4 is blank, use the string returned by sqlite3_sql().
**
** If P2 is not zero, jump to instruction P2.
+**
+** Increment the value of P1 so that OP_Once opcodes will jump the
+** first time they are evaluated for this run.
*/
case OP_Init: { /* jump */
char *zTrace;
- char *z;
+ int i;
+
+ /* If the P4 argument is not NULL, then it must be an SQL comment string.
+ ** The "--" string is broken up to prevent false-positives with srcck1.c.
+ **
+ ** This assert() provides evidence for:
+ ** EVIDENCE-OF: R-50676-09860 The callback can compute the same text that
+ ** would have been returned by the legacy sqlite3_trace() interface by
+ ** using the X argument when X begins with "--" and invoking
+ ** sqlite3_expanded_sql(P) otherwise.
+ */
+ assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 );
+ assert( pOp==p->aOp ); /* Always instruction 0 */
#ifndef SQLITE_OMIT_TRACE
- if( db->xTrace
+ if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
&& !p->doingRerun
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
){
- z = sqlite3VdbeExpandSql(p, zTrace);
- db->xTrace(db->pTraceArg, z);
- sqlite3DbFree(db, z);
+#ifndef SQLITE_OMIT_DEPRECATED
+ if( db->mTrace & SQLITE_TRACE_LEGACY ){
+ void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
+ char *z = sqlite3VdbeExpandSql(p, zTrace);
+ x(db->pTraceArg, z);
+ sqlite3_free(z);
+ }else
+#endif
+ {
+ (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
+ }
}
#ifdef SQLITE_USE_FCNTL_TRACE
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
if( zTrace ){
- int i;
- for(i=0; i<db->nDb; i++){
- if( DbMaskTest(p->btreeMask, i)==0 ) continue;
- sqlite3_file_control(db, db->aDb[i].zName, SQLITE_FCNTL_TRACE, zTrace);
+ int j;
+ for(j=0; j<db->nDb; j++){
+ if( DbMaskTest(p->btreeMask, j)==0 ) continue;
+ sqlite3_file_control(db, db->aDb[j].zDbSName, SQLITE_FCNTL_TRACE, zTrace);
}
}
#endif /* SQLITE_USE_FCNTL_TRACE */
@@ -80910,8 +84706,15 @@ case OP_Init: { /* jump */
}
#endif /* SQLITE_DEBUG */
#endif /* SQLITE_OMIT_TRACE */
- if( pOp->p2 ) goto jump_to_p2;
- break;
+ assert( pOp->p2>0 );
+ if( pOp->p1>=sqlite3GlobalConfig.iOnceResetThreshold ){
+ for(i=1; i<p->nOp; i++){
+ if( p->aOp[i].opcode==OP_Once ) p->aOp[i].p1 = 0;
+ }
+ pOp->p1 = 0;
+ }
+ pOp->p1++;
+ goto jump_to_p2;
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
@@ -80979,11 +84782,12 @@ default: { /* This is really OP_Noop and OP_Explain */
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeTrace ){
+ u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode];
if( rc!=0 ) printf("rc=%d\n",rc);
- if( pOrigOp->opflags & (OPFLG_OUT2) ){
+ if( opProperty & (OPFLG_OUT2) ){
registerTrace(pOrigOp->p2, &aMem[pOrigOp->p2]);
}
- if( pOrigOp->opflags & OPFLG_OUT3 ){
+ if( opProperty & OPFLG_OUT3 ){
registerTrace(pOrigOp->p3, &aMem[pOrigOp->p3]);
}
}
@@ -80994,9 +84798,14 @@ default: { /* This is really OP_Noop and OP_Explain */
/* If we reach this point, it means that execution is finished with
** an error of some kind.
*/
-vdbe_error_halt:
+abort_due_to_error:
+ if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT;
assert( rc );
+ if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
+ sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
+ }
p->rc = rc;
+ sqlite3SystemError(db, rc);
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(rc, "statement aborts at %d: [%s] %s",
(int)(pOp - aOp), p->zSql, p->zErrMsg);
@@ -81026,36 +84835,25 @@ vdbe_return:
too_big:
sqlite3VdbeError(p, "string or blob too big");
rc = SQLITE_TOOBIG;
- goto vdbe_error_halt;
+ goto abort_due_to_error;
/* Jump to here if a malloc() fails.
*/
no_mem:
sqlite3OomFault(db);
sqlite3VdbeError(p, "out of memory");
- rc = SQLITE_NOMEM;
- goto vdbe_error_halt;
-
- /* Jump to here for any other kind of fatal error. The "rc" variable
- ** should hold the error number.
- */
-abort_due_to_error:
- assert( p->zErrMsg==0 );
- if( db->mallocFailed ) rc = SQLITE_NOMEM;
- if( rc!=SQLITE_IOERR_NOMEM ){
- sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
- }
- goto vdbe_error_halt;
+ rc = SQLITE_NOMEM_BKPT;
+ goto abort_due_to_error;
/* Jump to here if the sqlite3_interrupt() API sets the interrupt
** flag.
*/
abort_due_to_interrupt:
assert( db->u1.isInterrupted );
- rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_INTERRUPT;
+ rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
p->rc = rc;
sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
- goto vdbe_error_halt;
+ goto abort_due_to_error;
}
@@ -81093,6 +84891,8 @@ struct Incrblob {
BtCursor *pCsr; /* Cursor pointing at blob row */
sqlite3_stmt *pStmt; /* Statement holding cursor open */
sqlite3 *db; /* The associated database */
+ char *zDb; /* Database name */
+ Table *pTab; /* Table object */
};
@@ -81167,7 +84967,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
/*
** Open a blob handle.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
+SQLITE_API int sqlite3_blob_open(
sqlite3* db, /* The database connection */
const char *zDb, /* The attached database containing the blob */
const char *zTable, /* The table containing the blob */
@@ -81236,6 +85036,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
sqlite3BtreeLeaveAll(db);
goto blob_open_out;
}
+ pBlob->pTab = pTab;
+ pBlob->zDb = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName;
/* Now search pTab for the exact column. */
for(iCol=0; iCol<pTab->nCol; iCol++) {
@@ -81321,8 +85123,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
{OP_Column, 0, 0, 1}, /* 4 */
{OP_ResultRow, 1, 0, 0}, /* 5 */
{OP_Goto, 0, 2, 0}, /* 6 */
- {OP_Close, 0, 0, 0}, /* 7 */
- {OP_Halt, 0, 0, 0}, /* 8 */
+ {OP_Halt, 0, 0, 0}, /* 7 */
};
Vdbe *v = (Vdbe *)pBlob->pStmt;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -81406,7 +85207,7 @@ blob_open_out:
** Close a blob handle that was previously created using
** sqlite3_blob_open().
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *pBlob){
+SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
int rc;
sqlite3 *db;
@@ -81457,6 +85258,30 @@ static int blobReadWrite(
*/
assert( db == v->db );
sqlite3BtreeEnterCursor(p->pCsr);
+
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){
+ /* If a pre-update hook is registered and this is a write cursor,
+ ** invoke it here.
+ **
+ ** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this
+ ** operation should really be an SQLITE_UPDATE. This is probably
+ ** incorrect, but is convenient because at this point the new.* values
+ ** are not easily obtainable. And for the sessions module, an
+ ** SQLITE_UPDATE where the PK columns do not change is handled in the
+ ** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually
+ ** slightly more efficient). Since you cannot write to a PK column
+ ** using the incremental-blob API, this works. For the sessions module
+ ** anyhow.
+ */
+ sqlite3_int64 iKey;
+ iKey = sqlite3BtreeIntegerKey(p->pCsr);
+ sqlite3VdbePreUpdateHook(
+ v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1
+ );
+ }
+#endif
+
rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
sqlite3BtreeLeaveCursor(p->pCsr);
if( rc==SQLITE_ABORT ){
@@ -81475,14 +85300,14 @@ static int blobReadWrite(
/*
** Read data from a blob handle.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
- return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
+SQLITE_API int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
+ return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreePayloadChecked);
}
/*
** Write data to a blob handle.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
+SQLITE_API int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
}
@@ -81492,7 +85317,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *pBlob, const void
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
** so no mutex is required for access.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){
+SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
return (p && p->pStmt) ? p->nByte : 0;
}
@@ -81507,7 +85332,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *pBlob){
** subsequent calls to sqlite3_blob_xxx() functions (except blob_close())
** immediately return SQLITE_ABORT.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
+SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
int rc;
Incrblob *p = (Incrblob *)pBlob;
sqlite3 *db;
@@ -82083,7 +85908,7 @@ static int vdbePmaReadBlob(
int nNew = MAX(128, p->nAlloc*2);
while( nByte>nNew ) nNew = nNew*2;
aNew = sqlite3Realloc(p->aAlloc, nNew);
- if( !aNew ) return SQLITE_NOMEM;
+ if( !aNew ) return SQLITE_NOMEM_BKPT;
p->nAlloc = nNew;
p->aAlloc = aNew;
}
@@ -82195,7 +86020,7 @@ static int vdbePmaReaderSeek(
int iBuf = pReadr->iReadOff % pgsz;
if( pReadr->aBuffer==0 ){
pReadr->aBuffer = (u8*)sqlite3Malloc(pgsz);
- if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM;
+ if( pReadr->aBuffer==0 ) rc = SQLITE_NOMEM_BKPT;
pReadr->nBuffer = pgsz;
}
if( rc==SQLITE_OK && iBuf ){
@@ -82474,7 +86299,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
){
int pgsz; /* Page size of main database */
int i; /* Used to iterate through aTask[] */
- int mxCache; /* Cache size */
VdbeSorter *pSorter; /* The new sorter */
KeyInfo *pKeyInfo; /* Copy of pCsr->pKeyInfo with db==0 */
int szKeyInfo; /* Size of pCsr->pKeyInfo in bytes */
@@ -82503,7 +86327,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
}
#endif
- assert( pCsr->pKeyInfo && pCsr->pBt==0 );
+ assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
assert( pCsr->eCurType==CURTYPE_SORTER );
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nField-1)*sizeof(CollSeq*);
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
@@ -82511,7 +86335,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
pCsr->uc.pSorter = pSorter;
if( pSorter==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz);
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
@@ -82531,11 +86355,20 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
}
if( !sqlite3TempInMemory(db) ){
+ i64 mxCache; /* Cache size in bytes*/
u32 szPma = sqlite3GlobalConfig.szPma;
pSorter->mnPmaSize = szPma * pgsz;
+
mxCache = db->aDb[0].pSchema->cache_size;
- if( mxCache<(int)szPma ) mxCache = (int)szPma;
- pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_PMASZ);
+ if( mxCache<0 ){
+ /* A negative cache-size value C indicates that the cache is abs(C)
+ ** KiB in size. */
+ mxCache = mxCache * -1024;
+ }else{
+ mxCache = mxCache * pgsz;
+ }
+ mxCache = MIN(mxCache, SQLITE_MAX_PMASZ);
+ pSorter->mxPmaSize = MAX(pSorter->mnPmaSize, (int)mxCache);
/* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
@@ -82545,7 +86378,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
assert( pSorter->iMemory==0 );
pSorter->nMemory = pgsz;
pSorter->list.aMemory = (u8*)sqlite3Malloc(pgsz);
- if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM;
+ if( !pSorter->list.aMemory ) rc = SQLITE_NOMEM_BKPT;
}
}
@@ -82862,12 +86695,8 @@ static int vdbeSorterOpenTempFile(
*/
static int vdbeSortAllocUnpacked(SortSubtask *pTask){
if( pTask->pUnpacked==0 ){
- char *pFree;
- pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(
- pTask->pSorter->pKeyInfo, 0, 0, &pFree
- );
- assert( pTask->pUnpacked==(UnpackedRecord*)pFree );
- if( pFree==0 ) return SQLITE_NOMEM;
+ pTask->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pTask->pSorter->pKeyInfo);
+ if( pTask->pUnpacked==0 ) return SQLITE_NOMEM_BKPT;
pTask->pUnpacked->nField = pTask->pSorter->pKeyInfo->nField;
pTask->pUnpacked->errCode = 0;
}
@@ -82877,19 +86706,18 @@ static int vdbeSortAllocUnpacked(SortSubtask *pTask){
/*
** Merge the two sorted lists p1 and p2 into a single list.
-** Set *ppOut to the head of the new list.
*/
-static void vdbeSorterMerge(
+static SorterRecord *vdbeSorterMerge(
SortSubtask *pTask, /* Calling thread context */
SorterRecord *p1, /* First list to merge */
- SorterRecord *p2, /* Second list to merge */
- SorterRecord **ppOut /* OUT: Head of merged list */
+ SorterRecord *p2 /* Second list to merge */
){
SorterRecord *pFinal = 0;
SorterRecord **pp = &pFinal;
int bCached = 0;
- while( p1 && p2 ){
+ assert( p1!=0 && p2!=0 );
+ for(;;){
int res;
res = pTask->xCompare(
pTask, &bCached, SRVAL(p1), p1->nVal, SRVAL(p2), p2->nVal
@@ -82899,15 +86727,22 @@ static void vdbeSorterMerge(
*pp = p1;
pp = &p1->u.pNext;
p1 = p1->u.pNext;
+ if( p1==0 ){
+ *pp = p2;
+ break;
+ }
}else{
*pp = p2;
pp = &p2->u.pNext;
p2 = p2->u.pNext;
bCached = 0;
+ if( p2==0 ){
+ *pp = p1;
+ break;
+ }
}
}
- *pp = p1 ? p1 : p2;
- *ppOut = pFinal;
+ return pFinal;
}
/*
@@ -82942,7 +86777,7 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *));
if( !aSlot ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
while( p ){
@@ -82960,7 +86795,7 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
p->u.pNext = 0;
for(i=0; aSlot[i]; i++){
- vdbeSorterMerge(pTask, p, aSlot[i], &p);
+ p = vdbeSorterMerge(pTask, p, aSlot[i]);
aSlot[i] = 0;
}
aSlot[i] = p;
@@ -82969,7 +86804,8 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
p = 0;
for(i=0; i<64; i++){
- vdbeSorterMerge(pTask, p, aSlot[i], &p);
+ if( aSlot[i]==0 ) continue;
+ p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i];
}
pList->pList = p;
@@ -82992,7 +86828,7 @@ static void vdbePmaWriterInit(
memset(p, 0, sizeof(PmaWriter));
p->aBuffer = (u8*)sqlite3Malloc(nBuf);
if( !p->aBuffer ){
- p->eFWErr = SQLITE_NOMEM;
+ p->eFWErr = SQLITE_NOMEM_BKPT;
}else{
p->iBufEnd = p->iBufStart = (iStart % nBuf);
p->iWriteOff = iStart - p->iBufStart;
@@ -83280,7 +87116,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
pSorter->nMemory = sqlite3MallocSize(aMem);
}else if( pSorter->list.aMemory ){
pSorter->list.aMemory = sqlite3Malloc(pSorter->nMemory);
- if( !pSorter->list.aMemory ) return SQLITE_NOMEM;
+ if( !pSorter->list.aMemory ) return SQLITE_NOMEM_BKPT;
}
rc = vdbeSorterCreateThread(pTask, vdbeSorterFlushThread, pCtx);
@@ -83371,7 +87207,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
if( nNew < nMin ) nNew = nMin;
aNew = sqlite3Realloc(pSorter->list.aMemory, nNew);
- if( !aNew ) return SQLITE_NOMEM;
+ if( !aNew ) return SQLITE_NOMEM_BKPT;
pSorter->list.pList = (SorterRecord*)&aNew[iListOff];
pSorter->list.aMemory = aNew;
pSorter->nMemory = nNew;
@@ -83385,7 +87221,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
}else{
pNew = (SorterRecord *)sqlite3Malloc(nReq);
if( pNew==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pNew->u.pNext = pSorter->list.pList;
}
@@ -83532,7 +87368,7 @@ static int vdbeIncrMergerNew(
pTask->file2.iEof += pIncr->mxSz;
}else{
vdbeMergeEngineFree(pMerger);
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
return rc;
}
@@ -83837,10 +87673,10 @@ static int vdbeMergeEngineLevel0(
int rc = SQLITE_OK;
*ppOut = pNew = vdbeMergeEngineNew(nPMA);
- if( pNew==0 ) rc = SQLITE_NOMEM;
+ if( pNew==0 ) rc = SQLITE_NOMEM_BKPT;
for(i=0; i<nPMA && rc==SQLITE_OK; i++){
- i64 nDummy;
+ i64 nDummy = 0;
PmaReader *pReadr = &pNew->aReadr[i];
rc = vdbePmaReaderInit(pTask, &pTask->file, iOff, pReadr, &nDummy);
iOff = pReadr->iEof;
@@ -83908,7 +87744,7 @@ static int vdbeSorterAddToTree(
if( pReadr->pIncr==0 ){
MergeEngine *pNew = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
if( pNew==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
rc = vdbeIncrMergerNew(pTask, pNew, &pReadr->pIncr);
}
@@ -83953,7 +87789,7 @@ static int vdbeSorterMergeTreeBuild(
assert( pSorter->bUseThreads || pSorter->nTask==1 );
if( pSorter->nTask>1 ){
pMain = vdbeMergeEngineNew(pSorter->nTask);
- if( pMain==0 ) rc = SQLITE_NOMEM;
+ if( pMain==0 ) rc = SQLITE_NOMEM_BKPT;
}
#endif
@@ -83971,7 +87807,7 @@ static int vdbeSorterMergeTreeBuild(
int i;
int iSeq = 0;
pRoot = vdbeMergeEngineNew(SORTER_MAX_MERGE_COUNT);
- if( pRoot==0 ) rc = SQLITE_NOMEM;
+ if( pRoot==0 ) rc = SQLITE_NOMEM_BKPT;
for(i=0; i<pTask->nPMA && rc==SQLITE_OK; i += SORTER_MAX_MERGE_COUNT){
MergeEngine *pMerger = 0; /* New level-0 PMA merger */
int nReader; /* Number of level-0 PMAs to merge */
@@ -84042,7 +87878,7 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
if( rc==SQLITE_OK ){
pReadr = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
pSorter->pReader = pReadr;
- if( pReadr==0 ) rc = SQLITE_NOMEM;
+ if( pReadr==0 ) rc = SQLITE_NOMEM_BKPT;
}
if( rc==SQLITE_OK ){
rc = vdbeIncrMergerNew(pLast, pMain, &pReadr->pIncr);
@@ -84219,7 +88055,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRowkey(const VdbeCursor *pCsr, Mem *pOut){
pSorter = pCsr->uc.pSorter;
pKey = vdbeSorterRowkey(pSorter, &nKey);
if( sqlite3VdbeMemClearAndResize(pOut, nKey) ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pOut->n = nKey;
MemSetTypeFlag(pOut, MEM_Blob);
@@ -84261,10 +88097,8 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
r2 = pSorter->pUnpacked;
pKeyInfo = pCsr->pKeyInfo;
if( r2==0 ){
- char *p;
- r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo,0,0,&p);
- assert( pSorter->pUnpacked==(UnpackedRecord*)p );
- if( r2==0 ) return SQLITE_NOMEM;
+ r2 = pSorter->pUnpacked = sqlite3VdbeAllocUnpackedRecord(pKeyInfo);
+ if( r2==0 ) return SQLITE_NOMEM_BKPT;
r2->nField = nKeyCol;
}
assert( r2->nField==nKeyCol );
@@ -84283,265 +88117,6 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
}
/************** End of vdbesort.c ********************************************/
-/************** Begin file journal.c *****************************************/
-/*
-** 2007 August 22
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-**
-** This file implements a special kind of sqlite3_file object used
-** by SQLite to create journal files if the atomic-write optimization
-** is enabled.
-**
-** The distinctive characteristic of this sqlite3_file is that the
-** actual on disk file is created lazily. When the file is created,
-** the caller specifies a buffer size for an in-memory buffer to
-** be used to service read() and write() requests. The actual file
-** on disk is not created or populated until either:
-**
-** 1) The in-memory representation grows too large for the allocated
-** buffer, or
-** 2) The sqlite3JournalCreate() function is called.
-*/
-#ifdef SQLITE_ENABLE_ATOMIC_WRITE
-/* #include "sqliteInt.h" */
-
-
-/*
-** A JournalFile object is a subclass of sqlite3_file used by
-** as an open file handle for journal files.
-*/
-struct JournalFile {
- sqlite3_io_methods *pMethod; /* I/O methods on journal files */
- int nBuf; /* Size of zBuf[] in bytes */
- char *zBuf; /* Space to buffer journal writes */
- int iSize; /* Amount of zBuf[] currently used */
- int flags; /* xOpen flags */
- sqlite3_vfs *pVfs; /* The "real" underlying VFS */
- sqlite3_file *pReal; /* The "real" underlying file descriptor */
- const char *zJournal; /* Name of the journal file */
-};
-typedef struct JournalFile JournalFile;
-
-/*
-** If it does not already exists, create and populate the on-disk file
-** for JournalFile p.
-*/
-static int createFile(JournalFile *p){
- int rc = SQLITE_OK;
- if( !p->pReal ){
- sqlite3_file *pReal = (sqlite3_file *)&p[1];
- rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
- if( rc==SQLITE_OK ){
- p->pReal = pReal;
- if( p->iSize>0 ){
- assert(p->iSize<=p->nBuf);
- rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0);
- }
- if( rc!=SQLITE_OK ){
- /* If an error occurred while writing to the file, close it before
- ** returning. This way, SQLite uses the in-memory journal data to
- ** roll back changes made to the internal page-cache before this
- ** function was called. */
- sqlite3OsClose(pReal);
- p->pReal = 0;
- }
- }
- }
- return rc;
-}
-
-/*
-** Close the file.
-*/
-static int jrnlClose(sqlite3_file *pJfd){
- JournalFile *p = (JournalFile *)pJfd;
- if( p->pReal ){
- sqlite3OsClose(p->pReal);
- }
- sqlite3_free(p->zBuf);
- return SQLITE_OK;
-}
-
-/*
-** Read data from the file.
-*/
-static int jrnlRead(
- sqlite3_file *pJfd, /* The journal file from which to read */
- void *zBuf, /* Put the results here */
- int iAmt, /* Number of bytes to read */
- sqlite_int64 iOfst /* Begin reading at this offset */
-){
- int rc = SQLITE_OK;
- JournalFile *p = (JournalFile *)pJfd;
- if( p->pReal ){
- rc = sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
- }else if( (iAmt+iOfst)>p->iSize ){
- rc = SQLITE_IOERR_SHORT_READ;
- }else{
- memcpy(zBuf, &p->zBuf[iOfst], iAmt);
- }
- return rc;
-}
-
-/*
-** Write data to the file.
-*/
-static int jrnlWrite(
- sqlite3_file *pJfd, /* The journal file into which to write */
- const void *zBuf, /* Take data to be written from here */
- int iAmt, /* Number of bytes to write */
- sqlite_int64 iOfst /* Begin writing at this offset into the file */
-){
- int rc = SQLITE_OK;
- JournalFile *p = (JournalFile *)pJfd;
- if( !p->pReal && (iOfst+iAmt)>p->nBuf ){
- rc = createFile(p);
- }
- if( rc==SQLITE_OK ){
- if( p->pReal ){
- rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
- }else{
- memcpy(&p->zBuf[iOfst], zBuf, iAmt);
- if( p->iSize<(iOfst+iAmt) ){
- p->iSize = (iOfst+iAmt);
- }
- }
- }
- return rc;
-}
-
-/*
-** Truncate the file.
-*/
-static int jrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
- int rc = SQLITE_OK;
- JournalFile *p = (JournalFile *)pJfd;
- if( p->pReal ){
- rc = sqlite3OsTruncate(p->pReal, size);
- }else if( size<p->iSize ){
- p->iSize = size;
- }
- return rc;
-}
-
-/*
-** Sync the file.
-*/
-static int jrnlSync(sqlite3_file *pJfd, int flags){
- int rc;
- JournalFile *p = (JournalFile *)pJfd;
- if( p->pReal ){
- rc = sqlite3OsSync(p->pReal, flags);
- }else{
- rc = SQLITE_OK;
- }
- return rc;
-}
-
-/*
-** Query the size of the file in bytes.
-*/
-static int jrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
- int rc = SQLITE_OK;
- JournalFile *p = (JournalFile *)pJfd;
- if( p->pReal ){
- rc = sqlite3OsFileSize(p->pReal, pSize);
- }else{
- *pSize = (sqlite_int64) p->iSize;
- }
- return rc;
-}
-
-/*
-** Table of methods for JournalFile sqlite3_file object.
-*/
-static struct sqlite3_io_methods JournalFileMethods = {
- 1, /* iVersion */
- jrnlClose, /* xClose */
- jrnlRead, /* xRead */
- jrnlWrite, /* xWrite */
- jrnlTruncate, /* xTruncate */
- jrnlSync, /* xSync */
- jrnlFileSize, /* xFileSize */
- 0, /* xLock */
- 0, /* xUnlock */
- 0, /* xCheckReservedLock */
- 0, /* xFileControl */
- 0, /* xSectorSize */
- 0, /* xDeviceCharacteristics */
- 0, /* xShmMap */
- 0, /* xShmLock */
- 0, /* xShmBarrier */
- 0 /* xShmUnmap */
-};
-
-/*
-** Open a journal file.
-*/
-SQLITE_PRIVATE int sqlite3JournalOpen(
- sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
- const char *zName, /* Name of the journal file */
- sqlite3_file *pJfd, /* Preallocated, blank file handle */
- int flags, /* Opening flags */
- int nBuf /* Bytes buffered before opening the file */
-){
- JournalFile *p = (JournalFile *)pJfd;
- memset(p, 0, sqlite3JournalSize(pVfs));
- if( nBuf>0 ){
- p->zBuf = sqlite3MallocZero(nBuf);
- if( !p->zBuf ){
- return SQLITE_NOMEM;
- }
- }else{
- return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
- }
- p->pMethod = &JournalFileMethods;
- p->nBuf = nBuf;
- p->flags = flags;
- p->zJournal = zName;
- p->pVfs = pVfs;
- return SQLITE_OK;
-}
-
-/*
-** If the argument p points to a JournalFile structure, and the underlying
-** file has not yet been created, create it now.
-*/
-SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){
- if( p->pMethods!=&JournalFileMethods ){
- return SQLITE_OK;
- }
- return createFile((JournalFile *)p);
-}
-
-/*
-** The file-handle passed as the only argument is guaranteed to be an open
-** file. It may or may not be of class JournalFile. If the file is a
-** JournalFile, and the underlying file on disk has not yet been opened,
-** return 0. Otherwise, return 1.
-*/
-SQLITE_PRIVATE int sqlite3JournalExists(sqlite3_file *p){
- return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0);
-}
-
-/*
-** Return the number of bytes required to store a JournalFile that uses vfs
-** pVfs to create the underlying on-disk files.
-*/
-SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
- return (pVfs->szOsFile+sizeof(JournalFile));
-}
-#endif
-
-/************** End of journal.c *********************************************/
/************** Begin file memjournal.c **************************************/
/*
** 2008 October 7
@@ -84558,6 +88133,15 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
** This file contains code use to implement an in-memory rollback journal.
** The in-memory rollback journal is used to journal transactions for
** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
+**
+** Update: The in-memory journal is also used to temporarily cache
+** smaller journals that are not critical for power-loss recovery.
+** For example, statement journals that are not too big will be held
+** entirely in memory, thus reducing the number of file I/O calls, and
+** more importantly, reducing temporary file creation events. If these
+** journals become too large for memory, they are spilled to disk. But
+** in the common case, they are usually small and no file I/O needs to
+** occur.
*/
/* #include "sqliteInt.h" */
@@ -84566,25 +88150,29 @@ typedef struct MemJournal MemJournal;
typedef struct FilePoint FilePoint;
typedef struct FileChunk FileChunk;
-/* Space to hold the rollback journal is allocated in increments of
-** this many bytes.
-**
-** The size chosen is a little less than a power of two. That way,
-** the FileChunk object will have a size that almost exactly fills
-** a power-of-two allocation. This minimizes wasted space in power-of-two
-** memory allocators.
-*/
-#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
-
/*
** The rollback journal is composed of a linked list of these structures.
+**
+** The zChunk array is always at least 8 bytes in size - usually much more.
+** Its actual size is stored in the MemJournal.nChunkSize variable.
*/
struct FileChunk {
FileChunk *pNext; /* Next chunk in the journal */
- u8 zChunk[JOURNAL_CHUNKSIZE]; /* Content of this chunk */
+ u8 zChunk[8]; /* Content of this chunk */
};
/*
+** By default, allocate this many bytes of memory for each FileChunk object.
+*/
+#define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024
+
+/*
+** For chunk size nChunkSize, return the number of bytes that should
+** be allocated for each FileChunk structure.
+*/
+#define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8))
+
+/*
** An instance of this object serves as a cursor into the rollback journal.
** The cursor can be either for reading or writing.
*/
@@ -84594,14 +88182,22 @@ struct FilePoint {
};
/*
-** This subclass is a subclass of sqlite3_file. Each open memory-journal
+** This structure is a subclass of sqlite3_file. Each open memory-journal
** is an instance of this class.
*/
struct MemJournal {
- sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
+ const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
+ int nChunkSize; /* In-memory chunk-size */
+
+ int nSpill; /* Bytes of data before flushing */
+ int nSize; /* Bytes of data currently in memory */
FileChunk *pFirst; /* Head of in-memory chunk-list */
FilePoint endpoint; /* Pointer to the end of the file */
FilePoint readpoint; /* Pointer to the end of the last xRead() */
+
+ int flags; /* xOpen flags */
+ sqlite3_vfs *pVfs; /* The "real" underlying VFS */
+ const char *zJournal; /* Name of the journal file */
};
/*
@@ -84620,37 +88216,95 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
- /* SQLite never tries to read past the end of a rollback journal file */
- assert( iOfst+iAmt<=p->endpoint.iOffset );
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ if( (iAmt+iOfst)>p->endpoint.iOffset ){
+ return SQLITE_IOERR_SHORT_READ;
+ }
+#endif
+ assert( (iAmt+iOfst)<=p->endpoint.iOffset );
+ assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
sqlite3_int64 iOff = 0;
for(pChunk=p->pFirst;
- ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
+ ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
pChunk=pChunk->pNext
){
- iOff += JOURNAL_CHUNKSIZE;
+ iOff += p->nChunkSize;
}
}else{
pChunk = p->readpoint.pChunk;
+ assert( pChunk!=0 );
}
- iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
+ iChunkOffset = (int)(iOfst%p->nChunkSize);
do {
- int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
- int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
- memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
+ int iSpace = p->nChunkSize - iChunkOffset;
+ int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
+ memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
zOut += nCopy;
nRead -= iSpace;
iChunkOffset = 0;
} while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
- p->readpoint.iOffset = iOfst+iAmt;
+ p->readpoint.iOffset = pChunk ? iOfst+iAmt : 0;
p->readpoint.pChunk = pChunk;
return SQLITE_OK;
}
/*
+** Free the list of FileChunk structures headed at MemJournal.pFirst.
+*/
+static void memjrnlFreeChunks(MemJournal *p){
+ FileChunk *pIter;
+ FileChunk *pNext;
+ for(pIter=p->pFirst; pIter; pIter=pNext){
+ pNext = pIter->pNext;
+ sqlite3_free(pIter);
+ }
+ p->pFirst = 0;
+}
+
+/*
+** Flush the contents of memory to a real file on disk.
+*/
+static int memjrnlCreateFile(MemJournal *p){
+ int rc;
+ sqlite3_file *pReal = (sqlite3_file*)p;
+ MemJournal copy = *p;
+
+ memset(p, 0, sizeof(MemJournal));
+ rc = sqlite3OsOpen(copy.pVfs, copy.zJournal, pReal, copy.flags, 0);
+ if( rc==SQLITE_OK ){
+ int nChunk = copy.nChunkSize;
+ i64 iOff = 0;
+ FileChunk *pIter;
+ for(pIter=copy.pFirst; pIter; pIter=pIter->pNext){
+ if( iOff + nChunk > copy.endpoint.iOffset ){
+ nChunk = copy.endpoint.iOffset - iOff;
+ }
+ rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nChunk, iOff);
+ if( rc ) break;
+ iOff += nChunk;
+ }
+ if( rc==SQLITE_OK ){
+ /* No error has occurred. Free the in-memory buffers. */
+ memjrnlFreeChunks(&copy);
+ }
+ }
+ if( rc!=SQLITE_OK ){
+ /* If an error occurred while creating or writing to the file, restore
+ ** the original before returning. This way, SQLite uses the in-memory
+ ** journal data to roll back changes made to the internal page-cache
+ ** before this function was called. */
+ sqlite3OsClose(pReal);
+ *p = copy;
+ }
+ return rc;
+}
+
+
+/*
** Write data to the file.
*/
static int memjrnlWrite(
@@ -84663,38 +88317,62 @@ static int memjrnlWrite(
int nWrite = iAmt;
u8 *zWrite = (u8 *)zBuf;
- /* An in-memory journal file should only ever be appended to. Random
- ** access writes are not required by sqlite.
- */
- assert( iOfst==p->endpoint.iOffset );
- UNUSED_PARAMETER(iOfst);
+ /* If the file should be created now, create it and write the new data
+ ** into the file on disk. */
+ if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
+ int rc = memjrnlCreateFile(p);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pJfd, zBuf, iAmt, iOfst);
+ }
+ return rc;
+ }
- while( nWrite>0 ){
- FileChunk *pChunk = p->endpoint.pChunk;
- int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
- int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
+ /* If the contents of this write should be stored in memory */
+ else{
+ /* An in-memory journal file should only ever be appended to. Random
+ ** access writes are not required. The only exception to this is when
+ ** the in-memory journal is being used by a connection using the
+ ** atomic-write optimization. In this case the first 28 bytes of the
+ ** journal file may be written as part of committing the transaction. */
+ assert( iOfst==p->endpoint.iOffset || iOfst==0 );
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
+ if( iOfst==0 && p->pFirst ){
+ assert( p->nChunkSize>iAmt );
+ memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
+ }else
+#else
+ assert( iOfst>0 || p->pFirst==0 );
+#endif
+ {
+ while( nWrite>0 ){
+ FileChunk *pChunk = p->endpoint.pChunk;
+ int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
+ int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
+
+ if( iChunkOffset==0 ){
+ /* New chunk is required to extend the file. */
+ FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
+ if( !pNew ){
+ return SQLITE_IOERR_NOMEM_BKPT;
+ }
+ pNew->pNext = 0;
+ if( pChunk ){
+ assert( p->pFirst );
+ pChunk->pNext = pNew;
+ }else{
+ assert( !p->pFirst );
+ p->pFirst = pNew;
+ }
+ p->endpoint.pChunk = pNew;
+ }
- if( iChunkOffset==0 ){
- /* New chunk is required to extend the file. */
- FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
- if( !pNew ){
- return SQLITE_IOERR_NOMEM;
- }
- pNew->pNext = 0;
- if( pChunk ){
- assert( p->pFirst );
- pChunk->pNext = pNew;
- }else{
- assert( !p->pFirst );
- p->pFirst = pNew;
+ memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace);
+ zWrite += iSpace;
+ nWrite -= iSpace;
+ p->endpoint.iOffset += iSpace;
}
- p->endpoint.pChunk = pNew;
+ p->nSize = iAmt + iOfst;
}
-
- memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
- zWrite += iSpace;
- nWrite -= iSpace;
- p->endpoint.iOffset += iSpace;
}
return SQLITE_OK;
@@ -84702,19 +88380,21 @@ static int memjrnlWrite(
/*
** Truncate the file.
+**
+** If the journal file is already on disk, truncate it there. Or, if it
+** is still in main memory but is being truncated to zero bytes in size,
+** ignore
*/
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
MemJournal *p = (MemJournal *)pJfd;
- FileChunk *pChunk;
- assert(size==0);
- UNUSED_PARAMETER(size);
- pChunk = p->pFirst;
- while( pChunk ){
- FileChunk *pTmp = pChunk;
- pChunk = pChunk->pNext;
- sqlite3_free(pTmp);
- }
- sqlite3MemJournalOpen(pJfd);
+ if( ALWAYS(size==0) ){
+ memjrnlFreeChunks(p);
+ p->nSize = 0;
+ p->endpoint.pChunk = 0;
+ p->endpoint.iOffset = 0;
+ p->readpoint.pChunk = 0;
+ p->readpoint.iOffset = 0;
+ }
return SQLITE_OK;
}
@@ -84722,21 +88402,19 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
** Close the file.
*/
static int memjrnlClose(sqlite3_file *pJfd){
- memjrnlTruncate(pJfd, 0);
+ MemJournal *p = (MemJournal *)pJfd;
+ memjrnlFreeChunks(p);
return SQLITE_OK;
}
-
/*
** Sync the file.
**
-** Syncing an in-memory journal is a no-op. And, in fact, this routine
-** is never called in a working implementation. This implementation
-** exists purely as a contingency, in case some malfunction in some other
-** part of SQLite causes Sync to be called by mistake.
+** If the real file has been created, call its xSync method. Otherwise,
+** syncing an in-memory journal is a no-op.
*/
-static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
+static int memjrnlSync(sqlite3_file *pJfd, int flags){
+ UNUSED_PARAMETER2(pJfd, flags);
return SQLITE_OK;
}
@@ -84775,28 +88453,88 @@ static const struct sqlite3_io_methods MemJournalMethods = {
};
/*
-** Open a journal file.
+** Open a journal file.
+**
+** The behaviour of the journal file depends on the value of parameter
+** nSpill. If nSpill is 0, then the journal file is always create and
+** accessed using the underlying VFS. If nSpill is less than zero, then
+** all content is always stored in main-memory. Finally, if nSpill is a
+** positive value, then the journal file is initially created in-memory
+** but may be flushed to disk later on. In this case the journal file is
+** flushed to disk either when it grows larger than nSpill bytes in size,
+** or when sqlite3JournalCreate() is called.
+*/
+SQLITE_PRIVATE int sqlite3JournalOpen(
+ sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
+ const char *zName, /* Name of the journal file */
+ sqlite3_file *pJfd, /* Preallocated, blank file handle */
+ int flags, /* Opening flags */
+ int nSpill /* Bytes buffered before opening the file */
+){
+ MemJournal *p = (MemJournal*)pJfd;
+
+ /* Zero the file-handle object. If nSpill was passed zero, initialize
+ ** it using the sqlite3OsOpen() function of the underlying VFS. In this
+ ** case none of the code in this module is executed as a result of calls
+ ** made on the journal file-handle. */
+ memset(p, 0, sizeof(MemJournal));
+ if( nSpill==0 ){
+ return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
+ }
+
+ if( nSpill>0 ){
+ p->nChunkSize = nSpill;
+ }else{
+ p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
+ assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
+ }
+
+ p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
+ p->nSpill = nSpill;
+ p->flags = flags;
+ p->zJournal = zName;
+ p->pVfs = pVfs;
+ return SQLITE_OK;
+}
+
+/*
+** Open an in-memory journal file.
*/
SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){
- MemJournal *p = (MemJournal *)pJfd;
- assert( EIGHT_BYTE_ALIGNMENT(p) );
- memset(p, 0, sqlite3MemJournalSize());
- p->pMethod = (sqlite3_io_methods*)&MemJournalMethods;
+ sqlite3JournalOpen(0, 0, pJfd, 0, -1);
}
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
/*
-** Return true if the file-handle passed as an argument is
-** an in-memory journal
+** If the argument p points to a MemJournal structure that is not an
+** in-memory-only journal file (i.e. is one that was opened with a +ve
+** nSpill parameter), and the underlying file has not yet been created,
+** create it now.
*/
-SQLITE_PRIVATE int sqlite3IsMemJournal(sqlite3_file *pJfd){
- return pJfd->pMethods==&MemJournalMethods;
+SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *p){
+ int rc = SQLITE_OK;
+ if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
+ rc = memjrnlCreateFile((MemJournal*)p);
+ }
+ return rc;
+}
+#endif
+
+/*
+** The file-handle passed as the only argument is open on a journal file.
+** Return true if this "journal file" is currently stored in heap memory,
+** or false otherwise.
+*/
+SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){
+ return p->pMethods==&MemJournalMethods;
}
/*
-** Return the number of bytes required to store a MemJournal file descriptor.
+** Return the number of bytes required to store a JournalFile that uses vfs
+** pVfs to create the underlying on-disk files.
*/
-SQLITE_PRIVATE int sqlite3MemJournalSize(void){
- return sizeof(MemJournal);
+SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
+ return MAX(pVfs->szOsFile, (int)sizeof(MemJournal));
}
/************** End of memjournal.c ******************************************/
@@ -84844,17 +88582,17 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
rc = pWalker->xExprCallback(pWalker, pExpr);
- if( rc==WRC_Continue
- && !ExprHasProperty(pExpr,EP_TokenOnly) ){
- if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
- if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
- }else{
- if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
- }
+ if( rc || ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
+ return rc & WRC_Abort;
}
- return rc & WRC_Abort;
+ if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
+ if( pExpr->pRight && walkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
+ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+ if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
+ }else if( pExpr->x.pList ){
+ if( sqlite3WalkExprList(pWalker, pExpr->x.pList) ) return WRC_Abort;
+ }
+ return WRC_Continue;
}
SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
@@ -85188,8 +88926,8 @@ static int lookupName(
zDb = 0;
}else{
for(i=0; i<db->nDb; i++){
- assert( db->aDb[i].zName );
- if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
+ assert( db->aDb[i].zDbSName );
+ if( sqlite3StrICmp(db->aDb[i].zDbSName,zDb)==0 ){
pSchema = db->aDb[i].pSchema;
break;
}
@@ -85367,6 +89105,10 @@ static int lookupName(
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
return WRC_Abort;
}
+ if( sqlite3ExprVectorSize(pOrig)!=1 ){
+ sqlite3ErrorMsg(pParse, "row value misused");
+ return WRC_Abort;
+ }
resolveAlias(pParse, pEList, j, pExpr, "", nSubquery);
cnt = 1;
pMatch = 0;
@@ -85590,7 +89332,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
/* if( pSrcList==0 ) break; */
notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
- /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
zDb = 0;
@@ -85613,19 +89354,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
int no_such_func = 0; /* True if no such function exists */
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
- int auth; /* Authorization to use the function */
int nId; /* Number of characters in function name */
const char *zId; /* The function name. */
FuncDef *pDef; /* Information about the function */
u8 enc = ENC(pParse->db); /* The database encoding */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- notValid(pParse, pNC, "functions", NC_PartIdx);
zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId);
- pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
+ pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
if( pDef==0 ){
- pDef = sqlite3FindFunction(pParse->db, zId, nId, -2, enc, 0);
+ pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
if( pDef==0 ){
no_such_func = 1;
}else{
@@ -85657,15 +89396,17 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
}
#ifndef SQLITE_OMIT_AUTHORIZATION
- auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
- if( auth!=SQLITE_OK ){
- if( auth==SQLITE_DENY ){
- sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
- pDef->zName);
- pNC->nErr++;
+ {
+ int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0);
+ if( auth!=SQLITE_OK ){
+ if( auth==SQLITE_DENY ){
+ sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
+ pDef->zName);
+ pNC->nErr++;
+ }
+ pExpr->op = TK_NULL;
+ return WRC_Prune;
}
- pExpr->op = TK_NULL;
- return WRC_Prune;
}
#endif
if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){
@@ -85678,14 +89419,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
/* Date/time functions that use 'now', and other functions like
** sqlite_version() that might change over time cannot be used
** in an index. */
- notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr);
+ notValid(pParse, pNC, "non-deterministic functions",
+ NC_IdxExpr|NC_PartIdx);
}
}
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++;
is_agg = 0;
- }else if( no_such_func && pParse->db->init.busy==0 ){
+ }else if( no_such_func && pParse->db->init.busy==0
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ && pParse->explain==0
+#endif
+ ){
sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
pNC->nErr++;
}else if( wrong_num_args ){
@@ -85730,6 +89476,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
+ pNC->ncFlags |= NC_VarSelect;
}
}
break;
@@ -85738,6 +89485,42 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
break;
}
+ case TK_BETWEEN:
+ case TK_EQ:
+ case TK_NE:
+ case TK_LT:
+ case TK_LE:
+ case TK_GT:
+ case TK_GE:
+ case TK_IS:
+ case TK_ISNOT: {
+ int nLeft, nRight;
+ if( pParse->db->mallocFailed ) break;
+ assert( pExpr->pLeft!=0 );
+ nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
+ if( pExpr->op==TK_BETWEEN ){
+ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr);
+ if( nRight==nLeft ){
+ nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr);
+ }
+ }else{
+ assert( pExpr->pRight!=0 );
+ nRight = sqlite3ExprVectorSize(pExpr->pRight);
+ }
+ if( nLeft!=nRight ){
+ testcase( pExpr->op==TK_EQ );
+ testcase( pExpr->op==TK_NE );
+ testcase( pExpr->op==TK_LT );
+ testcase( pExpr->op==TK_LE );
+ testcase( pExpr->op==TK_GT );
+ testcase( pExpr->op==TK_GE );
+ testcase( pExpr->op==TK_IS );
+ testcase( pExpr->op==TK_ISNOT );
+ testcase( pExpr->op==TK_BETWEEN );
+ sqlite3ErrorMsg(pParse, "row value misused");
+ }
+ break;
+ }
}
return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
}
@@ -86480,6 +90263,18 @@ SQLITE_PRIVATE void sqlite3ResolveSelfReference(
*/
/* #include "sqliteInt.h" */
+/* Forward declarations */
+static void exprCodeBetween(Parse*,Expr*,int,void(*)(Parse*,Expr*,int,int),int);
+static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree);
+
+/*
+** Return the affinity character for a single column of a table.
+*/
+SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){
+ assert( iCol<pTab->nCol );
+ return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
+}
+
/*
** Return the 'affinity' of the expression pExpr if any.
**
@@ -86505,21 +90300,21 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
assert( pExpr->flags&EP_xIsSelect );
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
}
+ if( op==TK_REGISTER ) op = pExpr->op2;
#ifndef SQLITE_OMIT_CAST
if( op==TK_CAST ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
return sqlite3AffinityType(pExpr->u.zToken, 0);
}
#endif
- if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER)
- && pExpr->pTab!=0
- ){
- /* op==TK_REGISTER && pExpr->pTab!=0 happens when pExpr was originally
- ** a TK_COLUMN but was previously evaluated and cached in a register */
- int j = pExpr->iColumn;
- if( j<0 ) return SQLITE_AFF_INTEGER;
- assert( pExpr->pTab && j<pExpr->pTab->nCol );
- return pExpr->pTab->aCol[j].affinity;
+ if( op==TK_AGG_COLUMN || op==TK_COLUMN ){
+ return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn);
+ }
+ if( op==TK_SELECT_COLUMN ){
+ assert( pExpr->pLeft->flags&EP_xIsSelect );
+ return sqlite3ExprAffinity(
+ pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
+ );
}
return pExpr->affinity;
}
@@ -86685,7 +90480,7 @@ static char comparisonAffinity(Expr *pExpr){
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
}else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
- }else if( !aff ){
+ }else if( NEVER(aff==0) ){
aff = SQLITE_AFF_BLOB;
}
return aff;
@@ -86775,6 +90570,274 @@ static int codeCompare(
return addr;
}
+/*
+** Return true if expression pExpr is a vector, or false otherwise.
+**
+** A vector is defined as any expression that results in two or more
+** columns of result. Every TK_VECTOR node is an vector because the
+** parser will not generate a TK_VECTOR with fewer than two entries.
+** But a TK_SELECT might be either a vector or a scalar. It is only
+** considered a vector if it has two or more result columns.
+*/
+SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){
+ return sqlite3ExprVectorSize(pExpr)>1;
+}
+
+/*
+** If the expression passed as the only argument is of type TK_VECTOR
+** return the number of expressions in the vector. Or, if the expression
+** is a sub-select, return the number of columns in the sub-select. For
+** any other type of expression, return 1.
+*/
+SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){
+ u8 op = pExpr->op;
+ if( op==TK_REGISTER ) op = pExpr->op2;
+ if( op==TK_VECTOR ){
+ return pExpr->x.pList->nExpr;
+ }else if( op==TK_SELECT ){
+ return pExpr->x.pSelect->pEList->nExpr;
+ }else{
+ return 1;
+ }
+}
+
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
+** Return a pointer to a subexpression of pVector that is the i-th
+** column of the vector (numbered starting with 0). The caller must
+** ensure that i is within range.
+**
+** If pVector is really a scalar (and "scalar" here includes subqueries
+** that return a single column!) then return pVector unmodified.
+**
+** pVector retains ownership of the returned subexpression.
+**
+** If the vector is a (SELECT ...) then the expression returned is
+** just the expression for the i-th term of the result set, and may
+** not be ready for evaluation because the table cursor has not yet
+** been positioned.
+*/
+SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
+ assert( i<sqlite3ExprVectorSize(pVector) );
+ if( sqlite3ExprIsVector(pVector) ){
+ assert( pVector->op2==0 || pVector->op==TK_REGISTER );
+ if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){
+ return pVector->x.pSelect->pEList->a[i].pExpr;
+ }else{
+ return pVector->x.pList->a[i].pExpr;
+ }
+ }
+ return pVector;
+}
+#endif /* !defined(SQLITE_OMIT_SUBQUERY) */
+
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
+** Compute and return a new Expr object which when passed to
+** sqlite3ExprCode() will generate all necessary code to compute
+** the iField-th column of the vector expression pVector.
+**
+** It is ok for pVector to be a scalar (as long as iField==0).
+** In that case, this routine works like sqlite3ExprDup().
+**
+** The caller owns the returned Expr object and is responsible for
+** ensuring that the returned value eventually gets freed.
+**
+** The caller retains ownership of pVector. If pVector is a TK_SELECT,
+** then the returned object will reference pVector and so pVector must remain
+** valid for the life of the returned object. If pVector is a TK_VECTOR
+** or a scalar expression, then it can be deleted as soon as this routine
+** returns.
+**
+** A trick to cause a TK_SELECT pVector to be deleted together with
+** the returned Expr object is to attach the pVector to the pRight field
+** of the returned TK_SELECT_COLUMN Expr object.
+*/
+SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
+ Parse *pParse, /* Parsing context */
+ Expr *pVector, /* The vector. List of expressions or a sub-SELECT */
+ int iField /* Which column of the vector to return */
+){
+ Expr *pRet;
+ if( pVector->op==TK_SELECT ){
+ assert( pVector->flags & EP_xIsSelect );
+ /* The TK_SELECT_COLUMN Expr node:
+ **
+ ** pLeft: pVector containing TK_SELECT. Not deleted.
+ ** pRight: not used. But recursively deleted.
+ ** iColumn: Index of a column in pVector
+ ** iTable: 0 or the number of columns on the LHS of an assignment
+ ** pLeft->iTable: First in an array of register holding result, or 0
+ ** if the result is not yet computed.
+ **
+ ** sqlite3ExprDelete() specifically skips the recursive delete of
+ ** pLeft on TK_SELECT_COLUMN nodes. But pRight is followed, so pVector
+ ** can be attached to pRight to cause this node to take ownership of
+ ** pVector. Typically there will be multiple TK_SELECT_COLUMN nodes
+ ** with the same pLeft pointer to the pVector, but only one of them
+ ** will own the pVector.
+ */
+ pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
+ if( pRet ){
+ pRet->iColumn = iField;
+ pRet->pLeft = pVector;
+ }
+ assert( pRet==0 || pRet->iTable==0 );
+ }else{
+ if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr;
+ pRet = sqlite3ExprDup(pParse->db, pVector, 0);
+ }
+ return pRet;
+}
+#endif /* !define(SQLITE_OMIT_SUBQUERY) */
+
+/*
+** If expression pExpr is of type TK_SELECT, generate code to evaluate
+** it. Return the register in which the result is stored (or, if the
+** sub-select returns more than one column, the first in an array
+** of registers in which the result is stored).
+**
+** If pExpr is not a TK_SELECT expression, return 0.
+*/
+static int exprCodeSubselect(Parse *pParse, Expr *pExpr){
+ int reg = 0;
+#ifndef SQLITE_OMIT_SUBQUERY
+ if( pExpr->op==TK_SELECT ){
+ reg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
+ }
+#endif
+ return reg;
+}
+
+/*
+** Argument pVector points to a vector expression - either a TK_VECTOR
+** or TK_SELECT that returns more than one column. This function returns
+** the register number of a register that contains the value of
+** element iField of the vector.
+**
+** If pVector is a TK_SELECT expression, then code for it must have
+** already been generated using the exprCodeSubselect() routine. In this
+** case parameter regSelect should be the first in an array of registers
+** containing the results of the sub-select.
+**
+** If pVector is of type TK_VECTOR, then code for the requested field
+** is generated. In this case (*pRegFree) may be set to the number of
+** a temporary register to be freed by the caller before returning.
+**
+** Before returning, output parameter (*ppExpr) is set to point to the
+** Expr object corresponding to element iElem of the vector.
+*/
+static int exprVectorRegister(
+ Parse *pParse, /* Parse context */
+ Expr *pVector, /* Vector to extract element from */
+ int iField, /* Field to extract from pVector */
+ int regSelect, /* First in array of registers */
+ Expr **ppExpr, /* OUT: Expression element */
+ int *pRegFree /* OUT: Temp register to free */
+){
+ u8 op = pVector->op;
+ assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT );
+ if( op==TK_REGISTER ){
+ *ppExpr = sqlite3VectorFieldSubexpr(pVector, iField);
+ return pVector->iTable+iField;
+ }
+ if( op==TK_SELECT ){
+ *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr;
+ return regSelect+iField;
+ }
+ *ppExpr = pVector->x.pList->a[iField].pExpr;
+ return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree);
+}
+
+/*
+** Expression pExpr is a comparison between two vector values. Compute
+** the result of the comparison (1, 0, or NULL) and write that
+** result into register dest.
+**
+** The caller must satisfy the following preconditions:
+**
+** if pExpr->op==TK_IS: op==TK_EQ and p5==SQLITE_NULLEQ
+** if pExpr->op==TK_ISNOT: op==TK_NE and p5==SQLITE_NULLEQ
+** otherwise: op==pExpr->op and p5==0
+*/
+static void codeVectorCompare(
+ Parse *pParse, /* Code generator context */
+ Expr *pExpr, /* The comparison operation */
+ int dest, /* Write results into this register */
+ u8 op, /* Comparison operator */
+ u8 p5 /* SQLITE_NULLEQ or zero */
+){
+ Vdbe *v = pParse->pVdbe;
+ Expr *pLeft = pExpr->pLeft;
+ Expr *pRight = pExpr->pRight;
+ int nLeft = sqlite3ExprVectorSize(pLeft);
+ int i;
+ int regLeft = 0;
+ int regRight = 0;
+ u8 opx = op;
+ int addrDone = sqlite3VdbeMakeLabel(v);
+
+ if( nLeft!=sqlite3ExprVectorSize(pRight) ){
+ sqlite3ErrorMsg(pParse, "row value misused");
+ return;
+ }
+ assert( pExpr->op==TK_EQ || pExpr->op==TK_NE
+ || pExpr->op==TK_IS || pExpr->op==TK_ISNOT
+ || pExpr->op==TK_LT || pExpr->op==TK_GT
+ || pExpr->op==TK_LE || pExpr->op==TK_GE
+ );
+ assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ)
+ || (pExpr->op==TK_ISNOT && op==TK_NE) );
+ assert( p5==0 || pExpr->op!=op );
+ assert( p5==SQLITE_NULLEQ || pExpr->op==op );
+
+ p5 |= SQLITE_STOREP2;
+ if( opx==TK_LE ) opx = TK_LT;
+ if( opx==TK_GE ) opx = TK_GT;
+
+ regLeft = exprCodeSubselect(pParse, pLeft);
+ regRight = exprCodeSubselect(pParse, pRight);
+
+ for(i=0; 1 /*Loop exits by "break"*/; i++){
+ int regFree1 = 0, regFree2 = 0;
+ Expr *pL, *pR;
+ int r1, r2;
+ assert( i>=0 && i<nLeft );
+ if( i>0 ) sqlite3ExprCachePush(pParse);
+ r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, &regFree1);
+ r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, &regFree2);
+ codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5);
+ testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
+ testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
+ testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
+ testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
+ testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
+ testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
+ sqlite3ReleaseTempReg(pParse, regFree1);
+ sqlite3ReleaseTempReg(pParse, regFree2);
+ if( i>0 ) sqlite3ExprCachePop(pParse);
+ if( i==nLeft-1 ){
+ break;
+ }
+ if( opx==TK_EQ ){
+ sqlite3VdbeAddOp2(v, OP_IfNot, dest, addrDone); VdbeCoverage(v);
+ p5 |= SQLITE_KEEPNULL;
+ }else if( opx==TK_NE ){
+ sqlite3VdbeAddOp2(v, OP_If, dest, addrDone); VdbeCoverage(v);
+ p5 |= SQLITE_KEEPNULL;
+ }else{
+ assert( op==TK_LT || op==TK_GT || op==TK_LE || op==TK_GE );
+ sqlite3VdbeAddOp2(v, OP_ElseNotEq, 0, addrDone);
+ VdbeCoverageIf(v, op==TK_LT);
+ VdbeCoverageIf(v, op==TK_GT);
+ VdbeCoverageIf(v, op==TK_LE);
+ VdbeCoverageIf(v, op==TK_GE);
+ if( i==nLeft-2 ) opx = op;
+ }
+ }
+ sqlite3VdbeResolveLabel(v, addrDone);
+}
+
#if SQLITE_MAX_EXPR_DEPTH>0
/*
** Check that argument nHeight is less than or equal to the maximum
@@ -86910,7 +90973,7 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
** is allocated to hold the integer text and the dequote flag is ignored.
*/
SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
- sqlite3 *db, /* Handle for sqlite3DbMallocZero() (may be null) */
+ sqlite3 *db, /* Handle for sqlite3DbMallocRawNN() */
int op, /* Expression opcode */
const Token *pToken, /* Token argument. Might be NULL */
int dequote /* True to dequote */
@@ -86937,15 +91000,13 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
pNew->flags |= EP_IntValue;
pNew->u.iValue = iValue;
}else{
- int c;
pNew->u.zToken = (char*)&pNew[1];
assert( pToken->z!=0 || pToken->n==0 );
if( pToken->n ) memcpy(pNew->u.zToken, pToken->z, pToken->n);
pNew->u.zToken[pToken->n] = 0;
- if( dequote && nExtra>=3
- && ((c = pToken->z[0])=='\'' || c=='"' || c=='[' || c=='`') ){
+ if( dequote && sqlite3Isquote(pNew->u.zToken[0]) ){
+ if( pNew->u.zToken[0]=='"' ) pNew->flags |= EP_DblQuoted;
sqlite3Dequote(pNew->u.zToken);
- if( c=='"' ) pNew->flags |= EP_DblQuoted;
}
}
}
@@ -87011,15 +91072,19 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
Parse *pParse, /* Parsing context */
int op, /* Expression opcode */
Expr *pLeft, /* Left operand */
- Expr *pRight, /* Right operand */
- const Token *pToken /* Argument token */
+ Expr *pRight /* Right operand */
){
Expr *p;
if( op==TK_AND && pParse->nErr==0 ){
/* Take advantage of short-circuit false optimization for AND */
p = sqlite3ExprAnd(pParse->db, pLeft, pRight);
}else{
- p = sqlite3ExprAlloc(pParse->db, op & TKFLG_MASK, pToken, 1);
+ p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr));
+ if( p ){
+ memset(p, 0, sizeof(Expr));
+ p->op = op & TKFLG_MASK;
+ p->iAgg = -1;
+ }
sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
}
if( p ) {
@@ -87029,6 +91094,22 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(
}
/*
+** Add pSelect to the Expr.x.pSelect field. Or, if pExpr is NULL (due
+** do a memory allocation failure) then delete the pSelect object.
+*/
+SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pSelect){
+ if( pExpr ){
+ pExpr->x.pSelect = pSelect;
+ ExprSetProperty(pExpr, EP_xIsSelect|EP_Subquery);
+ sqlite3ExprSetHeightAndFlags(pParse, pExpr);
+ }else{
+ assert( pParse->db->mallocFailed );
+ sqlite3SelectDelete(pParse->db, pSelect);
+ }
+}
+
+
+/*
** If the expression is always either TRUE or FALSE (respectively),
** then return 1. If one cannot determine the truth value of the
** expression at compile-time return 0.
@@ -87106,7 +91187,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
** variable number.
**
** Wildcards of the form "?nnn" are assigned the number "nnn". We make
-** sure "nnn" is not too be to avoid a denial of service attack when
+** sure "nnn" is not too big to avoid a denial of service attack when
** the SQL statement comes from an external source.
**
** Wildcards of the form ":aaa", "@aaa", or "$aaa" are assigned the same number
@@ -87114,28 +91195,29 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse *pParse, ExprList *pList, Token *
** instance of the wildcard, the next sequential variable number is
** assigned.
*/
-SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
+SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n){
sqlite3 *db = pParse->db;
const char *z;
+ ynVar x;
if( pExpr==0 ) return;
assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
z = pExpr->u.zToken;
assert( z!=0 );
assert( z[0]!=0 );
+ assert( n==sqlite3Strlen30(z) );
if( z[1]==0 ){
/* Wildcard of the form "?". Assign the next variable number */
assert( z[0]=='?' );
- pExpr->iColumn = (ynVar)(++pParse->nVar);
+ x = (ynVar)(++pParse->nVar);
}else{
- ynVar x = 0;
- u32 n = sqlite3Strlen30(z);
+ int doAdd = 0;
if( z[0]=='?' ){
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
** use it as the variable number */
i64 i;
int bOk = 0==sqlite3Atoi64(&z[1], &i, n-1, SQLITE_UTF8);
- pExpr->iColumn = x = (ynVar)i;
+ x = (ynVar)i;
testcase( i==0 );
testcase( i==1 );
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
@@ -87143,44 +91225,31 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
- x = 0;
+ return;
}
- if( i>pParse->nVar ){
- pParse->nVar = (int)i;
+ if( x>pParse->nVar ){
+ pParse->nVar = (int)x;
+ doAdd = 1;
+ }else if( sqlite3VListNumToName(pParse->pVList, x)==0 ){
+ doAdd = 1;
}
}else{
/* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable
** number as the prior appearance of the same name, or if the name
** has never appeared before, reuse the same variable number
*/
- ynVar i;
- for(i=0; i<pParse->nzVar; i++){
- if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){
- pExpr->iColumn = x = (ynVar)i+1;
- break;
- }
+ x = (ynVar)sqlite3VListNameToNum(pParse->pVList, z, n);
+ if( x==0 ){
+ x = (ynVar)(++pParse->nVar);
+ doAdd = 1;
}
- if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar);
}
- if( x>0 ){
- if( x>pParse->nzVar ){
- char **a;
- a = sqlite3DbRealloc(db, pParse->azVar, x*sizeof(a[0]));
- if( a==0 ){
- assert( db->mallocFailed ); /* Error reported through mallocFailed */
- return;
- }
- pParse->azVar = a;
- memset(&a[pParse->nzVar], 0, (x-pParse->nzVar)*sizeof(a[0]));
- pParse->nzVar = x;
- }
- if( z[0]!='?' || pParse->azVar[x-1]==0 ){
- sqlite3DbFree(db, pParse->azVar[x-1]);
- pParse->azVar[x-1] = sqlite3DbStrNDup(db, z, n);
- }
+ if( doAdd ){
+ pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x);
}
- }
- if( !pParse->nErr && pParse->nVar>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
+ }
+ pExpr->iColumn = x;
+ if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
sqlite3ErrorMsg(pParse, "too many SQL variables");
}
}
@@ -87188,26 +91257,36 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
/*
** Recursively delete an expression tree.
*/
-SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
- if( p==0 ) return;
+static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
+ assert( p!=0 );
/* Sanity check: Assert that the IntValue is non-negative if it exists */
assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
- if( !ExprHasProperty(p, EP_TokenOnly) ){
+#ifdef SQLITE_DEBUG
+ if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){
+ assert( p->pLeft==0 );
+ assert( p->pRight==0 );
+ assert( p->x.pSelect==0 );
+ }
+#endif
+ if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){
/* The Expr.x union is never used at the same time as Expr.pRight */
assert( p->x.pList==0 || p->pRight==0 );
- sqlite3ExprDelete(db, p->pLeft);
+ if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
sqlite3ExprDelete(db, p->pRight);
- if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
if( ExprHasProperty(p, EP_xIsSelect) ){
sqlite3SelectDelete(db, p->x.pSelect);
}else{
sqlite3ExprListDelete(db, p->x.pList);
}
}
+ if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
if( !ExprHasProperty(p, EP_Static) ){
sqlite3DbFree(db, p);
}
}
+SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
+ if( p ) sqlite3ExprDeleteNN(db, p);
+}
/*
** Return the number of bytes allocated for the expression structure
@@ -87259,7 +91338,7 @@ static int dupedExprStructSize(Expr *p, int flags){
assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
assert( EXPR_FULLSIZE<=0xfff );
assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
- if( 0==(flags&EXPRDUP_REDUCE) ){
+ if( 0==flags || p->op==TK_SELECT_COLUMN ){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
@@ -87321,88 +91400,94 @@ static int dupedExprSize(Expr *p, int flags){
** if any. Before returning, *pzBuffer is set to the first byte past the
** portion of the buffer copied into by this function.
*/
-static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
- Expr *pNew = 0; /* Value to return */
- assert( flags==0 || flags==EXPRDUP_REDUCE );
+static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
+ Expr *pNew; /* Value to return */
+ u8 *zAlloc; /* Memory space from which to build Expr object */
+ u32 staticFlag; /* EP_Static if space not obtained from malloc */
+
assert( db!=0 );
- if( p ){
- const int isReduced = (flags&EXPRDUP_REDUCE);
- u8 *zAlloc;
- u32 staticFlag = 0;
+ assert( p );
+ assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
+ assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE );
- assert( pzBuffer==0 || isReduced );
+ /* Figure out where to write the new Expr structure. */
+ if( pzBuffer ){
+ zAlloc = *pzBuffer;
+ staticFlag = EP_Static;
+ }else{
+ zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
+ staticFlag = 0;
+ }
+ pNew = (Expr *)zAlloc;
- /* Figure out where to write the new Expr structure. */
- if( pzBuffer ){
- zAlloc = *pzBuffer;
- staticFlag = EP_Static;
+ if( pNew ){
+ /* Set nNewSize to the size allocated for the structure pointed to
+ ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
+ ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
+ ** by the copy of the p->u.zToken string (if any).
+ */
+ const unsigned nStructSize = dupedExprStructSize(p, dupFlags);
+ const int nNewSize = nStructSize & 0xfff;
+ int nToken;
+ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = sqlite3Strlen30(p->u.zToken) + 1;
}else{
- zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, flags));
+ nToken = 0;
}
- pNew = (Expr *)zAlloc;
-
- if( pNew ){
- /* Set nNewSize to the size allocated for the structure pointed to
- ** by pNew. This is either EXPR_FULLSIZE, EXPR_REDUCEDSIZE or
- ** EXPR_TOKENONLYSIZE. nToken is set to the number of bytes consumed
- ** by the copy of the p->u.zToken string (if any).
- */
- const unsigned nStructSize = dupedExprStructSize(p, flags);
- const int nNewSize = nStructSize & 0xfff;
- int nToken;
- if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
- nToken = sqlite3Strlen30(p->u.zToken) + 1;
- }else{
- nToken = 0;
- }
- if( isReduced ){
- assert( ExprHasProperty(p, EP_Reduced)==0 );
- memcpy(zAlloc, p, nNewSize);
- }else{
- u32 nSize = (u32)exprStructSize(p);
- memcpy(zAlloc, p, nSize);
- if( nSize<EXPR_FULLSIZE ){
- memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
- }
+ if( dupFlags ){
+ assert( ExprHasProperty(p, EP_Reduced)==0 );
+ memcpy(zAlloc, p, nNewSize);
+ }else{
+ u32 nSize = (u32)exprStructSize(p);
+ memcpy(zAlloc, p, nSize);
+ if( nSize<EXPR_FULLSIZE ){
+ memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
+ }
- /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
- pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
- pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
- pNew->flags |= staticFlag;
+ /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
+ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
+ pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
+ pNew->flags |= staticFlag;
- /* Copy the p->u.zToken string, if any. */
- if( nToken ){
- char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
- memcpy(zToken, p->u.zToken, nToken);
- }
+ /* Copy the p->u.zToken string, if any. */
+ if( nToken ){
+ char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
+ memcpy(zToken, p->u.zToken, nToken);
+ }
- if( 0==((p->flags|pNew->flags) & EP_TokenOnly) ){
- /* Fill in the pNew->x.pSelect or pNew->x.pList member. */
- if( ExprHasProperty(p, EP_xIsSelect) ){
- pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, isReduced);
- }else{
- pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, isReduced);
- }
+ if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){
+ /* Fill in the pNew->x.pSelect or pNew->x.pList member. */
+ if( ExprHasProperty(p, EP_xIsSelect) ){
+ pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
+ }else{
+ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
}
+ }
- /* Fill in pNew->pLeft and pNew->pRight. */
- if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
- zAlloc += dupedExprNodeSize(p, flags);
- if( ExprHasProperty(pNew, EP_Reduced) ){
- pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
- pNew->pRight = exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc);
- }
- if( pzBuffer ){
- *pzBuffer = zAlloc;
- }
- }else{
- if( !ExprHasProperty(p, EP_TokenOnly) ){
+ /* Fill in pNew->pLeft and pNew->pRight. */
+ if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
+ zAlloc += dupedExprNodeSize(p, dupFlags);
+ if( !ExprHasProperty(pNew, EP_TokenOnly|EP_Leaf) ){
+ pNew->pLeft = p->pLeft ?
+ exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc) : 0;
+ pNew->pRight = p->pRight ?
+ exprDup(db, p->pRight, EXPRDUP_REDUCE, &zAlloc) : 0;
+ }
+ if( pzBuffer ){
+ *pzBuffer = zAlloc;
+ }
+ }else{
+ if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
+ if( pNew->op==TK_SELECT_COLUMN ){
+ pNew->pLeft = p->pLeft;
+ assert( p->iColumn==0 || p->pRight==0 );
+ assert( p->pRight==0 || p->pRight==p->pLeft );
+ }else{
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
- pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
}
+ pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
}
-
}
}
return pNew;
@@ -87454,12 +91539,13 @@ static With *withDup(sqlite3 *db, With *p){
*/
SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
assert( flags==0 || flags==EXPRDUP_REDUCE );
- return exprDup(db, p, flags, 0);
+ return p ? exprDup(db, p, flags, 0) : 0;
}
SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
ExprList *pNew;
struct ExprList_item *pItem, *pOldItem;
int i;
+ Expr *pPriorSelectCol = 0;
assert( db!=0 );
if( p==0 ) return 0;
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
@@ -87474,7 +91560,24 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags)
pOldItem = p->a;
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
Expr *pOldExpr = pOldItem->pExpr;
+ Expr *pNewExpr;
pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags);
+ if( pOldExpr
+ && pOldExpr->op==TK_SELECT_COLUMN
+ && (pNewExpr = pItem->pExpr)!=0
+ ){
+ assert( pNewExpr->iColumn==0 || i>0 );
+ if( pNewExpr->iColumn==0 ){
+ assert( pOldExpr->pLeft==pOldExpr->pRight );
+ pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight;
+ }else{
+ assert( i>0 );
+ assert( pItem[-1].pExpr!=0 );
+ assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 );
+ assert( pPriorSelectCol==pItem[-1].pExpr->pLeft );
+ pNewExpr->pLeft = pPriorSelectCol;
+ }
+ }
pItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan);
pItem->sortOrder = pOldItem->sortOrder;
@@ -87525,7 +91628,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
}
pTab = pNewItem->pTab = pOldItem->pTab;
if( pTab ){
- pTab->nRef++;
+ pTab->nTabRef++;
}
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
@@ -87642,6 +91745,75 @@ no_mem:
}
/*
+** pColumns and pExpr form a vector assignment which is part of the SET
+** clause of an UPDATE statement. Like this:
+**
+** (a,b,c) = (expr1,expr2,expr3)
+** Or: (a,b,c) = (SELECT x,y,z FROM ....)
+**
+** For each term of the vector assignment, append new entries to the
+** expression list pList. In the case of a subquery on the LHS, append
+** TK_SELECT_COLUMN expressions.
+*/
+SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(
+ Parse *pParse, /* Parsing context */
+ ExprList *pList, /* List to which to append. Might be NULL */
+ IdList *pColumns, /* List of names of LHS of the assignment */
+ Expr *pExpr /* Vector expression to be appended. Might be NULL */
+){
+ sqlite3 *db = pParse->db;
+ int n;
+ int i;
+ int iFirst = pList ? pList->nExpr : 0;
+ /* pColumns can only be NULL due to an OOM but an OOM will cause an
+ ** exit prior to this routine being invoked */
+ if( NEVER(pColumns==0) ) goto vector_append_error;
+ if( pExpr==0 ) goto vector_append_error;
+
+ /* If the RHS is a vector, then we can immediately check to see that
+ ** the size of the RHS and LHS match. But if the RHS is a SELECT,
+ ** wildcards ("*") in the result set of the SELECT must be expanded before
+ ** we can do the size check, so defer the size check until code generation.
+ */
+ if( pExpr->op!=TK_SELECT && pColumns->nId!=(n=sqlite3ExprVectorSize(pExpr)) ){
+ sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
+ pColumns->nId, n);
+ goto vector_append_error;
+ }
+
+ for(i=0; i<pColumns->nId; i++){
+ Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i);
+ pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
+ if( pList ){
+ assert( pList->nExpr==iFirst+i+1 );
+ pList->a[pList->nExpr-1].zName = pColumns->a[i].zName;
+ pColumns->a[i].zName = 0;
+ }
+ }
+
+ if( pExpr->op==TK_SELECT ){
+ if( pList && pList->a[iFirst].pExpr ){
+ Expr *pFirst = pList->a[iFirst].pExpr;
+ assert( pFirst->op==TK_SELECT_COLUMN );
+
+ /* Store the SELECT statement in pRight so it will be deleted when
+ ** sqlite3ExprListDelete() is called */
+ pFirst->pRight = pExpr;
+ pExpr = 0;
+
+ /* Remember the size of the LHS in iTable so that we can check that
+ ** the RHS and LHS sizes match during code generation. */
+ pFirst->iTable = pColumns->nId;
+ }
+ }
+
+vector_append_error:
+ sqlite3ExprDelete(db, pExpr);
+ sqlite3IdListDelete(db, pColumns);
+ return pList;
+}
+
+/*
** Set the sort order for the last element on the given ExprList.
*/
SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){
@@ -87676,7 +91848,7 @@ SQLITE_PRIVATE void sqlite3ExprListSetName(
pItem = &pList->a[pList->nExpr-1];
assert( pItem->zName==0 );
pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
- if( dequote && pItem->zName ) sqlite3Dequote(pItem->zName);
+ if( dequote ) sqlite3Dequote(pItem->zName);
}
}
@@ -87725,10 +91897,9 @@ SQLITE_PRIVATE void sqlite3ExprListCheckLength(
/*
** Delete an entire expression list.
*/
-SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
+static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
int i;
struct ExprList_item *pItem;
- if( pList==0 ) return;
assert( pList->a!=0 || pList->nExpr==0 );
for(pItem=pList->a, i=0; i<pList->nExpr; i++, pItem++){
sqlite3ExprDelete(db, pItem->pExpr);
@@ -87738,6 +91909,9 @@ SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
sqlite3DbFree(db, pList->a);
sqlite3DbFree(db, pList);
}
+SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
+ if( pList ) exprListDeleteNN(db, pList);
+}
/*
** Return the bitwise-OR of all Expr.flags fields in the given
@@ -87749,7 +91923,8 @@ SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList *pList){
if( pList ){
for(i=0; i<pList->nExpr; i++){
Expr *pExpr = pList->a[i].pExpr;
- if( ALWAYS(pExpr) ) m |= pExpr->flags;
+ assert( pExpr!=0 );
+ m |= pExpr->flags;
}
}
return m;
@@ -88034,23 +92209,22 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){
}
/*
-** Return true if we are able to the IN operator optimization on a
-** query of the form
-**
-** x IN (SELECT ...)
-**
-** Where the SELECT... clause is as specified by the parameter to this
-** routine.
-**
-** The Select object passed in has already been preprocessed and no
-** errors have been found.
+** pX is the RHS of an IN operator. If pX is a SELECT statement
+** that can be simplified to a direct table access, then return
+** a pointer to the SELECT statement. If pX is not a SELECT statement,
+** or if the SELECT statement needs to be manifested into a transient
+** table, then return NULL.
*/
#ifndef SQLITE_OMIT_SUBQUERY
-static int isCandidateForInOpt(Select *p){
+static Select *isCandidateForInOpt(Expr *pX){
+ Select *p;
SrcList *pSrc;
ExprList *pEList;
Table *pTab;
- if( p==0 ) return 0; /* right-hand side of IN is SELECT */
+ int i;
+ if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
+ if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
+ p = pX->x.pSelect;
if( p->pPrior ) return 0; /* Not a compound SELECT */
if( p->selFlags & (SF_Distinct|SF_Aggregate) ){
testcase( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
@@ -88066,25 +92240,22 @@ static int isCandidateForInOpt(Select *p){
if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */
if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
pTab = pSrc->a[0].pTab;
- if( NEVER(pTab==0) ) return 0;
+ assert( pTab!=0 );
assert( pTab->pSelect==0 ); /* FROM clause is not a view */
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
pEList = p->pEList;
- if( pEList->nExpr!=1 ) return 0; /* One column in the result set */
- if( pEList->a[0].pExpr->op!=TK_COLUMN ) return 0; /* Result is a column */
- return 1;
+ assert( pEList!=0 );
+ /* All SELECT results must be columns. */
+ for(i=0; i<pEList->nExpr; i++){
+ Expr *pRes = pEList->a[i].pExpr;
+ if( pRes->op!=TK_COLUMN ) return 0;
+ assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
+ }
+ return p;
}
#endif /* SQLITE_OMIT_SUBQUERY */
-/*
-** Code an OP_Once instruction and allocate space for its flag. Return the
-** address of the new instruction.
-*/
-SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
- Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
- return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
-}
-
+#ifndef SQLITE_OMIT_SUBQUERY
/*
** Generate code that checks the left-most column of index table iCur to see if
** it contains any NULL entries. Cause the register at regHasNull to be set
@@ -88100,6 +92271,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
VdbeComment((v, "first_entry_in(%d)", iCur));
sqlite3VdbeJumpHere(v, addr1);
}
+#endif
#ifndef SQLITE_OMIT_SUBQUERY
@@ -88144,7 +92316,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
** An existing b-tree might be used if the RHS expression pX is a simple
** subquery such as:
**
-** SELECT <column> FROM <table>
+** SELECT <column1>, <column2>... FROM <table>
**
** If the RHS of the IN operator is a list or a more complex subquery, then
** an ephemeral table might need to be generated from the RHS and then
@@ -88160,14 +92332,14 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
**
** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate
** through the set members) then the b-tree must not contain duplicates.
-** An epheremal table must be used unless the selected <column> is guaranteed
-** to be unique - either because it is an INTEGER PRIMARY KEY or it
-** has a UNIQUE constraint or UNIQUE index.
+** An epheremal table must be used unless the selected columns are guaranteed
+** to be unique - either because it is an INTEGER PRIMARY KEY or due to
+** a UNIQUE constraint or index.
**
** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
** for fast set membership tests) then an epheremal table must
-** be used unless <column> is an INTEGER PRIMARY KEY or an index can
-** be found with <column> as its left-most column.
+** be used unless <columns> is a single INTEGER PRIMARY KEY column or an
+** index can be found with the specified <columns> as its left-most.
**
** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and
** if the RHS of the IN operator is a list (not a subquery) then this
@@ -88188,9 +92360,26 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
** the value in that register will be NULL if the b-tree contains one or more
** NULL values, and it will be some non-NULL value if the b-tree contains no
** NULL values.
+**
+** If the aiMap parameter is not NULL, it must point to an array containing
+** one element for each column returned by the SELECT statement on the RHS
+** of the IN(...) operator. The i'th entry of the array is populated with the
+** offset of the index column that matches the i'th column returned by the
+** SELECT. For example, if the expression and selected index are:
+**
+** (?,?,?) IN (SELECT a, b, c FROM t1)
+** CREATE INDEX i1 ON t1(b, c, a);
+**
+** then aiMap[] is populated with {2, 0, 1}.
*/
#ifndef SQLITE_OMIT_SUBQUERY
-SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
+SQLITE_PRIVATE int sqlite3FindInIndex(
+ Parse *pParse, /* Parsing context */
+ Expr *pX, /* The right-hand side (RHS) of the IN operator */
+ u32 inFlags, /* IN_INDEX_LOOP, _MEMBERSHIP, and/or _NOOP_OK */
+ int *prRhsHasNull, /* Register holding NULL status. See notes */
+ int *aiMap /* Mapping from Index fields to RHS fields */
+){
Select *p; /* SELECT to the right of IN operator */
int eType = 0; /* Type of RHS table. IN_INDEX_* */
int iTab = pParse->nTab++; /* Cursor of the RHS table */
@@ -88200,38 +92389,46 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
assert( pX->op==TK_IN );
mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
+ /* If the RHS of this IN(...) operator is a SELECT, and if it matters
+ ** whether or not the SELECT result contains NULL values, check whether
+ ** or not NULL is actually possible (it may not be, for example, due
+ ** to NOT NULL constraints in the schema). If no NULL values are possible,
+ ** set prRhsHasNull to 0 before continuing. */
+ if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){
+ int i;
+ ExprList *pEList = pX->x.pSelect->pEList;
+ for(i=0; i<pEList->nExpr; i++){
+ if( sqlite3ExprCanBeNull(pEList->a[i].pExpr) ) break;
+ }
+ if( i==pEList->nExpr ){
+ prRhsHasNull = 0;
+ }
+ }
+
/* Check to see if an existing table or index can be used to
** satisfy the query. This is preferable to generating a new
- ** ephemeral table.
- */
- p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
- if( pParse->nErr==0 && isCandidateForInOpt(p) ){
+ ** ephemeral table. */
+ if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
sqlite3 *db = pParse->db; /* Database connection */
Table *pTab; /* Table <table>. */
- Expr *pExpr; /* Expression <column> */
- i16 iCol; /* Index of column <column> */
i16 iDb; /* Database idx for pTab */
+ ExprList *pEList = p->pEList;
+ int nExpr = pEList->nExpr;
- assert( p ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
pTab = p->pSrc->a[0].pTab;
- pExpr = p->pEList->a[0].pExpr;
- iCol = (i16)pExpr->iColumn;
-
+
/* Code an OP_Transaction and OP_TableLock for <table>. */
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
- /* This function is only called from two places. In both cases the vdbe
- ** has already been allocated. So assume sqlite3GetVdbe() is always
- ** successful here.
- */
- assert(v);
- if( iCol<0 ){
- int iAddr = sqlite3CodeOnce(pParse);
+ assert(v); /* sqlite3GetVdbe() has always been previously called */
+ if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){
+ /* The "x IN (SELECT rowid FROM table)" case */
+ int iAddr = sqlite3VdbeAddOp0(v, OP_Once);
VdbeCoverage(v);
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
@@ -88240,44 +92437,114 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
sqlite3VdbeJumpHere(v, iAddr);
}else{
Index *pIdx; /* Iterator variable */
+ int affinity_ok = 1;
+ int i;
- /* The collation sequence used by the comparison. If an index is to
- ** be used in place of a temp-table, it must be ordered according
- ** to this collation sequence. */
- CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr);
-
- /* Check that the affinity that will be used to perform the
- ** comparison is the same as the affinity of the column. If
- ** it is not, it is not possible to use any index.
- */
- int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
-
- for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
- if( (pIdx->aiColumn[0]==iCol)
- && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
- && (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx)))
- ){
- int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
- sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
- VdbeComment((v, "%s", pIdx->zName));
- assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
- eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
-
- if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
- *prRhsHasNull = ++pParse->nMem;
- sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
+ /* Check that the affinity that will be used to perform each
+ ** comparison is the same as the affinity of each column in table
+ ** on the RHS of the IN operator. If it not, it is not possible to
+ ** use any index of the RHS table. */
+ for(i=0; i<nExpr && affinity_ok; i++){
+ Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
+ int iCol = pEList->a[i].pExpr->iColumn;
+ char idxaff = sqlite3TableColumnAffinity(pTab,iCol); /* RHS table */
+ char cmpaff = sqlite3CompareAffinity(pLhs, idxaff);
+ testcase( cmpaff==SQLITE_AFF_BLOB );
+ testcase( cmpaff==SQLITE_AFF_TEXT );
+ switch( cmpaff ){
+ case SQLITE_AFF_BLOB:
+ break;
+ case SQLITE_AFF_TEXT:
+ /* sqlite3CompareAffinity() only returns TEXT if one side or the
+ ** other has no affinity and the other side is TEXT. Hence,
+ ** the only way for cmpaff to be TEXT is for idxaff to be TEXT
+ ** and for the term on the LHS of the IN to have no affinity. */
+ assert( idxaff==SQLITE_AFF_TEXT );
+ break;
+ default:
+ affinity_ok = sqlite3IsNumericAffinity(idxaff);
+ }
+ }
+
+ if( affinity_ok ){
+ /* Search for an existing index that will work for this IN operator */
+ for(pIdx=pTab->pIndex; pIdx && eType==0; pIdx=pIdx->pNext){
+ Bitmask colUsed; /* Columns of the index used */
+ Bitmask mCol; /* Mask for the current column */
+ if( pIdx->nColumn<nExpr ) continue;
+ /* Maximum nColumn is BMS-2, not BMS-1, so that we can compute
+ ** BITMASK(nExpr) without overflowing */
+ testcase( pIdx->nColumn==BMS-2 );
+ testcase( pIdx->nColumn==BMS-1 );
+ if( pIdx->nColumn>=BMS-1 ) continue;
+ if( mustBeUnique ){
+ if( pIdx->nKeyCol>nExpr
+ ||(pIdx->nColumn>nExpr && !IsUniqueIndex(pIdx))
+ ){
+ continue; /* This index is not unique over the IN RHS columns */
+ }
}
- sqlite3VdbeJumpHere(v, iAddr);
- }
- }
- }
- }
+
+ colUsed = 0; /* Columns of index used so far */
+ for(i=0; i<nExpr; i++){
+ Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
+ Expr *pRhs = pEList->a[i].pExpr;
+ CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
+ int j;
+
+ assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
+ for(j=0; j<nExpr; j++){
+ if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
+ assert( pIdx->azColl[j] );
+ if( pReq!=0 && sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ){
+ continue;
+ }
+ break;
+ }
+ if( j==nExpr ) break;
+ mCol = MASKBIT(j);
+ if( mCol & colUsed ) break; /* Each column used only once */
+ colUsed |= mCol;
+ if( aiMap ) aiMap[i] = j;
+ }
+
+ assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) );
+ if( colUsed==(MASKBIT(nExpr)-1) ){
+ /* If we reach this point, that means the index pIdx is usable */
+ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
+#ifndef SQLITE_OMIT_EXPLAIN
+ sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0,
+ sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName),
+ P4_DYNAMIC);
+#endif
+ sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
+ sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
+ VdbeComment((v, "%s", pIdx->zName));
+ assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
+ eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
+
+ if( prRhsHasNull ){
+#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
+ i64 mask = (1<<nExpr)-1;
+ sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
+ iTab, 0, 0, (u8*)&mask, P4_INT64);
+#endif
+ *prRhsHasNull = ++pParse->nMem;
+ if( nExpr==1 ){
+ sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
+ }
+ }
+ sqlite3VdbeJumpHere(v, iAddr);
+ }
+ } /* End loop over indexes */
+ } /* End if( affinity_ok ) */
+ } /* End if not an rowid index */
+ } /* End attempt to optimize using an index */
/* If no preexisting index is available for the IN clause
** and IN_INDEX_NOOP is an allowed reply
** and the RHS of the IN operator is a list, not a subquery
- ** and the RHS is not contant or has two or fewer terms,
+ ** and the RHS is not constant or has two or fewer terms,
** then it is not worth creating an ephemeral table to evaluate
** the IN operator so return IN_INDEX_NOOP.
*/
@@ -88288,7 +92555,6 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
){
eType = IN_INDEX_NOOP;
}
-
if( eType==0 ){
/* Could not find an existing table or index to use as the RHS b-tree.
@@ -88310,10 +92576,85 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
}else{
pX->iTable = iTab;
}
+
+ if( aiMap && eType!=IN_INDEX_INDEX_ASC && eType!=IN_INDEX_INDEX_DESC ){
+ int i, n;
+ n = sqlite3ExprVectorSize(pX->pLeft);
+ for(i=0; i<n; i++) aiMap[i] = i;
+ }
return eType;
}
#endif
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
+** Argument pExpr is an (?, ?...) IN(...) expression. This
+** function allocates and returns a nul-terminated string containing
+** the affinities to be used for each column of the comparison.
+**
+** It is the responsibility of the caller to ensure that the returned
+** string is eventually freed using sqlite3DbFree().
+*/
+static char *exprINAffinity(Parse *pParse, Expr *pExpr){
+ Expr *pLeft = pExpr->pLeft;
+ int nVal = sqlite3ExprVectorSize(pLeft);
+ Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0;
+ char *zRet;
+
+ assert( pExpr->op==TK_IN );
+ zRet = sqlite3DbMallocZero(pParse->db, nVal+1);
+ if( zRet ){
+ int i;
+ for(i=0; i<nVal; i++){
+ Expr *pA = sqlite3VectorFieldSubexpr(pLeft, i);
+ char a = sqlite3ExprAffinity(pA);
+ if( pSelect ){
+ zRet[i] = sqlite3CompareAffinity(pSelect->pEList->a[i].pExpr, a);
+ }else{
+ zRet[i] = a;
+ }
+ }
+ zRet[nVal] = '\0';
+ }
+ return zRet;
+}
+#endif
+
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
+** Load the Parse object passed as the first argument with an error
+** message of the form:
+**
+** "sub-select returns N columns - expected M"
+*/
+SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
+ const char *zFmt = "sub-select returns %d columns - expected %d";
+ sqlite3ErrorMsg(pParse, zFmt, nActual, nExpect);
+}
+#endif
+
+/*
+** Expression pExpr is a vector that has been used in a context where
+** it is not permitted. If pExpr is a sub-select vector, this routine
+** loads the Parse object with a message of the form:
+**
+** "sub-select returns N columns - expected 1"
+**
+** Or, if it is a regular scalar vector:
+**
+** "row value misused"
+*/
+SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
+#ifndef SQLITE_OMIT_SUBQUERY
+ if( pExpr->flags & EP_xIsSelect ){
+ sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1);
+ }else
+#endif
+ {
+ sqlite3ErrorMsg(pParse, "row value misused");
+ }
+}
+
/*
** Generate code for scalar subqueries used as a subquery expression, EXISTS,
** or IN operators. Examples:
@@ -88339,7 +92680,9 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int
** value to non-NULL if the RHS is NULL-free.
**
** For a SELECT or EXISTS operator, return the register that holds the
-** result. For IN operators or if an error occurs, the return value is 0.
+** result. For a multi-column SELECT, the result is stored in a contiguous
+** array of registers and the return value is the register of the left-most
+** result column. Return 0 for IN operators or if an error occurs.
*/
#ifndef SQLITE_OMIT_SUBQUERY
SQLITE_PRIVATE int sqlite3CodeSubselect(
@@ -88354,8 +92697,8 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
if( NEVER(v==0) ) return 0;
sqlite3ExprCachePush(pParse);
- /* This code must be run in its entirety every time it is encountered
- ** if any of the following is true:
+ /* The evaluation of the IN/EXISTS/SELECT must be repeated every time it
+ ** is encountered if any of the following is true:
**
** * The right-hand side is a correlated subquery
** * The right-hand side is an expression list containing variables
@@ -88365,7 +92708,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
** save the results, and reuse the same result on subsequent invocations.
*/
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
- jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v);
+ jmpIfDynamic = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
#ifndef SQLITE_OMIT_EXPLAIN
@@ -88381,17 +92724,18 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
switch( pExpr->op ){
case TK_IN: {
- char affinity; /* Affinity of the LHS of the IN */
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
KeyInfo *pKeyInfo = 0; /* Key information */
-
- affinity = sqlite3ExprAffinity(pLeft);
+ int nVal; /* Size of vector pLeft */
+
+ nVal = sqlite3ExprVectorSize(pLeft);
+ assert( !isRowid || nVal==1 );
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
** expression it is handled the same way. An ephemeral table is
- ** filled with single-field index keys representing the results
- ** from the SELECT or the <exprlist>.
+ ** filled with index keys representing the results from the
+ ** SELECT or the <exprlist>.
**
** If the 'x' expression is a column value, or the SELECT...
** statement returns a column value, then the affinity of that
@@ -88402,8 +92746,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
** is used.
*/
pExpr->iTable = pParse->nTab++;
- addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
- pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1);
+ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral,
+ pExpr->iTable, (isRowid?0:nVal));
+ pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
@@ -88412,27 +92757,37 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
** table allocated and opened above.
*/
Select *pSelect = pExpr->x.pSelect;
- SelectDest dest;
- ExprList *pEList;
+ ExprList *pEList = pSelect->pEList;
assert( !isRowid );
- sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
- dest.affSdst = (u8)affinity;
- assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
- pSelect->iLimit = 0;
- testcase( pSelect->selFlags & SF_Distinct );
- testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
- if( sqlite3Select(pParse, pSelect, &dest) ){
- sqlite3KeyInfoUnref(pKeyInfo);
- return 0;
+ /* If the LHS and RHS of the IN operator do not match, that
+ ** error will have been caught long before we reach this point. */
+ if( ALWAYS(pEList->nExpr==nVal) ){
+ SelectDest dest;
+ int i;
+ sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
+ dest.zAffSdst = exprINAffinity(pParse, pExpr);
+ assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
+ pSelect->iLimit = 0;
+ testcase( pSelect->selFlags & SF_Distinct );
+ testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
+ if( sqlite3Select(pParse, pSelect, &dest) ){
+ sqlite3DbFree(pParse->db, dest.zAffSdst);
+ sqlite3KeyInfoUnref(pKeyInfo);
+ return 0;
+ }
+ sqlite3DbFree(pParse->db, dest.zAffSdst);
+ assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
+ assert( pEList!=0 );
+ assert( pEList->nExpr>0 );
+ assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
+ for(i=0; i<nVal; i++){
+ Expr *p = sqlite3VectorFieldSubexpr(pLeft, i);
+ pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq(
+ pParse, p, pEList->a[i].pExpr
+ );
+ }
}
- pEList = pSelect->pEList;
- assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
- assert( pEList!=0 );
- assert( pEList->nExpr>0 );
- assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
- pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
- pEList->a[0].pExpr);
}else if( ALWAYS(pExpr->x.pList!=0) ){
/* Case 2: expr IN (exprlist)
**
@@ -88441,11 +92796,13 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
** that columns affinity when building index keys. If <expr> is not
** a column, use numeric affinity.
*/
+ char affinity; /* Affinity of the LHS of the IN */
int i;
ExprList *pList = pExpr->x.pList;
struct ExprList_item *pItem;
int r1, r2, r3;
+ affinity = sqlite3ExprAffinity(pLeft);
if( !affinity ){
affinity = SQLITE_AFF_BLOB;
}
@@ -88485,7 +92842,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
}else{
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
sqlite3ExprCacheAffinityChange(pParse, r3, 1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1);
}
}
}
@@ -88501,26 +92858,37 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
case TK_EXISTS:
case TK_SELECT:
default: {
- /* If this has to be a scalar SELECT. Generate code to put the
- ** value of this select in a memory cell and record the number
- ** of the memory cell in iColumn. If this is an EXISTS, write
- ** an integer 0 (not exists) or 1 (exists) into a memory cell
- ** and record that memory cell in iColumn.
+ /* Case 3: (SELECT ... FROM ...)
+ ** or: EXISTS(SELECT ... FROM ...)
+ **
+ ** For a SELECT, generate code to put the values for all columns of
+ ** the first row into an array of registers and return the index of
+ ** the first register.
+ **
+ ** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists)
+ ** into a register and return that register number.
+ **
+ ** In both cases, the query is augmented with "LIMIT 1". Any
+ ** preexisting limit is discarded in place of the new LIMIT 1.
*/
Select *pSel; /* SELECT statement to encode */
- SelectDest dest; /* How to deal with SELECt result */
+ SelectDest dest; /* How to deal with SELECT result */
+ int nReg; /* Registers to allocate */
testcase( pExpr->op==TK_EXISTS );
testcase( pExpr->op==TK_SELECT );
assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
-
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
+
pSel = pExpr->x.pSelect;
- sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
+ nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
+ sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
+ pParse->nMem += nReg;
if( pExpr->op==TK_SELECT ){
dest.eDest = SRT_Mem;
dest.iSdst = dest.iSDParm;
- sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iSDParm);
+ dest.nSdst = nReg;
+ sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
VdbeComment((v, "Init subquery result"));
}else{
dest.eDest = SRT_Exists;
@@ -88528,8 +92896,8 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
VdbeComment((v, "Init EXISTS result"));
}
sqlite3ExprDelete(pParse->db, pSel->pLimit);
- pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
- &sqlite3IntTokens[1]);
+ pSel->pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER,
+ &sqlite3IntTokens[1], 0);
pSel->iLimit = 0;
pSel->selFlags &= ~SF_MultiValue;
if( sqlite3Select(pParse, pSel, &dest) ){
@@ -88556,21 +92924,51 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
#ifndef SQLITE_OMIT_SUBQUERY
/*
+** Expr pIn is an IN(...) expression. This function checks that the
+** sub-select on the RHS of the IN() operator has the same number of
+** columns as the vector on the LHS. Or, if the RHS of the IN() is not
+** a sub-query, that the LHS is a vector of size 1.
+*/
+SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
+ int nVector = sqlite3ExprVectorSize(pIn->pLeft);
+ if( (pIn->flags & EP_xIsSelect) ){
+ if( nVector!=pIn->x.pSelect->pEList->nExpr ){
+ sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector);
+ return 1;
+ }
+ }else if( nVector!=1 ){
+ sqlite3VectorErrorMsg(pParse, pIn->pLeft);
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+#ifndef SQLITE_OMIT_SUBQUERY
+/*
** Generate code for an IN expression.
**
** x IN (SELECT ...)
** x IN (value, value, ...)
**
-** The left-hand side (LHS) is a scalar expression. The right-hand side (RHS)
-** is an array of zero or more values. The expression is true if the LHS is
-** contained within the RHS. The value of the expression is unknown (NULL)
-** if the LHS is NULL or if the LHS is not contained within the RHS and the
-** RHS contains one or more NULL values.
+** The left-hand side (LHS) is a scalar or vector expression. The
+** right-hand side (RHS) is an array of zero or more scalar values, or a
+** subquery. If the RHS is a subquery, the number of result columns must
+** match the number of columns in the vector on the LHS. If the RHS is
+** a list of values, the LHS must be a scalar.
+**
+** The IN operator is true if the LHS value is contained within the RHS.
+** The result is false if the LHS is definitely not in the RHS. The
+** result is NULL if the presence of the LHS in the RHS cannot be
+** determined due to NULLs.
**
** This routine generates code that jumps to destIfFalse if the LHS is not
** contained within the RHS. If due to NULLs we cannot determine if the LHS
** is contained in the RHS then jump to destIfNull. If the LHS is contained
** within the RHS then fall through.
+**
+** See the separate in-operator.md documentation file in the canonical
+** SQLite source tree for additional information.
*/
static void sqlite3ExprCodeIN(
Parse *pParse, /* Parsing and code generating context */
@@ -88579,36 +92977,83 @@ static void sqlite3ExprCodeIN(
int destIfNull /* Jump here if the results are unknown due to NULLs */
){
int rRhsHasNull = 0; /* Register that is true if RHS contains NULL values */
- char affinity; /* Comparison affinity to use */
int eType; /* Type of the RHS */
- int r1; /* Temporary use register */
+ int rLhs; /* Register(s) holding the LHS values */
+ int rLhsOrig; /* LHS values prior to reordering by aiMap[] */
Vdbe *v; /* Statement under construction */
+ int *aiMap = 0; /* Map from vector field to index column */
+ char *zAff = 0; /* Affinity string for comparisons */
+ int nVector; /* Size of vectors for this IN operator */
+ int iDummy; /* Dummy parameter to exprCodeVector() */
+ Expr *pLeft; /* The LHS of the IN operator */
+ int i; /* loop counter */
+ int destStep2; /* Where to jump when NULLs seen in step 2 */
+ int destStep6 = 0; /* Start of code for Step 6 */
+ int addrTruthOp; /* Address of opcode that determines the IN is true */
+ int destNotNull; /* Jump here if a comparison is not true in step 6 */
+ int addrTop; /* Top of the step-6 loop */
+
+ pLeft = pExpr->pLeft;
+ if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
+ zAff = exprINAffinity(pParse, pExpr);
+ nVector = sqlite3ExprVectorSize(pExpr->pLeft);
+ aiMap = (int*)sqlite3DbMallocZero(
+ pParse->db, nVector*(sizeof(int) + sizeof(char)) + 1
+ );
+ if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error;
- /* Compute the RHS. After this step, the table with cursor
- ** pExpr->iTable will contains the values that make up the RHS.
- */
+ /* Attempt to compute the RHS. After this step, if anything other than
+ ** IN_INDEX_NOOP is returned, the table opened ith cursor pExpr->iTable
+ ** contains the values that make up the RHS. If IN_INDEX_NOOP is returned,
+ ** the RHS has not yet been coded. */
v = pParse->pVdbe;
assert( v!=0 ); /* OOM detected prior to this routine */
VdbeNoopComment((v, "begin IN expr"));
eType = sqlite3FindInIndex(pParse, pExpr,
IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
- destIfFalse==destIfNull ? 0 : &rRhsHasNull);
+ destIfFalse==destIfNull ? 0 : &rRhsHasNull, aiMap);
- /* Figure out the affinity to use to create a key from the results
- ** of the expression. affinityStr stores a static string suitable for
- ** P4 of OP_MakeRecord.
- */
- affinity = comparisonAffinity(pExpr);
+ assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH
+ || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC
+ );
+#ifdef SQLITE_DEBUG
+ /* Confirm that aiMap[] contains nVector integer values between 0 and
+ ** nVector-1. */
+ for(i=0; i<nVector; i++){
+ int j, cnt;
+ for(cnt=j=0; j<nVector; j++) if( aiMap[j]==i ) cnt++;
+ assert( cnt==1 );
+ }
+#endif
- /* Code the LHS, the <expr> from "<expr> IN (...)".
+ /* Code the LHS, the <expr> from "<expr> IN (...)". If the LHS is a
+ ** vector, then it is stored in an array of nVector registers starting
+ ** at r1.
+ **
+ ** sqlite3FindInIndex() might have reordered the fields of the LHS vector
+ ** so that the fields are in the same order as an existing index. The
+ ** aiMap[] array contains a mapping from the original LHS field order to
+ ** the field order that matches the RHS index.
*/
sqlite3ExprCachePush(pParse);
- r1 = sqlite3GetTempReg(pParse);
- sqlite3ExprCode(pParse, pExpr->pLeft, r1);
+ rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy);
+ for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */
+ if( i==nVector ){
+ /* LHS fields are not reordered */
+ rLhs = rLhsOrig;
+ }else{
+ /* Need to reorder the LHS fields according to aiMap */
+ rLhs = sqlite3GetTempRange(pParse, nVector);
+ for(i=0; i<nVector; i++){
+ sqlite3VdbeAddOp3(v, OP_Copy, rLhsOrig+i, rLhs+aiMap[i], 0);
+ }
+ }
/* If sqlite3FindInIndex() did not find or create an index that is
** suitable for evaluating the IN operator, then evaluate using a
** sequence of comparisons.
+ **
+ ** This is step (1) in the in-operator.md optimized algorithm.
*/
if( eType==IN_INDEX_NOOP ){
ExprList *pList = pExpr->x.pList;
@@ -88620,7 +93065,7 @@ static void sqlite3ExprCodeIN(
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
if( destIfNull!=destIfFalse ){
regCkNull = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull);
+ sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull);
}
for(ii=0; ii<pList->nExpr; ii++){
r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, &regToFree);
@@ -88628,16 +93073,16 @@ static void sqlite3ExprCodeIN(
sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
}
if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){
- sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2,
+ sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2,
(void*)pColl, P4_COLLSEQ);
VdbeCoverageIf(v, ii<pList->nExpr-1);
VdbeCoverageIf(v, ii==pList->nExpr-1);
- sqlite3VdbeChangeP5(v, affinity);
+ sqlite3VdbeChangeP5(v, zAff[0]);
}else{
assert( destIfNull==destIfFalse );
- sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2,
+ sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2,
(void*)pColl, P4_COLLSEQ); VdbeCoverage(v);
- sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL);
+ sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL);
}
sqlite3ReleaseTempReg(pParse, regToFree);
}
@@ -88647,78 +93092,113 @@ static void sqlite3ExprCodeIN(
}
sqlite3VdbeResolveLabel(v, labelOk);
sqlite3ReleaseTempReg(pParse, regCkNull);
+ goto sqlite3ExprCodeIN_finished;
+ }
+
+ /* Step 2: Check to see if the LHS contains any NULL columns. If the
+ ** LHS does contain NULLs then the result must be either FALSE or NULL.
+ ** We will then skip the binary search of the RHS.
+ */
+ if( destIfNull==destIfFalse ){
+ destStep2 = destIfFalse;
}else{
-
- /* If the LHS is NULL, then the result is either false or NULL depending
- ** on whether the RHS is empty or not, respectively.
- */
- if( sqlite3ExprCanBeNull(pExpr->pLeft) ){
- if( destIfNull==destIfFalse ){
- /* Shortcut for the common case where the false and NULL outcomes are
- ** the same. */
- sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v);
- }else{
- int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
- VdbeCoverage(v);
- sqlite3VdbeGoto(v, destIfNull);
- sqlite3VdbeJumpHere(v, addr1);
- }
- }
-
- if( eType==IN_INDEX_ROWID ){
- /* In this case, the RHS is the ROWID of table b-tree
- */
- sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
+ destStep2 = destStep6 = sqlite3VdbeMakeLabel(v);
+ }
+ for(i=0; i<nVector; i++){
+ Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i);
+ if( sqlite3ExprCanBeNull(p) ){
+ sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2);
VdbeCoverage(v);
- }else{
- /* In this case, the RHS is an index b-tree.
- */
- sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1);
-
- /* If the set membership test fails, then the result of the
- ** "x IN (...)" expression must be either 0 or NULL. If the set
- ** contains no NULL values, then the result is 0. If the set
- ** contains one or more NULL values, then the result of the
- ** expression is also NULL.
- */
- assert( destIfFalse!=destIfNull || rRhsHasNull==0 );
- if( rRhsHasNull==0 ){
- /* This branch runs if it is known at compile time that the RHS
- ** cannot contain NULL values. This happens as the result
- ** of a "NOT NULL" constraint in the database schema.
- **
- ** Also run this branch if NULL is equivalent to FALSE
- ** for this particular IN operator.
- */
- sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
- VdbeCoverage(v);
- }else{
- /* In this branch, the RHS of the IN might contain a NULL and
- ** the presence of a NULL on the RHS makes a difference in the
- ** outcome.
- */
- int addr1;
-
- /* First check to see if the LHS is contained in the RHS. If so,
- ** then the answer is TRUE the presence of NULLs in the RHS does
- ** not matter. If the LHS is not contained in the RHS, then the
- ** answer is NULL if the RHS contains NULLs and the answer is
- ** FALSE if the RHS is NULL-free.
- */
- addr1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
- VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull);
- VdbeCoverage(v);
- sqlite3VdbeGoto(v, destIfFalse);
- sqlite3VdbeJumpHere(v, addr1);
- }
}
}
- sqlite3ReleaseTempReg(pParse, r1);
+
+ /* Step 3. The LHS is now known to be non-NULL. Do the binary search
+ ** of the RHS using the LHS as a probe. If found, the result is
+ ** true.
+ */
+ if( eType==IN_INDEX_ROWID ){
+ /* In this case, the RHS is the ROWID of table b-tree and so we also
+ ** know that the RHS is non-NULL. Hence, we combine steps 3 and 4
+ ** into a single opcode. */
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, pExpr->iTable, destIfFalse, rLhs);
+ VdbeCoverage(v);
+ addrTruthOp = sqlite3VdbeAddOp0(v, OP_Goto); /* Return True */
+ }else{
+ sqlite3VdbeAddOp4(v, OP_Affinity, rLhs, nVector, 0, zAff, nVector);
+ if( destIfFalse==destIfNull ){
+ /* Combine Step 3 and Step 5 into a single opcode */
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse,
+ rLhs, nVector); VdbeCoverage(v);
+ goto sqlite3ExprCodeIN_finished;
+ }
+ /* Ordinary Step 3, for the case where FALSE and NULL are distinct */
+ addrTruthOp = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0,
+ rLhs, nVector); VdbeCoverage(v);
+ }
+
+ /* Step 4. If the RHS is known to be non-NULL and we did not find
+ ** an match on the search above, then the result must be FALSE.
+ */
+ if( rRhsHasNull && nVector==1 ){
+ sqlite3VdbeAddOp2(v, OP_NotNull, rRhsHasNull, destIfFalse);
+ VdbeCoverage(v);
+ }
+
+ /* Step 5. If we do not care about the difference between NULL and
+ ** FALSE, then just return false.
+ */
+ if( destIfFalse==destIfNull ) sqlite3VdbeGoto(v, destIfFalse);
+
+ /* Step 6: Loop through rows of the RHS. Compare each row to the LHS.
+ ** If any comparison is NULL, then the result is NULL. If all
+ ** comparisons are FALSE then the final result is FALSE.
+ **
+ ** For a scalar LHS, it is sufficient to check just the first row
+ ** of the RHS.
+ */
+ if( destStep6 ) sqlite3VdbeResolveLabel(v, destStep6);
+ addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
+ VdbeCoverage(v);
+ if( nVector>1 ){
+ destNotNull = sqlite3VdbeMakeLabel(v);
+ }else{
+ /* For nVector==1, combine steps 6 and 7 by immediately returning
+ ** FALSE if the first comparison is not NULL */
+ destNotNull = destIfFalse;
+ }
+ for(i=0; i<nVector; i++){
+ Expr *p;
+ CollSeq *pColl;
+ int r3 = sqlite3GetTempReg(pParse);
+ p = sqlite3VectorFieldSubexpr(pLeft, i);
+ pColl = sqlite3ExprCollSeq(pParse, p);
+ sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, i, r3);
+ sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3,
+ (void*)pColl, P4_COLLSEQ);
+ VdbeCoverage(v);
+ sqlite3ReleaseTempReg(pParse, r3);
+ }
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
+ if( nVector>1 ){
+ sqlite3VdbeResolveLabel(v, destNotNull);
+ sqlite3VdbeAddOp2(v, OP_Next, pExpr->iTable, addrTop+1);
+ VdbeCoverage(v);
+
+ /* Step 7: If we reach this point, we know that the result must
+ ** be false. */
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
+ }
+
+ /* Jumps here in order to return true. */
+ sqlite3VdbeJumpHere(v, addrTruthOp);
+
+sqlite3ExprCodeIN_finished:
+ if( rLhs!=rLhsOrig ) sqlite3ReleaseTempReg(pParse, rLhs);
sqlite3ExprCachePop(pParse);
VdbeComment((v, "end IN expr"));
+sqlite3ExprCodeIN_oom_error:
+ sqlite3DbFree(pParse->db, aiMap);
+ sqlite3DbFree(pParse->db, zAff);
}
#endif /* SQLITE_OMIT_SUBQUERY */
@@ -88762,35 +93242,38 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
const char *z = pExpr->u.zToken;
assert( z!=0 );
c = sqlite3DecOrHexToI64(z, &value);
- if( c==0 || (c==2 && negFlag) ){
- if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
- sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
- }else{
+ if( c==1 || (c==2 && !negFlag) || (negFlag && value==SMALLEST_INT64)){
#ifdef SQLITE_OMIT_FLOATING_POINT
sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
#ifndef SQLITE_OMIT_HEX_INTEGER
if( sqlite3_strnicmp(z,"0x",2)==0 ){
- sqlite3ErrorMsg(pParse, "hex literal too big: %s", z);
+ sqlite3ErrorMsg(pParse, "hex literal too big: %s%s", negFlag?"-":"",z);
}else
#endif
{
codeReal(v, z, negFlag, iMem);
}
#endif
+ }else{
+ if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
+ sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64);
}
}
}
/*
-** Clear a cache entry.
+** Erase column-cache entry number i
*/
-static void cacheEntryClear(Parse *pParse, struct yColCache *p){
- if( p->tempReg ){
+static void cacheEntryClear(Parse *pParse, int i){
+ if( pParse->aColCache[i].tempReg ){
if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
- pParse->aTempReg[pParse->nTempReg++] = p->iReg;
+ pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg;
}
- p->tempReg = 0;
+ }
+ pParse->nColCache--;
+ if( i<pParse->nColCache ){
+ pParse->aColCache[i] = pParse->aColCache[pParse->nColCache];
}
}
@@ -88821,43 +93304,33 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
** that the object will never already be in cache. Verify this guarantee.
*/
#ifndef NDEBUG
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
- assert( p->iReg==0 || p->iTable!=iTab || p->iColumn!=iCol );
+ for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
+ assert( p->iTable!=iTab || p->iColumn!=iCol );
}
#endif
- /* Find an empty slot and replace it */
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
- if( p->iReg==0 ){
- p->iLevel = pParse->iCacheLevel;
- p->iTable = iTab;
- p->iColumn = iCol;
- p->iReg = iReg;
- p->tempReg = 0;
- p->lru = pParse->iCacheCnt++;
- return;
- }
- }
-
- /* Replace the last recently used */
- minLru = 0x7fffffff;
- idxLru = -1;
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
- if( p->lru<minLru ){
- idxLru = i;
- minLru = p->lru;
+ /* If the cache is already full, delete the least recently used entry */
+ if( pParse->nColCache>=SQLITE_N_COLCACHE ){
+ minLru = 0x7fffffff;
+ idxLru = -1;
+ for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ if( p->lru<minLru ){
+ idxLru = i;
+ minLru = p->lru;
+ }
}
- }
- if( ALWAYS(idxLru>=0) ){
p = &pParse->aColCache[idxLru];
- p->iLevel = pParse->iCacheLevel;
- p->iTable = iTab;
- p->iColumn = iCol;
- p->iReg = iReg;
- p->tempReg = 0;
- p->lru = pParse->iCacheCnt++;
- return;
+ }else{
+ p = &pParse->aColCache[pParse->nColCache++];
}
+
+ /* Add the new entry to the end of the cache */
+ p->iLevel = pParse->iCacheLevel;
+ p->iTable = iTab;
+ p->iColumn = iCol;
+ p->iReg = iReg;
+ p->tempReg = 0;
+ p->lru = pParse->iCacheCnt++;
}
/*
@@ -88865,14 +93338,13 @@ SQLITE_PRIVATE void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int
** Purge the range of registers from the column cache.
*/
SQLITE_PRIVATE void sqlite3ExprCacheRemove(Parse *pParse, int iReg, int nReg){
- int i;
- int iLast = iReg + nReg - 1;
- struct yColCache *p;
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
- int r = p->iReg;
- if( r>=iReg && r<=iLast ){
- cacheEntryClear(pParse, p);
- p->iReg = 0;
+ int i = 0;
+ while( i<pParse->nColCache ){
+ struct yColCache *p = &pParse->aColCache[i];
+ if( p->iReg >= iReg && p->iReg < iReg+nReg ){
+ cacheEntryClear(pParse, i);
+ }else{
+ i++;
}
}
}
@@ -88897,8 +93369,7 @@ SQLITE_PRIVATE void sqlite3ExprCachePush(Parse *pParse){
** the cache to the state it was in prior the most recent Push.
*/
SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
- int i;
- struct yColCache *p;
+ int i = 0;
assert( pParse->iCacheLevel>=1 );
pParse->iCacheLevel--;
#ifdef SQLITE_DEBUG
@@ -88906,10 +93377,11 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
printf("POP to %d\n", pParse->iCacheLevel);
}
#endif
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
- if( p->iReg && p->iLevel>pParse->iCacheLevel ){
- cacheEntryClear(pParse, p);
- p->iReg = 0;
+ while( i<pParse->nColCache ){
+ if( pParse->aColCache[i].iLevel>pParse->iCacheLevel ){
+ cacheEntryClear(pParse, i);
+ }else{
+ i++;
}
}
}
@@ -88923,7 +93395,7 @@ SQLITE_PRIVATE void sqlite3ExprCachePop(Parse *pParse){
static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){
int i;
struct yColCache *p;
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
if( p->iReg==iReg ){
p->tempReg = 0;
}
@@ -88967,7 +93439,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
}else{
int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
int x = iCol;
- if( !HasRowid(pTab) ){
+ if( !HasRowid(pTab) && !IsVirtual(pTab) ){
x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol);
}
sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut);
@@ -89001,8 +93473,8 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
int i;
struct yColCache *p;
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
- if( p->iReg>0 && p->iTable==iTable && p->iColumn==iColumn ){
+ for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
+ if( p->iTable==iTable && p->iColumn==iColumn ){
p->lru = pParse->iCacheCnt++;
sqlite3ExprCachePinRegister(pParse, p->iReg);
return p->iReg;
@@ -89034,19 +93506,20 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnToReg(
*/
SQLITE_PRIVATE void sqlite3ExprCacheClear(Parse *pParse){
int i;
- struct yColCache *p;
#if SQLITE_DEBUG
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
printf("CLEAR\n");
}
#endif
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
- if( p->iReg ){
- cacheEntryClear(pParse, p);
- p->iReg = 0;
+ for(i=0; i<pParse->nColCache; i++){
+ if( pParse->aColCache[i].tempReg
+ && pParse->nTempReg<ArraySize(pParse->aTempReg)
+ ){
+ pParse->aTempReg[pParse->nTempReg++] = pParse->aColCache[i].iReg;
}
}
+ pParse->nColCache = 0;
}
/*
@@ -89078,7 +93551,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n
static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
int i;
struct yColCache *p;
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
int r = p->iReg;
if( r>=iFrom && r<=iTo ) return 1; /*NO_TEST*/
}
@@ -89086,8 +93559,11 @@ static int usedAsColumnCache(Parse *pParse, int iFrom, int iTo){
}
#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
+
/*
-** Convert an expression node to a TK_REGISTER
+** Convert a scalar expression node to a TK_REGISTER referencing
+** register iReg. The caller must ensure that iReg already contains
+** the correct value for the expression.
*/
static void exprToRegister(Expr *p, int iReg){
p->op2 = p->op;
@@ -89097,6 +93573,38 @@ static void exprToRegister(Expr *p, int iReg){
}
/*
+** Evaluate an expression (either a vector or a scalar expression) and store
+** the result in continguous temporary registers. Return the index of
+** the first register used to store the result.
+**
+** If the returned result register is a temporary scalar, then also write
+** that register number into *piFreeable. If the returned result register
+** is not a temporary or if the expression is a vector set *piFreeable
+** to 0.
+*/
+static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
+ int iResult;
+ int nResult = sqlite3ExprVectorSize(p);
+ if( nResult==1 ){
+ iResult = sqlite3ExprCodeTemp(pParse, p, piFreeable);
+ }else{
+ *piFreeable = 0;
+ if( p->op==TK_SELECT ){
+ iResult = sqlite3CodeSubselect(pParse, p, 0, 0);
+ }else{
+ int i;
+ iResult = pParse->nMem+1;
+ pParse->nMem += nResult;
+ for(i=0; i<nResult; i++){
+ sqlite3ExprCodeFactorable(pParse, p->x.pList->a[i].pExpr, i+iResult);
+ }
+ }
+ }
+ return iResult;
+}
+
+
+/*
** Generate code into the current Vdbe to evaluate the given
** expression. Attempt to store the results in register "target".
** Return the register where results are stored.
@@ -89113,9 +93621,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
int inReg = target; /* Results stored in register inReg */
int regFree1 = 0; /* If non-zero free this temporary register */
int regFree2 = 0; /* If non-zero free this temporary register */
- int r1, r2, r3, r4; /* Various register numbers */
- sqlite3 *db = pParse->db; /* The database connection */
+ int r1, r2; /* Various register numbers */
Expr tempX; /* Temporary expression node */
+ int p5 = 0;
assert( target>0 && target<=pParse->nMem );
if( v==0 ){
@@ -89134,12 +93642,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
assert( pCol->iMem>0 );
- inReg = pCol->iMem;
- break;
+ return pCol->iMem;
}else if( pAggInfo->useSortingIdx ){
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
pCol->iSorterColumn, target);
- break;
+ return target;
}
/* Otherwise, fall thru into the TK_COLUMN case */
}
@@ -89148,38 +93655,36 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
if( iTab<0 ){
if( pParse->ckBase>0 ){
/* Generating CHECK constraints or inserting into partial index */
- inReg = pExpr->iColumn + pParse->ckBase;
- break;
+ return pExpr->iColumn + pParse->ckBase;
}else{
/* Coding an expression that is part of an index where column names
** in the index refer to the table to which the index belongs */
iTab = pParse->iSelfTab;
}
}
- inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
+ return sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
pExpr->iColumn, iTab, target,
pExpr->op2);
- break;
}
case TK_INTEGER: {
codeInteger(pParse, pExpr, 0, target);
- break;
+ return target;
}
#ifndef SQLITE_OMIT_FLOATING_POINT
case TK_FLOAT: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
codeReal(v, pExpr->u.zToken, 0, target);
- break;
+ return target;
}
#endif
case TK_STRING: {
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3VdbeLoadString(v, target, pExpr->u.zToken);
- break;
+ return target;
}
case TK_NULL: {
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
- break;
+ return target;
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
case TK_BLOB: {
@@ -89194,7 +93699,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
assert( z[n]=='\'' );
zBlob = sqlite3HexToBlob(sqlite3VdbeDb(v), z, n);
sqlite3VdbeAddOp4(v, OP_Blob, n/2, target, 0, zBlob, P4_DYNAMIC);
- break;
+ return target;
}
#endif
case TK_VARIABLE: {
@@ -89203,15 +93708,15 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
assert( pExpr->u.zToken[0]!=0 );
sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
if( pExpr->u.zToken[1]!=0 ){
- assert( pExpr->u.zToken[0]=='?'
- || strcmp(pExpr->u.zToken, pParse->azVar[pExpr->iColumn-1])==0 );
- sqlite3VdbeChangeP4(v, -1, pParse->azVar[pExpr->iColumn-1], P4_STATIC);
+ const char *z = sqlite3VListNumToName(pParse->pVList, pExpr->iColumn);
+ assert( pExpr->u.zToken[0]=='?' || strcmp(pExpr->u.zToken, z)==0 );
+ pParse->pVList[0] = 0; /* Indicate VList may no longer be enlarged */
+ sqlite3VdbeAppendP4(v, (char*)z, P4_STATIC);
}
- break;
+ return target;
}
case TK_REGISTER: {
- inReg = pExpr->iTable;
- break;
+ return pExpr->iTable;
}
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
@@ -89225,42 +93730,37 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3AffinityType(pExpr->u.zToken, 0));
testcase( usedAsColumnCache(pParse, inReg, inReg) );
sqlite3ExprCacheAffinityChange(pParse, inReg, 1);
- break;
+ return inReg;
}
#endif /* SQLITE_OMIT_CAST */
+ case TK_IS:
+ case TK_ISNOT:
+ op = (op==TK_IS) ? TK_EQ : TK_NE;
+ p5 = SQLITE_NULLEQ;
+ /* fall-through */
case TK_LT:
case TK_LE:
case TK_GT:
case TK_GE:
case TK_NE:
case TK_EQ: {
- r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
- r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, inReg, SQLITE_STOREP2);
- assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
- assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
- assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
- assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
- assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
- assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
- testcase( regFree1==0 );
- testcase( regFree2==0 );
- break;
- }
- case TK_IS:
- case TK_ISNOT: {
- testcase( op==TK_IS );
- testcase( op==TK_ISNOT );
- r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
- r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
- op = (op==TK_IS) ? TK_EQ : TK_NE;
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ);
- VdbeCoverageIf(v, op==TK_EQ);
- VdbeCoverageIf(v, op==TK_NE);
- testcase( regFree1==0 );
- testcase( regFree2==0 );
+ Expr *pLeft = pExpr->pLeft;
+ if( sqlite3ExprIsVector(pLeft) ){
+ codeVectorCompare(pParse, pExpr, target, op, p5);
+ }else{
+ r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
+ r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
+ codeCompare(pParse, pLeft, pExpr->pRight, op,
+ r1, r2, inReg, SQLITE_STOREP2 | p5);
+ assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
+ assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
+ assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
+ assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
+ assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
+ assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
+ testcase( regFree1==0 );
+ testcase( regFree2==0 );
+ }
break;
}
case TK_AND:
@@ -89298,10 +93798,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
assert( pLeft );
if( pLeft->op==TK_INTEGER ){
codeInteger(pParse, pLeft, 1, target);
+ return target;
#ifndef SQLITE_OMIT_FLOATING_POINT
}else if( pLeft->op==TK_FLOAT ){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
codeReal(v, pLeft->u.zToken, 1, target);
+ return target;
#endif
}else{
tempX.op = TK_INTEGER;
@@ -89312,7 +93814,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
testcase( regFree2==0 );
}
- inReg = target;
break;
}
case TK_BITNOT:
@@ -89321,7 +93822,6 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
assert( TK_NOT==OP_Not ); testcase( op==TK_NOT );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
testcase( regFree1==0 );
- inReg = target;
sqlite3VdbeAddOp2(v, op, r1, inReg);
break;
}
@@ -89346,7 +93846,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
}else{
- inReg = pInfo->aFunc[pExpr->iAgg].iMem;
+ return pInfo->aFunc[pExpr->iAgg].iMem;
}
break;
}
@@ -89354,10 +93854,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
ExprList *pFarg; /* List of function arguments */
int nFarg; /* Number of function arguments */
FuncDef *pDef; /* The function definition object */
- int nId; /* Length of the function name in bytes */
const char *zId; /* The function name */
u32 constMask = 0; /* Mask of function arguments that are constant */
int i; /* Loop counter */
+ sqlite3 *db = pParse->db; /* The database connection */
u8 enc = ENC(db); /* The text encoding used by this database */
CollSeq *pColl = 0; /* A collating sequence */
@@ -89370,10 +93870,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
nFarg = pFarg ? pFarg->nExpr : 0;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
zId = pExpr->u.zToken;
- nId = sqlite3Strlen30(zId);
- pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
+ pDef = sqlite3FindFunction(db, zId, nFarg, enc, 0);
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ if( pDef==0 && pParse->explain ){
+ pDef = sqlite3FindFunction(db, "unknown", nFarg, enc, 0);
+ }
+#endif
if( pDef==0 || pDef->xFinalize!=0 ){
- sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
+ sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
break;
}
@@ -89402,8 +93906,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
*/
if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){
assert( nFarg>=1 );
- inReg = sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
- break;
+ return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target);
}
for(i=0; i<nFarg; i++){
@@ -89478,16 +93981,35 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
if( nFarg && constMask==0 ){
sqlite3ReleaseTempRange(pParse, r1, nFarg);
}
- break;
+ return target;
}
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS:
case TK_SELECT: {
+ int nCol;
testcase( op==TK_EXISTS );
testcase( op==TK_SELECT );
- inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
+ if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
+ sqlite3SubselectError(pParse, nCol, 1);
+ }else{
+ return sqlite3CodeSubselect(pParse, pExpr, 0, 0);
+ }
break;
}
+ case TK_SELECT_COLUMN: {
+ int n;
+ if( pExpr->pLeft->iTable==0 ){
+ pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft, 0, 0);
+ }
+ assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT );
+ if( pExpr->iTable
+ && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft))
+ ){
+ sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
+ pExpr->iTable, n);
+ }
+ return pExpr->pLeft->iTable + pExpr->iColumn;
+ }
case TK_IN: {
int destIfFalse = sqlite3VdbeMakeLabel(v);
int destIfNull = sqlite3VdbeMakeLabel(v);
@@ -89497,7 +94019,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
sqlite3VdbeResolveLabel(v, destIfFalse);
sqlite3VdbeAddOp2(v, OP_AddImm, target, 0);
sqlite3VdbeResolveLabel(v, destIfNull);
- break;
+ return target;
}
#endif /* SQLITE_OMIT_SUBQUERY */
@@ -89514,34 +94036,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
** Z is stored in pExpr->pList->a[1].pExpr.
*/
case TK_BETWEEN: {
- Expr *pLeft = pExpr->pLeft;
- struct ExprList_item *pLItem = pExpr->x.pList->a;
- Expr *pRight = pLItem->pExpr;
-
- r1 = sqlite3ExprCodeTemp(pParse, pLeft, &regFree1);
- r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
- testcase( regFree1==0 );
- testcase( regFree2==0 );
- r3 = sqlite3GetTempReg(pParse);
- r4 = sqlite3GetTempReg(pParse);
- codeCompare(pParse, pLeft, pRight, OP_Ge,
- r1, r2, r3, SQLITE_STOREP2); VdbeCoverage(v);
- pLItem++;
- pRight = pLItem->pExpr;
- sqlite3ReleaseTempReg(pParse, regFree2);
- r2 = sqlite3ExprCodeTemp(pParse, pRight, &regFree2);
- testcase( regFree2==0 );
- codeCompare(pParse, pLeft, pRight, OP_Le, r1, r2, r4, SQLITE_STOREP2);
- VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_And, r3, r4, target);
- sqlite3ReleaseTempReg(pParse, r3);
- sqlite3ReleaseTempReg(pParse, r4);
- break;
+ exprCodeBetween(pParse, pExpr, target, 0, 0);
+ return target;
}
+ case TK_SPAN:
case TK_COLLATE:
case TK_UPLUS: {
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- break;
+ return sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
}
case TK_TRIGGER: {
@@ -89600,6 +94101,10 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
break;
}
+ case TK_VECTOR: {
+ sqlite3ErrorMsg(pParse, "row value misused");
+ break;
+ }
/*
** Form A:
@@ -89643,8 +94148,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
if( (pX = pExpr->pLeft)!=0 ){
tempX = *pX;
testcase( pX->op==TK_COLUMN );
- exprToRegister(&tempX, sqlite3ExprCodeTemp(pParse, pX, &regFree1));
+ exprToRegister(&tempX, exprCodeVector(pParse, &tempX, &regFree1));
testcase( regFree1==0 );
+ memset(&opCompare, 0, sizeof(opCompare));
opCompare.op = TK_EQ;
opCompare.pLeft = &tempX;
pTest = &opCompare;
@@ -89678,7 +94184,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
}
- assert( db->mallocFailed || pParse->nErr>0
+ assert( pParse->db->mallocFailed || pParse->nErr>0
|| pParse->iCacheLevel==iCacheLevel );
sqlite3VdbeResolveLabel(v, endLabel);
break;
@@ -89889,8 +94395,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR;
for(pItem=pList->a, i=0; i<n; i++, pItem++){
Expr *pExpr = pItem->pExpr;
- if( (flags & SQLITE_ECEL_REF)!=0 && (j = pList->a[i].u.x.iOrderByCol)>0 ){
- sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
+ if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){
+ if( flags & SQLITE_ECEL_OMITREF ){
+ i--;
+ n--;
+ }else{
+ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
+ }
}else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
}else{
@@ -89923,20 +94434,33 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
**
** Code it as such, taking care to do the common subexpression
** elimination of x.
+**
+** The xJumpIf parameter determines details:
+**
+** NULL: Store the boolean result in reg[dest]
+** sqlite3ExprIfTrue: Jump to dest if true
+** sqlite3ExprIfFalse: Jump to dest if false
+**
+** The jumpIfNull parameter is ignored if xJumpIf is NULL.
*/
static void exprCodeBetween(
Parse *pParse, /* Parsing and code generating context */
Expr *pExpr, /* The BETWEEN expression */
- int dest, /* Jump here if the jump is taken */
- int jumpIfTrue, /* Take the jump if the BETWEEN is true */
+ int dest, /* Jump destination or storage location */
+ void (*xJump)(Parse*,Expr*,int,int), /* Action to take */
int jumpIfNull /* Take the jump if the BETWEEN is NULL */
){
- Expr exprAnd; /* The AND operator in x>=y AND x<=z */
+ Expr exprAnd; /* The AND operator in x>=y AND x<=z */
Expr compLeft; /* The x>=y term */
Expr compRight; /* The x<=z term */
Expr exprX; /* The x subexpression */
int regFree1 = 0; /* Temporary use register */
+
+ memset(&compLeft, 0, sizeof(Expr));
+ memset(&compRight, 0, sizeof(Expr));
+ memset(&exprAnd, 0, sizeof(Expr));
+
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
exprX = *pExpr->pLeft;
exprAnd.op = TK_AND;
@@ -89948,23 +94472,30 @@ static void exprCodeBetween(
compRight.op = TK_LE;
compRight.pLeft = &exprX;
compRight.pRight = pExpr->x.pList->a[1].pExpr;
- exprToRegister(&exprX, sqlite3ExprCodeTemp(pParse, &exprX, &regFree1));
- if( jumpIfTrue ){
- sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull);
- }else{
- sqlite3ExprIfFalse(pParse, &exprAnd, dest, jumpIfNull);
+ exprToRegister(&exprX, exprCodeVector(pParse, &exprX, &regFree1));
+ if( xJump ){
+ xJump(pParse, &exprAnd, dest, jumpIfNull);
+ }else{
+ /* Mark the expression is being from the ON or USING clause of a join
+ ** so that the sqlite3ExprCodeTarget() routine will not attempt to move
+ ** it into the Parse.pConstExpr list. We should use a new bit for this,
+ ** for clarity, but we are out of bits in the Expr.flags field so we
+ ** have to reuse the EP_FromJoin bit. Bummer. */
+ exprX.flags |= EP_FromJoin;
+ sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
}
sqlite3ReleaseTempReg(pParse, regFree1);
/* Ensure adequate test coverage */
- testcase( jumpIfTrue==0 && jumpIfNull==0 && regFree1==0 );
- testcase( jumpIfTrue==0 && jumpIfNull==0 && regFree1!=0 );
- testcase( jumpIfTrue==0 && jumpIfNull!=0 && regFree1==0 );
- testcase( jumpIfTrue==0 && jumpIfNull!=0 && regFree1!=0 );
- testcase( jumpIfTrue!=0 && jumpIfNull==0 && regFree1==0 );
- testcase( jumpIfTrue!=0 && jumpIfNull==0 && regFree1!=0 );
- testcase( jumpIfTrue!=0 && jumpIfNull!=0 && regFree1==0 );
- testcase( jumpIfTrue!=0 && jumpIfNull!=0 && regFree1!=0 );
+ testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 );
+ testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1!=0 );
+ testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1==0 );
+ testcase( xJump==sqlite3ExprIfTrue && jumpIfNull!=0 && regFree1!=0 );
+ testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1==0 );
+ testcase( xJump==sqlite3ExprIfFalse && jumpIfNull==0 && regFree1!=0 );
+ testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1==0 );
+ testcase( xJump==sqlite3ExprIfFalse && jumpIfNull!=0 && regFree1!=0 );
+ testcase( xJump==0 );
}
/*
@@ -90016,12 +94547,20 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
+ case TK_IS:
+ case TK_ISNOT:
+ testcase( op==TK_IS );
+ testcase( op==TK_ISNOT );
+ op = (op==TK_IS) ? TK_EQ : TK_NE;
+ jumpIfNull = SQLITE_NULLEQ;
+ /* Fall thru */
case TK_LT:
case TK_LE:
case TK_GT:
case TK_GE:
case TK_NE:
case TK_EQ: {
+ if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr;
testcase( jumpIfNull==0 );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
@@ -90031,23 +94570,12 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
- assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
- assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
- testcase( regFree1==0 );
- testcase( regFree2==0 );
- break;
- }
- case TK_IS:
- case TK_ISNOT: {
- testcase( op==TK_IS );
- testcase( op==TK_ISNOT );
- r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
- r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
- op = (op==TK_IS) ? TK_EQ : TK_NE;
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, dest, SQLITE_NULLEQ);
- VdbeCoverageIf(v, op==TK_EQ);
- VdbeCoverageIf(v, op==TK_NE);
+ assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
+ VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
+ VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
+ assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
+ VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
+ VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -90065,7 +94593,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
}
case TK_BETWEEN: {
testcase( jumpIfNull==0 );
- exprCodeBetween(pParse, pExpr, dest, 1, jumpIfNull);
+ exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfTrue, jumpIfNull);
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
@@ -90079,6 +94607,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
}
#endif
default: {
+ default_expr:
if( exprAlwaysTrue(pExpr) ){
sqlite3VdbeGoto(v, dest);
}else if( exprAlwaysFalse(pExpr) ){
@@ -90172,12 +94701,20 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
sqlite3ExprIfTrue(pParse, pExpr->pLeft, dest, jumpIfNull);
break;
}
+ case TK_IS:
+ case TK_ISNOT:
+ testcase( pExpr->op==TK_IS );
+ testcase( pExpr->op==TK_ISNOT );
+ op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
+ jumpIfNull = SQLITE_NULLEQ;
+ /* Fall thru */
case TK_LT:
case TK_LE:
case TK_GT:
case TK_GE:
case TK_NE:
case TK_EQ: {
+ if( sqlite3ExprIsVector(pExpr->pLeft) ) goto default_expr;
testcase( jumpIfNull==0 );
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
@@ -90187,23 +94724,12 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
assert(TK_GT==OP_Gt); testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
- assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
- assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
- testcase( regFree1==0 );
- testcase( regFree2==0 );
- break;
- }
- case TK_IS:
- case TK_ISNOT: {
- testcase( pExpr->op==TK_IS );
- testcase( pExpr->op==TK_ISNOT );
- r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
- r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, &regFree2);
- op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
- codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op,
- r1, r2, dest, SQLITE_NULLEQ);
- VdbeCoverageIf(v, op==TK_EQ);
- VdbeCoverageIf(v, op==TK_NE);
+ assert(TK_EQ==OP_Eq); testcase(op==OP_Eq);
+ VdbeCoverageIf(v, op==OP_Eq && jumpIfNull!=SQLITE_NULLEQ);
+ VdbeCoverageIf(v, op==OP_Eq && jumpIfNull==SQLITE_NULLEQ);
+ assert(TK_NE==OP_Ne); testcase(op==OP_Ne);
+ VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ);
+ VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ);
testcase( regFree1==0 );
testcase( regFree2==0 );
break;
@@ -90219,7 +94745,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
}
case TK_BETWEEN: {
testcase( jumpIfNull==0 );
- exprCodeBetween(pParse, pExpr, dest, 0, jumpIfNull);
+ exprCodeBetween(pParse, pExpr, dest, sqlite3ExprIfFalse, jumpIfNull);
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
@@ -90235,6 +94761,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
}
#endif
default: {
+ default_expr:
if( exprAlwaysFalse(pExpr) ){
sqlite3VdbeGoto(v, dest);
}else if( exprAlwaysTrue(pExpr) ){
@@ -90392,17 +94919,71 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){
){
return 1;
}
- if( pE2->op==TK_NOTNULL
- && sqlite3ExprCompare(pE1->pLeft, pE2->pLeft, iTab)==0
- && (pE1->op!=TK_ISNULL && pE1->op!=TK_IS)
- ){
- return 1;
+ if( pE2->op==TK_NOTNULL && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){
+ Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft);
+ testcase( pX!=pE1->pLeft );
+ if( sqlite3ExprCompare(pX, pE2->pLeft, iTab)==0 ) return 1;
}
return 0;
}
/*
** An instance of the following structure is used by the tree walker
+** to determine if an expression can be evaluated by reference to the
+** index only, without having to do a search for the corresponding
+** table entry. The IdxCover.pIdx field is the index. IdxCover.iCur
+** is the cursor for the table.
+*/
+struct IdxCover {
+ Index *pIdx; /* The index to be tested for coverage */
+ int iCur; /* Cursor number for the table corresponding to the index */
+};
+
+/*
+** Check to see if there are references to columns in table
+** pWalker->u.pIdxCover->iCur can be satisfied using the index
+** pWalker->u.pIdxCover->pIdx.
+*/
+static int exprIdxCover(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_COLUMN
+ && pExpr->iTable==pWalker->u.pIdxCover->iCur
+ && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0
+ ){
+ pWalker->eCode = 1;
+ return WRC_Abort;
+ }
+ return WRC_Continue;
+}
+
+/*
+** Determine if an index pIdx on table with cursor iCur contains will
+** the expression pExpr. Return true if the index does cover the
+** expression and false if the pExpr expression references table columns
+** that are not found in the index pIdx.
+**
+** An index covering an expression means that the expression can be
+** evaluated using only the index and without having to lookup the
+** corresponding table entry.
+*/
+SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(
+ Expr *pExpr, /* The index to be tested */
+ int iCur, /* The cursor number for the corresponding table */
+ Index *pIdx /* The index that might be used for coverage */
+){
+ Walker w;
+ struct IdxCover xcov;
+ memset(&w, 0, sizeof(w));
+ xcov.iCur = iCur;
+ xcov.pIdx = pIdx;
+ w.xExprCallback = exprIdxCover;
+ w.u.pIdxCover = &xcov;
+ sqlite3WalkExpr(&w, pExpr);
+ return !w.eCode;
+}
+
+
+/*
+** An instance of the following structure is used by the tree walker
** to count references to table columns in the arguments of an
** aggregate function, in order to implement the
** sqlite3FunctionThisSrc() routine.
@@ -90598,7 +95179,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
pItem->iMem = ++pParse->nMem;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
pItem->pFunc = sqlite3FindFunction(pParse->db,
- pExpr->u.zToken, sqlite3Strlen30(pExpr->u.zToken),
+ pExpr->u.zToken,
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
if( pExpr->flags & EP_Distinct ){
pItem->iDistinct = pParse->nTab++;
@@ -90684,7 +95265,7 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
if( iReg && pParse->nTempReg<ArraySize(pParse->aTempReg) ){
int i;
struct yColCache *p;
- for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
+ for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){
if( p->iReg==iReg ){
p->tempReg = 1;
return;
@@ -90695,10 +95276,11 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse *pParse, int iReg){
}
/*
-** Allocate or deallocate a block of nReg consecutive registers
+** Allocate or deallocate a block of nReg consecutive registers.
*/
SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){
int i, n;
+ if( nReg==1 ) return sqlite3GetTempReg(pParse);
i = pParse->iRangeReg;
n = pParse->nRangeReg;
if( nReg<=n ){
@@ -90712,6 +95294,10 @@ SQLITE_PRIVATE int sqlite3GetTempRange(Parse *pParse, int nReg){
return i;
}
SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){
+ if( nReg==1 ){
+ sqlite3ReleaseTempReg(pParse, iReg);
+ return;
+ }
sqlite3ExprCacheRemove(pParse, iReg, nReg);
if( nReg>pParse->nRangeReg ){
pParse->nRangeReg = nReg;
@@ -90727,6 +95313,29 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
pParse->nRangeReg = 0;
}
+/*
+** Validate that no temporary register falls within the range of
+** iFirst..iLast, inclusive. This routine is only call from within assert()
+** statements.
+*/
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
+ int i;
+ if( pParse->nRangeReg>0
+ && pParse->iRangeReg+pParse->nRangeReg<iLast
+ && pParse->iRangeReg>=iFirst
+ ){
+ return 0;
+ }
+ for(i=0; i<pParse->nTempReg; i++){
+ if( pParse->aTempReg[i]>=iFirst && pParse->aTempReg[i]<=iLast ){
+ return 0;
+ }
+ }
+ return 1;
+}
+#endif /* SQLITE_DEBUG */
+
/************** End of expr.c ************************************************/
/************** Begin file alter.c *******************************************/
/*
@@ -90960,7 +95569,7 @@ static void renameTriggerFunc(
** Register built-in functions used to help implement ALTER TABLE
*/
SQLITE_PRIVATE void sqlite3AlterFunctions(void){
- static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
+ static FuncDef aAlterTableFuncs[] = {
FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
#ifndef SQLITE_OMIT_TRIGGER
FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
@@ -90969,13 +95578,7 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){
FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
#endif
};
- int i;
- FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
- FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
-
- for(i=0; i<ArraySize(aAlterTableFuncs); i++){
- sqlite3FuncDefInsert(pHash, &aFunc[i]);
- }
+ sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
}
/*
@@ -91150,7 +95753,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
- zDb = db->aDb[iDb].zName;
+ zDb = db->aDb[iDb].zDbSName;
db->flags |= SQLITE_PreferBuiltin;
/* Get a NULL terminated version of the new table name. */
@@ -91241,7 +95844,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
sqlite3NestedParse(pParse,
"UPDATE \"%w\".%s SET "
"sql = sqlite_rename_parent(sql, %Q, %Q) "
- "WHERE %s;", zDb, SCHEMA_TABLE(iDb), zTabName, zName, zWhere);
+ "WHERE %s;", zDb, MASTER_NAME, zTabName, zName, zWhere);
sqlite3DbFree(db, zWhere);
}
}
@@ -91265,7 +95868,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
"ELSE name END "
"WHERE tbl_name=%Q COLLATE nocase AND "
"(type='table' OR type='index' OR type='trigger');",
- zDb, SCHEMA_TABLE(iDb), zName, zName, zName,
+ zDb, MASTER_NAME, zName, zName, zName,
#ifndef SQLITE_OMIT_TRIGGER
zName,
#endif
@@ -91338,6 +95941,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
Expr *pDflt; /* Default value for the new column */
sqlite3 *db; /* The database connection; */
Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */
+ int r1; /* Temporary registers */
db = pParse->db;
if( pParse->nErr || db->mallocFailed ) return;
@@ -91347,7 +95951,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
assert( sqlite3BtreeHoldsAllMutexes(db) );
iDb = sqlite3SchemaToIndex(db, pNew->pSchema);
- zDb = db->aDb[iDb].zName;
+ zDb = db->aDb[iDb].zDbSName;
zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */
pCol = &pNew->aCol[pNew->nCol-1];
pDflt = pCol->pDflt;
@@ -91365,7 +95969,8 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
** literal NULL, then set pDflt to 0. This simplifies checking
** for an SQL NULL default below.
*/
- if( pDflt && pDflt->op==TK_NULL ){
+ assert( pDflt==0 || pDflt->op==TK_SPAN );
+ if( pDflt && pDflt->pLeft->op==TK_NULL ){
pDflt = 0;
}
@@ -91424,23 +96029,25 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
"UPDATE \"%w\".%s SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
"WHERE type = 'table' AND name = %Q",
- zDb, SCHEMA_TABLE(iDb), pNew->addColOffset, zCol, pNew->addColOffset+1,
+ zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1,
zTab
);
sqlite3DbFree(db, zCol);
db->flags = savedDbFlags;
}
- /* If the default value of the new column is NULL, then the file
- ** format to 2. If the default value of the new column is not NULL,
- ** the file format be 3. Back when this feature was first added
- ** in 2006, we went to the trouble to upgrade the file format to the
- ** minimum support values. But 10-years on, we can assume that all
- ** extent versions of SQLite support file-format 4, so we always and
- ** unconditionally upgrade to 4.
+ /* Make sure the schema version is at least 3. But do not upgrade
+ ** from less than 3 to 4, as that will corrupt any preexisting DESC
+ ** index.
*/
- sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT,
- SQLITE_MAX_FILE_FORMAT);
+ r1 = sqlite3GetTempReg(pParse);
+ sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
+ sqlite3VdbeUsesBtree(v, iDb);
+ sqlite3VdbeAddOp2(v, OP_AddImm, r1, -2);
+ sqlite3VdbeAddOp2(v, OP_IfPos, r1, sqlite3VdbeCurrentAddr(v)+2);
+ VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3);
+ sqlite3ReleaseTempReg(pParse, r1);
/* Reload the schema of the modified table. */
reloadTableSchema(pParse, pTab, pTab->zName);
@@ -91506,7 +96113,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pNew = (Table*)sqlite3DbMallocZero(db, sizeof(Table));
if( !pNew ) goto exit_begin_add_column;
pParse->pNewTable = pNew;
- pNew->nRef = 1;
+ pNew->nTabRef = 1;
pNew->nCol = pTab->nCol;
assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8;
@@ -91522,13 +96129,11 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
Column *pCol = &pNew->aCol[i];
pCol->zName = sqlite3DbStrDup(db, pCol->zName);
pCol->zColl = 0;
- pCol->zType = 0;
pCol->pDflt = 0;
- pCol->zDflt = 0;
}
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->addColOffset = pTab->addColOffset;
- pNew->nRef = 1;
+ pNew->nTabRef = 1;
/* Begin a transaction and increment the schema cookie. */
sqlite3BeginWriteOperation(pParse, 0, iDb);
@@ -91756,14 +96361,14 @@ static void openStatTable(
for(i=0; i<ArraySize(aTable); i++){
const char *zTab = aTable[i].zName;
Table *pStat;
- if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){
+ if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
if( aTable[i].zCols ){
/* The sqlite_statN table does not exist. Create it. Note that a
** side-effect of the CREATE TABLE statement is to leave the rootpage
** of the new table in register pParse->regRoot. This is important
** because the OpenWrite opcode below will be needing it. */
sqlite3NestedParse(pParse,
- "CREATE TABLE %Q.%s(%s)", pDb->zName, zTab, aTable[i].zCols
+ "CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
);
aRoot[i] = pParse->regRoot;
aCreateTbl[i] = OPFLAG_P2ISREG;
@@ -91778,7 +96383,7 @@ static void openStatTable(
if( zWhere ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE %s=%Q",
- pDb->zName, zTab, zWhereType, zWhere
+ pDb->zDbSName, zTab, zWhereType, zWhere
);
}else{
/* The sqlite_stat[134] table already exists. Delete all rows. */
@@ -92027,8 +96632,7 @@ static const FuncDef statInitFuncdef = {
statInit, /* xSFunc */
0, /* xFinalize */
"stat_init", /* zName */
- 0, /* pHash */
- 0 /* pDestructor */
+ {0}
};
#ifdef SQLITE_ENABLE_STAT4
@@ -92327,8 +96931,7 @@ static const FuncDef statPushFuncdef = {
statPush, /* xSFunc */
0, /* xFinalize */
"stat_push", /* zName */
- 0, /* pHash */
- 0 /* pDestructor */
+ {0}
};
#define STAT_GET_STAT1 0 /* "stat" column of stat1 table */
@@ -92473,8 +97076,7 @@ static const FuncDef statGetFuncdef = {
statGet, /* xSFunc */
0, /* xFinalize */
"stat_get", /* zName */
- 0, /* pHash */
- 0 /* pDestructor */
+ {0}
};
static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){
@@ -92543,7 +97145,7 @@ static void analyzeOneTable(
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0,
- db->aDb[iDb].zName ) ){
+ db->aDb[iDb].zDbSName ) ){
return;
}
#endif
@@ -92933,7 +97535,7 @@ SQLITE_PRIVATE void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
/* Form 3: Analyze the fully qualified table name */
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pTableName);
if( iDb>=0 ){
- zDb = db->aDb[iDb].zName;
+ zDb = db->aDb[iDb].zDbSName;
z = sqlite3NameFromToken(db, pTableName);
if( z ){
if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
@@ -93219,7 +97821,7 @@ static int loadStatTbl(
assert( db->lookaside.bDisable );
zSql = sqlite3MPrintf(db, zSql1, zDb);
if( !zSql ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
sqlite3DbFree(db, zSql);
@@ -93259,7 +97861,7 @@ static int loadStatTbl(
pIdx->aSample = sqlite3DbMallocZero(db, nByte);
if( pIdx->aSample==0 ){
sqlite3_finalize(pStmt);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
@@ -93275,7 +97877,7 @@ static int loadStatTbl(
zSql = sqlite3MPrintf(db, zSql2, zDb);
if( !zSql ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
sqlite3DbFree(db, zSql);
@@ -93313,9 +97915,11 @@ static int loadStatTbl(
pSample->p = sqlite3DbMallocZero(db, pSample->n + 2);
if( pSample->p==0 ){
sqlite3_finalize(pStmt);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
+ }
+ if( pSample->n ){
+ memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
}
- memcpy(pSample->p, sqlite3_column_blob(pStmt, 4), pSample->n);
pIdx->nSample++;
}
rc = sqlite3_finalize(pStmt);
@@ -93375,7 +97979,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
analysisInfo sInfo;
HashElem *i;
char *zSql;
- int rc;
+ int rc = SQLITE_OK;
assert( iDb>=0 && iDb<db->nDb );
assert( db->aDb[iDb].pBt!=0 );
@@ -93384,31 +97988,34 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
Index *pIdx = sqliteHashData(i);
- sqlite3DefaultRowEst(pIdx);
+ pIdx->aiRowLogEst[0] = 0;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
sqlite3DeleteIndexSamples(db, pIdx);
pIdx->aSample = 0;
#endif
}
- /* Check to make sure the sqlite_stat1 table exists */
+ /* Load new statistics out of the sqlite_stat1 table */
sInfo.db = db;
- sInfo.zDatabase = db->aDb[iDb].zName;
- if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){
- return SQLITE_ERROR;
+ sInfo.zDatabase = db->aDb[iDb].zDbSName;
+ if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){
+ zSql = sqlite3MPrintf(db,
+ "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
+ if( zSql==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ }else{
+ rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
+ sqlite3DbFree(db, zSql);
+ }
}
- /* Load new statistics out of the sqlite_stat1 table */
- zSql = sqlite3MPrintf(db,
- "SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
- if( zSql==0 ){
- rc = SQLITE_NOMEM;
- }else{
- rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0);
- sqlite3DbFree(db, zSql);
+ /* Set appropriate defaults on all indexes not in the sqlite_stat1 table */
+ assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
+ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
+ Index *pIdx = sqliteHashData(i);
+ if( pIdx->aiRowLogEst[0]==0 ) sqlite3DefaultRowEst(pIdx);
}
-
/* Load the statistics from the sqlite_stat4 table. */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( rc==SQLITE_OK && OptimizationEnabled(db, SQLITE_Stat34) ){
@@ -93533,7 +98140,7 @@ static void attachFunc(
goto attach_error;
}
for(i=0; i<db->nDb; i++){
- char *z = db->aDb[i].zName;
+ char *z = db->aDb[i].zDbSName;
assert( z && zName );
if( sqlite3StrICmp(z, zName)==0 ){
zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
@@ -93580,7 +98187,7 @@ static void attachFunc(
Pager *pPager;
aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt);
if( !aNew->pSchema ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){
zErrDyn = sqlite3MPrintf(db,
"attached databases must use the same text encoding as main database");
@@ -93597,10 +98204,10 @@ static void attachFunc(
#endif
sqlite3BtreeLeave(aNew->pBt);
}
- aNew->safety_level = 3;
- aNew->zName = sqlite3DbStrDup(db, zName);
- if( rc==SQLITE_OK && aNew->zName==0 ){
- rc = SQLITE_NOMEM;
+ aNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
+ aNew->zDbSName = sqlite3DbStrDup(db, zName);
+ if( rc==SQLITE_OK && aNew->zDbSName==0 ){
+ rc = SQLITE_NOMEM_BKPT;
}
@@ -93628,7 +98235,7 @@ static void attachFunc(
case SQLITE_NULL:
/* No key specified. Use the key from the main database */
sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
- if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
+ if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
}
break;
@@ -93711,7 +98318,7 @@ static void detachFunc(
for(i=0; i<db->nDb; i++){
pDb = &db->aDb[i];
if( pDb->pBt==0 ) continue;
- if( sqlite3StrICmp(pDb->zName, zName)==0 ) break;
+ if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break;
}
if( i>=db->nDb ){
@@ -93761,6 +98368,7 @@ static void codeAttach(
sqlite3* db = pParse->db;
int regArgs;
+ if( pParse->nErr ) goto attach_end;
memset(&sName, 0, sizeof(NameContext));
sName.pParse = pParse;
@@ -93828,8 +98436,7 @@ SQLITE_PRIVATE void sqlite3Detach(Parse *pParse, Expr *pDbname){
detachFunc, /* xSFunc */
0, /* xFinalize */
"sqlite_detach", /* zName */
- 0, /* pHash */
- 0 /* pDestructor */
+ {0}
};
codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname);
}
@@ -93848,8 +98455,7 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p
attachFunc, /* xSFunc */
0, /* xFinalize */
"sqlite_attach", /* zName */
- 0, /* pHash */
- 0 /* pDestructor */
+ {0}
};
codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey);
}
@@ -93871,7 +98477,7 @@ SQLITE_PRIVATE void sqlite3FixInit(
db = pParse->db;
assert( db->nDb>iDb );
pFix->pParse = pParse;
- pFix->zDb = db->aDb[iDb].zName;
+ pFix->zDb = db->aDb[iDb].zDbSName;
pFix->pSchema = db->aDb[iDb].pSchema;
pFix->zType = zType;
pFix->pName = pName;
@@ -93968,7 +98574,7 @@ SQLITE_PRIVATE int sqlite3FixExpr(
return 1;
}
}
- if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
+ if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
}else{
@@ -94089,7 +98695,7 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(
** Setting the auth function to NULL disables this hook. The default
** setting of the auth function is NULL.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
+SQLITE_API int sqlite3_set_authorizer(
sqlite3 *db,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pArg
@@ -94129,10 +98735,11 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
const char *zCol, /* Column name */
int iDb /* Index of containing database. */
){
- sqlite3 *db = pParse->db; /* Database handle */
- char *zDb = db->aDb[iDb].zName; /* Name of attached database */
- int rc; /* Auth callback return code */
+ sqlite3 *db = pParse->db; /* Database handle */
+ char *zDb = db->aDb[iDb].zDbSName; /* Schema name of attached database */
+ int rc; /* Auth callback return code */
+ if( db->init.busy ) return SQLITE_OK;
rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext
#ifdef SQLITE_USER_AUTHENTICATION
,db->auth.zAuthUser
@@ -94315,10 +98922,10 @@ SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){
** codeTableLocks() functions.
*/
struct TableLock {
- int iDb; /* The database containing the table to be locked */
- int iTab; /* The root page of the table to be locked */
- u8 isWriteLock; /* True for write lock. False for a read lock */
- const char *zName; /* Name of the table */
+ int iDb; /* The database containing the table to be locked */
+ int iTab; /* The root page of the table to be locked */
+ u8 isWriteLock; /* True for write lock. False for a read lock */
+ const char *zLockName; /* Name of the table */
};
/*
@@ -94344,6 +98951,8 @@ SQLITE_PRIVATE void sqlite3TableLock(
TableLock *p;
assert( iDb>=0 );
+ if( iDb==1 ) return;
+ if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return;
for(i=0; i<pToplevel->nTableLock; i++){
p = &pToplevel->aTableLock[i];
if( p->iDb==iDb && p->iTab==iTab ){
@@ -94360,7 +98969,7 @@ SQLITE_PRIVATE void sqlite3TableLock(
p->iDb = iDb;
p->iTab = iTab;
p->isWriteLock = isWriteLock;
- p->zName = zName;
+ p->zLockName = zName;
}else{
pToplevel->nTableLock = 0;
sqlite3OomFault(pToplevel->db);
@@ -94382,7 +98991,7 @@ static void codeTableLocks(Parse *pParse){
TableLock *p = &pParse->aTableLock[i];
int p1 = p->iDb;
sqlite3VdbeAddOp4(pVdbe, OP_TableLock, p1, p->iTab, p->isWriteLock,
- p->zName, P4_STATIC);
+ p->zLockName, P4_STATIC);
}
}
#else
@@ -94431,15 +99040,14 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
assert( !pParse->isMultiWrite
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
if( v ){
- while( sqlite3VdbeDeletePriorOpcode(v, OP_Close) ){}
sqlite3VdbeAddOp0(v, OP_Halt);
#if SQLITE_USER_AUTHENTICATION
if( pParse->nTableLock>0 && db->init.busy==0 ){
sqlite3UserAuthInit(db);
if( db->auth.authLevel<UAUTH_User ){
- pParse->rc = SQLITE_AUTH_USER;
sqlite3ErrorMsg(pParse, "user not authenticated");
+ pParse->rc = SQLITE_AUTH_USER;
return;
}
}
@@ -94458,14 +99066,16 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
sqlite3VdbeJumpHere(v, 0);
for(iDb=0; iDb<db->nDb; iDb++){
+ Schema *pSchema;
if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
sqlite3VdbeUsesBtree(v, iDb);
+ pSchema = db->aDb[iDb].pSchema;
sqlite3VdbeAddOp4Int(v,
OP_Transaction, /* Opcode */
iDb, /* P1 */
DbMaskTest(pParse->writeMask,iDb), /* P2 */
- pParse->cookieValue[iDb], /* P3 */
- db->aDb[iDb].pSchema->iGeneration /* P4 */
+ pSchema->schema_cookie, /* P3 */
+ pSchema->iGeneration /* P4 */
);
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
VdbeComment((v,
@@ -94516,16 +99126,6 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
}else{
pParse->rc = SQLITE_ERROR;
}
-
- /* We are done with this Parse object. There is no need to de-initialize it */
-#if 0
- pParse->colNamesSet = 0;
- pParse->nTab = 0;
- pParse->nMem = 0;
- pParse->nSet = 0;
- pParse->nVar = 0;
- DbMaskZero(pParse->cookieMask);
-#endif
}
/*
@@ -94545,8 +99145,7 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
char *zSql;
char *zErrMsg = 0;
sqlite3 *db = pParse->db;
-# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar))
- char saveBuf[SAVE_SZ];
+ char saveBuf[PARSE_TAIL_SZ];
if( pParse->nErr ) return;
assert( pParse->nested<10 ); /* Nesting should only be of limited depth */
@@ -94557,12 +99156,12 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
return; /* A malloc must have failed */
}
pParse->nested++;
- memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
- memset(&pParse->nVar, 0, SAVE_SZ);
+ memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ);
+ memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
sqlite3RunParser(pParse, zSql, &zErrMsg);
sqlite3DbFree(db, zErrMsg);
sqlite3DbFree(db, zSql);
- memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
+ memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
pParse->nested--;
}
@@ -94601,14 +99200,22 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha
return 0;
}
#endif
- for(i=OMIT_TEMPDB; i<db->nDb; i++){
- int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
- if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue;
- assert( sqlite3SchemaMutexHeld(db, j, 0) );
- p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
- if( p ) break;
+ while(1){
+ for(i=OMIT_TEMPDB; i<db->nDb; i++){
+ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
+ if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
+ assert( sqlite3SchemaMutexHeld(db, j, 0) );
+ p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
+ if( p ) return p;
+ }
+ }
+ /* Not found. If the name we were looking for was temp.sqlite_master
+ ** then change the name to sqlite_temp_master and try again. */
+ if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break;
+ if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
+ zName = TEMP_MASTER_NAME;
}
- return p;
+ return 0;
}
/*
@@ -94623,7 +99230,7 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha
*/
SQLITE_PRIVATE Table *sqlite3LocateTable(
Parse *pParse, /* context in which to report errors */
- int isView, /* True if looking for a VIEW rather than a TABLE */
+ u32 flags, /* LOCATE_VIEW or LOCATE_NOERR */
const char *zName, /* Name of the table we are looking for */
const char *zDbase /* Name of the database. Might be NULL */
){
@@ -94637,24 +99244,29 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
p = sqlite3FindTable(pParse->db, zName, zDbase);
if( p==0 ){
- const char *zMsg = isView ? "no such view" : "no such table";
+ const char *zMsg = flags & LOCATE_VIEW ? "no such view" : "no such table";
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( sqlite3FindDbName(pParse->db, zDbase)<1 ){
/* If zName is the not the name of a table in the schema created using
** CREATE, then check to see if it is the name of an virtual table that
** can be an eponymous virtual table. */
Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName);
+ if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
+ pMod = sqlite3PragmaVtabRegister(pParse->db, zName);
+ }
if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
return pMod->pEpoTab;
}
}
#endif
- if( zDbase ){
- sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
- }else{
- sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
+ if( (flags & LOCATE_NOERR)==0 ){
+ if( zDbase ){
+ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName);
+ }else{
+ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
+ }
+ pParse->checkSchema = 1;
}
- pParse->checkSchema = 1;
}
return p;
@@ -94671,18 +99283,18 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
*/
SQLITE_PRIVATE Table *sqlite3LocateTableItem(
Parse *pParse,
- int isView,
+ u32 flags,
struct SrcList_item *p
){
const char *zDb;
assert( p->pSchema==0 || p->zDatabase==0 );
if( p->pSchema ){
int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
- zDb = pParse->db->aDb[iDb].zName;
+ zDb = pParse->db->aDb[iDb].zDbSName;
}else{
zDb = p->zDatabase;
}
- return sqlite3LocateTable(pParse, isView, p->zName, zDb);
+ return sqlite3LocateTable(pParse, flags, p->zName, zDb);
}
/*
@@ -94706,7 +99318,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
Schema *pSchema = db->aDb[j].pSchema;
assert( pSchema );
- if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue;
+ if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
p = sqlite3HashFind(&pSchema->idxHash, zName);
if( p ) break;
@@ -94775,8 +99387,8 @@ SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3 *db){
for(i=j=2; i<db->nDb; i++){
struct Db *pDb = &db->aDb[i];
if( pDb->pBt==0 ){
- sqlite3DbFree(db, pDb->zName);
- pDb->zName = 0;
+ sqlite3DbFree(db, pDb->zDbSName);
+ pDb->zDbSName = 0;
continue;
}
if( j<i ){
@@ -94856,8 +99468,6 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
for(i=0; i<pTable->nCol; i++, pCol++){
sqlite3DbFree(db, pCol->zName);
sqlite3ExprDelete(db, pCol->pDflt);
- sqlite3DbFree(db, pCol->zDflt);
- sqlite3DbFree(db, pCol->zType);
sqlite3DbFree(db, pCol->zColl);
}
sqlite3DbFree(db, pTable->aCol);
@@ -94879,16 +99489,10 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
** db parameter can be used with db->pnBytesFreed to measure the memory
** used by the Table object.
*/
-SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
+static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
Index *pIndex, *pNext;
TESTONLY( int nLookaside; ) /* Used to verify lookaside not used for schema */
- assert( !pTable || pTable->nRef>0 );
-
- /* Do not delete the table until the reference count reaches zero. */
- if( !pTable ) return;
- if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
-
/* Record the number of outstanding lookaside allocations in schema Tables
** prior to doing any free() operations. Since schema Tables do not use
** lookaside, this number should not change. */
@@ -94898,8 +99502,9 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Delete all indices associated with this table. */
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
- assert( pIndex->pSchema==pTable->pSchema );
- if( !db || db->pnBytesFreed==0 ){
+ assert( pIndex->pSchema==pTable->pSchema
+ || (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
+ if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
char *zName = pIndex->zName;
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
&pIndex->pSchema->idxHash, zName, 0
@@ -94928,6 +99533,13 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
/* Verify that no lookaside memory was used by schema tables */
assert( nLookaside==0 || nLookaside==db->lookaside.nOut );
}
+SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
+ /* Do not delete the table until the reference count reaches zero. */
+ if( !pTable ) return;
+ if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return;
+ deleteTable(db, pTable);
+}
+
/*
** Unlink the given table from the hash tables and the delete the
@@ -94978,7 +99590,7 @@ SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
*/
SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){
Vdbe *v = sqlite3GetVdbe(p);
- sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb));
+ sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME);
sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5);
if( p->nTab==0 ){
p->nTab = 1;
@@ -94995,12 +99607,11 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){
int i = -1; /* Database number */
if( zName ){
Db *pDb;
- int n = sqlite3Strlen30(zName);
for(i=(db->nDb-1), pDb=&db->aDb[i]; i>=0; i--, pDb--){
- if( (!OMIT_TEMPDB || i!=1 ) && n==sqlite3Strlen30(pDb->zName) &&
- 0==sqlite3StrICmp(pDb->zName, zName) ){
- break;
- }
+ if( 0==sqlite3_stricmp(pDb->zDbSName, zName) ) break;
+ /* "main" is always an acceptable alias for the primary database
+ ** even if it has been renamed using SQLITE_DBCONFIG_MAINDBNAME. */
+ if( i==0 && 0==sqlite3_stricmp("main", zName) ) break;
}
}
return i;
@@ -95059,7 +99670,7 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
return -1;
}
}else{
- assert( db->init.iDb==0 || db->init.busy );
+ assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0);
iDb = db->init.iDb;
*pUnqual = pName1;
}
@@ -95170,7 +99781,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
SQLITE_CREATE_VIEW,
SQLITE_CREATE_TEMP_VIEW
};
- char *zDb = db->aDb[iDb].zName;
+ char *zDb = db->aDb[iDb].zDbSName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
goto begin_table_error;
}
@@ -95189,7 +99800,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
** collisions.
*/
if( !IN_DECLARE_VTAB ){
- char *zDb = db->aDb[iDb].zName;
+ char *zDb = db->aDb[iDb].zDbSName;
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
goto begin_table_error;
}
@@ -95212,14 +99823,14 @@ SQLITE_PRIVATE void sqlite3StartTable(
pTable = sqlite3DbMallocZero(db, sizeof(Table));
if( pTable==0 ){
assert( db->mallocFailed );
- pParse->rc = SQLITE_NOMEM;
+ pParse->rc = SQLITE_NOMEM_BKPT;
pParse->nErr++;
goto begin_table_error;
}
pTable->zName = zName;
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
- pTable->nRef = 1;
+ pTable->nTabRef = 1;
pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
assert( pParse->pNewTable==0 );
pParse->pNewTable = pTable;
@@ -95328,10 +99939,11 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
** first to get things going. Then this routine is called for each
** column.
*/
-SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){
+SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
Table *p;
int i;
char *z;
+ char *zType;
Column *pCol;
sqlite3 *db = pParse->db;
if( (p = pParse->pNewTable)==0 ) return;
@@ -95341,8 +99953,11 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){
return;
}
#endif
- z = sqlite3NameFromToken(db, pName);
+ z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
if( z==0 ) return;
+ memcpy(z, pName->z, pName->n);
+ z[pName->n] = 0;
+ sqlite3Dequote(z);
for(i=0; i<p->nCol; i++){
if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
@@ -95364,13 +99979,21 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName){
pCol->zName = z;
sqlite3ColumnPropertiesFromName(p, pCol);
- /* If there is no type specified, columns have the default affinity
- ** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will
- ** be called next to set pCol->affinity correctly.
- */
- pCol->affinity = SQLITE_AFF_BLOB;
- pCol->szEst = 1;
+ if( pType->n==0 ){
+ /* If there is no type specified, columns have the default affinity
+ ** 'BLOB'. */
+ pCol->affinity = SQLITE_AFF_BLOB;
+ pCol->szEst = 1;
+ }else{
+ zType = z + sqlite3Strlen30(z) + 1;
+ memcpy(zType, pType->z, pType->n);
+ zType[pType->n] = 0;
+ sqlite3Dequote(zType);
+ pCol->affinity = sqlite3AffinityType(zType, &pCol->szEst);
+ pCol->colFlags |= COLFLAG_HASTYPE;
+ }
p->nCol++;
+ pParse->constraintName.n = 0;
}
/*
@@ -95416,7 +100039,7 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
char aff = SQLITE_AFF_NUMERIC;
const char *zChar = 0;
- if( zIn==0 ) return aff;
+ assert( zIn!=0 );
while( zIn[0] ){
h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
zIn++;
@@ -95474,28 +100097,6 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, u8 *pszEst){
}
/*
-** This routine is called by the parser while in the middle of
-** parsing a CREATE TABLE statement. The pFirst token is the first
-** token in the sequence of tokens that describe the type of the
-** column currently under construction. pLast is the last token
-** in the sequence. Use this information to construct a string
-** that contains the typename of the column and store that string
-** in zType.
-*/
-SQLITE_PRIVATE void sqlite3AddColumnType(Parse *pParse, Token *pType){
- Table *p;
- Column *pCol;
-
- p = pParse->pNewTable;
- if( p==0 || NEVER(p->nCol<1) ) return;
- pCol = &p->aCol[p->nCol-1];
- assert( pCol->zType==0 || CORRUPT_DB );
- sqlite3DbFree(pParse->db, pCol->zType);
- pCol->zType = sqlite3NameFromToken(pParse->db, pType);
- pCol->affinity = sqlite3AffinityType(pCol->zType, &pCol->szEst);
-}
-
-/*
** The expression is the default value for the most recently added column
** of the table currently under construction.
**
@@ -95520,11 +100121,16 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse *pParse, ExprSpan *pSpan){
** tokens that point to volatile memory. The 'span' of the expression
** is required by pragma table_info.
*/
+ Expr x;
sqlite3ExprDelete(db, pCol->pDflt);
- pCol->pDflt = sqlite3ExprDup(db, pSpan->pExpr, EXPRDUP_REDUCE);
- sqlite3DbFree(db, pCol->zDflt);
- pCol->zDflt = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
- (int)(pSpan->zEnd - pSpan->zStart));
+ memset(&x, 0, sizeof(x));
+ x.op = TK_SPAN;
+ x.u.zToken = sqlite3DbStrNDup(db, (char*)pSpan->zStart,
+ (int)(pSpan->zEnd - pSpan->zStart));
+ x.pLeft = pSpan->pExpr;
+ x.flags = EP_Skip;
+ pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
+ sqlite3DbFree(db, x.u.zToken);
}
}
sqlite3ExprDelete(db, pSpan->pExpr);
@@ -95580,10 +100186,10 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */
){
Table *pTab = pParse->pNewTable;
- char *zType = 0;
+ Column *pCol = 0;
int iCol = -1, i;
int nTerm;
- if( pTab==0 || IN_DECLARE_VTAB ) goto primary_key_exit;
+ if( pTab==0 ) goto primary_key_exit;
if( pTab->tabFlags & TF_HasPrimaryKey ){
sqlite3ErrorMsg(pParse,
"table \"%s\" has more than one primary key", pTab->zName);
@@ -95592,8 +100198,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
pTab->tabFlags |= TF_HasPrimaryKey;
if( pList==0 ){
iCol = pTab->nCol - 1;
- pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
- zType = pTab->aCol[iCol].zType;
+ pCol = &pTab->aCol[iCol];
+ pCol->colFlags |= COLFLAG_PRIMKEY;
nTerm = 1;
}else{
nTerm = pList->nExpr;
@@ -95605,8 +100211,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
const char *zCName = pCExpr->u.zToken;
for(iCol=0; iCol<pTab->nCol; iCol++){
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
- pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY;
- zType = pTab->aCol[iCol].zType;
+ pCol = &pTab->aCol[iCol];
+ pCol->colFlags |= COLFLAG_PRIMKEY;
break;
}
}
@@ -95614,7 +100220,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
}
}
if( nTerm==1
- && zType && sqlite3StrICmp(zType, "INTEGER")==0
+ && pCol
+ && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
&& sortOrder!=SQLITE_SO_DESC
){
pTab->iPKey = iCol;
@@ -95628,12 +100235,8 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
"INTEGER PRIMARY KEY");
#endif
}else{
- Index *p;
- p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
- 0, sortOrder, 0);
- if( p ){
- p->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
- }
+ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
+ 0, sortOrder, 0, SQLITE_IDXTYPE_PRIMARYKEY);
pList = 0;
}
@@ -95752,6 +100355,9 @@ SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
** set back to prior value. But schema changes are infrequent
** and the probability of hitting the same cookie value is only
** 1 chance in 2^32. So we're safe enough.
+**
+** IMPLEMENTATION-OF: R-34230-56049 SQLite automatically increments
+** the schema-version whenever the schema changes.
*/
SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){
sqlite3 *db = pParse->db;
@@ -95893,7 +100499,7 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
assert( pIdx->isResized==0 );
nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
zExtra = sqlite3DbMallocZero(db, nByte);
- if( zExtra==0 ) return SQLITE_NOMEM;
+ if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
pIdx->azColl = (const char**)zExtra;
zExtra += sizeof(char*)*N;
@@ -95950,21 +100556,23 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
** are appropriate for a WITHOUT ROWID table instead of a rowid table.
** Changes include:
**
-** (1) Convert the OP_CreateTable into an OP_CreateIndex. There is
+** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
+** (2) Convert the OP_CreateTable into an OP_CreateIndex. There is
** no rowid btree for a WITHOUT ROWID. Instead, the canonical
** data storage is a covering index btree.
-** (2) Bypass the creation of the sqlite_master table entry
+** (3) Bypass the creation of the sqlite_master table entry
** for the PRIMARY KEY as the primary key index is now
** identified by the sqlite_master table entry of the table itself.
-** (3) Set the Index.tnum of the PRIMARY KEY Index object in the
+** (4) Set the Index.tnum of the PRIMARY KEY Index object in the
** schema to the rootpage from the main table.
-** (4) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
** (5) Add all table columns to the PRIMARY KEY Index object
** so that the PRIMARY KEY is a covering index. The surplus
** columns are part of KeyInfo.nXField and are not used for
** sorting or lookup or uniqueness checks.
** (6) Replace the rowid tail on all automatically generated UNIQUE
** indices with the PRIMARY KEY columns.
+**
+** For virtual tables, only (1) is performed.
*/
static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
Index *pIdx;
@@ -95974,6 +100582,20 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
sqlite3 *db = pParse->db;
Vdbe *v = pParse->pVdbe;
+ /* Mark every PRIMARY KEY column as NOT NULL (except for imposter tables)
+ */
+ if( !db->init.imposterTable ){
+ for(i=0; i<pTab->nCol; i++){
+ if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){
+ pTab->aCol[i].notNull = OE_Abort;
+ }
+ }
+ }
+
+ /* The remaining transformations only apply to b-tree tables, not to
+ ** virtual tables */
+ if( IN_DECLARE_VTAB ) return;
+
/* Convert the OP_CreateTable opcode that would normally create the
** root-page for the table into an OP_CreateIndex opcode. The index
** created will become the PRIMARY KEY index.
@@ -95995,9 +100617,10 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
if( pList==0 ) return;
pList->a[0].sortOrder = pParse->iPkSortOrder;
assert( pParse->pNewTable==pTab );
- pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
- if( pPk==0 ) return;
- pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY;
+ sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
+ SQLITE_IDXTYPE_PRIMARYKEY);
+ if( db->mallocFailed ) return;
+ pPk = sqlite3PrimaryKeyIndex(pTab);
pTab->iPKey = -1;
}else{
pPk = sqlite3PrimaryKeyIndex(pTab);
@@ -96025,19 +100648,11 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
}
pPk->nKeyCol = j;
}
- pPk->isCovering = 1;
assert( pPk!=0 );
+ pPk->isCovering = 1;
+ if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
nPk = pPk->nKeyCol;
- /* Make sure every column of the PRIMARY KEY is NOT NULL. (Except,
- ** do not enforce this for imposter tables.) */
- if( !db->init.imposterTable ){
- for(i=0; i<nPk; i++){
- pTab->aCol[pPk->aiColumn[i]].notNull = OE_Abort;
- }
- pPk->uniqNotNull = 1;
- }
-
/* The root page of the PRIMARY KEY is the table root page */
pPk->tnum = pTab->tnum;
@@ -96281,7 +100896,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
"UPDATE %Q.%s "
"SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
"WHERE rowid=#%d",
- db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
+ db->aDb[iDb].zDbSName, MASTER_NAME,
zType,
p->zName,
p->zName,
@@ -96296,13 +100911,13 @@ SQLITE_PRIVATE void sqlite3EndTable(
/* Check to see if we need to create an sqlite_sequence table for
** keeping track of autoincrement keys.
*/
- if( p->tabFlags & TF_Autoincrement ){
+ if( (p->tabFlags & TF_Autoincrement)!=0 ){
Db *pDb = &db->aDb[iDb];
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( pDb->pSchema->pSeqTab==0 ){
sqlite3NestedParse(pParse,
"CREATE TABLE %Q.sqlite_sequence(name,seq)",
- pDb->zName
+ pDb->zDbSName
);
}
}
@@ -96426,7 +101041,9 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
int nErr = 0; /* Number of errors encountered */
int n; /* Temporarily holds the number of cursors assigned */
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
+#ifndef SQLITE_OMIT_AUTHORIZATION
sqlite3_xauth xAuth; /* Saved xAuth pointer */
+#endif
assert( pTable );
@@ -96472,44 +101089,55 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
** statement that defines the view.
*/
assert( pTable->pSelect );
- if( pTable->pCheck ){
+ pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
+ if( pSel ){
+ n = pParse->nTab;
+ sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
+ pTable->nCol = -1;
db->lookaside.bDisable++;
- sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
- &pTable->nCol, &pTable->aCol);
- db->lookaside.bDisable--;
- }else{
- pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
- if( pSel ){
- n = pParse->nTab;
- sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
- pTable->nCol = -1;
- db->lookaside.bDisable++;
#ifndef SQLITE_OMIT_AUTHORIZATION
- xAuth = db->xAuth;
- db->xAuth = 0;
- pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
- db->xAuth = xAuth;
+ xAuth = db->xAuth;
+ db->xAuth = 0;
+ pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
+ db->xAuth = xAuth;
#else
- pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
-#endif
- db->lookaside.bDisable--;
- pParse->nTab = n;
- if( pSelTab ){
- assert( pTable->aCol==0 );
- pTable->nCol = pSelTab->nCol;
- pTable->aCol = pSelTab->aCol;
- pSelTab->nCol = 0;
- pSelTab->aCol = 0;
- sqlite3DeleteTable(db, pSelTab);
- assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
- }else{
- pTable->nCol = 0;
- nErr++;
+ pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
+#endif
+ pParse->nTab = n;
+ if( pTable->pCheck ){
+ /* CREATE VIEW name(arglist) AS ...
+ ** The names of the columns in the table are taken from
+ ** arglist which is stored in pTable->pCheck. The pCheck field
+ ** normally holds CHECK constraints on an ordinary table, but for
+ ** a VIEW it holds the list of column names.
+ */
+ sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
+ &pTable->nCol, &pTable->aCol);
+ if( db->mallocFailed==0
+ && pParse->nErr==0
+ && pTable->nCol==pSel->pEList->nExpr
+ ){
+ sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel);
}
- sqlite3SelectDelete(db, pSel);
- } else {
+ }else if( pSelTab ){
+ /* CREATE VIEW name AS... without an argument list. Construct
+ ** the column names from the SELECT statement that defines the view.
+ */
+ assert( pTable->aCol==0 );
+ pTable->nCol = pSelTab->nCol;
+ pTable->aCol = pSelTab->aCol;
+ pSelTab->nCol = 0;
+ pSelTab->aCol = 0;
+ assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
+ }else{
+ pTable->nCol = 0;
nErr++;
}
+ sqlite3DeleteTable(db, pSelTab);
+ sqlite3SelectDelete(db, pSel);
+ db->lookaside.bDisable--;
+ } else {
+ nErr++;
}
pTable->pSchema->schemaFlags |= DB_UnresetViews;
#endif /* SQLITE_OMIT_VIEW */
@@ -96605,7 +101233,7 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
*/
sqlite3NestedParse(pParse,
"UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
- pParse->db->aDb[iDb].zName, SCHEMA_TABLE(iDb), iTable, r1, r1);
+ pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1);
#endif
sqlite3ReleaseTempReg(pParse, r1);
}
@@ -96681,7 +101309,7 @@ static void sqlite3ClearStatTables(
const char *zName /* Name of index or table */
){
int i;
- const char *zDbName = pParse->db->aDb[iDb].zName;
+ const char *zDbName = pParse->db->aDb[iDb].zDbSName;
for(i=1; i<=4; i++){
char zTab[24];
sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
@@ -96734,7 +101362,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
if( pTab->tabFlags & TF_Autoincrement ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.sqlite_sequence WHERE name=%Q",
- pDb->zName, pTab->zName
+ pDb->zDbSName, pTab->zName
);
}
#endif
@@ -96748,7 +101376,7 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
*/
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
- pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
+ pDb->zDbSName, MASTER_NAME, pTab->zName);
if( !isView && !IsVirtual(pTab) ){
destroyTable(pParse, pTab);
}
@@ -96781,6 +101409,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
assert( pName->nSrc==1 );
if( sqlite3ReadSchema(pParse) ) goto exit_drop_table;
if( noErr ) db->suppressErr++;
+ assert( isView==0 || isView==LOCATE_VIEW );
pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
if( noErr ) db->suppressErr--;
@@ -96801,7 +101430,7 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
{
int code;
const char *zTab = SCHEMA_TABLE(iDb);
- const char *zDb = db->aDb[iDb].zName;
+ const char *zDb = db->aDb[iDb].zDbSName;
const char *zArg2 = 0;
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){
goto exit_drop_table;
@@ -97042,7 +101671,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
#ifndef SQLITE_OMIT_AUTHORIZATION
if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0,
- db->aDb[iDb].zName ) ){
+ db->aDb[iDb].zDbSName ) ){
return;
}
#endif
@@ -97058,6 +101687,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
tnum = pIndex->tnum;
}
pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
+ assert( pKey!=0 || db->mallocFailed || pParse->nErr );
/* Open the sorter cursor if we are to use one. */
iSorter = pParse->nTab++;
@@ -97081,8 +101711,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
- assert( pKey!=0 || db->mallocFailed || pParse->nErr );
- if( IsUniqueIndex(pIndex) && pKey!=0 ){
+ if( IsUniqueIndex(pIndex) ){
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
sqlite3VdbeGoto(v, j2);
addr2 = sqlite3VdbeCurrentAddr(v);
@@ -97094,7 +101723,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
}
sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
- sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
@@ -97151,12 +101780,8 @@ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
** pList is a list of columns to be indexed. pList will be NULL if this
** is a primary key or unique-constraint on the most recent column added
** to the table currently under construction.
-**
-** If the index is created successfully, return a pointer to the new Index
-** structure. This is used by sqlite3AddPrimaryKey() to mark the index
-** as the tables primary key (Index.idxType==SQLITE_IDXTYPE_PRIMARYKEY)
*/
-SQLITE_PRIVATE Index *sqlite3CreateIndex(
+SQLITE_PRIVATE void sqlite3CreateIndex(
Parse *pParse, /* All information about this parse */
Token *pName1, /* First part of index name. May be NULL */
Token *pName2, /* Second part of index name. May be NULL */
@@ -97166,9 +101791,9 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
Token *pStart, /* The CREATE token that begins this statement */
Expr *pPIWhere, /* WHERE clause for partial indices */
int sortOrder, /* Sort order of primary key when pList==NULL */
- int ifNotExist /* Omit error if index already exists */
+ int ifNotExist, /* Omit error if index already exists */
+ u8 idxType /* The index type */
){
- Index *pRet = 0; /* Pointer to return */
Table *pTab = 0; /* Table to be indexed */
Index *pIndex = 0; /* The index to be created */
char *zName = 0; /* Name of the index */
@@ -97186,7 +101811,10 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
char *zExtra = 0; /* Extra space after the Index object */
Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */
- if( db->mallocFailed || IN_DECLARE_VTAB || pParse->nErr>0 ){
+ if( db->mallocFailed || pParse->nErr>0 ){
+ goto exit_create_index;
+ }
+ if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
goto exit_create_index;
}
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
@@ -97295,7 +101923,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
goto exit_create_index;
}
}
- if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
+ if( sqlite3FindIndex(db, zName, pDb->zDbSName)!=0 ){
if( !ifNotExist ){
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
}else{
@@ -97312,13 +101940,20 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
if( zName==0 ){
goto exit_create_index;
}
+
+ /* Automatic index names generated from within sqlite3_declare_vtab()
+ ** must have names that are distinct from normal automatic index names.
+ ** The following statement converts "sqlite3_autoindex..." into
+ ** "sqlite3_butoindex..." in order to make the names distinct.
+ ** The "vtab_err.test" test demonstrates the need of this statement. */
+ if( IN_DECLARE_VTAB ) zName[7]++;
}
/* Check for authorization to create an index.
*/
#ifndef SQLITE_OMIT_AUTHORIZATION
{
- const char *zDb = pDb->zName;
+ const char *zDb = pDb->zDbSName;
if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){
goto exit_create_index;
}
@@ -97375,7 +102010,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
pIndex->pTable = pTab;
pIndex->onError = (u8)onError;
pIndex->uniqNotNull = onError!=OE_None;
- pIndex->idxType = pName ? SQLITE_IDXTYPE_APPDEF : SQLITE_IDXTYPE_UNIQUE;
+ pIndex->idxType = idxType;
pIndex->pSchema = db->aDb[iDb].pSchema;
pIndex->nKeyCol = pList->nExpr;
if( pPIWhere ){
@@ -97485,6 +102120,20 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
sqlite3DefaultRowEst(pIndex);
if( pParse->pNewTable==0 ) estimateIndexWidth(pIndex);
+ /* If this index contains every column of its table, then mark
+ ** it as a covering index */
+ assert( HasRowid(pTab)
+ || pTab->iPKey<0 || sqlite3ColumnOfIndex(pIndex, pTab->iPKey)>=0 );
+ if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
+ pIndex->isCovering = 1;
+ for(j=0; j<pTab->nCol; j++){
+ if( j==pTab->iPKey ) continue;
+ if( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue;
+ pIndex->isCovering = 0;
+ break;
+ }
+ }
+
if( pTab==pParse->pNewTable ){
/* This routine has been called to create an automatic index as a
** result of a PRIMARY KEY or UNIQUE clause on a column definition, or
@@ -97522,7 +102171,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
z1 = pIdx->azColl[k];
z2 = pIndex->azColl[k];
- if( z1!=z2 && sqlite3StrICmp(z1, z2) ) break;
+ if( sqlite3StrICmp(z1, z2) ) break;
}
if( k==pIdx->nKeyCol ){
if( pIdx->onError!=pIndex->onError ){
@@ -97541,7 +102190,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
pIdx->onError = pIndex->onError;
}
}
- pRet = pIdx;
+ if( idxType==SQLITE_IDXTYPE_PRIMARYKEY ) pIdx->idxType = idxType;
goto exit_create_index;
}
}
@@ -97553,6 +102202,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
assert( pParse->nErr==0 );
if( db->init.busy ){
Index *p;
+ assert( !IN_DECLARE_VTAB );
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
pIndex->zName, pIndex);
@@ -97618,7 +102268,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
*/
sqlite3NestedParse(pParse,
"INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
- db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
+ db->aDb[iDb].zDbSName, MASTER_NAME,
pIndex->zName,
pTab->zName,
iMem,
@@ -97634,7 +102284,7 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
- sqlite3VdbeAddOp1(v, OP_Expire, 0);
+ sqlite3VdbeAddOp0(v, OP_Expire);
}
sqlite3VdbeJumpHere(v, pIndex->tnum);
@@ -97659,7 +102309,6 @@ SQLITE_PRIVATE Index *sqlite3CreateIndex(
pIndex->pNext = pOther->pNext;
pOther->pNext = pIndex;
}
- pRet = pIndex;
pIndex = 0;
}
@@ -97670,7 +102319,6 @@ exit_create_index:
sqlite3ExprListDelete(db, pList);
sqlite3SrcListDelete(db, pTblName);
sqlite3DbFree(db, zName);
- return pRet;
}
/*
@@ -97699,10 +102347,11 @@ SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){
int i;
/* Set the first entry (number of rows in the index) to the estimated
- ** number of rows in the table. Or 10, if the estimated number of rows
- ** in the table is less than that. */
+ ** number of rows in the table, or half the number of rows in the table
+ ** for a partial index. But do not let the estimate drop below 10. */
a[0] = pIdx->pTable->nRowLogEst;
- if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
+ if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) );
+ if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
** 6 and each subsequent value (if any) is 5. */
@@ -97753,7 +102402,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
{
int code = SQLITE_DROP_INDEX;
Table *pTab = pIndex->pTable;
- const char *zDb = db->aDb[iDb].zName;
+ const char *zDb = db->aDb[iDb].zDbSName;
const char *zTab = SCHEMA_TABLE(iDb);
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
goto exit_drop_index;
@@ -97771,7 +102420,7 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
sqlite3BeginWriteOperation(pParse, 1, iDb);
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
- db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName
+ db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName
);
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
sqlite3ChangeCookie(pParse, iDb);
@@ -97914,7 +102563,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
/* Allocate additional space if needed */
if( (u32)pSrc->nSrc+nExtra>pSrc->nAlloc ){
SrcList *pNew;
- int nAlloc = pSrc->nSrc+nExtra;
+ int nAlloc = pSrc->nSrc*2+nExtra;
int nGot;
pNew = sqlite3DbRealloc(db, pSrc,
sizeof(*pSrc) + (nAlloc-1)*sizeof(pSrc->a[0]) );
@@ -97992,9 +102641,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
pList = sqlite3DbMallocRawNN(db, sizeof(SrcList) );
if( pList==0 ) return 0;
pList->nAlloc = 1;
- pList->nSrc = 0;
+ pList->nSrc = 1;
+ memset(&pList->a[0], 0, sizeof(pList->a[0]));
+ pList->a[0].iCursor = -1;
+ }else{
+ pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
}
- pList = sqlite3SrcListEnlarge(db, pList, 1, pList->nSrc);
if( db->mallocFailed ){
sqlite3SrcListDelete(db, pList);
return 0;
@@ -98292,15 +102944,13 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
*/
SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
- sqlite3 *db = pToplevel->db;
- assert( iDb>=0 && iDb<db->nDb );
- assert( db->aDb[iDb].pBt!=0 || iDb==1 );
+ assert( iDb>=0 && iDb<pParse->db->nDb );
+ assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 );
assert( iDb<SQLITE_MAX_ATTACHED+2 );
- assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
+ assert( sqlite3SchemaMutexHeld(pParse->db, iDb, 0) );
if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
DbMaskSet(pToplevel->cookieMask, iDb);
- pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
if( !OMIT_TEMPDB && iDb==1 ){
sqlite3OpenTempDatabase(pToplevel);
}
@@ -98316,7 +102966,7 @@ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb)
int i;
for(i=0; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
- if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){
+ if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zDbSName)) ){
sqlite3CodeVerifySchema(pParse, i);
}
}
@@ -98563,7 +103213,7 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
if( iDb<0 ) return;
z = sqlite3NameFromToken(db, pObjName);
if( z==0 ) return;
- zDb = db->aDb[iDb].zName;
+ zDb = db->aDb[iDb].zDbSName;
pTab = sqlite3FindTable(db, z, zDb);
if( pTab ){
reindexTable(pParse, pTab, 0);
@@ -98584,10 +103234,6 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
/*
** Return a KeyInfo structure that is appropriate for the given Index.
**
-** The KeyInfo structure for an index is cached in the Index object.
-** So there might be multiple references to the returned pointer. The
-** caller should not try to modify the KeyInfo object.
-**
** The caller should invoke sqlite3KeyInfoUnref() on the returned object
** when it has finished using it.
*/
@@ -98975,14 +103621,12 @@ static int matchQuality(
** a pointer to the matching FuncDef if found, or 0 if there is no match.
*/
static FuncDef *functionSearch(
- FuncDefHash *pHash, /* Hash table to search */
int h, /* Hash of the name */
- const char *zFunc, /* Name of function */
- int nFunc /* Number of bytes in zFunc */
+ const char *zFunc /* Name of function */
){
FuncDef *p;
- for(p=pHash->a[h]; p; p=p->pHash){
- if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 && p->zName[nFunc]==0 ){
+ for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
+ if( sqlite3StrICmp(p->zName, zFunc)==0 ){
return p;
}
}
@@ -98992,23 +103636,26 @@ static FuncDef *functionSearch(
/*
** Insert a new FuncDef into a FuncDefHash hash table.
*/
-SQLITE_PRIVATE void sqlite3FuncDefInsert(
- FuncDefHash *pHash, /* The hash table into which to insert */
- FuncDef *pDef /* The function definition to insert */
+SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
+ FuncDef *aDef, /* List of global functions to be inserted */
+ int nDef /* Length of the apDef[] list */
){
- FuncDef *pOther;
- int nName = sqlite3Strlen30(pDef->zName);
- u8 c1 = (u8)pDef->zName[0];
- int h = (sqlite3UpperToLower[c1] + nName) % ArraySize(pHash->a);
- pOther = functionSearch(pHash, h, pDef->zName, nName);
- if( pOther ){
- assert( pOther!=pDef && pOther->pNext!=pDef );
- pDef->pNext = pOther->pNext;
- pOther->pNext = pDef;
- }else{
- pDef->pNext = 0;
- pDef->pHash = pHash->a[h];
- pHash->a[h] = pDef;
+ int i;
+ for(i=0; i<nDef; i++){
+ FuncDef *pOther;
+ const char *zName = aDef[i].zName;
+ int nName = sqlite3Strlen30(zName);
+ int h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
+ pOther = functionSearch(h, zName);
+ if( pOther ){
+ assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
+ aDef[i].pNext = pOther->pNext;
+ pOther->pNext = &aDef[i];
+ }else{
+ aDef[i].pNext = 0;
+ aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h];
+ sqlite3BuiltinFunctions.a[h] = &aDef[i];
+ }
}
}
@@ -99035,8 +103682,7 @@ SQLITE_PRIVATE void sqlite3FuncDefInsert(
*/
SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
sqlite3 *db, /* An open database */
- const char *zName, /* Name of the function. Not null-terminated */
- int nName, /* Number of characters in the name */
+ const char *zName, /* Name of the function. zero-terminated */
int nArg, /* Number of arguments. -1 means any number */
u8 enc, /* Preferred text encoding */
u8 createFlag /* Create new entry if true and does not otherwise exist */
@@ -99045,14 +103691,15 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
FuncDef *pBest = 0; /* Best match found so far */
int bestScore = 0; /* Score of best match */
int h; /* Hash value */
+ int nName; /* Length of the name */
assert( nArg>=(-2) );
assert( nArg>=(-1) || createFlag==0 );
- h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
+ nName = sqlite3Strlen30(zName);
/* First search for a match amongst the application-defined functions.
*/
- p = functionSearch(&db->aFunc, h, zName, nName);
+ p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@@ -99075,9 +103722,9 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
** So we must not search for built-ins when creating a new function.
*/
if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
- FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
bestScore = 0;
- p = functionSearch(pHash, h, zName, nName);
+ h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ;
+ p = functionSearch(h, zName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
@@ -99094,12 +103741,19 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
*/
if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
- pBest->zName = (char *)&pBest[1];
+ FuncDef *pOther;
+ pBest->zName = (const char*)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->funcFlags = enc;
- memcpy(pBest->zName, zName, nName);
- pBest->zName[nName] = 0;
- sqlite3FuncDefInsert(&db->aFunc, pBest);
+ memcpy((char*)&pBest[1], zName, nName+1);
+ pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
+ if( pOther==pBest ){
+ sqlite3DbFree(db, pBest);
+ sqlite3OomFault(db);
+ return 0;
+ }else{
+ pBest->pNext = pOther;
+ }
}
if( pBest && (pBest->xSFunc || createFlag) ){
@@ -99207,7 +103861,7 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
sqlite3DeleteTable(pParse->db, pItem->pTab);
pItem->pTab = pTab;
if( pTab ){
- pTab->nRef++;
+ pTab->nTabRef++;
}
if( sqlite3IndexedByLookup(pParse, pItem) ){
pTab = 0;
@@ -99273,7 +103927,7 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
if( pFrom ){
assert( pFrom->nSrc==1 );
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
- pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
+ pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
assert( pFrom->a[0].pOn==0 );
assert( pFrom->a[0].pUsing==0 );
}
@@ -99314,7 +103968,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
*/
if( pOrderBy && (pLimit == 0) ) {
sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
- goto limit_where_cleanup_2;
+ goto limit_where_cleanup;
}
/* We only need to generate a select expression if there
@@ -99335,17 +103989,17 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
** );
*/
- pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
- if( pSelectRowid == 0 ) goto limit_where_cleanup_2;
+ pSelectRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0);
+ if( pSelectRowid == 0 ) goto limit_where_cleanup;
pEList = sqlite3ExprListAppend(pParse, 0, pSelectRowid);
- if( pEList == 0 ) goto limit_where_cleanup_2;
+ if( pEList == 0 ) goto limit_where_cleanup;
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
** and the SELECT subtree. */
pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
if( pSelectSrc == 0 ) {
sqlite3ExprListDelete(pParse->db, pEList);
- goto limit_where_cleanup_2;
+ goto limit_where_cleanup;
}
/* generate the SELECT expression tree. */
@@ -99354,22 +104008,12 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
if( pSelect == 0 ) return 0;
/* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
- pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0, 0);
- if( pWhereRowid == 0 ) goto limit_where_cleanup_1;
- pInClause = sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0, 0);
- if( pInClause == 0 ) goto limit_where_cleanup_1;
-
- pInClause->x.pSelect = pSelect;
- pInClause->flags |= EP_xIsSelect;
- sqlite3ExprSetHeightAndFlags(pParse, pInClause);
+ pWhereRowid = sqlite3PExpr(pParse, TK_ROW, 0, 0);
+ pInClause = pWhereRowid ? sqlite3PExpr(pParse, TK_IN, pWhereRowid, 0) : 0;
+ sqlite3PExprAddSelect(pParse, pInClause, pSelect);
return pInClause;
- /* something went wrong. clean up anything allocated. */
-limit_where_cleanup_1:
- sqlite3SelectDelete(pParse->db, pSelect);
- return 0;
-
-limit_where_cleanup_2:
+limit_where_cleanup:
sqlite3ExprDelete(pParse->db, pWhere);
sqlite3ExprListDelete(pParse->db, pOrderBy);
sqlite3ExprDelete(pParse->db, pLimit);
@@ -99393,7 +104037,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
){
Vdbe *v; /* The virtual database engine */
Table *pTab; /* The table from which records will be deleted */
- const char *zDb; /* Name of database holding pTab */
int i; /* Loop counter */
WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */
@@ -99420,11 +104063,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
int addrBypass = 0; /* Address of jump over the delete logic */
int addrLoop = 0; /* Top of the delete loop */
int addrEphOpen = 0; /* Instruction to open the Ephemeral table */
+ int bComplex; /* True if there are triggers or FKs or
+ ** subqueries in the WHERE clause */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
Trigger *pTrigger; /* List of table triggers, if required */
- int bComplex; /* True if there are either triggers or FKs */
#endif
memset(&sContext, 0, sizeof(sContext));
@@ -99452,7 +104096,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
#else
# define pTrigger 0
# define isView 0
-# define bComplex 0
#endif
#ifdef SQLITE_OMIT_VIEW
# undef isView
@@ -99470,8 +104113,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb<db->nDb );
- zDb = db->aDb[iDb].zName;
- rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb);
+ rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0,
+ db->aDb[iDb].zDbSName);
assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
if( rcauth==SQLITE_DENY ){
goto delete_from_cleanup;
@@ -99537,6 +104180,9 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
&& pWhere==0
&& !bComplex
&& !IsVirtual(pTab)
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ && db->xPreUpdateCallback==0
+#endif
){
assert( !isView );
sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
@@ -99551,7 +104197,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}else
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
{
- u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
+ u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE;
+ if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
if( HasRowid(pTab) ){
/* For a rowid table, initialize the RowSet to an empty set */
@@ -99627,7 +104274,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
nKey = 0; /* Zero tells OP_Found to use a composite key */
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk);
}else{
/* Add the rowid of the row to be deleted to the RowSet */
nKey = 1; /* OP_Seek always uses a single rowid */
@@ -99651,7 +104298,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
if( !isView ){
int iAddrOnce = 0;
if( eOnePass==ONEPASS_MULTI ){
- iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
+ iAddrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
testcase( IsVirtual(pTab) );
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, OPFLAG_FORDELETE,
@@ -99673,7 +104320,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
}
}else if( pPk ){
addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
+ sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
assert( nKey==0 ); /* OP_Found will use a composite key */
}else{
addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
@@ -99716,14 +104363,6 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
sqlite3VdbeGoto(v, addrLoop);
sqlite3VdbeJumpHere(v, addrLoop);
}
-
- /* Close the cursors open on the table and its indexes. */
- if( !isView && !IsVirtual(pTab) ){
- if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
- for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
- }
- }
} /* End non-truncate path */
/* Update the sqlite_sequence table by storing the content of the
@@ -99886,14 +104525,19 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
/* Delete the index and table entries. Skip this step if pTab is really
** a view (in which case the only effect of the DELETE statement is to
- ** fire the INSTEAD OF triggers). */
+ ** fire the INSTEAD OF triggers).
+ **
+ ** If variable 'count' is non-zero, then this OP_Delete instruction should
+ ** invoke the update-hook. The pre-update-hook, on the other hand should
+ ** be invoked unless table pTab is a system table. The difference is that
+ ** the update-hook is not invoked for rows removed by REPLACE, but the
+ ** pre-update-hook is.
+ */
if( pTab->pSelect==0 ){
u8 p5 = 0;
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
- if( count ){
- sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
- }
+ sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE);
if( eMode!=ONEPASS_OFF ){
sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE);
}
@@ -100272,23 +104916,28 @@ static void instrFunc(
if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return;
nHaystack = sqlite3_value_bytes(argv[0]);
nNeedle = sqlite3_value_bytes(argv[1]);
- if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
- zHaystack = sqlite3_value_blob(argv[0]);
- zNeedle = sqlite3_value_blob(argv[1]);
- isText = 0;
- }else{
- zHaystack = sqlite3_value_text(argv[0]);
- zNeedle = sqlite3_value_text(argv[1]);
- isText = 1;
- }
- while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
- N++;
- do{
- nHaystack--;
- zHaystack++;
- }while( isText && (zHaystack[0]&0xc0)==0x80 );
+ if( nNeedle>0 ){
+ if( typeHaystack==SQLITE_BLOB && typeNeedle==SQLITE_BLOB ){
+ zHaystack = sqlite3_value_blob(argv[0]);
+ zNeedle = sqlite3_value_blob(argv[1]);
+ assert( zNeedle!=0 );
+ assert( zHaystack!=0 || nHaystack==0 );
+ isText = 0;
+ }else{
+ zHaystack = sqlite3_value_text(argv[0]);
+ zNeedle = sqlite3_value_text(argv[1]);
+ isText = 1;
+ if( zHaystack==0 || zNeedle==0 ) return;
+ }
+ while( nNeedle<=nHaystack && memcmp(zHaystack, zNeedle, nNeedle)!=0 ){
+ N++;
+ do{
+ nHaystack--;
+ zHaystack++;
+ }while( isText && (zHaystack[0]&0xc0)==0x80 );
+ }
+ if( nNeedle>nHaystack ) N = 0;
}
- if( nNeedle>nHaystack ) N = 0;
sqlite3_result_int(context, N);
}
@@ -100668,9 +105317,19 @@ static const struct compareInfo likeInfoNorm = { '%', '_', 0, 1 };
static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
/*
-** Compare two UTF-8 strings for equality where the first string can
-** potentially be a "glob" or "like" expression. Return true (1) if they
-** are the same and false (0) if they are different.
+** Possible error returns from patternMatch()
+*/
+#define SQLITE_MATCH 0
+#define SQLITE_NOMATCH 1
+#define SQLITE_NOWILDCARDMATCH 2
+
+/*
+** Compare two UTF-8 strings for equality where the first string is
+** a GLOB or LIKE expression. Return values:
+**
+** SQLITE_MATCH: Match
+** SQLITE_NOMATCH: No match
+** SQLITE_NOWILDCARDMATCH: No match in spite of having * or % wildcards.
**
** Globbing rules:
**
@@ -100721,30 +105380,31 @@ static int patternCompare(
** single character of the input string for each "?" skipped */
while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
- return 0;
+ return SQLITE_NOWILDCARDMATCH;
}
}
if( c==0 ){
- return 1; /* "*" at the end of the pattern matches */
+ return SQLITE_MATCH; /* "*" at the end of the pattern matches */
}else if( c==matchOther ){
if( pInfo->matchSet==0 ){
c = sqlite3Utf8Read(&zPattern);
- if( c==0 ) return 0;
+ if( c==0 ) return SQLITE_NOWILDCARDMATCH;
}else{
/* "[...]" immediately follows the "*". We have to do a slow
** recursive search in this case, but it is an unusual case. */
assert( matchOther<0x80 ); /* '[' is a single-byte character */
- while( *zString
- && patternCompare(&zPattern[-1],zString,pInfo,matchOther)==0 ){
+ while( *zString ){
+ int bMatch = patternCompare(&zPattern[-1],zString,pInfo,matchOther);
+ if( bMatch!=SQLITE_NOMATCH ) return bMatch;
SQLITE_SKIP_UTF8(zString);
}
- return *zString!=0;
+ return SQLITE_NOWILDCARDMATCH;
}
}
/* At this point variable c contains the first character of the
** pattern string past the "*". Search in the input string for the
- ** first matching character and recursively contine the match from
+ ** first matching character and recursively continue the match from
** that point.
**
** For a case-insensitive search, set variable cx to be the same as
@@ -100753,6 +105413,7 @@ static int patternCompare(
*/
if( c<=0x80 ){
u32 cx;
+ int bMatch;
if( noCase ){
cx = sqlite3Toupper(c);
c = sqlite3Tolower(c);
@@ -100761,27 +105422,30 @@ static int patternCompare(
}
while( (c2 = *(zString++))!=0 ){
if( c2!=c && c2!=cx ) continue;
- if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
+ bMatch = patternCompare(zPattern,zString,pInfo,matchOther);
+ if( bMatch!=SQLITE_NOMATCH ) return bMatch;
}
}else{
+ int bMatch;
while( (c2 = Utf8Read(zString))!=0 ){
if( c2!=c ) continue;
- if( patternCompare(zPattern,zString,pInfo,matchOther) ) return 1;
+ bMatch = patternCompare(zPattern,zString,pInfo,matchOther);
+ if( bMatch!=SQLITE_NOMATCH ) return bMatch;
}
}
- return 0;
+ return SQLITE_NOWILDCARDMATCH;
}
if( c==matchOther ){
if( pInfo->matchSet==0 ){
c = sqlite3Utf8Read(&zPattern);
- if( c==0 ) return 0;
+ if( c==0 ) return SQLITE_NOMATCH;
zEscaped = zPattern;
}else{
u32 prior_c = 0;
int seen = 0;
int invert = 0;
c = sqlite3Utf8Read(&zString);
- if( c==0 ) return 0;
+ if( c==0 ) return SQLITE_NOMATCH;
c2 = sqlite3Utf8Read(&zPattern);
if( c2=='^' ){
invert = 1;
@@ -100805,34 +105469,36 @@ static int patternCompare(
c2 = sqlite3Utf8Read(&zPattern);
}
if( c2==0 || (seen ^ invert)==0 ){
- return 0;
+ return SQLITE_NOMATCH;
}
continue;
}
}
c2 = Utf8Read(zString);
if( c==c2 ) continue;
- if( noCase && c<0x80 && c2<0x80 && sqlite3Tolower(c)==sqlite3Tolower(c2) ){
+ if( noCase && sqlite3Tolower(c)==sqlite3Tolower(c2) && c<0x80 && c2<0x80 ){
continue;
}
if( c==matchOne && zPattern!=zEscaped && c2!=0 ) continue;
- return 0;
+ return SQLITE_NOMATCH;
}
- return *zString==0;
+ return *zString==0 ? SQLITE_MATCH : SQLITE_NOMATCH;
}
/*
-** The sqlite3_strglob() interface.
+** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and
+** non-zero if there is no match.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlobPattern, const char *zString){
- return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[')==0;
+SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
}
/*
-** The sqlite3_strlike() interface.
+** The sqlite3_strlike() interface. Return 0 on a match and non-zero for
+** a miss - like strcmp().
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
- return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc)==0;
+SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
+ return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
}
/*
@@ -100913,7 +105579,7 @@ static void likeFunc(
#ifdef SQLITE_TEST
sqlite3_like_count++;
#endif
- sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape));
+ sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH);
}
}
@@ -101388,6 +106054,26 @@ static void trimFunc(
}
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+/*
+** The "unknown" function is automatically substituted in place of
+** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
+** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used.
+** When the "sqlite3" command-line shell is built using this functionality,
+** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries
+** involving application-defined functions to be examined in a generic
+** sqlite3 shell.
+*/
+static void unknownFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ /* no-op */
+}
+#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/
+
+
/* IMP: R-25361-16150 This function is omitted from SQLite by default. It
** is only available if the SQLITE_SOUNDEX compile-time option is used
** when SQLite is built.
@@ -101458,6 +106144,14 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3 *db = sqlite3_context_db_handle(context);
char *zErrMsg = 0;
+ /* Disallow the load_extension() SQL function unless the SQLITE_LoadExtFunc
+ ** flag is set. See the sqlite3_enable_load_extension() API.
+ */
+ if( (db->flags & SQLITE_LoadExtFunc)==0 ){
+ sqlite3_result_error(context, "not authorized", -1);
+ return;
+ }
+
if( argc==2 ){
zProc = (const char *)sqlite3_value_text(argv[1]);
}else{
@@ -101656,7 +106350,7 @@ static void groupConcatStep(
zSep = ",";
nSep = 1;
}
- if( nSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
+ if( zSep ) sqlite3StrAccumAppend(pAccum, zSep, nSep);
}
zVal = (char*)sqlite3_value_text(argv[0]);
nVal = sqlite3_value_bytes(argv[0]);
@@ -101683,7 +106377,7 @@ static void groupConcatFinalize(sqlite3_context *context){
** of the built-in functions above are part of the global function set.
** This routine only deals with those that are not global.
*/
-SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
+SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
int rc = sqlite3_overload_function(db, "MATCH", 2);
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
if( rc==SQLITE_NOMEM ){
@@ -101696,8 +106390,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
*/
static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
FuncDef *pDef;
- pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
- 2, SQLITE_UTF8, 0);
+ pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0);
if( ALWAYS(pDef) ){
pDef->funcFlags |= flagVal;
}
@@ -101745,9 +106438,7 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas
return 0;
}
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- pDef = sqlite3FindFunction(db, pExpr->u.zToken,
- sqlite3Strlen30(pExpr->u.zToken),
- 2, SQLITE_UTF8, 0);
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, 2, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
@@ -101771,7 +106462,7 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas
**
** After this routine runs
*/
-SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
+SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
/*
** The following array holds FuncDef structures for all of the functions
** defined in this file.
@@ -101779,8 +106470,27 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
** The array cannot be constant since changes are made to the
** FuncDef.pHash elements at start-time. The elements of this array
** are read-only after initialization is complete.
+ **
+ ** For peak efficiency, put the most frequently used function last.
*/
- static SQLITE_WSD FuncDef aBuiltinFunc[] = {
+ static FuncDef aBuiltinFunc[] = {
+#ifdef SQLITE_SOUNDEX
+ FUNCTION(soundex, 1, 0, 0, soundexFunc ),
+#endif
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+ VFUNCTION(load_extension, 1, 0, 0, loadExt ),
+ VFUNCTION(load_extension, 2, 0, 0, loadExt ),
+#endif
+#if SQLITE_USER_AUTHENTICATION
+ FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
+#endif
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
+ DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
+ DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
+ FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
+ FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
+ FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
FUNCTION(rtrim, 1, 2, 0, trimFunc ),
@@ -101798,8 +106508,6 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
FUNCTION(instr, 2, 0, 0, instrFunc ),
- FUNCTION(substr, 2, 0, 0, substrFunc ),
- FUNCTION(substr, 3, 0, 0, substrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ),
@@ -101810,40 +106518,22 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
#endif
FUNCTION(upper, 1, 0, 0, upperFunc ),
FUNCTION(lower, 1, 0, 0, lowerFunc ),
- FUNCTION(coalesce, 1, 0, 0, 0 ),
- FUNCTION(coalesce, 0, 0, 0, 0 ),
- FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
- FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
- FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
- FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
-#if SQLITE_USER_AUTHENTICATION
- FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
-#endif
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
- DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
- DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION(quote, 1, 0, 0, quoteFunc ),
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
VFUNCTION(changes, 0, 0, 0, changes ),
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
FUNCTION(replace, 3, 0, 0, replaceFunc ),
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
- #ifdef SQLITE_SOUNDEX
- FUNCTION(soundex, 1, 0, 0, soundexFunc ),
- #endif
- #ifndef SQLITE_OMIT_LOAD_EXTENSION
- VFUNCTION(load_extension, 1, 0, 0, loadExt ),
- VFUNCTION(load_extension, 2, 0, 0, loadExt ),
- #endif
+ FUNCTION(substr, 2, 0, 0, substrFunc ),
+ FUNCTION(substr, 3, 0, 0, substrFunc ),
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
@@ -101854,29 +106544,44 @@ SQLITE_PRIVATE void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
- #ifdef SQLITE_CASE_SENSITIVE_LIKE
+#ifdef SQLITE_CASE_SENSITIVE_LIKE
LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
LIKEFUNC(like, 3, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
- #else
+#else
LIKEFUNC(like, 2, &likeInfoNorm, SQLITE_FUNC_LIKE),
LIKEFUNC(like, 3, &likeInfoNorm, SQLITE_FUNC_LIKE),
- #endif
+#endif
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ FUNCTION(unknown, -1, 0, 0, unknownFunc ),
+#endif
+ FUNCTION(coalesce, 1, 0, 0, 0 ),
+ FUNCTION(coalesce, 0, 0, 0, 0 ),
+ FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
};
-
- int i;
- FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
- FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aBuiltinFunc);
-
- for(i=0; i<ArraySize(aBuiltinFunc); i++){
- sqlite3FuncDefInsert(pHash, &aFunc[i]);
- }
- sqlite3RegisterDateTimeFunctions();
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
#endif
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
sqlite3AnalyzeFunctions();
#endif
+ sqlite3RegisterDateTimeFunctions();
+ sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
+
+#if 0 /* Enable to print out how the built-in functions are hashed */
+ {
+ int i;
+ FuncDef *p;
+ for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
+ printf("FUNC-HASH %02d:", i);
+ for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){
+ int n = sqlite3Strlen30(p->zName);
+ int h = p->zName[0] + n;
+ printf(" %s(%d)", p->zName, h);
+ }
+ printf("\n");
+ }
+ }
+#endif
}
/************** End of func.c ************************************************/
@@ -102108,7 +106813,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
}
for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
- if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){
+ if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){
/* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number
** of columns. If each indexed column corresponds to a foreign key
** column of pFKey, then this index is a winner. */
@@ -102467,7 +107172,7 @@ static void fkScanChildren(
assert( iCol>=0 );
zCol = pFKey->pFrom->aCol[iCol].zName;
pRight = sqlite3Expr(db, TK_ID, zCol);
- pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
+ pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
pWhere = sqlite3ExprAnd(db, pWhere, pEq);
}
@@ -102489,7 +107194,7 @@ static void fkScanChildren(
if( HasRowid(pTab) ){
pLeft = exprTableRegister(pParse, pTab, regData, -1);
pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, -1);
- pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight, 0);
+ pNe = sqlite3PExpr(pParse, TK_NE, pLeft, pRight);
}else{
Expr *pEq, *pAll = 0;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
@@ -102499,10 +107204,10 @@ static void fkScanChildren(
assert( iCol>=0 );
pLeft = exprTableRegister(pParse, pTab, regData, iCol);
pRight = exprTableColumn(db, pTab, pSrc->a[0].iCursor, iCol);
- pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight, 0);
+ pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
pAll = sqlite3ExprAnd(db, pAll, pEq);
}
- pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0, 0);
+ pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0);
}
pWhere = sqlite3ExprAnd(db, pWhere, pNe);
}
@@ -102754,7 +107459,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
if( (db->flags&SQLITE_ForeignKeys)==0 ) return;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- zDb = db->aDb[iDb].zName;
+ zDb = db->aDb[iDb].zDbSName;
/* Loop through all the foreign key constraints for which pTab is the
** child table (the table that the foreign key definition is part of). */
@@ -102890,7 +107595,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
struct SrcList_item *pItem = pSrc->a;
pItem->pTab = pFKey->pFrom;
pItem->zName = pFKey->pFrom->zName;
- pItem->pTab->nRef++;
+ pItem->pTab->nTabRef++;
pItem->iCursor = pParse->nTab++;
if( regNew!=0 ){
@@ -103045,6 +107750,9 @@ static Trigger *fkActionTrigger(
int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */
action = pFKey->aAction[iAction];
+ if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
+ return 0;
+ }
pTrigger = pFKey->apTrigger[iAction];
if( action!=OE_None && !pTrigger ){
@@ -103085,10 +107793,9 @@ static Trigger *fkActionTrigger(
pEq = sqlite3PExpr(pParse, TK_EQ,
sqlite3PExpr(pParse, TK_DOT,
sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
- sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
- , 0),
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0)
- , 0);
+ );
pWhere = sqlite3ExprAnd(db, pWhere, pEq);
/* For ON UPDATE, construct the next term of the WHEN clause.
@@ -103100,13 +107807,11 @@ static Trigger *fkActionTrigger(
pEq = sqlite3PExpr(pParse, TK_IS,
sqlite3PExpr(pParse, TK_DOT,
sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
- sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
- 0),
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
sqlite3PExpr(pParse, TK_DOT,
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
- sqlite3ExprAlloc(db, TK_ID, &tToCol, 0),
- 0),
- 0);
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0))
+ );
pWhen = sqlite3ExprAnd(db, pWhen, pEq);
}
@@ -103115,17 +107820,16 @@ static Trigger *fkActionTrigger(
if( action==OE_Cascade ){
pNew = sqlite3PExpr(pParse, TK_DOT,
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
- sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)
- , 0);
+ sqlite3ExprAlloc(db, TK_ID, &tToCol, 0));
}else if( action==OE_SetDflt ){
Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt;
if( pDflt ){
pNew = sqlite3ExprDup(db, pDflt, 0);
}else{
- pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
+ pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
}
}else{
- pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0);
+ pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
}
pList = sqlite3ExprListAppend(pParse, pList, pNew);
sqlite3ExprListSetName(pParse, pList, &tFromCol, 0);
@@ -103172,7 +107876,7 @@ static Trigger *fkActionTrigger(
pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
if( pWhen ){
- pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0, 0);
+ pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0);
pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE);
}
}
@@ -103252,7 +107956,8 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
FKey *pFKey; /* Iterator variable */
FKey *pNext; /* Copy of pFKey->pNextFrom */
- assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
+ assert( db==0 || IsVirtual(pTab)
+ || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
/* Remove the FK from the fkeyHash hash table. */
@@ -103490,7 +108195,9 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
/*
** Locate or create an AutoincInfo structure associated with table pTab
** which is in database iDb. Return the register number for the register
-** that holds the maximum rowid.
+** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT
+** table. (Also return zero when doing a VACUUM since we do not want to
+** update the AUTOINCREMENT counters during a VACUUM.)
**
** There is at most one AutoincInfo structure per table even if the
** same table is autoincremented multiple times due to inserts within
@@ -103513,7 +108220,9 @@ static int autoIncBegin(
Table *pTab /* The table we are writing to */
){
int memId = 0; /* Register holding maximum rowid */
- if( pTab->tabFlags & TF_Autoincrement ){
+ if( (pTab->tabFlags & TF_Autoincrement)!=0
+ && (pParse->db->flags & SQLITE_Vacuum)==0
+ ){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
AutoincInfo *pInfo;
@@ -103771,8 +108480,7 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3 *db; /* The main database structure */
Table *pTab; /* The table to insert into. aka TABLE */
char *zTab; /* Name of the table into which we are inserting */
- const char *zDb; /* Name of the database holding this table */
- int i, j, idx; /* Loop counters */
+ int i, j; /* Loop counters */
Vdbe *v; /* Generate code into this virtual machine */
Index *pIdx; /* For looping over indices of the table */
int nColumn; /* Number of columns in the data */
@@ -103786,7 +108494,6 @@ SQLITE_PRIVATE void sqlite3Insert(
int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */
SelectDest dest; /* Destination for SELECT on rhs of INSERT */
int iDb; /* Index of database holding TABLE */
- Db *pDb; /* The database containing table being inserted into */
u8 useTempTable = 0; /* Store SELECT results in intermediate table */
u8 appendFlag = 0; /* True if the insert is likely to be an append */
u8 withoutRowid; /* 0 for normal table. 1 for WITHOUT ROWID table */
@@ -103836,9 +108543,8 @@ SQLITE_PRIVATE void sqlite3Insert(
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
assert( iDb<db->nDb );
- pDb = &db->aDb[iDb];
- zDb = pDb->zName;
- if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){
+ if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0,
+ db->aDb[iDb].zDbSName) ){
goto insert_cleanup;
}
withoutRowid = !HasRowid(pTab);
@@ -104081,8 +108787,10 @@ SQLITE_PRIVATE void sqlite3Insert(
if( aRegIdx==0 ){
goto insert_cleanup;
}
- for(i=0; i<nIdx; i++){
+ for(i=0, pIdx=pTab->pIndex; i<nIdx; pIdx=pIdx->pNext, i++){
+ assert( pIdx );
aRegIdx[i] = ++pParse->nMem;
+ pParse->nMem += pIdx->nColumn;
}
}
@@ -104284,12 +108992,26 @@ SQLITE_PRIVATE void sqlite3Insert(
#endif
{
int isReplace; /* Set to true if constraints may cause a replace */
+ int bUseSeek; /* True to use OPFLAG_SEEKRESULT */
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0
);
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
+
+ /* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
+ ** constraints or (b) there are no triggers and this table is not a
+ ** parent table in a foreign key constraint. It is safe to set the
+ ** flag in the second case as if any REPLACE constraint is hit, an
+ ** OP_Delete or OP_IdxDelete instruction will be executed on each
+ ** cursor that is disturbed. And these instructions both clear the
+ ** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT
+ ** functionality. */
+ bUseSeek = (isReplace==0 || (pTrigger==0 &&
+ ((db->flags & SQLITE_ForeignKeys)==0 || sqlite3FkReferences(pTab)==0)
+ ));
sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
- regIns, aRegIdx, 0, appendFlag, isReplace==0);
+ regIns, aRegIdx, 0, appendFlag, bUseSeek
+ );
}
}
@@ -104318,14 +109040,6 @@ SQLITE_PRIVATE void sqlite3Insert(
sqlite3VdbeJumpHere(v, addrInsTop);
}
- if( !IsVirtual(pTab) && !isView ){
- /* Close all tables opened */
- if( iDataCur<iIdxCur ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
- for(idx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
- sqlite3VdbeAddOp1(v, OP_Close, idx+iIdxCur);
- }
- }
-
insert_end:
/* Update the sqlite_sequence table by storing the content of the
** maximum rowid counter values recorded while inserting into
@@ -104532,7 +109246,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
int ipkBottom = 0; /* Bottom of the rowid change constraint check */
u8 isUpdate; /* True if this is an UPDATE operation */
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
- int regRowid = -1; /* Register holding ROWID value */
isUpdate = regOldData!=0;
db = pParse->db;
@@ -104587,8 +109300,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
case OE_Fail: {
char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
pTab->aCol[i].zName);
- sqlite3VdbeAddOp4(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
- regNewData+1+i, zMsg, P4_DYNAMIC);
+ sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError,
+ regNewData+1+i);
+ sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
sqlite3VdbeChangeP5(v, P5_ConstraintNotNull);
VdbeCoverage(v);
break;
@@ -104652,7 +109366,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
}
if( isUpdate ){
- /* pkChng!=0 does not mean that the rowid has change, only that
+ /* pkChng!=0 does not mean that the rowid has changed, only that
** it might have changed. Skip the conflict logic below if the rowid
** is unchanged. */
sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
@@ -104721,9 +109435,18 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
- regNewData, 1, 0, OE_Replace,
- ONEPASS_SINGLE, -1);
+ regNewData, 1, 0, OE_Replace, 1, -1);
}else{
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ if( HasRowid(pTab) ){
+ /* This OP_Delete opcode fires the pre-update-hook only. It does
+ ** not modify the b-tree. It is more efficient to let the coming
+ ** OP_Insert replace the existing entry than it is to delete the
+ ** existing entry and then insert a new one. */
+ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, OPFLAG_ISNOOP);
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
+ }
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
if( pTab->pIndex ){
sqlite3MultiWrite(pParse);
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,-1);
@@ -104778,7 +109501,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
/* Create a record for this index entry as it should appear after
** the insert or update. Store that record in the aRegIdx[ix] register
*/
- regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
+ regIdx = aRegIdx[ix]+1;
for(i=0; i<pIdx->nColumn; i++){
int iField = pIdx->aiColumn[i];
int x;
@@ -104789,9 +109512,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
VdbeComment((v, "%s column %d", pIdx->zName, i));
}else{
if( iField==XN_ROWID || iField==pTab->iPKey ){
- if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
x = regNewData;
- regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
}else{
x = iField + regNewData + 1;
}
@@ -104801,7 +109522,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
VdbeComment((v, "for %s", pIdx->zName));
- sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
/* In an UPDATE operation, if this index is the PRIMARY KEY index
** of a WITHOUT ROWID table and there has been no change the
@@ -104815,7 +109535,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
/* Find out what action to take in case there is a uniqueness conflict */
onError = pIdx->onError;
if( onError==OE_None ){
- sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
sqlite3VdbeResolveLabel(v, addrUniqueOk);
continue; /* pIdx is not a UNIQUE index */
}
@@ -104824,6 +109543,12 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
}else if( onError==OE_Default ){
onError = OE_Abort;
}
+
+ if( ix==0 && pPk==pIdx && onError==OE_Replace && pPk->pNext==0 ){
+ sqlite3VdbeResolveLabel(v, addrUniqueOk);
+ continue;
+ }
+
/* Check to see if the new index entry will be unique */
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
@@ -104914,7 +109639,6 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
}
}
sqlite3VdbeResolveLabel(v, addrUniqueOk);
- sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
}
if( ipkTop ){
@@ -104964,7 +109688,9 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
}
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
+ aRegIdx[i]+1,
+ pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
pik_flags = 0;
if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
@@ -104977,8 +109703,10 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
regData = regNewData + 1;
regRec = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec);
- if( !bAffinityDone ) sqlite3TableAffinity(v, pTab, 0);
- sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
+ if( !bAffinityDone ){
+ sqlite3TableAffinity(v, pTab, 0);
+ sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol);
+ }
if( pParse->nested ){
pik_flags = 0;
}else{
@@ -104993,7 +109721,7 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
}
sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regNewData);
if( !pParse->nested ){
- sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
}
sqlite3VdbeChangeP5(v, pik_flags);
}
@@ -105058,15 +109786,15 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
int iIdxCur = iBase++;
assert( pIdx->pSchema==pTab->pSchema );
+ if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
+ if( piDataCur ) *piDataCur = iIdxCur;
+ p5 = 0;
+ }
if( aToOpen==0 || aToOpen[i+1] ){
sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
- VdbeComment((v, "%s", pIdx->zName));
- }
- if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
- if( piDataCur ) *piDataCur = iIdxCur;
- }else{
sqlite3VdbeChangeP5(v, p5);
+ VdbeComment((v, "%s", pIdx->zName));
}
}
if( iBase>pParse->nTab ) pParse->nTab = iBase;
@@ -105289,11 +110017,15 @@ static int xferOptimization(
return 0; /* tab2 must be NOT NULL if tab1 is */
}
/* Default values for second and subsequent columns need to match. */
- if( i>0
- && ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
- || (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
- ){
- return 0; /* Default values must be the same for all columns */
+ if( i>0 ){
+ assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
+ assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
+ if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
+ || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
+ pSrcCol->pDflt->u.zToken)!=0)
+ ){
+ return 0; /* Default values must be the same for all columns */
+ }
}
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
@@ -105372,6 +110104,7 @@ static int xferOptimization(
sqlite3VdbeJumpHere(v, addr1);
}
if( HasRowid(pSrc) ){
+ u8 insFlags;
sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
if( pDest->iPKey>=0 ){
@@ -105388,9 +110121,16 @@ static int xferOptimization(
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
}
sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
+ if( db->flags & SQLITE_Vacuum ){
+ sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1);
+ insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
+ OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
+ }else{
+ insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
+ }
sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
- pDest->zName, 0);
- sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND);
+ (char*)pDest, P4_TABLE);
+ sqlite3VdbeChangeP5(v, insFlags);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
@@ -105412,7 +110152,7 @@ static int xferOptimization(
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
VdbeComment((v, "%s", pDestIdx->zName));
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData);
+ sqlite3VdbeAddOp2(v, OP_RowData, iSrc, regData);
if( db->flags & SQLITE_Vacuum ){
/* This INSERT command is part of a VACUUM operation, which guarantees
** that the destination table is empty. If all indexed columns use
@@ -105442,8 +110182,8 @@ static int xferOptimization(
if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
idxInsFlags |= OPFLAG_NCHANGE;
}
- sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
- sqlite3VdbeChangeP5(v, idxInsFlags);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
+ sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
@@ -105453,6 +110193,7 @@ static int xferOptimization(
sqlite3ReleaseTempReg(pParse, regRowid);
sqlite3ReleaseTempReg(pParse, regData);
if( emptyDestTest ){
+ sqlite3AutoincrementEnd(pParse);
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, 0);
sqlite3VdbeJumpHere(v, emptyDestTest);
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
@@ -105494,7 +110235,7 @@ static int xferOptimization(
** argument to xCallback(). If xCallback=NULL then no callback
** is invoked, even for queries.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_exec(
+SQLITE_API int sqlite3_exec(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
sqlite3_callback xCallback, /* Invoke this callback routine */
@@ -105598,7 +110339,7 @@ exec_out:
if( *pzErrMsg ){
memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg);
}else{
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
sqlite3Error(db, SQLITE_NOMEM);
}
}else if( pzErrMsg ){
@@ -105649,12 +110390,10 @@ exec_out:
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
*/
-#ifndef _SQLITE3EXT_H_
-#define _SQLITE3EXT_H_
+#ifndef SQLITE3EXT_H
+#define SQLITE3EXT_H
/* #include "sqlite3.h" */
-typedef struct sqlite3_api_routines sqlite3_api_routines;
-
/*
** The following structure holds pointers to all of the SQLite API
** routines.
@@ -105913,9 +110652,24 @@ struct sqlite3_api_routines {
int (*status64)(int,sqlite3_int64*,sqlite3_int64*,int);
int (*strlike)(const char*,const char*,unsigned int);
int (*db_cacheflush)(sqlite3*);
+ /* Version 3.12.0 and later */
+ int (*system_errno)(sqlite3*);
+ /* Version 3.14.0 and later */
+ int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
+ char *(*expanded_sql)(sqlite3_stmt*);
};
/*
+** This is the function signature used for all extension entry points. It
+** is also defined in the file "loadext.c".
+*/
+typedef int (*sqlite3_loadext_entry)(
+ sqlite3 *db, /* Handle to the database. */
+ char **pzErrMsg, /* Used to set error string on failure. */
+ const sqlite3_api_routines *pThunk /* Extension API function pointers. */
+);
+
+/*
** The following macros redefine the API routines so that they are
** redirected through the global sqlite3_api structure.
**
@@ -106156,6 +110910,11 @@ struct sqlite3_api_routines {
#define sqlite3_status64 sqlite3_api->status64
#define sqlite3_strlike sqlite3_api->strlike
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
+/* Version 3.12.0 and later */
+#define sqlite3_system_errno sqlite3_api->system_errno
+/* Version 3.14.0 and later */
+#define sqlite3_trace_v2 sqlite3_api->trace_v2
+#define sqlite3_expanded_sql sqlite3_api->expanded_sql
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -106173,7 +110932,7 @@ struct sqlite3_api_routines {
# define SQLITE_EXTENSION_INIT3 /*no-op*/
#endif
-#endif /* _SQLITE3EXT_H_ */
+#endif /* SQLITE3EXT_H */
/************** End of sqlite3ext.h ******************************************/
/************** Continuing where we left off in loadext.c ********************/
@@ -106181,7 +110940,6 @@ struct sqlite3_api_routines {
/* #include <string.h> */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
-
/*
** Some API routines are omitted when various features are
** excluded from a build of SQLite. Substitute a NULL pointer
@@ -106251,7 +111009,7 @@ struct sqlite3_api_routines {
# define sqlite3_enable_shared_cache 0
#endif
-#ifdef SQLITE_OMIT_TRACE
+#if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED)
# define sqlite3_profile 0
# define sqlite3_trace 0
#endif
@@ -106271,6 +111029,10 @@ struct sqlite3_api_routines {
#define sqlite3_blob_reopen 0
#endif
+#if defined(SQLITE_OMIT_TRACE)
+# define sqlite3_trace_v2 0
+#endif
+
/*
** The following structure contains pointers to all SQLite API routines.
** A pointer to this structure is passed into extensions when they are
@@ -106574,7 +111336,12 @@ static const sqlite3_api_routines sqlite3Apis = {
/* Version 3.10.0 and later */
sqlite3_status64,
sqlite3_strlike,
- sqlite3_db_cacheflush
+ sqlite3_db_cacheflush,
+ /* Version 3.12.0 and later */
+ sqlite3_system_errno,
+ /* Version 3.14.0 and later */
+ sqlite3_trace_v2,
+ sqlite3_expanded_sql
};
/*
@@ -106597,13 +111364,14 @@ static int sqlite3LoadExtension(
){
sqlite3_vfs *pVfs = db->pVfs;
void *handle;
- int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
+ sqlite3_loadext_entry xInit;
char *zErrmsg = 0;
const char *zEntry;
char *zAltEntry = 0;
void **aHandle;
u64 nMsg = 300 + sqlite3Strlen30(zFile);
int ii;
+ int rc;
/* Shared library endings to try if zFile cannot be loaded as written */
static const char *azEndings[] = {
@@ -106622,8 +111390,9 @@ static int sqlite3LoadExtension(
/* Ticket #1863. To avoid a creating security problems for older
** applications that relink against newer versions of SQLite, the
** ability to run load_extension is turned off by default. One
- ** must call sqlite3_enable_load_extension() to turn on extension
- ** loading. Otherwise you get the following error.
+ ** must call either sqlite3_enable_load_extension(db) or
+ ** sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, 0)
+ ** to turn on extension loading.
*/
if( (db->flags & SQLITE_LoadExtension)==0 ){
if( pzErrMsg ){
@@ -106638,7 +111407,7 @@ static int sqlite3LoadExtension(
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
- if( zAltFile==0 ) return SQLITE_NOMEM;
+ if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
handle = sqlite3OsDlOpen(pVfs, zAltFile);
sqlite3_free(zAltFile);
}
@@ -106654,8 +111423,7 @@ static int sqlite3LoadExtension(
}
return SQLITE_ERROR;
}
- xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
- sqlite3OsDlSym(pVfs, handle, zEntry);
+ xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
/* If no entry point was specified and the default legacy
** entry point name "sqlite3_extension_init" was not found, then
@@ -106674,7 +111442,7 @@ static int sqlite3LoadExtension(
zAltEntry = sqlite3_malloc64(ncFile+30);
if( zAltEntry==0 ){
sqlite3OsDlClose(pVfs, handle);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memcpy(zAltEntry, "sqlite3_", 8);
for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
@@ -106687,8 +111455,7 @@ static int sqlite3LoadExtension(
}
memcpy(zAltEntry+iEntry, "_init", 6);
zEntry = zAltEntry;
- xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
- sqlite3OsDlSym(pVfs, handle, zEntry);
+ xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
}
if( xInit==0 ){
if( pzErrMsg ){
@@ -106705,7 +111472,9 @@ static int sqlite3LoadExtension(
return SQLITE_ERROR;
}
sqlite3_free(zAltEntry);
- if( xInit(db, &zErrmsg, &sqlite3Apis) ){
+ rc = xInit(db, &zErrmsg, &sqlite3Apis);
+ if( rc ){
+ if( rc==SQLITE_OK_LOAD_PERMANENTLY ) return SQLITE_OK;
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
}
@@ -106717,7 +111486,7 @@ static int sqlite3LoadExtension(
/* Append the new shared library handle to the db->aExtension array. */
aHandle = sqlite3DbMallocZero(db, sizeof(handle)*(db->nExtension+1));
if( aHandle==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
if( db->nExtension>0 ){
memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension);
@@ -106728,7 +111497,7 @@ static int sqlite3LoadExtension(
db->aExtension[db->nExtension++] = handle;
return SQLITE_OK;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
+SQLITE_API int sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
@@ -106759,29 +111528,18 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){
** Enable or disable extension loading. Extension loading is disabled by
** default so as not to open security holes in older applications.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff){
+SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
sqlite3_mutex_enter(db->mutex);
if( onoff ){
- db->flags |= SQLITE_LoadExtension;
+ db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
}else{
- db->flags &= ~SQLITE_LoadExtension;
+ db->flags &= ~(SQLITE_LoadExtension|SQLITE_LoadExtFunc);
}
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
-
-/*
-** The auto-extension code added regardless of whether or not extension
-** loading is supported. We need a dummy sqlite3Apis pointer for that
-** code if regular extension loading is not available. This is that
-** dummy pointer.
-*/
-#ifdef SQLITE_OMIT_LOAD_EXTENSION
-static const sqlite3_api_routines sqlite3Apis = { 0 };
-#endif
-
+#endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */
/*
** The following object holds the list of automatically loaded
@@ -106816,7 +111574,9 @@ static SQLITE_WSD struct sqlite3AutoExtList {
** Register a statically linked extension that is automatically
** loaded by every new database connection.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
+SQLITE_API int sqlite3_auto_extension(
+ void (*xInit)(void)
+){
int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
@@ -106839,7 +111599,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
void (**aNew)(void);
aNew = sqlite3_realloc64(wsdAutoext.aExt, nByte);
if( aNew==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
wsdAutoext.aExt = aNew;
wsdAutoext.aExt[wsdAutoext.nExt] = xInit;
@@ -106861,7 +111621,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xInit)(void)){
** Return 1 if xInit was found on the list and removed. Return 0 if xInit
** was not on the list.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void)){
+SQLITE_API int sqlite3_cancel_auto_extension(
+ void (*xInit)(void)
+){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
@@ -106884,7 +111646,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xInit)(void))
/*
** Reset the automatic extension loading mechanism.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void){
+SQLITE_API void sqlite3_reset_auto_extension(void){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize()==SQLITE_OK )
#endif
@@ -106910,7 +111672,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
u32 i;
int go = 1;
int rc;
- int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
+ sqlite3_loadext_entry xInit;
wsdAutoextInit;
if( wsdAutoext.nExt==0 ){
@@ -106922,17 +111684,21 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
#endif
+#ifdef SQLITE_OMIT_LOAD_EXTENSION
+ const sqlite3_api_routines *pThunk = 0;
+#else
+ const sqlite3_api_routines *pThunk = &sqlite3Apis;
+#endif
sqlite3_mutex_enter(mutex);
if( i>=wsdAutoext.nExt ){
xInit = 0;
go = 0;
}else{
- xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
- wsdAutoext.aExt[i];
+ xInit = (sqlite3_loadext_entry)wsdAutoext.aExt[i];
}
sqlite3_mutex_leave(mutex);
zErrmsg = 0;
- if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
+ if( xInit && (rc = xInit(db, &zErrmsg, pThunk))!=0 ){
sqlite3ErrorWithMsg(db, rc,
"automatic extension loading failed: %s", zErrmsg);
go = 0;
@@ -106980,6 +111746,8 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
** ../tool/mkpragmatab.tcl. To update the set of pragmas, edit
** that script and rerun it.
*/
+
+/* The various pragma types */
#define PragTyp_HEADER_VALUE 0
#define PragTyp_AUTO_VACUUM 1
#define PragTyp_FLAG 2
@@ -107023,419 +111791,559 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
#define PragTyp_REKEY 40
#define PragTyp_LOCK_STATUS 41
#define PragTyp_PARSER_TRACE 42
-#define PragFlag_NeedSchema 0x01
-#define PragFlag_ReadOnly 0x02
-static const struct sPragmaNames {
- const char *const zName; /* Name of pragma */
- u8 ePragTyp; /* PragTyp_XXX value */
- u8 mPragFlag; /* Zero or more PragFlag_XXX values */
- u32 iArg; /* Extra argument */
-} aPragmaNames[] = {
+
+/* Property flags associated with various pragma. */
+#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
+#define PragFlg_NoColumns 0x02 /* OP_ResultRow called with zero columns */
+#define PragFlg_ReadOnly 0x04 /* Read-only HEADER_VALUE */
+#define PragFlg_Result0 0x08 /* Acts as query when no argument */
+#define PragFlg_Result1 0x10 /* Acts as query when has one argument */
+#define PragFlg_SchemaOpt 0x20 /* Schema restricts name search if present */
+#define PragFlg_SchemaReq 0x40 /* Schema required - "main" is default */
+
+/* Names of columns for pragmas that return multi-column result
+** or that return single-column results where the name of the
+** result column is different from the name of the pragma
+*/
+static const char *const pragCName[] = {
+ /* 0 */ "cache_size", /* Used by: default_cache_size */
+ /* 1 */ "cid", /* Used by: table_info */
+ /* 2 */ "name",
+ /* 3 */ "type",
+ /* 4 */ "notnull",
+ /* 5 */ "dflt_value",
+ /* 6 */ "pk",
+ /* 7 */ "table", /* Used by: stats */
+ /* 8 */ "index",
+ /* 9 */ "width",
+ /* 10 */ "height",
+ /* 11 */ "seqno", /* Used by: index_info */
+ /* 12 */ "cid",
+ /* 13 */ "name",
+ /* 14 */ "seqno", /* Used by: index_xinfo */
+ /* 15 */ "cid",
+ /* 16 */ "name",
+ /* 17 */ "desc",
+ /* 18 */ "coll",
+ /* 19 */ "key",
+ /* 20 */ "seq", /* Used by: index_list */
+ /* 21 */ "name",
+ /* 22 */ "unique",
+ /* 23 */ "origin",
+ /* 24 */ "partial",
+ /* 25 */ "seq", /* Used by: database_list */
+ /* 26 */ "name",
+ /* 27 */ "file",
+ /* 28 */ "seq", /* Used by: collation_list */
+ /* 29 */ "name",
+ /* 30 */ "id", /* Used by: foreign_key_list */
+ /* 31 */ "seq",
+ /* 32 */ "table",
+ /* 33 */ "from",
+ /* 34 */ "to",
+ /* 35 */ "on_update",
+ /* 36 */ "on_delete",
+ /* 37 */ "match",
+ /* 38 */ "table", /* Used by: foreign_key_check */
+ /* 39 */ "rowid",
+ /* 40 */ "parent",
+ /* 41 */ "fkid",
+ /* 42 */ "busy", /* Used by: wal_checkpoint */
+ /* 43 */ "log",
+ /* 44 */ "checkpointed",
+ /* 45 */ "timeout", /* Used by: busy_timeout */
+ /* 46 */ "database", /* Used by: lock_status */
+ /* 47 */ "status",
+};
+
+/* Definitions of all built-in pragmas */
+typedef struct PragmaName {
+ const char *const zName; /* Name of pragma */
+ u8 ePragTyp; /* PragTyp_XXX value */
+ u8 mPragFlg; /* Zero or more PragFlg_XXX values */
+ u8 iPragCName; /* Start of column names in pragCName[] */
+ u8 nPragCName; /* Num of col names. 0 means use pragma name */
+ u32 iArg; /* Extra argument */
+} PragmaName;
+static const PragmaName aPragmaName[] = {
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
- { /* zName: */ "activate_extensions",
- /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "activate_extensions",
+ /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "application_id",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ BTREE_APPLICATION_ID },
+ {/* zName: */ "application_id",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_APPLICATION_ID },
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
- { /* zName: */ "auto_vacuum",
- /* ePragTyp: */ PragTyp_AUTO_VACUUM,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "auto_vacuum",
+ /* ePragTyp: */ PragTyp_AUTO_VACUUM,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_AUTOMATIC_INDEX)
- { /* zName: */ "automatic_index",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_AutoIndex },
-#endif
-#endif
- { /* zName: */ "busy_timeout",
- /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "automatic_index",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_AutoIndex },
+#endif
+#endif
+ {/* zName: */ "busy_timeout",
+ /* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 45, 1,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "cache_size",
- /* ePragTyp: */ PragTyp_CACHE_SIZE,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "cache_size",
+ /* ePragTyp: */ PragTyp_CACHE_SIZE,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "cache_spill",
- /* ePragTyp: */ PragTyp_CACHE_SPILL,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
- { /* zName: */ "case_sensitive_like",
- /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "cell_size_check",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CellSizeCk },
+ {/* zName: */ "cache_spill",
+ /* ePragTyp: */ PragTyp_CACHE_SPILL,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+#endif
+ {/* zName: */ "case_sensitive_like",
+ /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "cell_size_check",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_CellSizeCk },
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "checkpoint_fullfsync",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CkptFullFSync },
+ {/* zName: */ "checkpoint_fullfsync",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_CkptFullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "collation_list",
- /* ePragTyp: */ PragTyp_COLLATION_LIST,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "collation_list",
+ /* ePragTyp: */ PragTyp_COLLATION_LIST,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 28, 2,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
- { /* zName: */ "compile_options",
- /* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "compile_options",
+ /* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "count_changes",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_CountRows },
+ {/* zName: */ "count_changes",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_CountRows },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_OS_WIN
- { /* zName: */ "data_store_directory",
- /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "data_store_directory",
+ /* ePragTyp: */ PragTyp_DATA_STORE_DIRECTORY,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "data_version",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ PragFlag_ReadOnly,
- /* iArg: */ BTREE_DATA_VERSION },
+ {/* zName: */ "data_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_ReadOnly,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_DATA_VERSION },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "database_list",
- /* ePragTyp: */ PragTyp_DATABASE_LIST,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "database_list",
+ /* ePragTyp: */ PragTyp_DATABASE_LIST,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
+ /* ColNames: */ 25, 3,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
- { /* zName: */ "default_cache_size",
- /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "default_cache_size",
+ /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 1,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- { /* zName: */ "defer_foreign_keys",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_DeferFKs },
+ {/* zName: */ "defer_foreign_keys",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_DeferFKs },
#endif
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "empty_result_callbacks",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_NullCallback },
+ {/* zName: */ "empty_result_callbacks",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_NullCallback },
#endif
#if !defined(SQLITE_OMIT_UTF16)
- { /* zName: */ "encoding",
- /* ePragTyp: */ PragTyp_ENCODING,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "encoding",
+ /* ePragTyp: */ PragTyp_ENCODING,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- { /* zName: */ "foreign_key_check",
- /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "foreign_key_check",
+ /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
+ /* ePragFlg: */ PragFlg_NeedSchema,
+ /* ColNames: */ 38, 4,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
- { /* zName: */ "foreign_key_list",
- /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "foreign_key_list",
+ /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 30, 8,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
- { /* zName: */ "foreign_keys",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ForeignKeys },
+ {/* zName: */ "foreign_keys",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_ForeignKeys },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "freelist_count",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ PragFlag_ReadOnly,
- /* iArg: */ BTREE_FREE_PAGE_COUNT },
+ {/* zName: */ "freelist_count",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_ReadOnly,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_FREE_PAGE_COUNT },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "full_column_names",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_FullColNames },
- { /* zName: */ "fullfsync",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_FullFSync },
+ {/* zName: */ "full_column_names",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_FullColNames },
+ {/* zName: */ "fullfsync",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_FullFSync },
#endif
#if defined(SQLITE_HAS_CODEC)
- { /* zName: */ "hexkey",
- /* ePragTyp: */ PragTyp_HEXKEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "hexrekey",
- /* ePragTyp: */ PragTyp_HEXKEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "hexkey",
+ /* ePragTyp: */ PragTyp_HEXKEY,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "hexrekey",
+ /* ePragTyp: */ PragTyp_HEXKEY,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if !defined(SQLITE_OMIT_CHECK)
- { /* zName: */ "ignore_check_constraints",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_IgnoreChecks },
+ {/* zName: */ "ignore_check_constraints",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_IgnoreChecks },
#endif
#endif
#if !defined(SQLITE_OMIT_AUTOVACUUM)
- { /* zName: */ "incremental_vacuum",
- /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "incremental_vacuum",
+ /* ePragTyp: */ PragTyp_INCREMENTAL_VACUUM,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "index_info",
- /* ePragTyp: */ PragTyp_INDEX_INFO,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "index_list",
- /* ePragTyp: */ PragTyp_INDEX_LIST,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "index_xinfo",
- /* ePragTyp: */ PragTyp_INDEX_INFO,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 1 },
+ {/* zName: */ "index_info",
+ /* ePragTyp: */ PragTyp_INDEX_INFO,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 11, 3,
+ /* iArg: */ 0 },
+ {/* zName: */ "index_list",
+ /* ePragTyp: */ PragTyp_INDEX_LIST,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 20, 5,
+ /* iArg: */ 0 },
+ {/* zName: */ "index_xinfo",
+ /* ePragTyp: */ PragTyp_INDEX_INFO,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 14, 6,
+ /* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
- { /* zName: */ "integrity_check",
- /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "integrity_check",
+ /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
+ /* ePragFlg: */ PragFlg_NeedSchema,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "journal_mode",
- /* ePragTyp: */ PragTyp_JOURNAL_MODE,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "journal_size_limit",
- /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "journal_mode",
+ /* ePragTyp: */ PragTyp_JOURNAL_MODE,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "journal_size_limit",
+ /* ePragTyp: */ PragTyp_JOURNAL_SIZE_LIMIT,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if defined(SQLITE_HAS_CODEC)
- { /* zName: */ "key",
- /* ePragTyp: */ PragTyp_KEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "key",
+ /* ePragTyp: */ PragTyp_KEY,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "legacy_file_format",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_LegacyFileFmt },
+ {/* zName: */ "legacy_file_format",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_LegacyFileFmt },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && SQLITE_ENABLE_LOCKING_STYLE
- { /* zName: */ "lock_proxy_file",
- /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "lock_proxy_file",
+ /* ePragTyp: */ PragTyp_LOCK_PROXY_FILE,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
- { /* zName: */ "lock_status",
- /* ePragTyp: */ PragTyp_LOCK_STATUS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "lock_status",
+ /* ePragTyp: */ PragTyp_LOCK_STATUS,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 46, 2,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "locking_mode",
- /* ePragTyp: */ PragTyp_LOCKING_MODE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "max_page_count",
- /* ePragTyp: */ PragTyp_PAGE_COUNT,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "mmap_size",
- /* ePragTyp: */ PragTyp_MMAP_SIZE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "page_count",
- /* ePragTyp: */ PragTyp_PAGE_COUNT,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
- { /* zName: */ "page_size",
- /* ePragTyp: */ PragTyp_PAGE_SIZE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "locking_mode",
+ /* ePragTyp: */ PragTyp_LOCKING_MODE,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "max_page_count",
+ /* ePragTyp: */ PragTyp_PAGE_COUNT,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "mmap_size",
+ /* ePragTyp: */ PragTyp_MMAP_SIZE,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "page_count",
+ /* ePragTyp: */ PragTyp_PAGE_COUNT,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "page_size",
+ /* ePragTyp: */ PragTyp_PAGE_SIZE,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_PARSER_TRACE)
- { /* zName: */ "parser_trace",
- /* ePragTyp: */ PragTyp_PARSER_TRACE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "parser_trace",
+ /* ePragTyp: */ PragTyp_PARSER_TRACE,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "query_only",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_QueryOnly },
+ {/* zName: */ "query_only",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_QueryOnly },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
- { /* zName: */ "quick_check",
- /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "quick_check",
+ /* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
+ /* ePragFlg: */ PragFlg_NeedSchema,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "read_uncommitted",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ReadUncommitted },
- { /* zName: */ "recursive_triggers",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_RecTriggers },
+ {/* zName: */ "read_uncommitted",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_ReadUncommitted },
+ {/* zName: */ "recursive_triggers",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_RecTriggers },
#endif
#if defined(SQLITE_HAS_CODEC)
- { /* zName: */ "rekey",
- /* ePragTyp: */ PragTyp_REKEY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "rekey",
+ /* ePragTyp: */ PragTyp_REKEY,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "reverse_unordered_selects",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ReverseOrder },
+ {/* zName: */ "reverse_unordered_selects",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_ReverseOrder },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "schema_version",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ BTREE_SCHEMA_VERSION },
+ {/* zName: */ "schema_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_SCHEMA_VERSION },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "secure_delete",
- /* ePragTyp: */ PragTyp_SECURE_DELETE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "secure_delete",
+ /* ePragTyp: */ PragTyp_SECURE_DELETE,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "short_column_names",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_ShortColNames },
-#endif
- { /* zName: */ "shrink_memory",
- /* ePragTyp: */ PragTyp_SHRINK_MEMORY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "soft_heap_limit",
- /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "short_column_names",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_ShortColNames },
+#endif
+ {/* zName: */ "shrink_memory",
+ /* ePragTyp: */ PragTyp_SHRINK_MEMORY,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "soft_heap_limit",
+ /* ePragTyp: */ PragTyp_SOFT_HEAP_LIMIT,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if defined(SQLITE_DEBUG)
- { /* zName: */ "sql_trace",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_SqlTrace },
+ {/* zName: */ "sql_trace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_SqlTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "stats",
- /* ePragTyp: */ PragTyp_STATS,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "stats",
+ /* ePragTyp: */ PragTyp_STATS,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 7, 4,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "synchronous",
- /* ePragTyp: */ PragTyp_SYNCHRONOUS,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "synchronous",
+ /* ePragTyp: */ PragTyp_SYNCHRONOUS,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
- { /* zName: */ "table_info",
- /* ePragTyp: */ PragTyp_TABLE_INFO,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "table_info",
+ /* ePragTyp: */ PragTyp_TABLE_INFO,
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
+ /* ColNames: */ 1, 6,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
- { /* zName: */ "temp_store",
- /* ePragTyp: */ PragTyp_TEMP_STORE,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "temp_store_directory",
- /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
-#endif
- { /* zName: */ "threads",
- /* ePragTyp: */ PragTyp_THREADS,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
+ {/* zName: */ "temp_store",
+ /* ePragTyp: */ PragTyp_TEMP_STORE,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "temp_store_directory",
+ /* ePragTyp: */ PragTyp_TEMP_STORE_DIRECTORY,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+#endif
+ {/* zName: */ "threads",
+ /* ePragTyp: */ PragTyp_THREADS,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
- { /* zName: */ "user_version",
- /* ePragTyp: */ PragTyp_HEADER_VALUE,
- /* ePragFlag: */ 0,
- /* iArg: */ BTREE_USER_VERSION },
+ {/* zName: */ "user_version",
+ /* ePragTyp: */ PragTyp_HEADER_VALUE,
+ /* ePragFlg: */ PragFlg_Result0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ BTREE_USER_VERSION },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
#if defined(SQLITE_DEBUG)
- { /* zName: */ "vdbe_addoptrace",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeAddopTrace },
- { /* zName: */ "vdbe_debug",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
- { /* zName: */ "vdbe_eqp",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeEQP },
- { /* zName: */ "vdbe_listing",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeListing },
- { /* zName: */ "vdbe_trace",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_VdbeTrace },
+ {/* zName: */ "vdbe_addoptrace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_VdbeAddopTrace },
+ {/* zName: */ "vdbe_debug",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_SqlTrace|SQLITE_VdbeListing|SQLITE_VdbeTrace },
+ {/* zName: */ "vdbe_eqp",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_VdbeEQP },
+ {/* zName: */ "vdbe_listing",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_VdbeListing },
+ {/* zName: */ "vdbe_trace",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_VdbeTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_WAL)
- { /* zName: */ "wal_autocheckpoint",
- /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
- /* ePragFlag: */ 0,
- /* iArg: */ 0 },
- { /* zName: */ "wal_checkpoint",
- /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
- /* ePragFlag: */ PragFlag_NeedSchema,
- /* iArg: */ 0 },
+ {/* zName: */ "wal_autocheckpoint",
+ /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
+ /* ePragFlg: */ 0,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ 0 },
+ {/* zName: */ "wal_checkpoint",
+ /* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
+ /* ePragFlg: */ PragFlg_NeedSchema,
+ /* ColNames: */ 42, 3,
+ /* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
- { /* zName: */ "writable_schema",
- /* ePragTyp: */ PragTyp_FLAG,
- /* ePragFlag: */ 0,
- /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
+ {/* zName: */ "writable_schema",
+ /* ePragTyp: */ PragTyp_FLAG,
+ /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns,
+ /* ColNames: */ 0, 0,
+ /* iArg: */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
#endif
};
/* Number of pragmas: 60 on by default, 73 total. */
@@ -107576,29 +112484,29 @@ static int changeTempStorage(Parse *pParse, const char *zStorageType){
#endif /* SQLITE_PAGER_PRAGMAS */
/*
-** Set the names of the first N columns to the values in azCol[]
+** Set result column names for a pragma.
*/
-static void setAllColumnNames(
- Vdbe *v, /* The query under construction */
- int N, /* Number of columns */
- const char **azCol /* Names of columns */
+static void setPragmaResultColumnNames(
+ Vdbe *v, /* The query under construction */
+ const PragmaName *pPragma /* The pragma */
){
- int i;
- sqlite3VdbeSetNumCols(v, N);
- for(i=0; i<N; i++){
- sqlite3VdbeSetColName(v, i, COLNAME_NAME, azCol[i], SQLITE_STATIC);
+ u8 n = pPragma->nPragCName;
+ sqlite3VdbeSetNumCols(v, n==0 ? 1 : n);
+ if( n==0 ){
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, pPragma->zName, SQLITE_STATIC);
+ }else{
+ int i, j;
+ for(i=0, j=pPragma->iPragCName; i<n; i++, j++){
+ sqlite3VdbeSetColName(v, i, COLNAME_NAME, pragCName[j], SQLITE_STATIC);
+ }
}
}
-static void setOneColumnName(Vdbe *v, const char *z){
- setAllColumnNames(v, 1, &z);
-}
/*
** Generate code to return a single integer value.
*/
-static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
+static void returnSingleInt(Vdbe *v, i64 value){
sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, 1, 0, (const u8*)&value, P4_INT64);
- setOneColumnName(v, zLabel);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
@@ -107607,12 +112515,10 @@ static void returnSingleInt(Vdbe *v, const char *zLabel, i64 value){
*/
static void returnSingleText(
Vdbe *v, /* Prepared statement under construction */
- const char *zLabel, /* Name of the result column */
const char *zValue /* Value to be returned */
){
if( zValue ){
sqlite3VdbeLoadString(v, 1, (const char*)zValue);
- setOneColumnName(v, zLabel);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
}
@@ -107691,6 +112597,26 @@ SQLITE_PRIVATE const char *sqlite3JournalModename(int eMode){
}
/*
+** Locate a pragma in the aPragmaName[] array.
+*/
+static const PragmaName *pragmaLocate(const char *zName){
+ int upr, lwr, mid, rc;
+ lwr = 0;
+ upr = ArraySize(aPragmaName)-1;
+ while( lwr<=upr ){
+ mid = (lwr+upr)/2;
+ rc = sqlite3_stricmp(zName, aPragmaName[mid].zName);
+ if( rc==0 ) break;
+ if( rc<0 ){
+ upr = mid - 1;
+ }else{
+ lwr = mid + 1;
+ }
+ }
+ return lwr>upr ? 0 : &aPragmaName[mid];
+}
+
+/*
** Process a pragma statement.
**
** Pragmas are of this form:
@@ -107718,12 +112644,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
Token *pId; /* Pointer to <id> token */
char *aFcntl[4]; /* Argument to SQLITE_FCNTL_PRAGMA */
int iDb; /* Database index for <database> */
- int lwr, upr, mid = 0; /* Binary search bounds */
int rc; /* return value form SQLITE_FCNTL_PRAGMA */
sqlite3 *db = pParse->db; /* The database connection */
Db *pDb; /* The specific database being pragmaed */
Vdbe *v = sqlite3GetVdbe(pParse); /* Prepared statement */
- const struct sPragmaNames *pPragma;
+ const PragmaName *pPragma; /* The pragma */
if( v==0 ) return;
sqlite3VdbeRunOnlyOnce(v);
@@ -107751,7 +112676,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
assert( pId2 );
- zDb = pId2->n>0 ? pDb->zName : 0;
+ zDb = pId2->n>0 ? pDb->zDbSName : 0;
if( sqlite3AuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, zDb) ){
goto pragma_out;
}
@@ -107778,7 +112703,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
db->busyHandler.nBusy = 0;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_PRAGMA, (void*)aFcntl);
if( rc==SQLITE_OK ){
- returnSingleText(v, "result", aFcntl[0]);
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, aFcntl[0], SQLITE_TRANSIENT);
+ returnSingleText(v, aFcntl[0]);
sqlite3_free(aFcntl[0]);
goto pragma_out;
}
@@ -107793,26 +112720,19 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
/* Locate the pragma in the lookup table */
- lwr = 0;
- upr = ArraySize(aPragmaNames)-1;
- while( lwr<=upr ){
- mid = (lwr+upr)/2;
- rc = sqlite3_stricmp(zLeft, aPragmaNames[mid].zName);
- if( rc==0 ) break;
- if( rc<0 ){
- upr = mid - 1;
- }else{
- lwr = mid + 1;
- }
- }
- if( lwr>upr ) goto pragma_out;
- pPragma = &aPragmaNames[mid];
+ pPragma = pragmaLocate(zLeft);
+ if( pPragma==0 ) goto pragma_out;
/* Make sure the database schema is loaded if the pragma requires that */
- if( (pPragma->mPragFlag & PragFlag_NeedSchema)!=0 ){
+ if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
}
+ /* Register the result column names for pragmas that return results */
+ if( (pPragma->mPragFlg & PragFlg_NoColumns)==0 ){
+ setPragmaResultColumnNames(v, pPragma);
+ }
+
/* Jump to the appropriate pragma handler */
switch( pPragma->ePragTyp ){
@@ -107849,7 +112769,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
VdbeOp *aOp;
sqlite3VdbeUsesBtree(v, iDb);
if( !zRight ){
- setOneColumnName(v, "cache_size");
pParse->nMem += 2;
sqlite3VdbeVerifyNoMallocRequired(v, ArraySize(getCacheSize));
aOp = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize, iLn);
@@ -107884,7 +112803,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( pBt!=0 );
if( !zRight ){
int size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
- returnSingleInt(v, "page_size", size);
+ returnSingleInt(v, size);
}else{
/* Malloc may fail when setting the page-size, as there is an internal
** buffer that the pager module resizes using sqlite3_realloc().
@@ -107919,7 +112838,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
}
b = sqlite3BtreeSecureDelete(pBt, b);
- returnSingleInt(v, "secure_delete", b);
+ returnSingleInt(v, b);
break;
}
@@ -107951,8 +112870,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3AbsInt32(sqlite3Atoi(zRight)));
}
sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
break;
}
@@ -107998,7 +112915,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
zRet = "exclusive";
}
- returnSingleText(v, "locking_mode", zRet);
+ returnSingleText(v, zRet);
break;
}
@@ -108011,7 +112928,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
int ii; /* Loop counter */
- setOneColumnName(v, "journal_mode");
if( zRight==0 ){
/* If there is no "=MODE" part of the pragma, do a query for the
** current mode */
@@ -108057,7 +112973,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( iLimit<-1 ) iLimit = -1;
}
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
- returnSingleInt(v, "journal_size_limit", iLimit);
+ returnSingleInt(v, iLimit);
break;
}
@@ -108075,7 +112991,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
Btree *pBt = pDb->pBt;
assert( pBt!=0 );
if( !zRight ){
- returnSingleInt(v, "auto_vacuum", sqlite3BtreeGetAutoVacuum(pBt));
+ returnSingleInt(v, sqlite3BtreeGetAutoVacuum(pBt));
}else{
int eAuto = getAutoVacuum(zRight);
assert( eAuto>=0 && eAuto<=2 );
@@ -108154,7 +113070,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_CACHE_SIZE: {
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( !zRight ){
- returnSingleInt(v, "cache_size", pDb->pSchema->cache_size);
+ returnSingleInt(v, pDb->pSchema->cache_size);
}else{
int size = sqlite3Atoi(zRight);
pDb->pSchema->cache_size = size;
@@ -108188,7 +113104,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_CACHE_SPILL: {
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( !zRight ){
- returnSingleInt(v, "cache_spill",
+ returnSingleInt(v,
(db->flags & SQLITE_CacheSpill)==0 ? 0 :
sqlite3BtreeSetSpillSize(pDb->pBt,0));
}else{
@@ -108242,7 +113158,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
rc = SQLITE_OK;
#endif
if( rc==SQLITE_OK ){
- returnSingleInt(v, "mmap_size", sz);
+ returnSingleInt(v, sz);
}else if( rc!=SQLITE_NOTFOUND ){
pParse->nErr++;
pParse->rc = rc;
@@ -108263,7 +113179,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_TEMP_STORE: {
if( !zRight ){
- returnSingleInt(v, "temp_store", db->temp_store);
+ returnSingleInt(v, db->temp_store);
}else{
changeTempStorage(pParse, zRight);
}
@@ -108282,7 +113198,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_TEMP_STORE_DIRECTORY: {
if( !zRight ){
- returnSingleText(v, "temp_store_directory", sqlite3_temp_directory);
+ returnSingleText(v, sqlite3_temp_directory);
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
@@ -108326,7 +113242,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_DATA_STORE_DIRECTORY: {
if( !zRight ){
- returnSingleText(v, "data_store_directory", sqlite3_data_directory);
+ returnSingleText(v, sqlite3_data_directory);
}else{
#ifndef SQLITE_OMIT_WSD
if( zRight[0] ){
@@ -108365,7 +113281,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3_file *pFile = sqlite3PagerFile(pPager);
sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
&proxy_file_path);
- returnSingleText(v, "lock_proxy_file", proxy_file_path);
+ returnSingleText(v, proxy_file_path);
}else{
Pager *pPager = sqlite3BtreePager(pDb->pBt);
sqlite3_file *pFile = sqlite3PagerFile(pPager);
@@ -108397,7 +113313,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_SYNCHRONOUS: {
if( !zRight ){
- returnSingleInt(v, "synchronous", pDb->safety_level-1);
+ returnSingleInt(v, pDb->safety_level-1);
}else{
if( !db->autoCommit ){
sqlite3ErrorMsg(pParse,
@@ -108406,6 +113322,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
if( iLevel==0 ) iLevel = 1;
pDb->safety_level = iLevel;
+ pDb->bSyncSet = 1;
setAllPagerFlags(db);
}
}
@@ -108416,7 +113333,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
case PragTyp_FLAG: {
if( zRight==0 ){
- returnSingleInt(v, pPragma->zName, (db->flags & pPragma->iArg)!=0 );
+ setPragmaResultColumnNames(v, pPragma);
+ returnSingleInt(v, (db->flags & pPragma->iArg)!=0 );
}else{
int mask = pPragma->iArg; /* Mask of bits to set or clear. */
if( db->autoCommit==0 ){
@@ -108442,7 +113360,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** compiler (eg. count_changes). So add an opcode to expire all
** compiled SQL statements after modifying a pragma value.
*/
- sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
+ sqlite3VdbeAddOp0(v, OP_Expire);
setAllPagerFlags(db);
}
break;
@@ -108464,18 +113382,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
- pTab = sqlite3FindTable(db, zRight, zDb);
+ pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
if( pTab ){
- static const char *azCol[] = {
- "cid", "name", "type", "notnull", "dflt_value", "pk"
- };
int i, k;
int nHidden = 0;
Column *pCol;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
pParse->nMem = 6;
sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 6, azCol); assert( 6==ArraySize(azCol) );
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
if( IsHiddenColumn(pCol) ){
@@ -108489,12 +113403,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
}else{
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
}
+ assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN );
sqlite3VdbeMultiLoad(v, 1, "issisi",
i-nHidden,
pCol->zName,
- pCol->zType ? pCol->zType : "",
+ sqlite3ColumnType(pCol,""),
pCol->notNull ? 1 : 0,
- pCol->zDflt,
+ pCol->pDflt ? pCol->pDflt->u.zToken : 0,
k);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
}
@@ -108503,26 +113418,23 @@ SQLITE_PRIVATE void sqlite3Pragma(
break;
case PragTyp_STATS: {
- static const char *azCol[] = { "table", "index", "width", "height" };
Index *pIdx;
HashElem *i;
- v = sqlite3GetVdbe(pParse);
pParse->nMem = 4;
sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i);
sqlite3VdbeMultiLoad(v, 1, "ssii",
pTab->zName,
0,
- (int)sqlite3LogEstToInt(pTab->szTabRow),
- (int)sqlite3LogEstToInt(pTab->nRowLogEst));
+ pTab->szTabRow,
+ pTab->nRowLogEst);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqlite3VdbeMultiLoad(v, 2, "sii",
pIdx->zName,
- (int)sqlite3LogEstToInt(pIdx->szIdxRow),
- (int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]));
+ pIdx->szIdxRow,
+ pIdx->aiRowLogEst[0]);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
}
}
@@ -108534,9 +113446,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
Table *pTab;
pIdx = sqlite3FindIndex(db, zRight, zDb);
if( pIdx ){
- static const char *azCol[] = {
- "seqno", "cid", "name", "desc", "coll", "key"
- };
int i;
int mx;
if( pPragma->iArg ){
@@ -108550,8 +113459,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
pTab = pIdx->pTable;
sqlite3CodeVerifySchema(pParse, iDb);
- assert( pParse->nMem<=ArraySize(azCol) );
- setAllColumnNames(v, pParse->nMem, azCol);
+ assert( pParse->nMem<=pPragma->nPragCName );
for(i=0; i<mx; i++){
i16 cnum = pIdx->aiColumn[i];
sqlite3VdbeMultiLoad(v, 1, "iis", i, cnum,
@@ -108574,13 +113482,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
int i;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
- static const char *azCol[] = {
- "seq", "name", "unique", "origin", "partial"
- };
- v = sqlite3GetVdbe(pParse);
pParse->nMem = 5;
sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 5, azCol); assert( 5==ArraySize(azCol) );
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
const char *azOrigin[] = { "c", "u", "pk" };
sqlite3VdbeMultiLoad(v, 1, "isisi",
@@ -108596,16 +113499,14 @@ SQLITE_PRIVATE void sqlite3Pragma(
break;
case PragTyp_DATABASE_LIST: {
- static const char *azCol[] = { "seq", "name", "file" };
int i;
pParse->nMem = 3;
- setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ) continue;
- assert( db->aDb[i].zName!=0 );
+ assert( db->aDb[i].zDbSName!=0 );
sqlite3VdbeMultiLoad(v, 1, "iss",
i,
- db->aDb[i].zName,
+ db->aDb[i].zDbSName,
sqlite3BtreeGetFilename(db->aDb[i].pBt));
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
}
@@ -108613,11 +113514,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
break;
case PragTyp_COLLATION_LIST: {
- static const char *azCol[] = { "seq", "name" };
int i = 0;
HashElem *p;
pParse->nMem = 2;
- setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){
CollSeq *pColl = (CollSeq *)sqliteHashData(p);
sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName);
@@ -108633,17 +113532,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
Table *pTab;
pTab = sqlite3FindTable(db, zRight, zDb);
if( pTab ){
- v = sqlite3GetVdbe(pParse);
pFK = pTab->pFKey;
if( pFK ){
- static const char *azCol[] = {
- "id", "seq", "table", "from", "to", "on_update", "on_delete",
- "match"
- };
int i = 0;
pParse->nMem = 8;
sqlite3CodeVerifySchema(pParse, iDb);
- setAllColumnNames(v, 8, azCol); assert( 8==ArraySize(azCol) );
while(pFK){
int j;
for(j=0; j<pFK->nCol; j++){
@@ -108684,14 +113577,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
int addrTop; /* Top of a loop checking foreign keys */
int addrOk; /* Jump here if the key is OK */
int *aiCols; /* child to parent column mapping */
- static const char *azCol[] = { "table", "rowid", "parent", "fkid" };
regResult = pParse->nMem+1;
pParse->nMem += 4;
regKey = ++pParse->nMem;
regRow = ++pParse->nMem;
- v = sqlite3GetVdbe(pParse);
- setAllColumnNames(v, 4, azCol); assert( 4==ArraySize(azCol) );
sqlite3CodeVerifySchema(pParse, iDb);
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
while( k ){
@@ -108745,12 +113635,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow);
sqlite3ColumnDefault(v, pTab, iKey, regRow);
sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow,
- sqlite3VdbeCurrentAddr(v)+3); VdbeCoverage(v);
}else{
sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
}
- sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); VdbeCoverage(v);
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v);
sqlite3VdbeGoto(v, addrOk);
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
}else{
@@ -108832,7 +113720,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Initialize the VDBE program */
pParse->nMem = 6;
- setOneColumnName(v, "integrity_check");
/* Set the maximum error count */
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
@@ -108848,7 +113735,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
for(i=0; i<db->nDb; i++){
HashElem *x;
Hash *pTbls;
+ int *aRoot;
int cnt = 0;
+ int mxIdx = 0;
+ int nIdx;
if( OMIT_TEMPDB && i==1 ) continue;
if( iDb>=0 && i!=iDb ) continue;
@@ -108861,35 +113751,39 @@ SQLITE_PRIVATE void sqlite3Pragma(
/* Do an integrity check of the B-Tree
**
- ** Begin by filling registers 2, 3, ... with the root pages numbers
+ ** Begin by finding the root pages numbers
** for all tables and indices in the database.
*/
assert( sqlite3SchemaMutexHeld(db, i, 0) );
pTbls = &db->aDb[i].pSchema->tblHash;
- for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
- if( HasRowid(pTab) ){
- sqlite3VdbeAddOp2(v, OP_Integer, pTab->tnum, 2+cnt);
- VdbeComment((v, "%s", pTab->zName));
- cnt++;
- }
+ if( HasRowid(pTab) ) cnt++;
+ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
+ if( nIdx>mxIdx ) mxIdx = nIdx;
+ }
+ aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
+ if( aRoot==0 ) break;
+ for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ Table *pTab = sqliteHashData(x);
+ Index *pIdx;
+ if( HasRowid(pTab) ) aRoot[cnt++] = pTab->tnum;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3VdbeAddOp2(v, OP_Integer, pIdx->tnum, 2+cnt);
- VdbeComment((v, "%s", pIdx->zName));
- cnt++;
+ aRoot[cnt++] = pIdx->tnum;
}
}
+ aRoot[cnt] = 0;
/* Make sure sufficient number of registers have been allocated */
- pParse->nMem = MAX( pParse->nMem, cnt+8 );
+ pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
/* Do the b-tree integrity checks */
- sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
+ sqlite3VdbeAddOp4(v, OP_IntegrityCk, 2, cnt, 1, (char*)aRoot,P4_INTARRAY);
sqlite3VdbeChangeP5(v, (u8)i);
addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
- sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
+ sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zDbSName),
P4_DYNAMIC);
sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
@@ -108919,7 +113813,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
}
- pParse->nMem = MAX(pParse->nMem, 8+j);
+ assert( pParse->nMem>=8+j );
+ assert( sqlite3NoTempsInRange(pParse,1,7+j) );
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
/* Verify that all NOT NULL columns really are NOT NULL */
@@ -109076,7 +113971,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
assert( encnames[SQLITE_UTF8].enc==SQLITE_UTF8 );
assert( encnames[SQLITE_UTF16LE].enc==SQLITE_UTF16LE );
assert( encnames[SQLITE_UTF16BE].enc==SQLITE_UTF16BE );
- returnSingleText(v, "encoding", encnames[ENC(pParse->db)].zName);
+ returnSingleText(v, encnames[ENC(pParse->db)].zName);
}else{ /* "PRAGMA encoding = XXX" */
/* Only change the value of sqlite.enc if the database handle is not
** initialized. If the main database exists, the new sqlite.enc value
@@ -109111,7 +114006,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
** PRAGMA [schema.]user_version
** PRAGMA [schema.]user_version = <integer>
**
- ** PRAGMA [schema.]freelist_count = <integer>
+ ** PRAGMA [schema.]freelist_count
+ **
+ ** PRAGMA [schema.]data_version
**
** PRAGMA [schema.]application_id
** PRAGMA [schema.]application_id = <integer>
@@ -109137,7 +114034,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
case PragTyp_HEADER_VALUE: {
int iCookie = pPragma->iArg; /* Which cookie to read or write */
sqlite3VdbeUsesBtree(v, iDb);
- if( zRight && (pPragma->mPragFlag & PragFlag_ReadOnly)==0 ){
+ if( zRight && (pPragma->mPragFlg & PragFlg_ReadOnly)==0 ){
/* Write the specified cookie value */
static const VdbeOpList setCookie[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
@@ -109165,8 +114062,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
aOp[0].p1 = iDb;
aOp[1].p1 = iDb;
aOp[1].p3 = iCookie;
- sqlite3VdbeSetNumCols(v, 1);
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
+ sqlite3VdbeReusable(v);
}
}
break;
@@ -109183,11 +114079,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
int i = 0;
const char *zOpt;
pParse->nMem = 1;
- setOneColumnName(v, "compile_option");
while( (zOpt = sqlite3_compileoption_get(i++))!=0 ){
sqlite3VdbeLoadString(v, 1, zOpt);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}
+ sqlite3VdbeReusable(v);
}
break;
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
@@ -109199,7 +114095,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
** Checkpoint the database.
*/
case PragTyp_WAL_CHECKPOINT: {
- static const char *azCol[] = { "busy", "log", "checkpointed" };
int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
int eMode = SQLITE_CHECKPOINT_PASSIVE;
if( zRight ){
@@ -109211,7 +114106,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
eMode = SQLITE_CHECKPOINT_TRUNCATE;
}
}
- setAllColumnNames(v, 3, azCol); assert( 3==ArraySize(azCol) );
pParse->nMem = 3;
sqlite3VdbeAddOp3(v, OP_Checkpoint, iBt, eMode, 1);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
@@ -109230,7 +114124,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( zRight ){
sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
}
- returnSingleInt(v, "wal_autocheckpoint",
+ returnSingleInt(v,
db->xWalCallback==sqlite3WalDefaultHook ?
SQLITE_PTR_TO_INT(db->pWalArg) : 0);
}
@@ -109263,7 +114157,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( zRight ){
sqlite3_busy_timeout(db, sqlite3Atoi(zRight));
}
- returnSingleInt(v, "timeout", db->busyTimeout);
+ returnSingleInt(v, db->busyTimeout);
break;
}
@@ -109283,7 +114177,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){
sqlite3_soft_heap_limit64(N);
}
- returnSingleInt(v, "soft_heap_limit", sqlite3_soft_heap_limit64(-1));
+ returnSingleInt(v, sqlite3_soft_heap_limit64(-1));
break;
}
@@ -109302,8 +114196,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
){
sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, (int)(N&0x7fffffff));
}
- returnSingleInt(v, "threads",
- sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
+ returnSingleInt(v, sqlite3_limit(db, SQLITE_LIMIT_WORKER_THREADS, -1));
break;
}
@@ -109315,23 +114208,21 @@ SQLITE_PRIVATE void sqlite3Pragma(
static const char *const azLockName[] = {
"unlocked", "shared", "reserved", "pending", "exclusive"
};
- static const char *azCol[] = { "database", "status" };
int i;
- setAllColumnNames(v, 2, azCol); assert( 2==ArraySize(azCol) );
pParse->nMem = 2;
for(i=0; i<db->nDb; i++){
Btree *pBt;
const char *zState = "unknown";
int j;
- if( db->aDb[i].zName==0 ) continue;
+ if( db->aDb[i].zDbSName==0 ) continue;
pBt = db->aDb[i].pBt;
if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
zState = "closed";
- }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0,
+ }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0,
SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
zState = azLockName[j];
}
- sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zName, zState);
+ sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
}
break;
@@ -109387,6 +114278,312 @@ pragma_out:
sqlite3DbFree(db, zLeft);
sqlite3DbFree(db, zRight);
}
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+/*****************************************************************************
+** Implementation of an eponymous virtual table that runs a pragma.
+**
+*/
+typedef struct PragmaVtab PragmaVtab;
+typedef struct PragmaVtabCursor PragmaVtabCursor;
+struct PragmaVtab {
+ sqlite3_vtab base; /* Base class. Must be first */
+ sqlite3 *db; /* The database connection to which it belongs */
+ const PragmaName *pName; /* Name of the pragma */
+ u8 nHidden; /* Number of hidden columns */
+ u8 iHidden; /* Index of the first hidden column */
+};
+struct PragmaVtabCursor {
+ sqlite3_vtab_cursor base; /* Base class. Must be first */
+ sqlite3_stmt *pPragma; /* The pragma statement to run */
+ sqlite_int64 iRowid; /* Current rowid */
+ char *azArg[2]; /* Value of the argument and schema */
+};
+
+/*
+** Pragma virtual table module xConnect method.
+*/
+static int pragmaVtabConnect(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ const PragmaName *pPragma = (const PragmaName*)pAux;
+ PragmaVtab *pTab = 0;
+ int rc;
+ int i, j;
+ char cSep = '(';
+ StrAccum acc;
+ char zBuf[200];
+
+ UNUSED_PARAMETER(argc);
+ UNUSED_PARAMETER(argv);
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
+ sqlite3StrAccumAppendAll(&acc, "CREATE TABLE x");
+ for(i=0, j=pPragma->iPragCName; i<pPragma->nPragCName; i++, j++){
+ sqlite3XPrintf(&acc, "%c\"%s\"", cSep, pragCName[j]);
+ cSep = ',';
+ }
+ if( i==0 ){
+ sqlite3XPrintf(&acc, "(\"%s\"", pPragma->zName);
+ cSep = ',';
+ i++;
+ }
+ j = 0;
+ if( pPragma->mPragFlg & PragFlg_Result1 ){
+ sqlite3StrAccumAppendAll(&acc, ",arg HIDDEN");
+ j++;
+ }
+ if( pPragma->mPragFlg & (PragFlg_SchemaOpt|PragFlg_SchemaReq) ){
+ sqlite3StrAccumAppendAll(&acc, ",schema HIDDEN");
+ j++;
+ }
+ sqlite3StrAccumAppend(&acc, ")", 1);
+ sqlite3StrAccumFinish(&acc);
+ assert( strlen(zBuf) < sizeof(zBuf)-1 );
+ rc = sqlite3_declare_vtab(db, zBuf);
+ if( rc==SQLITE_OK ){
+ pTab = (PragmaVtab*)sqlite3_malloc(sizeof(PragmaVtab));
+ if( pTab==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pTab, 0, sizeof(PragmaVtab));
+ pTab->pName = pPragma;
+ pTab->db = db;
+ pTab->iHidden = i;
+ pTab->nHidden = j;
+ }
+ }else{
+ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }
+
+ *ppVtab = (sqlite3_vtab*)pTab;
+ return rc;
+}
+
+/*
+** Pragma virtual table module xDisconnect method.
+*/
+static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){
+ PragmaVtab *pTab = (PragmaVtab*)pVtab;
+ sqlite3_free(pTab);
+ return SQLITE_OK;
+}
+
+/* Figure out the best index to use to search a pragma virtual table.
+**
+** There are not really any index choices. But we want to encourage the
+** query planner to give == constraints on as many hidden parameters as
+** possible, and especially on the first hidden parameter. So return a
+** high cost if hidden parameters are unconstrained.
+*/
+static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+ PragmaVtab *pTab = (PragmaVtab*)tab;
+ const struct sqlite3_index_constraint *pConstraint;
+ int i, j;
+ int seen[2];
+
+ pIdxInfo->estimatedCost = (double)1;
+ if( pTab->nHidden==0 ){ return SQLITE_OK; }
+ pConstraint = pIdxInfo->aConstraint;
+ seen[0] = 0;
+ seen[1] = 0;
+ for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
+ if( pConstraint->usable==0 ) continue;
+ if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
+ if( pConstraint->iColumn < pTab->iHidden ) continue;
+ j = pConstraint->iColumn - pTab->iHidden;
+ assert( j < 2 );
+ seen[j] = i+1;
+ }
+ if( seen[0]==0 ){
+ pIdxInfo->estimatedCost = (double)2147483647;
+ pIdxInfo->estimatedRows = 2147483647;
+ return SQLITE_OK;
+ }
+ j = seen[0]-1;
+ pIdxInfo->aConstraintUsage[j].argvIndex = 1;
+ pIdxInfo->aConstraintUsage[j].omit = 1;
+ if( seen[1]==0 ) return SQLITE_OK;
+ pIdxInfo->estimatedCost = (double)20;
+ pIdxInfo->estimatedRows = 20;
+ j = seen[1]-1;
+ pIdxInfo->aConstraintUsage[j].argvIndex = 2;
+ pIdxInfo->aConstraintUsage[j].omit = 1;
+ return SQLITE_OK;
+}
+
+/* Create a new cursor for the pragma virtual table */
+static int pragmaVtabOpen(sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppCursor){
+ PragmaVtabCursor *pCsr;
+ pCsr = (PragmaVtabCursor*)sqlite3_malloc(sizeof(*pCsr));
+ if( pCsr==0 ) return SQLITE_NOMEM;
+ memset(pCsr, 0, sizeof(PragmaVtabCursor));
+ pCsr->base.pVtab = pVtab;
+ *ppCursor = &pCsr->base;
+ return SQLITE_OK;
+}
+
+/* Clear all content from pragma virtual table cursor. */
+static void pragmaVtabCursorClear(PragmaVtabCursor *pCsr){
+ int i;
+ sqlite3_finalize(pCsr->pPragma);
+ pCsr->pPragma = 0;
+ for(i=0; i<ArraySize(pCsr->azArg); i++){
+ sqlite3_free(pCsr->azArg[i]);
+ pCsr->azArg[i] = 0;
+ }
+}
+
+/* Close a pragma virtual table cursor */
+static int pragmaVtabClose(sqlite3_vtab_cursor *cur){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)cur;
+ pragmaVtabCursorClear(pCsr);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+/* Advance the pragma virtual table cursor to the next row */
+static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ int rc = SQLITE_OK;
+
+ /* Increment the xRowid value */
+ pCsr->iRowid++;
+ assert( pCsr->pPragma );
+ if( SQLITE_ROW!=sqlite3_step(pCsr->pPragma) ){
+ rc = sqlite3_finalize(pCsr->pPragma);
+ pCsr->pPragma = 0;
+ pragmaVtabCursorClear(pCsr);
+ }
+ return rc;
+}
+
+/*
+** Pragma virtual table module xFilter method.
+*/
+static int pragmaVtabFilter(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
+ int rc;
+ int i, j;
+ StrAccum acc;
+ char *zSql;
+
+ UNUSED_PARAMETER(idxNum);
+ UNUSED_PARAMETER(idxStr);
+ pragmaVtabCursorClear(pCsr);
+ j = (pTab->pName->mPragFlg & PragFlg_Result1)!=0 ? 0 : 1;
+ for(i=0; i<argc; i++, j++){
+ assert( j<ArraySize(pCsr->azArg) );
+ pCsr->azArg[j] = sqlite3_mprintf("%s", sqlite3_value_text(argv[i]));
+ if( pCsr->azArg[j]==0 ){
+ return SQLITE_NOMEM;
+ }
+ }
+ sqlite3StrAccumInit(&acc, 0, 0, 0, pTab->db->aLimit[SQLITE_LIMIT_SQL_LENGTH]);
+ sqlite3StrAccumAppendAll(&acc, "PRAGMA ");
+ if( pCsr->azArg[1] ){
+ sqlite3XPrintf(&acc, "%Q.", pCsr->azArg[1]);
+ }
+ sqlite3StrAccumAppendAll(&acc, pTab->pName->zName);
+ if( pCsr->azArg[0] ){
+ sqlite3XPrintf(&acc, "=%Q", pCsr->azArg[0]);
+ }
+ zSql = sqlite3StrAccumFinish(&acc);
+ if( zSql==0 ) return SQLITE_NOMEM;
+ rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pPragma, 0);
+ sqlite3_free(zSql);
+ if( rc!=SQLITE_OK ){
+ pTab->base.zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
+ return rc;
+ }
+ return pragmaVtabNext(pVtabCursor);
+}
+
+/*
+** Pragma virtual table module xEof method.
+*/
+static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ return (pCsr->pPragma==0);
+}
+
+/* The xColumn method simply returns the corresponding column from
+** the PRAGMA.
+*/
+static int pragmaVtabColumn(
+ sqlite3_vtab_cursor *pVtabCursor,
+ sqlite3_context *ctx,
+ int i
+){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ PragmaVtab *pTab = (PragmaVtab*)(pVtabCursor->pVtab);
+ if( i<pTab->iHidden ){
+ sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pPragma, i));
+ }else{
+ sqlite3_result_text(ctx, pCsr->azArg[i-pTab->iHidden],-1,SQLITE_TRANSIENT);
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Pragma virtual table module xRowid method.
+*/
+static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){
+ PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
+ *p = pCsr->iRowid;
+ return SQLITE_OK;
+}
+
+/* The pragma virtual table object */
+static const sqlite3_module pragmaVtabModule = {
+ 0, /* iVersion */
+ 0, /* xCreate - create a table */
+ pragmaVtabConnect, /* xConnect - connect to an existing table */
+ pragmaVtabBestIndex, /* xBestIndex - Determine search strategy */
+ pragmaVtabDisconnect, /* xDisconnect - Disconnect from a table */
+ 0, /* xDestroy - Drop a table */
+ pragmaVtabOpen, /* xOpen - open a cursor */
+ pragmaVtabClose, /* xClose - close a cursor */
+ pragmaVtabFilter, /* xFilter - configure scan constraints */
+ pragmaVtabNext, /* xNext - advance a cursor */
+ pragmaVtabEof, /* xEof */
+ pragmaVtabColumn, /* xColumn - read data */
+ pragmaVtabRowid, /* xRowid - read data */
+ 0, /* xUpdate - write data */
+ 0, /* xBegin - begin transaction */
+ 0, /* xSync - sync transaction */
+ 0, /* xCommit - commit transaction */
+ 0, /* xRollback - rollback transaction */
+ 0, /* xFindFunction - function overloading */
+ 0, /* xRename - rename the table */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0 /* xRollbackTo */
+};
+
+/*
+** Check to see if zTabName is really the name of a pragma. If it is,
+** then register an eponymous virtual table for that pragma and return
+** a pointer to the Module object for the new virtual table.
+*/
+SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName){
+ const PragmaName *pName;
+ assert( sqlite3_strnicmp(zName, "pragma_", 7)==0 );
+ pName = pragmaLocate(zName+7);
+ if( pName==0 ) return 0;
+ if( (pName->mPragFlg & (PragFlg_Result0|PragFlg_Result1))==0 ) return 0;
+ assert( sqlite3HashFind(&db->aModule, zName)==0 );
+ return sqlite3VtabCreateModule(db, zName, &pragmaVtabModule, (void*)pName, 0);
+}
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
#endif /* SQLITE_OMIT_PRAGMA */
@@ -109427,7 +114624,7 @@ static void corruptSchema(
sqlite3DbFree(db, *pData->pzErrMsg);
*pData->pzErrMsg = z;
}
- pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT;
+ pData->rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_CORRUPT_BKPT;
}
/*
@@ -109467,6 +114664,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
** structures that describe the table, index, or view.
*/
int rc;
+ u8 saved_iDb = db->init.iDb;
sqlite3_stmt *pStmt;
TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
@@ -109477,7 +114675,8 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
rc = db->errCode;
assert( (rc&0xFF)==(rcp&0xFF) );
- db->init.iDb = 0;
+ db->init.iDb = saved_iDb;
+ assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 );
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
@@ -109501,7 +114700,7 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
** to do here is record the root page number for that index.
*/
Index *pIndex;
- pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zName);
+ pIndex = sqlite3FindIndex(db, argv[0], db->aDb[iDb].zDbSName);
if( pIndex==0 ){
/* This can occur if there exists an index on a TEMP table which
** has the same name as another index on a permanent index. Since
@@ -109680,7 +114879,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
char *zSql;
zSql = sqlite3MPrintf(db,
"SELECT name, rootpage, sql FROM \"%w\".%s ORDER BY rowid",
- db->aDb[iDb].zName, zMasterName);
+ db->aDb[iDb].zDbSName, zMasterName);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
sqlite3_xauth xAuth;
@@ -109701,7 +114900,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
#endif
}
if( db->mallocFailed ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
sqlite3ResetAllSchemasOfConnection(db);
}
if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
@@ -109910,18 +115109,14 @@ static int sqlite3Prepare(
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
- Parse *pParse; /* Parsing context */
char *zErrMsg = 0; /* Error message */
int rc = SQLITE_OK; /* Result code */
int i; /* Loop counter */
+ Parse sParse; /* Parsing context */
- /* Allocate the parsing context */
- pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
- if( pParse==0 ){
- rc = SQLITE_NOMEM;
- goto end_prepare;
- }
- pParse->pReprepare = pReprepare;
+ memset(&sParse, 0, PARSE_HDR_SZ);
+ memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ);
+ sParse.pReprepare = pReprepare;
assert( ppStmt && *ppStmt==0 );
/* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
assert( sqlite3_mutex_held(db->mutex) );
@@ -109955,7 +115150,7 @@ static int sqlite3Prepare(
assert( sqlite3BtreeHoldsMutex(pBt) );
rc = sqlite3BtreeSchemaLocked(pBt);
if( rc ){
- const char *zDb = db->aDb[i].zName;
+ const char *zDb = db->aDb[i].zDbSName;
sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
testcase( db->flags & SQLITE_ReadUncommitted );
goto end_prepare;
@@ -109965,8 +115160,7 @@ static int sqlite3Prepare(
sqlite3VtabUnlockList(db);
- pParse->db = db;
- pParse->nQueryLoop = 0; /* Logarithmic, so 0 really means 1 */
+ sParse.db = db;
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
@@ -109979,61 +115173,61 @@ static int sqlite3Prepare(
}
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
if( zSqlCopy ){
- sqlite3RunParser(pParse, zSqlCopy, &zErrMsg);
- pParse->zTail = &zSql[pParse->zTail-zSqlCopy];
+ sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
+ sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
sqlite3DbFree(db, zSqlCopy);
}else{
- pParse->zTail = &zSql[nBytes];
+ sParse.zTail = &zSql[nBytes];
}
}else{
- sqlite3RunParser(pParse, zSql, &zErrMsg);
+ sqlite3RunParser(&sParse, zSql, &zErrMsg);
}
- assert( 0==pParse->nQueryLoop );
+ assert( 0==sParse.nQueryLoop );
- if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;
- if( pParse->checkSchema ){
- schemaIsValid(pParse);
+ if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
+ if( sParse.checkSchema ){
+ schemaIsValid(&sParse);
}
if( db->mallocFailed ){
- pParse->rc = SQLITE_NOMEM;
+ sParse.rc = SQLITE_NOMEM_BKPT;
}
if( pzTail ){
- *pzTail = pParse->zTail;
+ *pzTail = sParse.zTail;
}
- rc = pParse->rc;
+ rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN
- if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
+ if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
"selectid", "order", "from", "detail"
};
int iFirst, mx;
- if( pParse->explain==2 ){
- sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
+ if( sParse.explain==2 ){
+ sqlite3VdbeSetNumCols(sParse.pVdbe, 4);
iFirst = 8;
mx = 12;
}else{
- sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
+ sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
iFirst = 0;
mx = 8;
}
for(i=iFirst; i<mx; i++){
- sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME,
+ sqlite3VdbeSetColName(sParse.pVdbe, i-iFirst, COLNAME_NAME,
azColName[i], SQLITE_STATIC);
}
}
#endif
if( db->init.busy==0 ){
- Vdbe *pVdbe = pParse->pVdbe;
- sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);
+ Vdbe *pVdbe = sParse.pVdbe;
+ sqlite3VdbeSetSql(pVdbe, zSql, (int)(sParse.zTail-zSql), saveSqlFlag);
}
- if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
- sqlite3VdbeFinalize(pParse->pVdbe);
+ if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
+ sqlite3VdbeFinalize(sParse.pVdbe);
assert(!(*ppStmt));
}else{
- *ppStmt = (sqlite3_stmt*)pParse->pVdbe;
+ *ppStmt = (sqlite3_stmt*)sParse.pVdbe;
}
if( zErrMsg ){
@@ -110044,16 +115238,15 @@ static int sqlite3Prepare(
}
/* Delete any TriggerPrg structures allocated while parsing this statement. */
- while( pParse->pTriggerPrg ){
- TriggerPrg *pT = pParse->pTriggerPrg;
- pParse->pTriggerPrg = pT->pNext;
+ while( sParse.pTriggerPrg ){
+ TriggerPrg *pT = sParse.pTriggerPrg;
+ sParse.pTriggerPrg = pT->pNext;
sqlite3DbFree(db, pT);
}
end_prepare:
- sqlite3ParserReset(pParse);
- sqlite3StackFree(db, pParse);
+ sqlite3ParserReset(&sParse);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
return rc;
@@ -110134,7 +115327,7 @@ SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
** and the statement is automatically recompiled if an schema change
** occurs.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
+SQLITE_API int sqlite3_prepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -110146,7 +115339,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
+SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -110222,7 +115415,7 @@ static int sqlite3Prepare16(
** and the statement is automatically recompiled if an schema change
** occurs.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
+SQLITE_API int sqlite3_prepare16(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -110234,7 +115427,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
+SQLITE_API int sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-16 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
@@ -110309,6 +115502,7 @@ struct SortCtx {
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
int labelDone; /* Jump here when done, ex: LIMIT reached */
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
+ u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
};
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
@@ -110327,7 +115521,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
sqlite3ExprListDelete(db, p->pOrderBy);
sqlite3ExprDelete(db, p->pLimit);
sqlite3ExprDelete(db, p->pOffset);
- sqlite3WithDelete(db, p->pWith);
+ if( p->pWith ) sqlite3WithDelete(db, p->pWith);
if( bFree ) sqlite3DbFree(db, p);
p = pPrior;
bFree = 1;
@@ -110340,7 +115534,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
pDest->eDest = (u8)eDest;
pDest->iSDParm = iParm;
- pDest->affSdst = 0;
+ pDest->zAffSdst = 0;
pDest->iSdst = 0;
pDest->nSdst = 0;
}
@@ -110358,7 +115552,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
ExprList *pGroupBy, /* the GROUP BY clause */
Expr *pHaving, /* the HAVING clause */
ExprList *pOrderBy, /* the ORDER BY clause */
- u16 selFlags, /* Flag parameters, such as SF_Distinct */
+ u32 selFlags, /* Flag parameters, such as SF_Distinct */
Expr *pLimit, /* LIMIT value. NULL means not used */
Expr *pOffset /* OFFSET value. NULL means no offset */
){
@@ -110422,7 +115616,7 @@ SQLITE_PRIVATE void sqlite3SelectSetName(Select *p, const char *zName){
** Delete the given Select structure and all of its substructures.
*/
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
- clearSelect(db, p, 1);
+ if( p ) clearSelect(db, p, 1);
}
/*
@@ -110586,7 +115780,7 @@ static void addWhereTerm(
pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);
- pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0);
+ pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);
if( pEq && isOuterJoin ){
ExprSetProperty(pEq, EP_FromJoin);
assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
@@ -110773,7 +115967,7 @@ static void pushOntoSorter(
int iLimit; /* LIMIT counter */
assert( bSeq==0 || bSeq==1 );
- assert( nData==1 || regData==regOrigData );
+ assert( nData==1 || regData==regOrigData || regOrigData==0 );
if( nPrefixReg ){
assert( nPrefixReg==nExpr+bSeq );
regBase = regData - nExpr - bSeq;
@@ -110785,11 +115979,11 @@ static void pushOntoSorter(
iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
pSort->labelDone = sqlite3VdbeMakeLabel(v);
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
- SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
+ SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0));
if( bSeq ){
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
}
- if( nPrefixReg==0 ){
+ if( nPrefixReg==0 && nData>0 ){
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
@@ -110839,12 +116033,34 @@ static void pushOntoSorter(
}else{
op = OP_IdxInsert;
}
- sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
+ sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord,
+ regBase+nOBSat, nBase-nOBSat);
if( iLimit ){
int addr;
- addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
+ int r1 = 0;
+ /* Fill the sorter until it contains LIMIT+OFFSET entries. (The iLimit
+ ** register is initialized with value of LIMIT+OFFSET.) After the sorter
+ ** fills up, delete the least entry in the sorter after each insert.
+ ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */
+ addr = sqlite3VdbeAddOp1(v, OP_IfNotZero, iLimit); VdbeCoverage(v);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
+ if( pSort->bOrderedInnerLoop ){
+ r1 = ++pParse->nMem;
+ sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1);
+ VdbeComment((v, "seq"));
+ }
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
+ if( pSort->bOrderedInnerLoop ){
+ /* If the inner loop is driven by an index such that values from
+ ** the same iteration of the inner loop are in sorted order, then
+ ** immediately jump to the next iteration of an inner loop if the
+ ** entry from the current iteration does not fit into the top
+ ** LIMIT+OFFSET entries of the sorter. */
+ int iBrk = sqlite3VdbeCurrentAddr(v) + 2;
+ sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1);
+ sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
+ VdbeCoverage(v);
+ }
sqlite3VdbeJumpHere(v, addr);
}
}
@@ -110886,34 +116102,10 @@ static void codeDistinct(
r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N);
sqlite3ReleaseTempReg(pParse, r1);
}
-#ifndef SQLITE_OMIT_SUBQUERY
-/*
-** Generate an error message when a SELECT is used within a subexpression
-** (example: "a IN (SELECT * FROM table)") but it has more than 1 result
-** column. We do this in a subroutine because the error used to occur
-** in multiple places. (The error only occurs in one place now, but we
-** retain the subroutine to minimize code disruption.)
-*/
-static int checkForMultiColumnSelectError(
- Parse *pParse, /* Parse context. */
- SelectDest *pDest, /* Destination of SELECT results */
- int nExpr /* Number of result columns returned by SELECT */
-){
- int eDest = pDest->eDest;
- if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){
- sqlite3ErrorMsg(pParse, "only a single result allowed for "
- "a SELECT that is part of an expression");
- return 1;
- }else{
- return 0;
- }
-}
-#endif
-
/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
@@ -110921,7 +116113,7 @@ static int checkForMultiColumnSelectError(
** If srcTab is negative, then the pEList expressions
** are evaluated in order to get the data for this row. If srcTab is
** zero or more, then data is pulled from srcTab and pEList is used only
-** to get number columns and the datatype for each column.
+** to get the number of columns and the collation sequence for each column.
*/
static void selectInnerLoop(
Parse *pParse, /* The parser context */
@@ -110936,13 +116128,20 @@ static void selectInnerLoop(
){
Vdbe *v = pParse->pVdbe;
int i;
- int hasDistinct; /* True if the DISTINCT keyword is present */
- int regResult; /* Start of memory holding result set */
+ int hasDistinct; /* True if the DISTINCT keyword is present */
int eDest = pDest->eDest; /* How to dispose of results */
int iParm = pDest->iSDParm; /* First argument to disposal method */
int nResultCol; /* Number of result columns */
int nPrefixReg = 0; /* Number of extra registers before regResult */
+ /* Usually, regResult is the first cell in an array of memory cells
+ ** containing the current result row. In this case regOrig is set to the
+ ** same value. However, if the results are being sent to the sorter, the
+ ** values for any expressions that are also part of the sort-key are omitted
+ ** from this array. In this case regOrig is set to zero. */
+ int regResult; /* Start of memory holding current results */
+ int regOrig; /* Start of memory holding full result (or 0) */
+
assert( v );
assert( pEList!=0 );
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
@@ -110973,7 +116172,7 @@ static void selectInnerLoop(
pParse->nMem += nResultCol;
}
pDest->nSdst = nResultCol;
- regResult = pDest->iSdst;
+ regOrig = regResult = pDest->iSdst;
if( srcTab>=0 ){
for(i=0; i<nResultCol; i++){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
@@ -110989,7 +116188,26 @@ static void selectInnerLoop(
}else{
ecelFlags = 0;
}
- sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags);
+ assert( eDest!=SRT_Table || pSort==0 );
+ if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab ){
+ /* For each expression in pEList that is a copy of an expression in
+ ** the ORDER BY clause (pSort->pOrderBy), set the associated
+ ** iOrderByCol value to one more than the index of the ORDER BY
+ ** expression within the sort-key that pushOntoSorter() will generate.
+ ** This allows the pEList field to be omitted from the sorted record,
+ ** saving space and CPU cycles. */
+ ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF);
+ for(i=pSort->nOBSat; i<pSort->pOrderBy->nExpr; i++){
+ int j;
+ if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){
+ pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
+ }
+ }
+ regOrig = 0;
+ assert( eDest==SRT_Set || eDest==SRT_Mem
+ || eDest==SRT_Coroutine || eDest==SRT_Output );
+ }
+ nResultCol = sqlite3ExprCodeExprList(pParse,pEList,regResult,0,ecelFlags);
}
/* If the DISTINCT keyword was present on the SELECT statement
@@ -111063,7 +116281,7 @@ static void selectInnerLoop(
int r1;
r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
sqlite3ReleaseTempReg(pParse, r1);
break;
}
@@ -111100,7 +116318,7 @@ static void selectInnerLoop(
int addr = sqlite3VdbeCurrentAddr(v) + 4;
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0);
VdbeCoverage(v);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1,regResult,nResultCol);
assert( pSort==0 );
}
#endif
@@ -111123,20 +116341,20 @@ static void selectInnerLoop(
** item into the set table with bogus data.
*/
case SRT_Set: {
- assert( nResultCol==1 );
- pDest->affSdst =
- sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
if( pSort ){
/* At first glance you would think we could optimize out the
** ORDER BY in this case since the order of entries in the set
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
- pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
+ pushOntoSorter(
+ pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
}else{
int r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
- sqlite3ExprCacheAffinityChange(pParse, regResult, 1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
+ assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
+ r1, pDest->zAffSdst, nResultCol);
+ sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
sqlite3ReleaseTempReg(pParse, r1);
}
break;
@@ -111151,14 +116369,16 @@ static void selectInnerLoop(
}
/* If this is a scalar select that is part of an expression, then
- ** store the results in the appropriate memory cell and break out
- ** of the scan loop.
+ ** store the results in the appropriate memory cell or array of
+ ** memory cells and break out of the scan loop.
*/
case SRT_Mem: {
- assert( nResultCol==1 );
if( pSort ){
- pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg);
+ assert( nResultCol<=pDest->nSdst );
+ pushOntoSorter(
+ pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
}else{
+ assert( nResultCol==pDest->nSdst );
assert( regResult==iParm );
/* The LIMIT clause will jump out of the loop for us */
}
@@ -111171,7 +116391,7 @@ static void selectInnerLoop(
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pSort ){
- pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol,
+ pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol,
nPrefixReg);
}else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
@@ -111221,7 +116441,7 @@ static void selectInnerLoop(
}
sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey);
sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2);
if( addrTest ) sqlite3VdbeJumpHere(v, addrTest);
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempRange(pParse, r2, nKey+2);
@@ -111259,7 +116479,7 @@ static void selectInnerLoop(
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
int nExtra = (N+X)*(sizeof(CollSeq*)+1);
- KeyInfo *p = sqlite3Malloc(sizeof(KeyInfo) + nExtra);
+ KeyInfo *p = sqlite3DbMallocRawNN(db, sizeof(KeyInfo) + nExtra);
if( p ){
p->aSortOrder = (u8*)&p->aColl[N+X];
p->nField = (u16)N;
@@ -111281,7 +116501,7 @@ SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
if( p ){
assert( p->nRef>0 );
p->nRef--;
- if( p->nRef==0 ) sqlite3DbFree(0, p);
+ if( p->nRef==0 ) sqlite3DbFree(p->db, p);
}
}
@@ -111456,14 +116676,13 @@ static void generateSortTail(
int iParm = pDest->iSDParm;
int regRow;
int regRowid;
+ int iCol;
int nKey;
int iSortTab; /* Sorter cursor to read from */
int nSortData; /* Trailing values to read from sorter */
int i;
int bSeq; /* True if sorter record includes seq. no. */
-#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
struct ExprList_item *aOutEx = p->pEList->a;
-#endif
assert( addrBreak<0 );
if( pSort->labelBkOut ){
@@ -111472,21 +116691,21 @@ static void generateSortTail(
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
}
iTab = pSort->iECursor;
- if( eDest==SRT_Output || eDest==SRT_Coroutine ){
+ if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){
regRowid = 0;
regRow = pDest->iSdst;
nSortData = nColumn;
}else{
regRowid = sqlite3GetTempReg(pParse);
- regRow = sqlite3GetTempReg(pParse);
- nSortData = 1;
+ regRow = sqlite3GetTempRange(pParse, nColumn);
+ nSortData = nColumn;
}
nKey = pOrderBy->nExpr - pSort->nOBSat;
if( pSort->sortFlags & SORTFLAG_UseSorter ){
int regSortOut = ++pParse->nMem;
iSortTab = pParse->nTab++;
if( pSort->labelBkOut ){
- addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
@@ -111501,8 +116720,14 @@ static void generateSortTail(
iSortTab = iTab;
bSeq = 1;
}
- for(i=0; i<nSortData; i++){
- sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
+ for(i=0, iCol=nKey+bSeq; i<nSortData; i++){
+ int iRead;
+ if( aOutEx[i].u.x.iOrderByCol ){
+ iRead = aOutEx[i].u.x.iOrderByCol-1;
+ }else{
+ iRead = iCol++;
+ }
+ sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i);
VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
}
switch( eDest ){
@@ -111514,16 +116739,14 @@ static void generateSortTail(
}
#ifndef SQLITE_OMIT_SUBQUERY
case SRT_Set: {
- assert( nColumn==1 );
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid,
- &pDest->affSdst, 1);
- sqlite3ExprCacheAffinityChange(pParse, regRow, 1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
+ assert( nColumn==sqlite3Strlen30(pDest->zAffSdst) );
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid,
+ pDest->zAffSdst, nColumn);
+ sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn);
break;
}
case SRT_Mem: {
- assert( nColumn==1 );
- sqlite3ExprCodeMove(pParse, regRow, iParm, 1);
/* The LIMIT clause will terminate the loop for us */
break;
}
@@ -111542,7 +116765,11 @@ static void generateSortTail(
}
}
if( regRowid ){
- sqlite3ReleaseTempReg(pParse, regRow);
+ if( eDest==SRT_Set ){
+ sqlite3ReleaseTempRange(pParse, regRow, nColumn);
+ }else{
+ sqlite3ReleaseTempReg(pParse, regRow);
+ }
sqlite3ReleaseTempReg(pParse, regRowid);
}
/* The bottom of the loop
@@ -111682,20 +116909,20 @@ static const char *columnTypeImpl(
zType = "INTEGER";
zOrigCol = "rowid";
}else{
- zType = pTab->aCol[iCol].zType;
zOrigCol = pTab->aCol[iCol].zName;
+ zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
estWidth = pTab->aCol[iCol].szEst;
}
zOrigTab = pTab->zName;
if( pNC->pParse ){
int iDb = sqlite3SchemaToIndex(pNC->pParse->db, pTab->pSchema);
- zOrigDb = pNC->pParse->db->aDb[iDb].zName;
+ zOrigDb = pNC->pParse->db->aDb[iDb].zDbSName;
}
#else
if( iCol<0 ){
zType = "INTEGER";
}else{
- zType = pTab->aCol[iCol].zType;
+ zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
estWidth = pTab->aCol[iCol].szEst;
}
#endif
@@ -111941,7 +117168,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
sqlite3DbFree(db, aCol);
*paCol = 0;
*pnCol = 0;
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
return SQLITE_OK;
}
@@ -111957,7 +117184,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
** This routine requires that all identifiers in the SELECT
** statement be resolved.
*/
-static void selectAddColumnTypeAndCollation(
+SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
Parse *pParse, /* Parsing contexts */
Table *pTab, /* Add column type information to this table */
Select *pSelect /* SELECT used to determine types and collations */
@@ -111979,13 +117206,20 @@ static void selectAddColumnTypeAndCollation(
sNC.pSrcList = pSelect->pSrc;
a = pSelect->pEList->a;
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
+ const char *zType;
+ int n, m;
p = a[i].pExpr;
- if( pCol->zType==0 ){
- pCol->zType = sqlite3DbStrDup(db,
- columnType(&sNC, p,0,0,0, &pCol->szEst));
- }
+ zType = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
szAll += pCol->szEst;
pCol->affinity = sqlite3ExprAffinity(p);
+ if( zType && (m = sqlite3Strlen30(zType))>0 ){
+ n = sqlite3Strlen30(pCol->zName);
+ pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
+ if( pCol->zName ){
+ memcpy(&pCol->zName[n+1], zType, m+1);
+ pCol->colFlags |= COLFLAG_HASTYPE;
+ }
+ }
if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB;
pColl = sqlite3ExprCollSeq(pParse, p);
if( pColl && pCol->zColl==0 ){
@@ -112018,11 +117252,11 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
/* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
** is disabled */
assert( db->lookaside.bDisable );
- pTab->nRef = 1;
+ pTab->nTabRef = 1;
pTab->zName = 0;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
- selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
+ sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
pTab->iPKey = -1;
if( db->mallocFailed ){
sqlite3DeleteTable(db, pTab);
@@ -112035,20 +117269,20 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
** Get a VDBE for the given parser context. Create a new one if necessary.
** If an error occurs, return NULL and leave a message in pParse.
*/
-SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
- Vdbe *v = pParse->pVdbe;
- if( v==0 ){
- v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
- if( v ) sqlite3VdbeAddOp0(v, OP_Init);
- if( pParse->pToplevel==0
- && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
- ){
- pParse->okConstFactor = 1;
- }
-
+static SQLITE_NOINLINE Vdbe *allocVdbe(Parse *pParse){
+ Vdbe *v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
+ if( v ) sqlite3VdbeAddOp2(v, OP_Init, 0, 1);
+ if( pParse->pToplevel==0
+ && OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
+ ){
+ pParse->okConstFactor = 1;
}
return v;
}
+SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
+ Vdbe *v = pParse->pVdbe;
+ return v ? v : allocVdbe(pParse);
+}
/*
@@ -112098,8 +117332,9 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
VdbeComment((v, "LIMIT counter"));
if( n==0 ){
sqlite3VdbeGoto(v, iBreak);
- }else if( n>=0 && p->nSelectRow>(u64)n ){
- p->nSelectRow = n;
+ }else if( n>=0 && p->nSelectRow>sqlite3LogEst((u64)n) ){
+ p->nSelectRow = sqlite3LogEst((u64)n);
+ p->selFlags |= SF_FixedLimit;
}
}else{
sqlite3ExprCode(pParse, p->pLimit, iLimit);
@@ -112248,6 +117483,7 @@ static void generateWithRecursiveQuery(
/* Process the LIMIT and OFFSET clauses, if they exist */
addrBreak = sqlite3VdbeMakeLabel(v);
+ p->nSelectRow = 320; /* 4 billion rows */
computeLimitRegisters(pParse, p, addrBreak);
pLimit = p->pLimit;
pOffset = p->pOffset;
@@ -112477,7 +117713,6 @@ static int multiSelect(
if( dest.eDest==SRT_EphemTab ){
assert( p->pEList );
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
- sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
dest.eDest = SRT_Table;
}
@@ -112540,12 +117775,12 @@ static int multiSelect(
testcase( rc!=SQLITE_OK );
pDelete = p->pPrior;
p->pPrior = pPrior;
- p->nSelectRow += pPrior->nSelectRow;
+ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
if( pPrior->pLimit
&& sqlite3ExprIsInteger(pPrior->pLimit, &nLimit)
- && nLimit>0 && p->nSelectRow > (u64)nLimit
+ && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
){
- p->nSelectRow = nLimit;
+ p->nSelectRow = sqlite3LogEst((u64)nLimit);
}
if( addr ){
sqlite3VdbeJumpHere(v, addr);
@@ -112617,7 +117852,9 @@ static int multiSelect(
pDelete = p->pPrior;
p->pPrior = pPrior;
p->pOrderBy = 0;
- if( p->op==TK_UNION ) p->nSelectRow += pPrior->nSelectRow;
+ if( p->op==TK_UNION ){
+ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
+ }
sqlite3ExprDelete(db, p->pLimit);
p->pLimit = pLimit;
p->pOffset = pOffset;
@@ -112716,7 +117953,7 @@ static int multiSelect(
computeLimitRegisters(pParse, p, iBreak);
sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v);
r1 = sqlite3GetTempReg(pParse);
- iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1);
+ iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1);
sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v);
sqlite3ReleaseTempReg(pParse, r1);
selectInnerLoop(pParse, p, p->pEList, tab1,
@@ -112752,7 +117989,7 @@ static int multiSelect(
nCol = p->pEList->nExpr;
pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
if( !pKeyInfo ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto multi_select_end;
}
for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
@@ -112874,19 +118111,17 @@ static int generateOutputSubroutine(
}
#ifndef SQLITE_OMIT_SUBQUERY
- /* If we are creating a set for an "expr IN (SELECT ...)" construct,
- ** then there should be a single item on the stack. Write this
- ** item into the set table with bogus data.
+ /* If we are creating a set for an "expr IN (SELECT ...)".
*/
case SRT_Set: {
int r1;
- assert( pIn->nSdst==1 || pParse->nErr>0 );
- pDest->affSdst =
- sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affSdst);
+ testcase( pIn->nSdst>1 );
r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, 1, r1, &pDest->affSdst,1);
- sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, 1);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst,
+ r1, pDest->zAffSdst, pIn->nSdst);
+ sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1,
+ pIn->iSdst, pIn->nSdst);
sqlite3ReleaseTempReg(pParse, r1);
break;
}
@@ -113107,7 +118342,7 @@ static int multiSelectOrderBy(
}
if( j==nOrderBy ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
- if( pNew==0 ) return SQLITE_NOMEM;
+ if( pNew==0 ) return SQLITE_NOMEM_BKPT;
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
@@ -113254,7 +118489,7 @@ static int multiSelectOrderBy(
addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
VdbeCoverage(v);
sqlite3VdbeGoto(v, addrEofA);
- p->nSelectRow += pPrior->nSelectRow;
+ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
}
/* Generate a subroutine to run when the results from select B
@@ -113345,8 +118580,8 @@ static int multiSelectOrderBy(
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
/* Forward Declarations */
-static void substExprList(sqlite3*, ExprList*, int, ExprList*);
-static void substSelect(sqlite3*, Select *, int, ExprList*, int);
+static void substExprList(Parse*, ExprList*, int, ExprList*);
+static void substSelect(Parse*, Select *, int, ExprList*, int);
/*
** Scan through the expression pExpr. Replace every reference to
@@ -113362,36 +118597,46 @@ static void substSelect(sqlite3*, Select *, int, ExprList*, int);
** of the subquery rather the result set of the subquery.
*/
static Expr *substExpr(
- sqlite3 *db, /* Report malloc errors to this connection */
+ Parse *pParse, /* Report errors here */
Expr *pExpr, /* Expr in which substitution occurs */
int iTable, /* Table to be substituted */
ExprList *pEList /* Substitute expressions */
){
+ sqlite3 *db = pParse->db;
if( pExpr==0 ) return 0;
if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
if( pExpr->iColumn<0 ){
pExpr->op = TK_NULL;
}else{
Expr *pNew;
+ Expr *pCopy = pEList->a[pExpr->iColumn].pExpr;
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
- pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
- sqlite3ExprDelete(db, pExpr);
- pExpr = pNew;
+ if( sqlite3ExprIsVector(pCopy) ){
+ sqlite3VectorErrorMsg(pParse, pCopy);
+ }else{
+ pNew = sqlite3ExprDup(db, pCopy, 0);
+ if( pNew && (pExpr->flags & EP_FromJoin) ){
+ pNew->iRightJoinTable = pExpr->iRightJoinTable;
+ pNew->flags |= EP_FromJoin;
+ }
+ sqlite3ExprDelete(db, pExpr);
+ pExpr = pNew;
+ }
}
}else{
- pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList);
- pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList);
+ pExpr->pLeft = substExpr(pParse, pExpr->pLeft, iTable, pEList);
+ pExpr->pRight = substExpr(pParse, pExpr->pRight, iTable, pEList);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
- substSelect(db, pExpr->x.pSelect, iTable, pEList, 1);
+ substSelect(pParse, pExpr->x.pSelect, iTable, pEList, 1);
}else{
- substExprList(db, pExpr->x.pList, iTable, pEList);
+ substExprList(pParse, pExpr->x.pList, iTable, pEList);
}
}
return pExpr;
}
static void substExprList(
- sqlite3 *db, /* Report malloc errors here */
+ Parse *pParse, /* Report errors here */
ExprList *pList, /* List to scan and in which to make substitutes */
int iTable, /* Table to be substituted */
ExprList *pEList /* Substitute values */
@@ -113399,11 +118644,11 @@ static void substExprList(
int i;
if( pList==0 ) return;
for(i=0; i<pList->nExpr; i++){
- pList->a[i].pExpr = substExpr(db, pList->a[i].pExpr, iTable, pEList);
+ pList->a[i].pExpr = substExpr(pParse, pList->a[i].pExpr, iTable, pEList);
}
}
static void substSelect(
- sqlite3 *db, /* Report malloc errors here */
+ Parse *pParse, /* Report errors here */
Select *p, /* SELECT statement in which to make substitutions */
int iTable, /* Table to be replaced */
ExprList *pEList, /* Substitute values */
@@ -113414,17 +118659,17 @@ static void substSelect(
int i;
if( !p ) return;
do{
- substExprList(db, p->pEList, iTable, pEList);
- substExprList(db, p->pGroupBy, iTable, pEList);
- substExprList(db, p->pOrderBy, iTable, pEList);
- p->pHaving = substExpr(db, p->pHaving, iTable, pEList);
- p->pWhere = substExpr(db, p->pWhere, iTable, pEList);
+ substExprList(pParse, p->pEList, iTable, pEList);
+ substExprList(pParse, p->pGroupBy, iTable, pEList);
+ substExprList(pParse, p->pOrderBy, iTable, pEList);
+ p->pHaving = substExpr(pParse, p->pHaving, iTable, pEList);
+ p->pWhere = substExpr(pParse, p->pWhere, iTable, pEList);
pSrc = p->pSrc;
assert( pSrc!=0 );
for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
- substSelect(db, pItem->pSelect, iTable, pEList, 1);
+ substSelect(pParse, pItem->pSelect, iTable, pEList, 1);
if( pItem->fg.isTabFunc ){
- substExprList(db, pItem->u1.pFuncArg, iTable, pEList);
+ substExprList(pParse, pItem->u1.pFuncArg, iTable, pEList);
}
}
}while( doPrior && (p = p->pPrior)!=0 );
@@ -113821,12 +119066,12 @@ static int flattenSubquery(
*/
if( ALWAYS(pSubitem->pTab!=0) ){
Table *pTabToDel = pSubitem->pTab;
- if( pTabToDel->nRef==1 ){
+ if( pTabToDel->nTabRef==1 ){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
pTabToDel->pNextZombie = pToplevel->pZombieTab;
pToplevel->pZombieTab = pTabToDel;
}else{
- pTabToDel->nRef--;
+ pTabToDel->nTabRef--;
}
pSubitem->pTab = 0;
}
@@ -113941,14 +119186,15 @@ static int flattenSubquery(
assert( pParent->pHaving==0 );
pParent->pHaving = pParent->pWhere;
pParent->pWhere = pWhere;
- pParent->pHaving = sqlite3ExprAnd(db, pParent->pHaving,
- sqlite3ExprDup(db, pSub->pHaving, 0));
+ pParent->pHaving = sqlite3ExprAnd(db,
+ sqlite3ExprDup(db, pSub->pHaving, 0), pParent->pHaving
+ );
assert( pParent->pGroupBy==0 );
pParent->pGroupBy = sqlite3ExprListDup(db, pSub->pGroupBy, 0);
}else{
- pParent->pWhere = sqlite3ExprAnd(db, pParent->pWhere, pWhere);
+ pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->pWhere);
}
- substSelect(db, pParent, iParent, pSub->pEList, 0);
+ substSelect(pParse, pParent, iParent, pSub->pEList, 0);
/* The flattened query is distinct if either the inner or the
** outer query is distinct.
@@ -114022,31 +119268,37 @@ static int flattenSubquery(
** terms are duplicated into the subquery.
*/
static int pushDownWhereTerms(
- sqlite3 *db, /* The database connection (for malloc()) */
+ Parse *pParse, /* Parse context (for malloc() and error reporting) */
Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
Expr *pWhere, /* The WHERE clause of the outer query */
int iCursor /* Cursor number of the subquery */
){
Expr *pNew;
int nChng = 0;
+ Select *pX; /* For looping over compound SELECTs in pSubq */
if( pWhere==0 ) return 0;
- if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
- return 0; /* restrictions (1) and (2) */
+ for(pX=pSubq; pX; pX=pX->pPrior){
+ if( (pX->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){
+ testcase( pX->selFlags & SF_Aggregate );
+ testcase( pX->selFlags & SF_Recursive );
+ testcase( pX!=pSubq );
+ return 0; /* restrictions (1) and (2) */
+ }
}
if( pSubq->pLimit!=0 ){
- return 0; /* restriction (3) */
+ return 0; /* restriction (3) */
}
while( pWhere->op==TK_AND ){
- nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor);
+ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor);
pWhere = pWhere->pLeft;
}
if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */
if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
nChng++;
while( pSubq ){
- pNew = sqlite3ExprDup(db, pWhere, 0);
- pNew = substExpr(db, pNew, iCursor, pSubq->pEList);
- pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew);
+ pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
+ pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList);
+ pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew);
pSubq = pSubq->pPrior;
}
}
@@ -114338,13 +119590,13 @@ static int withExpand(
assert( pFrom->pTab==0 );
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
- pTab->nRef = 1;
+ pTab->nTabRef = 1;
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
pTab->iPKey = -1;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
- if( db->mallocFailed ) return SQLITE_NOMEM;
+ if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
assert( pFrom->pSelect );
/* Check if this is a recursive CTE. */
@@ -114361,20 +119613,20 @@ static int withExpand(
){
pItem->pTab = pTab;
pItem->fg.isRecursive = 1;
- pTab->nRef++;
+ pTab->nTabRef++;
pSel->selFlags |= SF_Recursive;
}
}
}
/* Only one recursive reference is permitted. */
- if( pTab->nRef>2 ){
+ if( pTab->nTabRef>2 ){
sqlite3ErrorMsg(
pParse, "multiple references to recursive table: %s", pCte->zName
);
return SQLITE_ERROR;
}
- assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 ));
+ assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
pCte->zCteErr = "circular reference: %s";
pSavedWith = pParse->pWith;
@@ -114507,7 +119759,7 @@ static int selectExpander(Walker *pWalker, Select *p){
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return WRC_Abort;
- pTab->nRef = 1;
+ pTab->nTabRef = 1;
pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab);
while( pSel->pPrior ){ pSel = pSel->pPrior; }
sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
@@ -114520,13 +119772,13 @@ static int selectExpander(Walker *pWalker, Select *p){
assert( pFrom->pTab==0 );
pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
if( pTab==0 ) return WRC_Abort;
- if( pTab->nRef==0xffff ){
+ if( pTab->nTabRef>=0xffff ){
sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535",
pTab->zName);
pFrom->pTab = 0;
return WRC_Abort;
}
- pTab->nRef++;
+ pTab->nTabRef++;
if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){
return WRC_Abort;
}
@@ -114630,7 +119882,7 @@ static int selectExpander(Walker *pWalker, Select *p){
continue;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*";
+ zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*";
}
for(j=0; j<pTab->nCol; j++){
char *zName = pTab->aCol[j].zName;
@@ -114676,10 +119928,10 @@ static int selectExpander(Walker *pWalker, Select *p){
if( longNames || pTabList->nSrc>1 ){
Expr *pLeft;
pLeft = sqlite3Expr(db, TK_ID, zTabName);
- pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
+ pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
if( zSchemaName ){
pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
- pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0);
+ pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr);
}
if( longNames ){
zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
@@ -114804,7 +120056,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
Select *pSel = pFrom->pSelect;
if( pSel ){
while( pSel->pPrior ) pSel = pSel->pPrior;
- selectAddColumnTypeAndCollation(pParse, pTab, pSel);
+ sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel);
}
}
}
@@ -114916,8 +120168,8 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
ExprList *pList = pF->pExpr->x.pList;
assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
- sqlite3VdbeAddOp4(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0, 0,
- (void*)pF->pFunc, P4_FUNCDEF);
+ sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
+ sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
}
}
@@ -114968,8 +120220,8 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
}
- sqlite3VdbeAddOp4(v, OP_AggStep0, 0, regAgg, pF->iMem,
- (void*)pF->pFunc, P4_FUNCDEF);
+ sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
+ sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nArg);
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
@@ -115113,16 +120365,6 @@ SQLITE_PRIVATE int sqlite3Select(
}
#endif
-
- /* If writing to memory or generating a set
- ** only a single column may be output.
- */
-#ifndef SQLITE_OMIT_SUBQUERY
- if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){
- goto select_end;
- }
-#endif
-
/* Try to flatten subqueries in the FROM clause up into the main query
*/
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
@@ -115213,7 +120455,7 @@ SQLITE_PRIVATE int sqlite3Select(
** inside the subquery. This can help the subquery to run more efficiently.
*/
if( (pItem->fg.jointype & JT_OUTER)==0
- && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor)
+ && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor)
){
#if SELECTTRACE_ENABLED
if( sqlite3SelectTrace & 0x100 ){
@@ -115224,10 +120466,24 @@ SQLITE_PRIVATE int sqlite3Select(
}
/* Generate code to implement the subquery
+ **
+ ** The subquery is implemented as a co-routine if all of these are true:
+ ** (1) The subquery is guaranteed to be the outer loop (so that it
+ ** does not need to be computed more than once)
+ ** (2) The ALL keyword after SELECT is omitted. (Applications are
+ ** allowed to say "SELECT ALL" instead of just "SELECT" to disable
+ ** the use of co-routines.)
+ ** (3) Co-routines are not disabled using sqlite3_test_control()
+ ** with SQLITE_TESTCTRL_OPTIMIZATIONS.
+ **
+ ** TODO: Are there other reasons beside (1) to use a co-routine
+ ** implementation?
*/
- if( pTabList->nSrc==1
- && (p->selFlags & SF_All)==0
- && OptimizationEnabled(db, SQLITE_SubqCoroutine)
+ if( i==0
+ && (pTabList->nSrc==1
+ || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
+ && (p->selFlags & SF_All)==0 /* (2) */
+ && OptimizationEnabled(db, SQLITE_SubqCoroutine) /* (3) */
){
/* Implement a co-routine that will return a single row of the result
** set on each invocation.
@@ -115240,7 +120496,7 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
- pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
+ pItem->pTab->nRowLogEst = pSub->nSelectRow;
pItem->fg.viaCoroutine = 1;
pItem->regResult = dest.iSdst;
sqlite3VdbeEndCoroutine(v, pItem->regReturn);
@@ -115263,7 +120519,7 @@ SQLITE_PRIVATE int sqlite3Select(
/* If the subquery is not correlated and if we are not inside of
** a trigger, then we only need to compute the value of the subquery
** once. */
- onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
+ onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
}else{
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
@@ -115271,7 +120527,7 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
- pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
+ pItem->pTab->nRowLogEst = pSub->nSelectRow;
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
VdbeComment((v, "end %s", pItem->pTab->zName));
@@ -115322,6 +120578,13 @@ SQLITE_PRIVATE int sqlite3Select(
** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */
assert( sDistinct.isTnct );
+
+#if SELECTTRACE_ENABLED
+ if( sqlite3SelectTrace & 0x400 ){
+ SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
}
/* If there is an ORDER BY clause, then create an ephemeral index to
@@ -115354,7 +120617,9 @@ SQLITE_PRIVATE int sqlite3Select(
/* Set the limiter.
*/
iEnd = sqlite3VdbeMakeLabel(v);
- p->nSelectRow = LARGEST_INT64;
+ if( (p->selFlags & SF_FixedLimit)==0 ){
+ p->nSelectRow = 320; /* 4 billion rows */
+ }
computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
@@ -115378,10 +120643,12 @@ SQLITE_PRIVATE int sqlite3Select(
if( !isAgg && pGroupBy==0 ){
/* No aggregate functions and no GROUP BY clause */
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
+ assert( WHERE_USE_LIMIT==SF_FixedLimit );
+ wctrlFlags |= p->selFlags & SF_FixedLimit;
/* Begin the database scan. */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
- p->pEList, wctrlFlags, 0);
+ p->pEList, wctrlFlags, p->nSelectRow);
if( pWInfo==0 ) goto select_end;
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
@@ -115391,6 +120658,7 @@ SQLITE_PRIVATE int sqlite3Select(
}
if( sSort.pOrderBy ){
sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
+ sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
sSort.pOrderBy = 0;
}
@@ -115441,9 +120709,11 @@ SQLITE_PRIVATE int sqlite3Select(
for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
pItem->u.x.iAlias = 0;
}
- if( p->nSelectRow>100 ) p->nSelectRow = 100;
+ assert( 66==sqlite3LogEst(100) );
+ if( p->nSelectRow>66 ) p->nSelectRow = 66;
}else{
- p->nSelectRow = 1;
+ assert( 0==sqlite3LogEst(1) );
+ p->nSelectRow = 0;
}
/* If there is both a GROUP BY and an ORDER BY clause and they are
@@ -116000,7 +121270,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
return 0;
malloc_failed:
- p->rc = SQLITE_NOMEM;
+ p->rc = SQLITE_NOMEM_BKPT;
return 1;
}
@@ -116014,7 +121284,7 @@ malloc_failed:
** Instead, the entire table should be passed to sqlite3_free_table() when
** the calling procedure is finished using it.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
+SQLITE_API int sqlite3_get_table(
sqlite3 *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
char ***pazResult, /* Write the result table here */
@@ -116041,7 +121311,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
res.azResult = sqlite3_malloc64(sizeof(char*)*res.nAlloc );
if( res.azResult==0 ){
db->errCode = SQLITE_NOMEM;
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
res.azResult[0] = 0;
rc = sqlite3_exec(db, zSql, sqlite3_get_table_cb, &res, pzErrMsg);
@@ -116070,7 +121340,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
if( azNew==0 ){
sqlite3_free_table(&res.azResult[1]);
db->errCode = SQLITE_NOMEM;
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
res.azResult = azNew;
}
@@ -116083,7 +121353,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
/*
** This routine frees the space the sqlite3_get_table() malloced.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_free_table(
+SQLITE_API void sqlite3_free_table(
char **azResult /* Result returned from sqlite3_get_table() */
){
if( azResult ){
@@ -116198,7 +121468,6 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
int iDb; /* The database to store the trigger in */
Token *pName; /* The unqualified db name */
DbFixer sFix; /* State vector for the DB fixer */
- int iTabDb; /* Index of the database holding pTab */
assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */
assert( pName2!=0 );
@@ -116311,13 +121580,13 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
" trigger on table: %S", pTableName, 0);
goto trigger_cleanup;
}
- iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
#ifndef SQLITE_OMIT_AUTHORIZATION
{
+ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
int code = SQLITE_CREATE_TRIGGER;
- const char *zDb = db->aDb[iTabDb].zName;
- const char *zDbTrig = isTemp ? db->aDb[1].zName : zDb;
+ const char *zDb = db->aDb[iTabDb].zDbSName;
+ const char *zDbTrig = isTemp ? db->aDb[1].zDbSName : zDb;
if( iTabDb==1 || isTemp ) code = SQLITE_CREATE_TEMP_TRIGGER;
if( sqlite3AuthCheck(pParse, code, zName, pTab->zName, zDbTrig) ){
goto trigger_cleanup;
@@ -116411,7 +121680,7 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
sqlite3NestedParse(pParse,
"INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
- db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zName,
+ db->aDb[iDb].zDbSName, MASTER_NAME, zName,
pTrig->table, z);
sqlite3DbFree(db, z);
sqlite3ChangeCookie(pParse, iDb);
@@ -116600,7 +121869,7 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr)
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
for(i=OMIT_TEMPDB; i<db->nDb; i++){
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
- if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
+ if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue;
assert( sqlite3SchemaMutexHeld(db, j, 0) );
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
if( pTrigger ) break;
@@ -116646,7 +121915,7 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
#ifndef SQLITE_OMIT_AUTHORIZATION
{
int code = SQLITE_DROP_TRIGGER;
- const char *zDb = db->aDb[iDb].zName;
+ const char *zDb = db->aDb[iDb].zDbSName;
const char *zTab = SCHEMA_TABLE(iDb);
if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER;
if( sqlite3AuthCheck(pParse, code, pTrigger->zName, pTable->zName, zDb) ||
@@ -116662,7 +121931,7 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
if( (v = sqlite3GetVdbe(pParse))!=0 ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
- db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pTrigger->zName
+ db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName
);
sqlite3ChangeCookie(pParse, iDb);
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0);
@@ -116765,8 +122034,10 @@ static SrcList *targetSrcList(
pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
if( iDb==0 || iDb>=2 ){
+ const char *zDb;
assert( iDb<db->nDb );
- pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
+ zDb = db->aDb[iDb].zDbSName;
+ pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb);
}
}
return pSrc;
@@ -116980,7 +122251,6 @@ static TriggerPrg *codeRowTrigger(
}
pProgram->nMem = pSubParse->nMem;
pProgram->nCsr = pSubParse->nTab;
- pProgram->nOnce = pSubParse->nOnce;
pProgram->token = (void *)pTrigger;
pPrg->aColmask[0] = pSubParse->oldmask;
pPrg->aColmask[1] = pSubParse->newmask;
@@ -117273,7 +122543,7 @@ SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc,
pCol->affinity, &pValue);
if( pValue ){
- sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM);
+ sqlite3VdbeAppendP4(v, pValue, P4_MEM);
}
#ifndef SQLITE_OMIT_FLOATING_POINT
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
@@ -117453,7 +122723,7 @@ SQLITE_PRIVATE void sqlite3Update(
int rc;
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
j<0 ? "ROWID" : pTab->aCol[j].zName,
- db->aDb[iDb].zName);
+ db->aDb[iDb].zDbSName);
if( rc==SQLITE_DENY ){
goto update_cleanup;
}else if( rc==SQLITE_IGNORE ){
@@ -117472,7 +122742,7 @@ SQLITE_PRIVATE void sqlite3Update(
** case, set all bits of the colUsed mask (to ensure that the virtual
** table implementation makes all columns available).
*/
- pTabList->a[0].colUsed = IsVirtual(pTab) ? (Bitmask)-1 : 0;
+ pTabList->a[0].colUsed = IsVirtual(pTab) ? ALLBITS : 0;
hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey);
@@ -117486,12 +122756,14 @@ SQLITE_PRIVATE void sqlite3Update(
int reg;
if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
reg = ++pParse->nMem;
+ pParse->nMem += pIdx->nColumn;
}else{
reg = 0;
for(i=0; i<pIdx->nKeyCol; i++){
i16 iIdxCol = pIdx->aiColumn[i];
if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
reg = ++pParse->nMem;
+ pParse->nMem += pIdx->nColumn;
break;
}
}
@@ -117556,7 +122828,8 @@ SQLITE_PRIVATE void sqlite3Update(
if( HasRowid(pTab) ){
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
pWInfo = sqlite3WhereBegin(
- pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur
+ pParse, pTabList, pWhere, 0, 0,
+ WHERE_ONEPASS_DESIRED | WHERE_SEEK_TABLE, iIdxCur
);
if( pWInfo==0 ) goto update_cleanup;
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
@@ -117601,7 +122874,7 @@ SQLITE_PRIVATE void sqlite3Update(
}else{
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
sqlite3IndexAffinityStr(db, pPk), nPk);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
}
sqlite3WhereEnd(pWInfo);
}
@@ -117653,7 +122926,7 @@ SQLITE_PRIVATE void sqlite3Update(
}else if( pPk ){
labelContinue = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
- addrTop = sqlite3VdbeAddOp2(v, OP_RowKey, iEph, regKey);
+ addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
VdbeCoverage(v);
}else{
@@ -117794,11 +123067,30 @@ SQLITE_PRIVATE void sqlite3Update(
VdbeCoverageNeverTaken(v);
}
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1);
-
- /* If changing the record number, delete the old record. */
+
+ /* If changing the rowid value, or if there are foreign key constraints
+ ** to process, delete the old record. Otherwise, add a noop OP_Delete
+ ** to invoke the pre-update hook.
+ **
+ ** That (regNew==regnewRowid+1) is true is also important for the
+ ** pre-update hook. If the caller invokes preupdate_new(), the returned
+ ** value is copied from memory cell (regNewRowid+1+iCol), where iCol
+ ** is the column index supplied by the user.
+ */
+ assert( regNew==regNewRowid+1 );
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+ sqlite3VdbeAddOp3(v, OP_Delete, iDataCur,
+ OPFLAG_ISUPDATE | ((hasFK || chngKey || pPk!=0) ? 0 : OPFLAG_ISNOOP),
+ regNewRowid
+ );
+ if( !pParse->nested ){
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
+ }
+#else
if( hasFK || chngKey || pPk!=0 ){
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
}
+#endif
if( bReplace || chngKey ){
sqlite3VdbeJumpHere(v, addr1);
}
@@ -117841,15 +123133,6 @@ SQLITE_PRIVATE void sqlite3Update(
}
sqlite3VdbeResolveLabel(v, labelBreak);
- /* Close all tables */
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- assert( aRegIdx );
- if( aToOpen[i+1] ){
- sqlite3VdbeAddOp2(v, OP_Close, iIdxCur+i, 0);
- }
- }
- if( iDataCur<iIdxCur ) sqlite3VdbeAddOp2(v, OP_Close, iDataCur, 0);
-
/* Update the sqlite_sequence table by storing the content of the
** maximum rowid counter values recorded while inserting into
** autoincrement tables.
@@ -118035,57 +123318,52 @@ static void updateVirtualTable(
/* #include "vdbeInt.h" */
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
-/*
-** Finalize a prepared statement. If there was an error, store the
-** text of the error message in *pzErrMsg. Return the result code.
-*/
-static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
- int rc;
- rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
- if( rc ){
- sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
- }
- return rc;
-}
/*
-** Execute zSql on database db. Return an error code.
+** Execute zSql on database db.
+**
+** If zSql returns rows, then each row will have exactly one
+** column. (This will only happen if zSql begins with "SELECT".)
+** Take each row of result and call execSql() again recursively.
+**
+** The execSqlF() routine does the same thing, except it accepts
+** a format string as its third argument
*/
static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
sqlite3_stmt *pStmt;
- VVA_ONLY( int rc; )
- if( !zSql ){
- return SQLITE_NOMEM;
- }
- if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
- sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
- return sqlite3_errcode(db);
- }
- VVA_ONLY( rc = ) sqlite3_step(pStmt);
- assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) );
- return vacuumFinalize(db, pStmt, pzErrMsg);
-}
-
-/*
-** Execute zSql on database db. The statement returns exactly
-** one column. Execute this as SQL on the same database.
-*/
-static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
- sqlite3_stmt *pStmt;
int rc;
- rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
+ /* printf("SQL: [%s]\n", zSql); fflush(stdout); */
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc!=SQLITE_OK ) return rc;
-
- while( SQLITE_ROW==sqlite3_step(pStmt) ){
- rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
- if( rc!=SQLITE_OK ){
- vacuumFinalize(db, pStmt, pzErrMsg);
- return rc;
+ while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
+ const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0);
+ assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
+ if( zSubSql ){
+ assert( zSubSql[0]!='S' );
+ rc = execSql(db, pzErrMsg, zSubSql);
+ if( rc!=SQLITE_OK ) break;
}
}
-
- return vacuumFinalize(db, pStmt, pzErrMsg);
+ assert( rc!=SQLITE_ROW );
+ if( rc==SQLITE_DONE ) rc = SQLITE_OK;
+ if( rc ){
+ sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
+ }
+ (void)sqlite3_finalize(pStmt);
+ return rc;
+}
+static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){
+ char *z;
+ va_list ap;
+ int rc;
+ va_start(ap, zSql);
+ z = sqlite3VMPrintf(db, zSql, ap);
+ va_end(ap);
+ if( z==0 ) return SQLITE_NOMEM;
+ rc = execSql(db, pzErrMsg, z);
+ sqlite3DbFree(db, z);
+ return rc;
}
/*
@@ -118118,11 +123396,12 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
** transient would cause the database file to appear to be deleted
** following reboot.
*/
-SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
+SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse, Token *pNm){
Vdbe *v = sqlite3GetVdbe(pParse);
- if( v ){
- sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
- sqlite3VdbeUsesBtree(v, 0);
+ int iDb = pNm ? sqlite3TwoPartName(pParse, pNm, pNm, &pNm) : 0;
+ if( v && (iDb>=2 || iDb==0) ){
+ sqlite3VdbeAddOp1(v, OP_Vacuum, iDb);
+ sqlite3VdbeUsesBtree(v, iDb);
}
return;
}
@@ -118130,19 +123409,19 @@ SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
/*
** This routine implements the OP_Vacuum opcode of the VDBE.
*/
-SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
+SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
int rc = SQLITE_OK; /* Return code from service routines */
Btree *pMain; /* The database being vacuumed */
Btree *pTemp; /* The temporary database we vacuum into */
- char *zSql = 0; /* SQL statements */
int saved_flags; /* Saved value of the db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
- void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
+ u8 saved_mTrace; /* Saved trace settings */
Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True if vacuuming a :memory: database */
int nRes; /* Bytes of reserved space at the end of each page */
int nDb; /* Number of attached databases */
+ const char *zDbMain; /* Schema name of database to vacuum */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -118159,12 +123438,14 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
saved_flags = db->flags;
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
- saved_xTrace = db->xTrace;
- db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
- db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
- db->xTrace = 0;
-
- pMain = db->aDb[0].pBt;
+ saved_mTrace = db->mTrace;
+ db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks
+ | SQLITE_PreferBuiltin | SQLITE_Vacuum);
+ db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
+ db->mTrace = 0;
+
+ zDbMain = db->aDb[iDb].zDbSName;
+ pMain = db->aDb[iDb].pBt;
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
@@ -118182,18 +123463,12 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** to write the journal header file.
*/
nDb = db->nDb;
- if( sqlite3TempInMemory(db) ){
- zSql = "ATTACH ':memory:' AS vacuum_db;";
- }else{
- zSql = "ATTACH '' AS vacuum_db;";
- }
- rc = execSql(db, pzErrMsg, zSql);
- if( db->nDb>nDb ){
- pDb = &db->aDb[db->nDb-1];
- assert( strcmp(pDb->zName,"vacuum_db")==0 );
- }
+ rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- pTemp = db->aDb[db->nDb-1].pBt;
+ assert( (db->nDb-1)==nDb );
+ pDb = &db->aDb[nDb];
+ assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
+ pTemp = pDb->pBt;
/* The call to execSql() to attach the temp database has left the file
** locked (as there was more than one active statement when the transaction
@@ -118214,14 +123489,15 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
}
#endif
- rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
+ sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
+ sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
+ sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);
/* Begin a transaction and take an exclusive lock on the main database
** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
** to ensure that we do not try to change the page-size on a WAL database.
*/
- rc = execSql(db, pzErrMsg, "BEGIN;");
+ rc = execSql(db, pzErrMsg, "BEGIN");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = sqlite3BtreeBeginTrans(pMain, 2);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
@@ -118236,7 +123512,7 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|| NEVER(db->mallocFailed)
){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
goto end_of_vacuum;
}
@@ -118248,64 +123524,48 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
/* Query the schema of the main database. Create a mirror schema
** in the temporary database.
*/
- rc = execExecSql(db, pzErrMsg,
- "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
- " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
- " AND coalesce(rootpage,1)>0"
+ db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
+ rc = execSqlF(db, pzErrMsg,
+ "SELECT sql FROM \"%w\".sqlite_master"
+ " WHERE type='table'AND name<>'sqlite_sequence'"
+ " AND coalesce(rootpage,1)>0",
+ zDbMain
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = execExecSql(db, pzErrMsg,
- "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
- " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = execExecSql(db, pzErrMsg,
- "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
- " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
+ rc = execSqlF(db, pzErrMsg,
+ "SELECT sql FROM \"%w\".sqlite_master"
+ " WHERE type='index' AND length(sql)>10",
+ zDbMain
+ );
if( rc!=SQLITE_OK ) goto end_of_vacuum;
+ db->init.iDb = 0;
/* Loop through the tables in the main database. For each, do
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
** the contents to the temporary database.
*/
- assert( (db->flags & SQLITE_Vacuum)==0 );
- db->flags |= SQLITE_Vacuum;
- rc = execExecSql(db, pzErrMsg,
- "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
- "|| ' SELECT * FROM main.' || quote(name) || ';'"
- "FROM main.sqlite_master "
- "WHERE type = 'table' AND name!='sqlite_sequence' "
- " AND coalesce(rootpage,1)>0"
+ rc = execSqlF(db, pzErrMsg,
+ "SELECT'INSERT INTO vacuum_db.'||quote(name)"
+ "||' SELECT*FROM\"%w\".'||quote(name)"
+ "FROM vacuum_db.sqlite_master "
+ "WHERE type='table'AND coalesce(rootpage,1)>0",
+ zDbMain
);
assert( (db->flags & SQLITE_Vacuum)!=0 );
db->flags &= ~SQLITE_Vacuum;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- /* Copy over the sequence table
- */
- rc = execExecSql(db, pzErrMsg,
- "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
- "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
- );
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = execExecSql(db, pzErrMsg,
- "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
- "|| ' SELECT * FROM main.' || quote(name) || ';' "
- "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
- );
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
-
/* Copy the triggers, views, and virtual tables from the main database
** over to the temporary database. None of these objects has any
** associated storage, so all we have to do is copy their entries
** from the SQLITE_MASTER table.
*/
- rc = execSql(db, pzErrMsg,
- "INSERT INTO vacuum_db.sqlite_master "
- " SELECT type, name, tbl_name, rootpage, sql"
- " FROM main.sqlite_master"
- " WHERE type='view' OR type='trigger'"
- " OR (type='table' AND rootpage=0)"
+ rc = execSqlF(db, pzErrMsg,
+ "INSERT INTO vacuum_db.sqlite_master"
+ " SELECT*FROM \"%w\".sqlite_master"
+ " WHERE type IN('view','trigger')"
+ " OR(type='table'AND rootpage=0)",
+ zDbMain
);
if( rc ) goto end_of_vacuum;
@@ -118359,10 +123619,11 @@ SQLITE_PRIVATE int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
end_of_vacuum:
/* Restore the original value of db->flags */
+ db->init.iDb = 0;
db->flags = saved_flags;
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
- db->xTrace = saved_xTrace;
+ db->mTrace = saved_mTrace;
sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
/* Currently there is an SQL level transaction open on the vacuum
@@ -118422,6 +123683,41 @@ struct VtabCtx {
};
/*
+** Construct and install a Module object for a virtual table. When this
+** routine is called, it is guaranteed that all appropriate locks are held
+** and the module is not already part of the connection.
+*/
+SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
+ sqlite3 *db, /* Database in which module is registered */
+ const char *zName, /* Name assigned to this module */
+ const sqlite3_module *pModule, /* The definition of the module */
+ void *pAux, /* Context pointer for xCreate/xConnect */
+ void (*xDestroy)(void *) /* Module destructor function */
+){
+ Module *pMod;
+ int nName = sqlite3Strlen30(zName);
+ pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1);
+ if( pMod ){
+ Module *pDel;
+ char *zCopy = (char *)(&pMod[1]);
+ memcpy(zCopy, zName, nName+1);
+ pMod->zName = zCopy;
+ pMod->pModule = pModule;
+ pMod->pAux = pAux;
+ pMod->xDestroy = xDestroy;
+ pMod->pEpoTab = 0;
+ pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
+ assert( pDel==0 || pDel==pMod );
+ if( pDel ){
+ sqlite3OomFault(db);
+ sqlite3DbFree(db, pDel);
+ pMod = 0;
+ }
+ }
+ return pMod;
+}
+
+/*
** The actual function that does the work of creating a new module.
** This function implements the sqlite3_create_module() and
** sqlite3_create_module_v2() interfaces.
@@ -118434,35 +123730,15 @@ static int createModule(
void (*xDestroy)(void *) /* Module destructor function */
){
int rc = SQLITE_OK;
- int nName;
sqlite3_mutex_enter(db->mutex);
- nName = sqlite3Strlen30(zName);
if( sqlite3HashFind(&db->aModule, zName) ){
rc = SQLITE_MISUSE_BKPT;
}else{
- Module *pMod;
- pMod = (Module *)sqlite3DbMallocRawNN(db, sizeof(Module) + nName + 1);
- if( pMod ){
- Module *pDel;
- char *zCopy = (char *)(&pMod[1]);
- memcpy(zCopy, zName, nName+1);
- pMod->zName = zCopy;
- pMod->pModule = pModule;
- pMod->pAux = pAux;
- pMod->xDestroy = xDestroy;
- pMod->pEpoTab = 0;
- pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod);
- assert( pDel==0 || pDel==pMod );
- if( pDel ){
- sqlite3OomFault(db);
- sqlite3DbFree(db, pDel);
- }
- }
+ (void)sqlite3VtabCreateModule(db, zName, pModule, pAux, xDestroy);
}
rc = sqlite3ApiExit(db, rc);
if( rc!=SQLITE_OK && xDestroy ) xDestroy(pAux);
-
sqlite3_mutex_leave(db->mutex);
return rc;
}
@@ -118471,7 +123747,7 @@ static int createModule(
/*
** External API function used to create a new virtual-table module.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
+SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
const sqlite3_module *pModule, /* The definition of the module */
@@ -118486,7 +123762,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
/*
** External API function used to create a new virtual-table module.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
+SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db, /* Database in which module is registered */
const char *zName, /* Name assigned to this module */
const sqlite3_module *pModule, /* The definition of the module */
@@ -118737,7 +124013,7 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
*/
if( pTable->azModuleArg ){
sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
- pTable->azModuleArg[0], pParse->db->aDb[iDb].zName);
+ pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName);
}
#endif
}
@@ -118801,7 +124077,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
"UPDATE %Q.%s "
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
"WHERE rowid=#%d",
- db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
+ db->aDb[iDb].zDbSName, MASTER_NAME,
pTab->zName,
pTab->zName,
zStmt,
@@ -118811,7 +124087,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
v = sqlite3GetVdbe(pParse);
sqlite3ChangeCookie(pParse, iDb);
- sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
+ sqlite3VdbeAddOp0(v, OP_Expire);
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
@@ -118899,19 +124175,19 @@ static int vtabCallConstructor(
zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
if( !zModuleName ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pVTable = sqlite3DbMallocZero(db, sizeof(VTable));
if( !pVTable ){
sqlite3DbFree(db, zModuleName);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
pVTable->db = db;
pVTable->pMod = pMod;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- pTab->azModuleArg[1] = db->aDb[iDb].zName;
+ pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
/* Invoke the virtual table constructor */
assert( &db->pVtabCtx );
@@ -118957,22 +124233,16 @@ static int vtabCallConstructor(
pTab->pVTable = pVTable;
for(iCol=0; iCol<pTab->nCol; iCol++){
- char *zType = pTab->aCol[iCol].zType;
+ char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
int nType;
int i = 0;
- if( !zType ){
- pTab->tabFlags |= oooHidden;
- continue;
- }
nType = sqlite3Strlen30(zType);
- if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){
- for(i=0; i<nType; i++){
- if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7))
- && (zType[i+7]=='\0' || zType[i+7]==' ')
- ){
- i++;
- break;
- }
+ for(i=0; i<nType; i++){
+ if( 0==sqlite3StrNICmp("hidden", &zType[i], 6)
+ && (i==0 || zType[i-1]==' ')
+ && (zType[i+6]=='\0' || zType[i+6]==' ')
+ ){
+ break;
}
}
if( i<nType ){
@@ -119048,7 +124318,7 @@ static int growVTrans(sqlite3 *db){
int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR);
aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes);
if( !aVTrans ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR);
db->aVTrans = aVTrans;
@@ -119071,7 +124341,7 @@ static void addToVTrans(sqlite3 *db, VTable *pVTab){
** This function is invoked by the vdbe to call the xCreate method
** of the virtual table named zTab in database iDb.
**
-** If an error occurs, *pzErr is set to point an an English language
+** If an error occurs, *pzErr is set to point to an English language
** description of the error and an SQLITE_XXX error code is returned.
** In this case the caller must call sqlite3DbFree(db, ) on *pzErr.
*/
@@ -119081,7 +124351,7 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
Module *pMod;
const char *zMod;
- pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
+ pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable );
/* Locate the required virtual table module */
@@ -119116,7 +124386,7 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
** valid to call this function from within the xCreate() or xConnect() of a
** virtual table module.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
+SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
VtabCtx *pCtx;
Parse *pParse;
int rc = SQLITE_OK;
@@ -119140,7 +124410,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCre
pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
if( pParse==0 ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}else{
pParse->declareVtab = 1;
pParse->db = db;
@@ -119153,10 +124423,24 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3 *db, const char *zCre
&& (pParse->pNewTable->tabFlags & TF_Virtual)==0
){
if( !pTab->aCol ){
- pTab->aCol = pParse->pNewTable->aCol;
- pTab->nCol = pParse->pNewTable->nCol;
- pParse->pNewTable->nCol = 0;
- pParse->pNewTable->aCol = 0;
+ Table *pNew = pParse->pNewTable;
+ Index *pIdx;
+ pTab->aCol = pNew->aCol;
+ pTab->nCol = pNew->nCol;
+ pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
+ pNew->nCol = 0;
+ pNew->aCol = 0;
+ assert( pTab->pIndex==0 );
+ if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){
+ rc = SQLITE_ERROR;
+ }
+ pIdx = pNew->pIndex;
+ if( pIdx ){
+ assert( pIdx->pNext==0 );
+ pTab->pIndex = pIdx;
+ pNew->pIndex = 0;
+ pIdx->pTable = pTab;
+ }
}
pCtx->bDeclared = 1;
}else{
@@ -119191,8 +124475,8 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
int rc = SQLITE_OK;
Table *pTab;
- pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName);
- if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){
+ pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
+ if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){
VTable *p;
int (*xDestroy)(sqlite3_vtab *);
for(p=pTab->pVTable; p; p=p->pNext){
@@ -119332,7 +124616,10 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
if( rc==SQLITE_OK ){
int iSvpt = db->nStatement + db->nSavepoint;
addToVTrans(db, pVTab);
- if( iSvpt ) rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, iSvpt-1);
+ if( iSvpt && pModule->xSavepoint ){
+ pVTab->iSavepoint = iSvpt;
+ rc = pModule->xSavepoint(pVTab->pVtab, iSvpt-1);
+ }
}
}
}
@@ -119452,8 +124739,8 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
return pDef;
}
*pNew = *pDef;
- pNew->zName = (char *)&pNew[1];
- memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
+ pNew->zName = (const char*)&pNew[1];
+ memcpy((char*)&pNew[1], pDef->zName, sqlite3Strlen30(pDef->zName)+1);
pNew->xSFunc = xSFunc;
pNew->pUserData = pArg;
pNew->funcFlags |= SQLITE_FUNC_EPHEM;
@@ -119486,7 +124773,7 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
}
/*
-** Check to see if virtual tale module pMod can be have an eponymous
+** Check to see if virtual table module pMod can be have an eponymous
** virtual table instance. If it can, create one if one does not already
** exist. Return non-zero if the eponymous virtual table instance exists
** when this routine returns, and return zero if it does not exist.
@@ -119503,18 +124790,19 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
const sqlite3_module *pModule = pMod->pModule;
Table *pTab;
char *zErr = 0;
- int nName;
int rc;
sqlite3 *db = pParse->db;
if( pMod->pEpoTab ) return 1;
if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0;
- nName = sqlite3Strlen30(pMod->zName) + 1;
- pTab = sqlite3DbMallocZero(db, sizeof(Table) + nName);
+ pTab = sqlite3DbMallocZero(db, sizeof(Table));
if( pTab==0 ) return 0;
+ pTab->zName = sqlite3DbStrDup(db, pMod->zName);
+ if( pTab->zName==0 ){
+ sqlite3DbFree(db, pTab);
+ return 0;
+ }
pMod->pEpoTab = pTab;
- pTab->zName = (char*)&pTab[1];
- memcpy(pTab->zName, pMod->zName, nName);
- pTab->nRef = 1;
+ pTab->nTabRef = 1;
pTab->pSchema = db->aDb[0].pSchema;
pTab->tabFlags |= TF_Virtual;
pTab->nModuleArg = 0;
@@ -119539,9 +124827,11 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
Table *pTab = pMod->pEpoTab;
if( pTab!=0 ){
- sqlite3DeleteColumnNames(db, pTab);
- sqlite3VtabClear(db, pTab);
- sqlite3DbFree(db, pTab);
+ /* Mark the table as Ephemeral prior to deleting it, so that the
+ ** sqlite3DeleteTable() routine will know that it is not stored in
+ ** the schema. */
+ pTab->tabFlags |= TF_Ephemeral;
+ sqlite3DeleteTable(db, pTab);
pMod->pEpoTab = 0;
}
}
@@ -119553,7 +124843,7 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
** The results of this routine are undefined unless it is called from
** within an xUpdate method.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){
+SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
static const unsigned char aMap[] = {
SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
};
@@ -119571,7 +124861,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *db){
** the SQLite core with additional information about the behavior
** of the virtual table being implemented.
*/
-SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3 *db, int op, ...){
+SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
va_list ap;
int rc = SQLITE_OK;
@@ -119700,7 +124990,7 @@ struct WhereLevel {
int addrFirst; /* First instruction of interior of the loop */
int addrBody; /* Beginning of the body of this loop */
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
- int iLikeRepCntr; /* LIKE range processing counter register */
+ u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */
int addrLikeRep; /* LIKE range processing address */
#endif
u8 iFrom; /* Which entry in the FROM clause */
@@ -119752,6 +125042,8 @@ struct WhereLoop {
union {
struct { /* Information for internal btree tables */
u16 nEq; /* Number of equality constraints */
+ u16 nBtm; /* Size of BTM vector */
+ u16 nTop; /* Size of TOP vector */
Index *pIndex; /* Index used, or NULL */
} btree;
struct { /* Information for virtual tables */
@@ -119874,19 +125166,20 @@ struct WherePath {
*/
struct WhereTerm {
Expr *pExpr; /* Pointer to the subexpression that is this term */
+ WhereClause *pWC; /* The clause this term is part of */
+ LogEst truthProb; /* Probability of truth for this expression */
+ u16 wtFlags; /* TERM_xxx bit flags. See below */
+ u16 eOperator; /* A WO_xx value describing <op> */
+ u8 nChild; /* Number of children that must disable us */
+ u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */
int iParent; /* Disable pWC->a[iParent] when this term disabled */
int leftCursor; /* Cursor number of X in "X <op> <expr>" */
+ int iField; /* Field in (?,?,?) IN (SELECT...) vector */
union {
int leftColumn; /* Column number of X in "X <op> <expr>" */
WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
} u;
- LogEst truthProb; /* Probability of truth for this expression */
- u16 eOperator; /* A WO_xx value describing <op> */
- u16 wtFlags; /* TERM_xxx bit flags. See below */
- u8 nChild; /* Number of children that must disable us */
- u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */
- WhereClause *pWC; /* The clause this term is part of */
Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */
Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */
};
@@ -120038,24 +125331,26 @@ struct WhereInfo {
Parse *pParse; /* Parsing and code generating context */
SrcList *pTabList; /* List of tables in the join */
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
- ExprList *pResultSet; /* Result set. DISTINCT operates on these */
- WhereLoop *pLoops; /* List of all WhereLoop objects */
- Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
- LogEst nRowOut; /* Estimated number of output rows */
+ ExprList *pDistinctSet; /* DISTINCT over all these values */
+ LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
+ int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
+ int iContinue; /* Jump here to continue with next record */
+ int iBreak; /* Jump here to break out of the loop */
+ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
+ u8 nLevel; /* Number of nested loop */
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
u8 sorted; /* True if really sorted (not just grouped) */
u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
- u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
- u8 nLevel; /* Number of nested loop */
+ u8 eDistinct; /* One of the WHERE_DISTINCT_* values */
+ u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */
int iTop; /* The very beginning of the WHERE loop */
- int iContinue; /* Jump here to continue with next record */
- int iBreak; /* Jump here to break out of the loop */
- int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
- int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
- WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
+ WhereLoop *pLoops; /* List of all WhereLoop objects */
+ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
+ LogEst nRowOut; /* Estimated number of output rows */
WhereClause sWC; /* Decomposition of the WHERE clause */
+ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
WhereLevel a[1]; /* Information about each nest loop in WHERE */
};
@@ -120065,6 +125360,9 @@ struct WhereInfo {
** where.c:
*/
SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
+#ifdef WHERETRACE_ENABLED
+SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC);
+#endif
SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
WhereClause *pWC, /* The WHERE clause to be searched */
int iCur, /* Cursor number of LHS */
@@ -120121,6 +125419,14 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
** operators that are of interest to the query planner. An
** OR-ed combination of these values can be used when searching for
** particular WhereTerms within a WhereClause.
+**
+** Value constraints:
+** WO_EQ == SQLITE_INDEX_CONSTRAINT_EQ
+** WO_LT == SQLITE_INDEX_CONSTRAINT_LT
+** WO_LE == SQLITE_INDEX_CONSTRAINT_LE
+** WO_GT == SQLITE_INDEX_CONSTRAINT_GT
+** WO_GE == SQLITE_INDEX_CONSTRAINT_GE
+** WO_MATCH == SQLITE_INDEX_CONSTRAINT_MATCH
*/
#define WO_IN 0x0001
#define WO_EQ 0x0002
@@ -120168,6 +125474,17 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
/************** Continuing where we left off in wherecode.c ******************/
#ifndef SQLITE_OMIT_EXPLAIN
+
+/*
+** Return the name of the i-th column of the pIdx index.
+*/
+static const char *explainIndexColumnName(Index *pIdx, int i){
+ i = pIdx->aiColumn[i];
+ if( i==XN_EXPR ) return "<expr>";
+ if( i==XN_ROWID ) return "rowid";
+ return pIdx->pTable->aCol[i].zName;
+}
+
/*
** This routine is a helper for explainIndexRange() below
**
@@ -120178,24 +125495,32 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
*/
static void explainAppendTerm(
StrAccum *pStr, /* The text expression being built */
- int iTerm, /* Index of this term. First is zero */
- const char *zColumn, /* Name of the column */
+ Index *pIdx, /* Index to read column names from */
+ int nTerm, /* Number of terms */
+ int iTerm, /* Zero-based index of first term. */
+ int bAnd, /* Non-zero to append " AND " */
const char *zOp /* Name of the operator */
){
- if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5);
- sqlite3StrAccumAppendAll(pStr, zColumn);
+ int i;
+
+ assert( nTerm>=1 );
+ if( bAnd ) sqlite3StrAccumAppend(pStr, " AND ", 5);
+
+ if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
+ for(i=0; i<nTerm; i++){
+ if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
+ sqlite3StrAccumAppendAll(pStr, explainIndexColumnName(pIdx, iTerm+i));
+ }
+ if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
+
sqlite3StrAccumAppend(pStr, zOp, 1);
- sqlite3StrAccumAppend(pStr, "?", 1);
-}
-/*
-** Return the name of the i-th column of the pIdx index.
-*/
-static const char *explainIndexColumnName(Index *pIdx, int i){
- i = pIdx->aiColumn[i];
- if( i==XN_EXPR ) return "<expr>";
- if( i==XN_ROWID ) return "rowid";
- return pIdx->pTable->aCol[i].zName;
+ if( nTerm>1 ) sqlite3StrAccumAppend(pStr, "(", 1);
+ for(i=0; i<nTerm; i++){
+ if( i ) sqlite3StrAccumAppend(pStr, ",", 1);
+ sqlite3StrAccumAppend(pStr, "?", 1);
+ }
+ if( nTerm>1 ) sqlite3StrAccumAppend(pStr, ")", 1);
}
/*
@@ -120228,12 +125553,11 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
j = i;
if( pLoop->wsFlags&WHERE_BTM_LIMIT ){
- const char *z = explainIndexColumnName(pIndex, i);
- explainAppendTerm(pStr, i++, z, ">");
+ explainAppendTerm(pStr, pIndex, pLoop->u.btree.nBtm, j, i, ">");
+ i = 1;
}
if( pLoop->wsFlags&WHERE_TOP_LIMIT ){
- const char *z = explainIndexColumnName(pIndex, j);
- explainAppendTerm(pStr, i, z, "<");
+ explainAppendTerm(pStr, pIndex, pLoop->u.btree.nTop, j, i, "<");
}
sqlite3StrAccumAppend(pStr, ")", 1);
}
@@ -120273,7 +125597,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
pLoop = pLevel->pWLoop;
flags = pLoop->wsFlags;
- if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0;
+ if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_OR_SUBCLAUSE) ) return 0;
isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
|| ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0))
@@ -120423,7 +125747,7 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
int nLoop = 0;
- while( pTerm
+ while( ALWAYS(pTerm!=0)
&& (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
&& (pLevel->notReady & pTerm->prereqAll)==0
@@ -120479,16 +125803,45 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
}
}
+/*
+** Expression pRight, which is the RHS of a comparison operation, is
+** either a vector of n elements or, if n==1, a scalar expression.
+** Before the comparison operation, affinity zAff is to be applied
+** to the pRight values. This function modifies characters within the
+** affinity string to SQLITE_AFF_BLOB if either:
+**
+** * the comparison will be performed with no affinity, or
+** * the affinity change in zAff is guaranteed not to change the value.
+*/
+static void updateRangeAffinityStr(
+ Expr *pRight, /* RHS of comparison */
+ int n, /* Number of vector elements in comparison */
+ char *zAff /* Affinity string to modify */
+){
+ int i;
+ for(i=0; i<n; i++){
+ Expr *p = sqlite3VectorFieldSubexpr(pRight, i);
+ if( sqlite3CompareAffinity(p, zAff[i])==SQLITE_AFF_BLOB
+ || sqlite3ExprNeedsNoAffinityChange(p, zAff[i])
+ ){
+ zAff[i] = SQLITE_AFF_BLOB;
+ }
+ }
+}
/*
** Generate code for a single equality term of the WHERE clause. An equality
** term can be either X=expr or X IN (...). pTerm is the term to be
** coded.
**
-** The current value for the constraint is left in register iReg.
+** The current value for the constraint is left in a register, the index
+** of which is returned. An attempt is made store the result in iTarget but
+** this is only guaranteed for TK_ISNULL and TK_IN constraints. If the
+** constraint is a TK_EQ or TK_IS, then the current value might be left in
+** some other register and it is the caller's responsibility to compensate.
**
-** For a constraint of the form X=expr, the expression is evaluated and its
-** result is left on the stack. For constraints of the form X IN (...)
+** For a constraint of the form X=expr, the expression is evaluated in
+** straight-line code. For constraints of the form X IN (...)
** this routine sets up a loop that will iterate over all values of X.
*/
static int codeEqualityTerm(
@@ -120503,6 +125856,7 @@ static int codeEqualityTerm(
Vdbe *v = pParse->pVdbe;
int iReg; /* Register holding results */
+ assert( pLevel->pWLoop->aLTerm[iEq]==pTerm );
assert( iTarget>0 );
if( pX->op==TK_EQ || pX->op==TK_IS ){
iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget);
@@ -120511,10 +125865,13 @@ static int codeEqualityTerm(
sqlite3VdbeAddOp2(v, OP_Null, 0, iReg);
#ifndef SQLITE_OMIT_SUBQUERY
}else{
- int eType;
+ int eType = IN_INDEX_NOOP;
int iTab;
struct InLoop *pIn;
WhereLoop *pLoop = pLevel->pWLoop;
+ int i;
+ int nEq = 0;
+ int *aiMap = 0;
if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
&& pLoop->u.btree.pIndex!=0
@@ -120526,7 +125883,78 @@ static int codeEqualityTerm(
}
assert( pX->op==TK_IN );
iReg = iTarget;
- eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
+
+ for(i=0; i<iEq; i++){
+ if( pLoop->aLTerm[i] && pLoop->aLTerm[i]->pExpr==pX ){
+ disableTerm(pLevel, pTerm);
+ return iTarget;
+ }
+ }
+ for(i=iEq;i<pLoop->nLTerm; i++){
+ if( ALWAYS(pLoop->aLTerm[i]) && pLoop->aLTerm[i]->pExpr==pX ) nEq++;
+ }
+
+ if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0);
+ }else{
+ Select *pSelect = pX->x.pSelect;
+ sqlite3 *db = pParse->db;
+ u16 savedDbOptFlags = db->dbOptFlags;
+ ExprList *pOrigRhs = pSelect->pEList;
+ ExprList *pOrigLhs = pX->pLeft->x.pList;
+ ExprList *pRhs = 0; /* New Select.pEList for RHS */
+ ExprList *pLhs = 0; /* New pX->pLeft vector */
+
+ for(i=iEq;i<pLoop->nLTerm; i++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ int iField = pLoop->aLTerm[i]->iField - 1;
+ Expr *pNewRhs = sqlite3ExprDup(db, pOrigRhs->a[iField].pExpr, 0);
+ Expr *pNewLhs = sqlite3ExprDup(db, pOrigLhs->a[iField].pExpr, 0);
+
+ pRhs = sqlite3ExprListAppend(pParse, pRhs, pNewRhs);
+ pLhs = sqlite3ExprListAppend(pParse, pLhs, pNewLhs);
+ }
+ }
+ if( !db->mallocFailed ){
+ Expr *pLeft = pX->pLeft;
+
+ if( pSelect->pOrderBy ){
+ /* If the SELECT statement has an ORDER BY clause, zero the
+ ** iOrderByCol variables. These are set to non-zero when an
+ ** ORDER BY term exactly matches one of the terms of the
+ ** result-set. Since the result-set of the SELECT statement may
+ ** have been modified or reordered, these variables are no longer
+ ** set correctly. Since setting them is just an optimization,
+ ** it's easiest just to zero them here. */
+ ExprList *pOrderBy = pSelect->pOrderBy;
+ for(i=0; i<pOrderBy->nExpr; i++){
+ pOrderBy->a[i].u.x.iOrderByCol = 0;
+ }
+ }
+
+ /* Take care here not to generate a TK_VECTOR containing only a
+ ** single value. Since the parser never creates such a vector, some
+ ** of the subroutines do not handle this case. */
+ if( pLhs->nExpr==1 ){
+ pX->pLeft = pLhs->a[0].pExpr;
+ }else{
+ pLeft->x.pList = pLhs;
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int) * nEq);
+ testcase( aiMap==0 );
+ }
+ pSelect->pEList = pRhs;
+ db->dbOptFlags |= SQLITE_QueryFlattener;
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap);
+ db->dbOptFlags = savedDbOptFlags;
+ testcase( aiMap!=0 && aiMap[0]!=0 );
+ pSelect->pEList = pOrigRhs;
+ pLeft->x.pList = pOrigLhs;
+ pX->pLeft = pLeft;
+ }
+ sqlite3ExprListDelete(pParse->db, pLhs);
+ sqlite3ExprListDelete(pParse->db, pRhs);
+ }
+
if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev );
bRev = !bRev;
@@ -120536,28 +125964,45 @@ static int codeEqualityTerm(
VdbeCoverageIf(v, bRev);
VdbeCoverageIf(v, !bRev);
assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
+
pLoop->wsFlags |= WHERE_IN_ABLE;
if( pLevel->u.in.nIn==0 ){
pLevel->addrNxt = sqlite3VdbeMakeLabel(v);
}
- pLevel->u.in.nIn++;
+
+ i = pLevel->u.in.nIn;
+ pLevel->u.in.nIn += nEq;
pLevel->u.in.aInLoop =
sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
pIn = pLevel->u.in.aInLoop;
if( pIn ){
- pIn += pLevel->u.in.nIn - 1;
- pIn->iCur = iTab;
- if( eType==IN_INDEX_ROWID ){
- pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
- }else{
- pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
+ int iMap = 0; /* Index in aiMap[] */
+ pIn += i;
+ for(i=iEq;i<pLoop->nLTerm; i++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ int iOut = iReg + i - iEq;
+ if( eType==IN_INDEX_ROWID ){
+ testcase( nEq>1 ); /* Happens with a UNIQUE index on ROWID */
+ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iOut);
+ }else{
+ int iCol = aiMap ? aiMap[iMap++] : 0;
+ pIn->addrInTop = sqlite3VdbeAddOp3(v,OP_Column,iTab, iCol, iOut);
+ }
+ sqlite3VdbeAddOp1(v, OP_IsNull, iOut); VdbeCoverage(v);
+ if( i==iEq ){
+ pIn->iCur = iTab;
+ pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
+ }else{
+ pIn->eEndLoopOp = OP_Noop;
+ }
+ pIn++;
+ }
}
- pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
- sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v);
}else{
pLevel->u.in.nIn = 0;
}
+ sqlite3DbFree(pParse->db, aiMap);
#endif
}
disableTerm(pLevel, pTerm);
@@ -120683,9 +126128,15 @@ static int codeAllEqualityTerms(
sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
}
}
- testcase( pTerm->eOperator & WO_ISNULL );
- testcase( pTerm->eOperator & WO_IN );
- if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
+ if( pTerm->eOperator & WO_IN ){
+ if( pTerm->pExpr->flags & EP_xIsSelect ){
+ /* No affinity ever needs to be (or should be) applied to a value
+ ** from the RHS of an "? IN (SELECT ...)" expression. The
+ ** sqlite3FindInIndex() routine has already ensured that the
+ ** affinity of the comparison has been applied to the value. */
+ if( zAff ) zAff[j] = SQLITE_AFF_BLOB;
+ }
+ }else if( (pTerm->eOperator & WO_ISNULL)==0 ){
Expr *pRight = pTerm->pExpr->pRight;
if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
@@ -120707,15 +126158,16 @@ static int codeAllEqualityTerms(
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
/*
-** If the most recently coded instruction is a constant range contraint
-** that originated from the LIKE optimization, then change the P3 to be
-** pLoop->iLikeRepCntr and set P5.
+** If the most recently coded instruction is a constant range constraint
+** (a string literal) that originated from the LIKE optimization, then
+** set P3 and P5 on the OP_String opcode so that the string will be cast
+** to a BLOB at appropriate times.
**
** The LIKE optimization trys to evaluate "x LIKE 'abc%'" as a range
** expression: "x>='ABC' AND x<'abd'". But this requires that the range
** scan loop run twice, once for strings and a second time for BLOBs.
** The OP_String opcodes on the second pass convert the upper and lower
-** bound string contants to blobs. This routine makes the necessary changes
+** bound string constants to blobs. This routine makes the necessary changes
** to the OP_String opcodes for that to happen.
**
** Except, of course, if SQLITE_LIKE_DOESNT_MATCH_BLOBS is defined, then
@@ -120734,8 +126186,8 @@ static void whereLikeOptimizationStringFixup(
assert( pOp!=0 );
assert( pOp->opcode==OP_String8
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed );
- pOp->p3 = pLevel->iLikeRepCntr;
- pOp->p5 = 1;
+ pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */
+ pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */
}
}
#else
@@ -120772,6 +126224,38 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
+/*
+** Test whether or not expression pExpr, which was part of a WHERE clause,
+** should be included in the cursor-hint for a table that is on the rhs
+** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the
+** expression is not suitable.
+**
+** An expression is unsuitable if it might evaluate to non NULL even if
+** a TK_COLUMN node that does affect the value of the expression is set
+** to NULL. For example:
+**
+** col IS NULL
+** col IS NOT NULL
+** coalesce(col, 1)
+** CASE WHEN col THEN 0 ELSE 1 END
+*/
+static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_IS
+ || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT
+ || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE
+ ){
+ pWalker->eCode = 1;
+ }else if( pExpr->op==TK_FUNCTION ){
+ int d1;
+ char d2[3];
+ if( 0==sqlite3IsLikeFunction(pWalker->pParse->db, pExpr, &d1, d2) ){
+ pWalker->eCode = 1;
+ }
+ }
+
+ return WRC_Continue;
+}
+
/*
** This function is called on every node of an expression tree used as an
@@ -120824,6 +126308,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
** Insert an OP_CursorHint instruction if it is appropriate to do so.
*/
static void codeCursorHint(
+ struct SrcList_item *pTabItem, /* FROM clause item */
WhereInfo *pWInfo, /* The where clause */
WhereLevel *pLevel, /* Which loop to provide hints for */
WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */
@@ -120854,7 +126339,42 @@ static void codeCursorHint(
pTerm = &pWC->a[i];
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( pTerm->prereqAll & pLevel->notReady ) continue;
- if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
+
+ /* Any terms specified as part of the ON(...) clause for any LEFT
+ ** JOIN for which the current table is not the rhs are omitted
+ ** from the cursor-hint.
+ **
+ ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms
+ ** that were specified as part of the WHERE clause must be excluded.
+ ** This is to address the following:
+ **
+ ** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL;
+ **
+ ** Say there is a single row in t2 that matches (t1.a=t2.b), but its
+ ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is
+ ** pushed down to the cursor, this row is filtered out, causing
+ ** SQLite to synthesize a row of NULL values. Which does match the
+ ** WHERE clause, and so the query returns a row. Which is incorrect.
+ **
+ ** For the same reason, WHERE terms such as:
+ **
+ ** WHERE 1 = (t2.c IS NULL)
+ **
+ ** are also excluded. See codeCursorHintIsOrFunction() for details.
+ */
+ if( pTabItem->fg.jointype & JT_LEFT ){
+ Expr *pExpr = pTerm->pExpr;
+ if( !ExprHasProperty(pExpr, EP_FromJoin)
+ || pExpr->iRightJoinTable!=pTabItem->iCursor
+ ){
+ sWalker.eCode = 0;
+ sWalker.xExprCallback = codeCursorHintIsOrFunction;
+ sqlite3WalkExpr(&sWalker, pTerm->pExpr);
+ if( sWalker.eCode ) continue;
+ }
+ }else{
+ if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
+ }
/* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
** the cursor. These terms are not needed as hints for a pure range
@@ -120888,7 +126408,7 @@ static void codeCursorHint(
}
}
#else
-# define codeCursorHint(A,B,C) /* No-op */
+# define codeCursorHint(A,B,C,D) /* No-op */
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
/*
@@ -120922,7 +126442,7 @@ static void codeDeferredSeek(
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
sqlite3VdbeAddOp3(v, OP_Seek, iIdxCur, 0, iCur);
- if( (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)
+ if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
){
int i;
@@ -120940,6 +126460,39 @@ static void codeDeferredSeek(
}
/*
+** If the expression passed as the second argument is a vector, generate
+** code to write the first nReg elements of the vector into an array
+** of registers starting with iReg.
+**
+** If the expression is not a vector, then nReg must be passed 1. In
+** this case, generate code to evaluate the expression and leave the
+** result in register iReg.
+*/
+static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
+ assert( nReg>0 );
+ if( sqlite3ExprIsVector(p) ){
+#ifndef SQLITE_OMIT_SUBQUERY
+ if( (p->flags & EP_xIsSelect) ){
+ Vdbe *v = pParse->pVdbe;
+ int iSelect = sqlite3CodeSubselect(pParse, p, 0, 0);
+ sqlite3VdbeAddOp3(v, OP_Copy, iSelect, iReg, nReg-1);
+ }else
+#endif
+ {
+ int i;
+ ExprList *pList = p->x.pList;
+ assert( nReg<=pList->nExpr );
+ for(i=0; i<nReg; i++){
+ sqlite3ExprCode(pParse, pList->a[i].pExpr, iReg+i);
+ }
+ }
+ }else{
+ assert( nReg==1 );
+ sqlite3ExprCode(pParse, p, iReg);
+ }
+}
+
+/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
*/
@@ -120977,7 +126530,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
- && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
+ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
/* Create labels for the "break" and "continue" instructions
@@ -121021,6 +126574,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int iReg; /* P3 Value for OP_VFilter */
int addrNotFound;
int nConstraint = pLoop->nLTerm;
+ int iIn; /* Counter for IN constraints */
sqlite3ExprCachePush(pParse);
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
@@ -121028,30 +126582,73 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
for(j=0; j<nConstraint; j++){
int iTarget = iReg+j+2;
pTerm = pLoop->aLTerm[j];
- if( pTerm==0 ) continue;
+ if( NEVER(pTerm==0) ) continue;
if( pTerm->eOperator & WO_IN ){
codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
addrNotFound = pLevel->addrNxt;
}else{
- sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
+ Expr *pRight = pTerm->pExpr->pRight;
+ codeExprOrVector(pParse, pRight, iTarget, 1);
}
}
sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1);
sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg,
pLoop->u.vtab.idxStr,
- pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC);
+ pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC);
VdbeCoverage(v);
pLoop->u.vtab.needFree = 0;
- for(j=0; j<nConstraint && j<16; j++){
- if( (pLoop->u.vtab.omitMask>>j)&1 ){
- disableTerm(pLevel, pLoop->aLTerm[j]);
- }
- }
pLevel->p1 = iCur;
pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext;
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
- sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
+ iIn = pLevel->u.in.nIn;
+ for(j=nConstraint-1; j>=0; j--){
+ pTerm = pLoop->aLTerm[j];
+ if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){
+ disableTerm(pLevel, pTerm);
+ }else if( (pTerm->eOperator & WO_IN)!=0 ){
+ Expr *pCompare; /* The comparison operator */
+ Expr *pRight; /* RHS of the comparison */
+ VdbeOp *pOp; /* Opcode to access the value of the IN constraint */
+
+ /* Reload the constraint value into reg[iReg+j+2]. The same value
+ ** was loaded into the same register prior to the OP_VFilter, but
+ ** the xFilter implementation might have changed the datatype or
+ ** encoding of the value in the register, so it *must* be reloaded. */
+ assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed );
+ if( !db->mallocFailed ){
+ assert( iIn>0 );
+ pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[--iIn].addrInTop);
+ assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid );
+ assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 );
+ assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 );
+ testcase( pOp->opcode==OP_Rowid );
+ sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
+ }
+
+ /* Generate code that will continue to the next row if
+ ** the IN constraint is not satisfied */
+ pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0);
+ assert( pCompare!=0 || db->mallocFailed );
+ if( pCompare ){
+ pCompare->pLeft = pTerm->pExpr->pLeft;
+ pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
+ if( pRight ){
+ pRight->iTable = iReg+j+2;
+ sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
+ }
+ pCompare->pLeft = 0;
+ sqlite3ExprDelete(db, pCompare);
+ }
+ }
+ }
+ /* These registers need to be preserved in case there is an IN operator
+ ** loop. So we could deallocate the registers here (and potentially
+ ** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems
+ ** simpler and safer to simply not reuse the registers.
+ **
+ ** sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2);
+ */
sqlite3ExprCachePop(pParse);
}else
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -121074,8 +126671,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
addrNxt = pLevel->addrNxt;
- sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v);
- sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
VdbeCoverage(v);
sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
@@ -121102,10 +126698,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
pStart = pEnd;
pEnd = pTerm;
}
- codeCursorHint(pWInfo, pLevel, pEnd);
+ codeCursorHint(pTabItem, pWInfo, pLevel, pEnd);
if( pStart ){
Expr *pX; /* The expression that defines the start bound */
int r1, rTemp; /* Registers for holding the start boundary */
+ int op; /* Cursor seek operation */
/* The following constant maps TK_xx codes into corresponding
** seek opcodes. It depends on a particular ordering of TK_xx
@@ -121125,8 +126722,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
pX = pStart->pExpr;
assert( pX!=0 );
testcase( pStart->leftCursor!=iCur ); /* transitive constraints */
- r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
- sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1);
+ if( sqlite3ExprIsVector(pX->pRight) ){
+ r1 = rTemp = sqlite3GetTempReg(pParse);
+ codeExprOrVector(pParse, pX->pRight, r1, 1);
+ op = aMoveOp[(pX->op - TK_GT) | 0x0001];
+ }else{
+ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp);
+ disableTerm(pLevel, pStart);
+ op = aMoveOp[(pX->op - TK_GT)];
+ }
+ sqlite3VdbeAddOp3(v, op, iCur, addrBrk, r1);
VdbeComment((v, "pk"));
VdbeCoverageIf(v, pX->op==TK_GT);
VdbeCoverageIf(v, pX->op==TK_LE);
@@ -121134,7 +126739,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
VdbeCoverageIf(v, pX->op==TK_GE);
sqlite3ExprCacheAffinityChange(pParse, r1, 1);
sqlite3ReleaseTempReg(pParse, rTemp);
- disableTerm(pLevel, pStart);
}else{
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk);
VdbeCoverageIf(v, bRev==0);
@@ -121148,13 +126752,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */
testcase( pEnd->wtFlags & TERM_VIRTUAL );
memEndValue = ++pParse->nMem;
- sqlite3ExprCode(pParse, pX->pRight, memEndValue);
- if( pX->op==TK_LT || pX->op==TK_GT ){
+ codeExprOrVector(pParse, pX->pRight, memEndValue, 1);
+ if( 0==sqlite3ExprIsVector(pX->pRight)
+ && (pX->op==TK_LT || pX->op==TK_GT)
+ ){
testOp = bRev ? OP_Le : OP_Ge;
}else{
testOp = bRev ? OP_Lt : OP_Gt;
}
- disableTerm(pLevel, pEnd);
+ if( 0==sqlite3ExprIsVector(pX->pRight) ){
+ disableTerm(pLevel, pEnd);
+ }
}
start = sqlite3VdbeCurrentAddr(v);
pLevel->op = bRev ? OP_Prev : OP_Next;
@@ -121221,6 +126829,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */
};
u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */
+ u16 nBtm = pLoop->u.btree.nBtm; /* Length of BTM vector */
+ u16 nTop = pLoop->u.btree.nTop; /* Length of TOP vector */
int regBase; /* Base register holding constraint values */
WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */
WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */
@@ -121233,7 +126843,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
int nExtraReg = 0; /* Number of extra registers needed */
int op; /* Instruction opcode */
char *zStartAff; /* Affinity for start of range constraint */
- char cEndAff = 0; /* Affinity for end of range constraint */
+ char *zEndAff = 0; /* Affinity for end of range constraint */
u8 bSeekPastNull = 0; /* True to seek past initial nulls */
u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */
@@ -121267,33 +126877,36 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
j = nEq;
if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
pRangeStart = pLoop->aLTerm[j++];
- nExtraReg = 1;
+ nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm);
/* Like optimization range constraints always occur in pairs */
assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
(pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
}
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
pRangeEnd = pLoop->aLTerm[j++];
- nExtraReg = 1;
+ nExtraReg = MAX(nExtraReg, pLoop->u.btree.nTop);
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
if( (pRangeEnd->wtFlags & TERM_LIKEOPT)!=0 ){
assert( pRangeStart!=0 ); /* LIKE opt constraints */
assert( pRangeStart->wtFlags & TERM_LIKEOPT ); /* occur in pairs */
- pLevel->iLikeRepCntr = ++pParse->nMem;
- testcase( bRev );
- testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
- sqlite3VdbeAddOp2(v, OP_Integer,
- bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC),
- pLevel->iLikeRepCntr);
+ pLevel->iLikeRepCntr = (u32)++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, (int)pLevel->iLikeRepCntr);
VdbeComment((v, "LIKE loop counter"));
pLevel->addrLikeRep = sqlite3VdbeCurrentAddr(v);
+ /* iLikeRepCntr actually stores 2x the counter register number. The
+ ** bottom bit indicates whether the search order is ASC or DESC. */
+ testcase( bRev );
+ testcase( pIdx->aSortOrder[nEq]==SQLITE_SO_DESC );
+ assert( (bRev & ~1)==0 );
+ pLevel->iLikeRepCntr <<=1;
+ pLevel->iLikeRepCntr |= bRev ^ (pIdx->aSortOrder[nEq]==SQLITE_SO_DESC);
}
#endif
- if( pRangeStart==0
- && (j = pIdx->aiColumn[nEq])>=0
- && pIdx->pTable->aCol[j].notNull==0
- ){
- bSeekPastNull = 1;
+ if( pRangeStart==0 ){
+ j = pIdx->aiColumn[nEq];
+ if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){
+ bSeekPastNull = 1;
+ }
}
}
assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
@@ -121307,16 +126920,19 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
){
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
SWAP(u8, bSeekPastNull, bStopAtNull);
+ SWAP(u8, nBtm, nTop);
}
/* Generate code to evaluate all constraint terms using == or IN
** and store the values of those terms in an array of registers
** starting at regBase.
*/
- codeCursorHint(pWInfo, pLevel, pRangeEnd);
+ codeCursorHint(pTabItem, pWInfo, pLevel, pRangeEnd);
regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
- if( zStartAff ) cEndAff = zStartAff[nEq];
+ if( zStartAff && nTop ){
+ zEndAff = sqlite3DbStrDup(db, &zStartAff[nEq]);
+ }
addrNxt = pLevel->addrNxt;
testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 );
@@ -121331,7 +126947,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
nConstraint = nEq;
if( pRangeStart ){
Expr *pRight = pRangeStart->pExpr->pRight;
- sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ codeExprOrVector(pParse, pRight, regBase+nEq, nBtm);
whereLikeOptimizationStringFixup(v, pLevel, pRangeStart);
if( (pRangeStart->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
@@ -121340,18 +126956,16 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
VdbeCoverage(v);
}
if( zStartAff ){
- if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_BLOB){
- /* Since the comparison is to be performed with no conversions
- ** applied to the operands, set the affinity to apply to pRight to
- ** SQLITE_AFF_BLOB. */
- zStartAff[nEq] = SQLITE_AFF_BLOB;
- }
- if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){
- zStartAff[nEq] = SQLITE_AFF_BLOB;
- }
+ updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]);
}
- nConstraint++;
+ nConstraint += nBtm;
testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
+ if( sqlite3ExprIsVector(pRight)==0 ){
+ disableTerm(pLevel, pRangeStart);
+ }else{
+ startEq = 1;
+ }
+ bSeekPastNull = 0;
}else if( bSeekPastNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
nConstraint++;
@@ -121359,16 +126973,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
start_constraints = 1;
}
codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff);
- op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
- assert( op!=0 );
- sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
- VdbeCoverage(v);
- VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
- VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
- VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT );
- VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
- VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
- VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
+ if( pLoop->nSkip>0 && nConstraint==pLoop->nSkip ){
+ /* The skip-scan logic inside the call to codeAllEqualityConstraints()
+ ** above has already left the cursor sitting on the correct row,
+ ** so no further seeking is needed */
+ }else{
+ op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
+ assert( op!=0 );
+ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
+ VdbeCoverage(v);
+ VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
+ VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last );
+ VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT );
+ VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE );
+ VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE );
+ VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT );
+ }
/* Load the value for the inequality constraint at the end of the
** range (if any).
@@ -121377,7 +126997,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
- sqlite3ExprCode(pParse, pRight, regBase+nEq);
+ codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
&& sqlite3ExprCanBeNull(pRight)
@@ -121385,19 +127005,27 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
VdbeCoverage(v);
}
- if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_BLOB
- && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff)
- ){
- codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff);
+ if( zEndAff ){
+ updateRangeAffinityStr(pRight, nTop, zEndAff);
+ codeApplyAffinity(pParse, regBase+nEq, nTop, zEndAff);
+ }else{
+ assert( pParse->db->mallocFailed );
}
- nConstraint++;
+ nConstraint += nTop;
testcase( pRangeEnd->wtFlags & TERM_VIRTUAL );
+
+ if( sqlite3ExprIsVector(pRight)==0 ){
+ disableTerm(pLevel, pRangeEnd);
+ }else{
+ endEq = 1;
+ }
}else if( bStopAtNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
endEq = 0;
nConstraint++;
}
sqlite3DbFree(db, zStartAff);
+ sqlite3DbFree(db, zEndAff);
/* Top of the loop body */
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
@@ -121413,12 +127041,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
/* Seek the table cursor, if required */
- disableTerm(pLevel, pRangeStart);
- disableTerm(pLevel, pRangeEnd);
if( omitTable ){
/* pIdx is a covering index. No need to access the main table. */
}else if( HasRowid(pIdx->pTable) ){
- if( pWInfo->eOnePass!=ONEPASS_OFF ){
+ if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)!=0 ){
iRowidReg = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
@@ -121438,9 +127064,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
}
- /* Record the instruction used to terminate the loop. Disable
- ** WHERE clause terms made redundant by the index range scan.
- */
+ /* Record the instruction used to terminate the loop. */
if( pLoop->wsFlags & WHERE_ONEROW ){
pLevel->op = OP_Noop;
}else if( bRev ){
@@ -121517,7 +127141,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
u16 wctrlFlags; /* Flags for sub-WHERE clause */
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
Table *pTab = pTabItem->pTab;
-
+
pTerm = pLoop->aLTerm[0];
assert( pTerm!=0 );
assert( pTerm->eOperator & WO_OR );
@@ -121603,7 +127227,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
}
if( pAndExpr ){
- pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr, 0);
+ pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr);
}
}
@@ -121611,10 +127235,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** eliminating duplicates from other WHERE clauses, the action for each
** sub-WHERE clause is to to invoke the main loop body as a subroutine.
*/
- wctrlFlags = WHERE_OMIT_OPEN_CLOSE
- | WHERE_FORCE_TABLE
- | WHERE_ONETABLE_ONLY
- | WHERE_NO_AUTOINDEX;
+ wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE);
for(ii=0; ii<pOrWc->nTerm; ii++){
WhereTerm *pOrTerm = &pOrWc->a[ii];
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
@@ -121679,7 +127300,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
}
if( iSet>=0 ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid);
- sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid,
+ r, nPk);
if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
}
@@ -121722,7 +127344,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
){
assert( pSubWInfo->a[0].iIdxCur==iCovCur );
pCov = pSubLoop->u.btree.pIndex;
- wctrlFlags |= WHERE_REOPEN_IDX;
}else{
pCov = 0;
}
@@ -121759,7 +127380,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** a pseudo-cursor. No need to Rewind or Next such cursors. */
pLevel->op = OP_Noop;
}else{
- codeCursorHint(pWInfo, pLevel, 0);
+ codeCursorHint(pTabItem, pWInfo, pLevel, 0);
pLevel->op = aStep[bRev];
pLevel->p1 = iCur;
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
@@ -121784,7 +127405,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
testcase( pWInfo->untestedTerms==0
- && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
+ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 );
pWInfo->untestedTerms = 1;
continue;
}
@@ -121794,11 +127415,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
continue;
}
if( pTerm->wtFlags & TERM_LIKECOND ){
+ /* If the TERM_LIKECOND flag is set, that means that the range search
+ ** is sufficient to guarantee that the LIKE operator is true, so we
+ ** can skip the call to the like(A,B) function. But this only works
+ ** for strings. So do not skip the call to the function on the pass
+ ** that compares BLOBs. */
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
continue;
#else
- assert( pLevel->iLikeRepCntr>0 );
- skipLikeAddr = sqlite3VdbeAddOp1(v, OP_IfNot, pLevel->iLikeRepCntr);
+ u32 x = pLevel->iLikeRepCntr;
+ assert( x>0 );
+ skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)? OP_IfNot : OP_If, (int)(x>>1));
VdbeCoverage(v);
#endif
}
@@ -121816,7 +127443,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** the implied "t1.a=123" constraint.
*/
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
- Expr *pE, *pEAlt;
+ Expr *pE, sEAlt;
WhereTerm *pAlt;
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
@@ -121834,13 +127461,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
testcase( pAlt->eOperator & WO_IS );
testcase( pAlt->eOperator & WO_IN );
VdbeModuleComment((v, "begin transitive constraint"));
- pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt));
- if( pEAlt ){
- *pEAlt = *pAlt->pExpr;
- pEAlt->pLeft = pE->pLeft;
- sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL);
- sqlite3StackFree(db, pEAlt);
- }
+ sEAlt = *pAlt->pExpr;
+ sEAlt.pLeft = pE->pLeft;
+ sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL);
}
/* For a LEFT OUTER JOIN, generate code that will record the fact that
@@ -121949,7 +127572,6 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
sqlite3DbFree(db, pOld);
}
pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
- memset(&pWC->a[pWC->nTerm], 0, sizeof(pWC->a[0])*(pWC->nSlot-pWC->nTerm));
}
pTerm = &pWC->a[idx = pWC->nTerm++];
if( p && ExprHasProperty(p, EP_Unlikely) ){
@@ -121961,13 +127583,15 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
pTerm->wtFlags = wtFlags;
pTerm->pWC = pWC;
pTerm->iParent = -1;
+ memset(&pTerm->eOperator, 0,
+ sizeof(WhereTerm) - offsetof(WhereTerm,eOperator));
return idx;
}
/*
** Return TRUE if the given operator is one of the operators that is
** allowed for an indexable WHERE clause term. The allowed operators are
-** "=", "<", ">", "<=", ">=", "IN", and "IS NULL"
+** "=", "<", ">", "<=", ">=", "IN", "IS", and "IS NULL"
*/
static int allowedOp(int op){
assert( TK_GT>TK_EQ && TK_GT<TK_GE );
@@ -122162,7 +127786,7 @@ static int isMatchOfColumn(
Expr *pExpr, /* Test this expression */
unsigned char *peOp2 /* OUT: 0 for MATCH, or else an op2 value */
){
- struct Op2 {
+ static const struct Op2 {
const char *zOp;
unsigned char eOp2;
} aOp[] = {
@@ -122405,6 +128029,7 @@ static void exprAnalyzeOrTerm(
if( pOrInfo==0 ) return;
pTerm->wtFlags |= TERM_ORINFO;
pOrWc = &pOrInfo->wc;
+ memset(pOrWc->aStatic, 0, sizeof(pOrWc->aStatic));
sqlite3WhereClauseInit(pOrWc, pWInfo);
sqlite3WhereSplit(pOrWc, pExpr, TK_OR);
sqlite3WhereExprAnalyze(pSrc, pOrWc);
@@ -122431,6 +128056,7 @@ static void exprAnalyzeOrTerm(
pOrTerm->wtFlags |= TERM_ANDINFO;
pOrTerm->eOperator = WO_AND;
pAndWC = &pAndInfo->wc;
+ memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic));
sqlite3WhereClauseInit(pAndWC, pWC->pWInfo);
sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND);
sqlite3WhereExprAnalyze(pSrc, pAndWC);
@@ -122438,7 +128064,9 @@ static void exprAnalyzeOrTerm(
if( !db->mallocFailed ){
for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
assert( pAndTerm->pExpr );
- if( allowedOp(pAndTerm->pExpr->op) ){
+ if( allowedOp(pAndTerm->pExpr->op)
+ || pAndTerm->eOperator==WO_MATCH
+ ){
b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
}
}
@@ -122601,7 +128229,7 @@ static void exprAnalyzeOrTerm(
}
assert( pLeft!=0 );
pDup = sqlite3ExprDup(db, pLeft, 0);
- pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0, 0);
+ pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0);
if( pNew ){
int idxNew;
transferJoinMarkings(pNew, pExpr);
@@ -122653,12 +128281,10 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1;
pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
- /* Since pLeft and pRight are both a column references, their collating
- ** sequence should always be defined. */
- zColl1 = ALWAYS(pColl) ? pColl->zName : 0;
+ zColl1 = pColl ? pColl->zName : 0;
pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight);
- zColl2 = ALWAYS(pColl) ? pColl->zName : 0;
- return sqlite3StrICmp(zColl1, zColl2)==0;
+ zColl2 = pColl ? pColl->zName : 0;
+ return sqlite3_stricmp(zColl1, zColl2)==0;
}
/*
@@ -122693,7 +128319,8 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
** in any index. Return TRUE (1) if pExpr is an indexed term and return
** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor
** number of the table that is indexed and *piColumn to the column number
-** of the column that is indexed, or -2 if an expression is being indexed.
+** of the column that is indexed, or XN_EXPR (-2) if an expression is being
+** indexed.
**
** If pExpr is a TK_COLUMN column reference, then this routine always returns
** true even if that particular column is not indexed, because the column
@@ -122701,6 +128328,7 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
*/
static int exprMightBeIndexed(
SrcList *pFrom, /* The FROM clause */
+ int op, /* The specific comparison operator */
Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
Expr *pExpr, /* An operand of a comparison operator */
int *piCur, /* Write the referenced table cursor number here */
@@ -122709,6 +128337,17 @@ static int exprMightBeIndexed(
Index *pIdx;
int i;
int iCur;
+
+ /* If this expression is a vector to the left or right of a
+ ** inequality constraint (>, <, >= or <=), perform the processing
+ ** on the first element of the vector. */
+ assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE );
+ assert( TK_IS<TK_GE && TK_ISNULL<TK_GE && TK_IN<TK_GE );
+ assert( op<=TK_GE );
+ if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){
+ pExpr = pExpr->x.pList->a[0].pExpr;
+ }
+
if( pExpr->op==TK_COLUMN ){
*piCur = pExpr->iTable;
*piColumn = pExpr->iColumn;
@@ -122721,10 +128360,10 @@ static int exprMightBeIndexed(
for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr==0 ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
- if( pIdx->aiColumn[i]!=(-2) ) continue;
+ if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
*piCur = iCur;
- *piColumn = -2;
+ *piColumn = XN_EXPR;
return 1;
}
}
@@ -122781,6 +128420,7 @@ static void exprAnalyze(
op = pExpr->op;
if( op==TK_IN ){
assert( pExpr->pRight==0 );
+ if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
}else{
@@ -122807,18 +128447,26 @@ static void exprAnalyze(
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
- if( exprMightBeIndexed(pSrc, prereqLeft, pLeft, &iCur, &iColumn) ){
+
+ if( pTerm->iField>0 ){
+ assert( op==TK_IN );
+ assert( pLeft->op==TK_VECTOR );
+ pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
+ }
+
+ if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){
pTerm->leftCursor = iCur;
pTerm->u.leftColumn = iColumn;
pTerm->eOperator = operatorMask(op) & opMask;
}
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
if( pRight
- && exprMightBeIndexed(pSrc, pTerm->prereqRight, pRight, &iCur, &iColumn)
+ && exprMightBeIndexed(pSrc, op, pTerm->prereqRight, pRight, &iCur,&iColumn)
){
WhereTerm *pNew;
Expr *pDup;
u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
+ assert( pTerm->iField==0 );
if( pTerm->leftCursor>=0 ){
int idxNew;
pDup = sqlite3ExprDup(db, pExpr, 0);
@@ -122879,7 +128527,7 @@ static void exprAnalyze(
int idxNew;
pNewExpr = sqlite3PExpr(pParse, ops[i],
sqlite3ExprDup(db, pExpr->pLeft, 0),
- sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
+ sqlite3ExprDup(db, pList->a[i].pExpr, 0));
transferJoinMarkings(pNewExpr, pExpr);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
@@ -122964,7 +128612,7 @@ static void exprAnalyze(
pNewExpr1 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName),
- pStr1, 0);
+ pStr1);
transferJoinMarkings(pNewExpr1, pExpr);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
testcase( idxNew1==0 );
@@ -122972,7 +128620,7 @@ static void exprAnalyze(
pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
- pStr2, 0);
+ pStr2);
transferJoinMarkings(pNewExpr2, pExpr);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
testcase( idxNew2==0 );
@@ -122992,7 +128640,7 @@ static void exprAnalyze(
** virtual tables. The native query optimizer does not attempt
** to do anything with MATCH functions.
*/
- if( isMatchOfColumn(pExpr, &eOp2) ){
+ if( pWC->op==TK_AND && isMatchOfColumn(pExpr, &eOp2) ){
int idxNew;
Expr *pRight, *pLeft;
WhereTerm *pNewTerm;
@@ -123005,7 +128653,7 @@ static void exprAnalyze(
if( (prereqExpr & prereqColumn)==0 ){
Expr *pNewExpr;
pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
- 0, sqlite3ExprDup(db, pRight, 0), 0);
+ 0, sqlite3ExprDup(db, pRight, 0));
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
pNewTerm = &pWC->a[idxNew];
@@ -123022,6 +128670,60 @@ static void exprAnalyze(
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+ /* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create
+ ** new terms for each component comparison - "a = ?" and "b = ?". The
+ ** new terms completely replace the original vector comparison, which is
+ ** no longer used.
+ **
+ ** This is only required if at least one side of the comparison operation
+ ** is not a sub-select. */
+ if( pWC->op==TK_AND
+ && (pExpr->op==TK_EQ || pExpr->op==TK_IS)
+ && sqlite3ExprIsVector(pExpr->pLeft)
+ && ( (pExpr->pLeft->flags & EP_xIsSelect)==0
+ || (pExpr->pRight->flags & EP_xIsSelect)==0
+ )){
+ int nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
+ int i;
+ assert( nLeft==sqlite3ExprVectorSize(pExpr->pRight) );
+ for(i=0; i<nLeft; i++){
+ int idxNew;
+ Expr *pNew;
+ Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i);
+ Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i);
+
+ pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight);
+ transferJoinMarkings(pNew, pExpr);
+ idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC);
+ exprAnalyze(pSrc, pWC, idxNew);
+ }
+ pTerm = &pWC->a[idxTerm];
+ pTerm->wtFlags = TERM_CODED|TERM_VIRTUAL; /* Disable the original */
+ pTerm->eOperator = 0;
+ }
+
+ /* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create
+ ** a virtual term for each vector component. The expression object
+ ** used by each such virtual term is pExpr (the full vector IN(...)
+ ** expression). The WhereTerm.iField variable identifies the index within
+ ** the vector on the LHS that the virtual term represents.
+ **
+ ** This only works if the RHS is a simple SELECT, not a compound
+ */
+ if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
+ && pExpr->pLeft->op==TK_VECTOR
+ && pExpr->x.pSelect->pPrior==0
+ ){
+ int i;
+ for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
+ int idxNew;
+ idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL);
+ pWC->a[idxNew].iField = i+1;
+ exprAnalyze(pSrc, pWC, idxNew);
+ markTermAsChild(pWC, idxNew, idxTerm);
+ }
+ }
+
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/* When sqlite_stat3 histogram data is available an operator of the
** form "x IS NOT NULL" can sometimes be evaluated more efficiently
@@ -123042,7 +128744,7 @@ static void exprAnalyze(
pNewExpr = sqlite3PExpr(pParse, TK_GT,
sqlite3ExprDup(db, pLeft, 0),
- sqlite3PExpr(pParse, TK_NULL, 0, 0, 0), 0);
+ sqlite3ExprAlloc(db, TK_NULL, 0, 0));
idxNew = whereClauseInsert(pWC, pNewExpr,
TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL);
@@ -123063,6 +128765,8 @@ static void exprAnalyze(
/* Prevent ON clause terms of a LEFT JOIN from being used to drive
** an index for tables to the left of the join.
*/
+ testcase( pTerm!=&pWC->a[idxTerm] );
+ pTerm = &pWC->a[idxTerm];
pTerm->prereqRight |= extraRight;
}
@@ -123145,17 +128849,18 @@ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
** tree.
*/
SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
- Bitmask mask = 0;
+ Bitmask mask;
if( p==0 ) return 0;
if( p->op==TK_COLUMN ){
mask = sqlite3WhereGetMask(pMaskSet, p->iTable);
return mask;
}
- mask = sqlite3WhereExprUsage(pMaskSet, p->pRight);
- mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
+ assert( !ExprHasProperty(p, EP_TokenOnly) );
+ mask = p->pRight ? sqlite3WhereExprUsage(pMaskSet, p->pRight) : 0;
+ if( p->pLeft ) mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft);
if( ExprHasProperty(p, EP_xIsSelect) ){
mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
- }else{
+ }else if( p->x.pList ){
mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
}
return mask;
@@ -123219,13 +128924,13 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
pTab->zName, j);
return;
}
- pColRef = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
+ pColRef = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
if( pColRef==0 ) return;
pColRef->iTable = pItem->iCursor;
pColRef->iColumn = k++;
pColRef->pTab = pTab;
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef,
- sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
+ sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0));
whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
}
}
@@ -123265,8 +128970,8 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int);
/*
** Return the estimated number of output rows from a WHERE clause
*/
-SQLITE_PRIVATE u64 sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
- return sqlite3LogEstToInt(pWInfo->nRowOut);
+SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
+ return pWInfo->nRowOut;
}
/*
@@ -123286,6 +128991,18 @@ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
}
/*
+** Return TRUE if the innermost loop of the WHERE clause implementation
+** returns rows in ORDER BY order for complete run of the inner loop.
+**
+** Across multiple iterations of outer loops, the output rows need not be
+** sorted. As long as rows are sorted for just the innermost loop, this
+** routine can return TRUE.
+*/
+SQLITE_PRIVATE int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){
+ return pWInfo->bOrderedInnerLoop;
+}
+
+/*
** Return the VDBE address or label to jump to in order to continue
** immediately with the next row of a WHERE clause.
*/
@@ -123420,11 +129137,13 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
WhereTerm *pTerm; /* The term being tested */
int k = pScan->k; /* Where to start scanning */
- while( pScan->iEquiv<=pScan->nEquiv ){
- iCur = pScan->aiCur[pScan->iEquiv-1];
+ assert( pScan->iEquiv<=pScan->nEquiv );
+ pWC = pScan->pWC;
+ while(1){
iColumn = pScan->aiColumn[pScan->iEquiv-1];
- if( iColumn==XN_EXPR && pScan->pIdxExpr==0 ) return 0;
- while( (pWC = pScan->pWC)!=0 ){
+ iCur = pScan->aiCur[pScan->iEquiv-1];
+ assert( pWC!=0 );
+ do{
for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
if( pTerm->leftCursor==iCur
&& pTerm->u.leftColumn==iColumn
@@ -123474,15 +129193,17 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
testcase( pTerm->eOperator & WO_IS );
continue;
}
+ pScan->pWC = pWC;
pScan->k = k+1;
return pTerm;
}
}
}
- pScan->pWC = pScan->pWC->pOuter;
+ pWC = pWC->pOuter;
k = 0;
- }
- pScan->pWC = pScan->pOrigWC;
+ }while( pWC!=0 );
+ if( pScan->iEquiv>=pScan->nEquiv ) break;
+ pWC = pScan->pOrigWC;
k = 0;
pScan->iEquiv++;
}
@@ -123495,7 +129216,10 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
**
** The scanner will be searching the WHERE clause pWC. It will look
** for terms of the form "X <op> <expr>" where X is column iColumn of table
-** iCur. The <op> must be one of the operators described by opMask.
+** iCur. Or if pIdx!=0 then X is column iColumn of index pIdx. pIdx
+** must be one of the indexes of table iCur.
+**
+** The <op> must be one of the operators described by opMask.
**
** If the search is for X and the WHERE clause contains terms of the
** form X=Y then this routine might also return terms of the form
@@ -123513,23 +129237,24 @@ static WhereTerm *whereScanInit(
u32 opMask, /* Operator(s) to scan for */
Index *pIdx /* Must be compatible with this index */
){
- int j = 0;
-
- /* memset(pScan, 0, sizeof(*pScan)); */
pScan->pOrigWC = pWC;
pScan->pWC = pWC;
pScan->pIdxExpr = 0;
+ pScan->idxaff = 0;
+ pScan->zCollName = 0;
if( pIdx ){
- j = iColumn;
+ int j = iColumn;
iColumn = pIdx->aiColumn[j];
- if( iColumn==XN_EXPR ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
- }
- if( pIdx && iColumn>=0 ){
- pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
- pScan->zCollName = pIdx->azColl[j];
- }else{
- pScan->idxaff = 0;
- pScan->zCollName = 0;
+ if( iColumn==XN_EXPR ){
+ pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
+ }else if( iColumn==pIdx->pTable->iPKey ){
+ iColumn = XN_ROWID;
+ }else if( iColumn>=0 ){
+ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
+ pScan->zCollName = pIdx->azColl[j];
+ }
+ }else if( iColumn==XN_EXPR ){
+ return 0;
}
pScan->opMask = opMask;
pScan->k = 0;
@@ -123542,11 +129267,12 @@ static WhereTerm *whereScanInit(
/*
** Search for a term in the WHERE clause that is of the form "X <op> <expr>"
-** where X is a reference to the iColumn of table iCur and <op> is one of
-** the WO_xx operator codes specified by the op parameter.
-** Return a pointer to the term. Return 0 if not found.
+** where X is a reference to the iColumn of table iCur or of index pIdx
+** if pIdx!=0 and <op> is one of the WO_xx operator codes specified by
+** the op parameter. Return a pointer to the term. Return 0 if not found.
**
-** If pIdx!=0 then search for terms matching the iColumn-th column of pIdx
+** If pIdx!=0 then it must be one of the indexes of table iCur.
+** Search for terms matching the iColumn-th column of pIdx
** rather than the iColumn-th column of table iCur.
**
** The term returned might by Y=<expr> if there is another constraint in
@@ -123868,7 +129594,7 @@ static void constructAutomaticIndex(
** transient index on 2nd and subsequent iterations of the loop. */
v = pParse->pVdbe;
assert( v!=0 );
- addrInit = sqlite3CodeOnce(pParse); VdbeCoverage(v);
+ addrInit = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
@@ -124043,7 +129769,8 @@ static sqlite3_index_info *allocateIndexInfo(
WhereClause *pWC,
Bitmask mUnusable, /* Ignore terms with these prereqs */
struct SrcList_item *pSrc,
- ExprList *pOrderBy
+ ExprList *pOrderBy,
+ u16 *pmNoOmit /* Mask of terms not to omit */
){
int i, j;
int nTerm;
@@ -124053,6 +129780,7 @@ static sqlite3_index_info *allocateIndexInfo(
WhereTerm *pTerm;
int nOrderBy;
sqlite3_index_info *pIdxInfo;
+ u16 mNoOmit = 0;
/* Count the number of possible WHERE clause constraints referring
** to this virtual table */
@@ -124141,6 +129869,15 @@ static sqlite3_index_info *allocateIndexInfo(
assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE );
assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH );
assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) );
+
+ if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
+ && sqlite3ExprIsVector(pTerm->pExpr->pRight)
+ ){
+ if( i<16 ) mNoOmit |= (1 << i);
+ if( op==WO_LT ) pIdxCons[j].op = WO_LE;
+ if( op==WO_GT ) pIdxCons[j].op = WO_GE;
+ }
+
j++;
}
for(i=0; i<nOrderBy; i++){
@@ -124149,6 +129886,7 @@ static sqlite3_index_info *allocateIndexInfo(
pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder;
}
+ *pmNoOmit = mNoOmit;
return pIdxInfo;
}
@@ -124168,7 +129906,6 @@ static sqlite3_index_info *allocateIndexInfo(
*/
static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3_vtab *pVtab = sqlite3GetVTable(pParse->db, pTab)->pVtab;
- int i;
int rc;
TRACE_IDX_INPUTS(p);
@@ -124187,12 +129924,16 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
+#if 0
+ /* This error is now caught by the caller.
+ ** Search for "xBestIndex malfunction" below */
for(i=0; i<p->nConstraint; i++){
if( !p->aConstraint[i].usable && p->aConstraintUsage[i].argvIndex>0 ){
sqlite3ErrorMsg(pParse,
"table %s: xBestIndex returned an invalid plan", pTab->zName);
}
}
+#endif
return pParse->nErr;
}
@@ -124421,7 +130162,7 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){
/*
** Return the affinity for a single column of an index.
*/
-static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){
+SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){
assert( iCol>=0 && iCol<pIdx->nColumn );
if( !pIdx->zColAff ){
if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB;
@@ -124598,7 +130339,8 @@ static int whereRangeScanEst(
if( nEq==pBuilder->nRecValid ){
UnpackedRecord *pRec = pBuilder->pRec;
tRowcnt a[2];
- u8 aff;
+ int nBtm = pLoop->u.btree.nBtm;
+ int nTop = pLoop->u.btree.nTop;
/* Variable iLower will be set to the estimate of the number of rows in
** the index that are less than the lower bound of the range query. The
@@ -124628,8 +130370,6 @@ static int whereRangeScanEst(
testcase( pRec->nField!=pBuilder->nRecValid );
pRec->nField = pBuilder->nRecValid;
}
- aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq);
- assert( nEq!=p->nKeyCol || aff==SQLITE_AFF_INTEGER );
/* Determine iLower and iUpper using ($P) only. */
if( nEq==0 ){
iLower = 0;
@@ -124648,17 +130388,20 @@ static int whereRangeScanEst(
if( p->aSortOrder[nEq] ){
/* The roles of pLower and pUpper are swapped for a DESC index */
SWAP(WhereTerm*, pLower, pUpper);
+ SWAP(int, nBtm, nTop);
}
/* If possible, improve on the iLower estimate using ($P:$L). */
if( pLower ){
- int bOk; /* True if value is extracted from pExpr */
+ int n; /* Values extracted from pExpr */
Expr *pExpr = pLower->pExpr->pRight;
- rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
- if( rc==SQLITE_OK && bOk ){
+ rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nBtm, nEq, &n);
+ if( rc==SQLITE_OK && n ){
tRowcnt iNew;
+ u16 mask = WO_GT|WO_LE;
+ if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT);
iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a);
- iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
+ iNew = a[0] + ((pLower->eOperator & mask) ? a[1] : 0);
if( iNew>iLower ) iLower = iNew;
nOut--;
pLower = 0;
@@ -124667,13 +130410,15 @@ static int whereRangeScanEst(
/* If possible, improve on the iUpper estimate using ($P:$U). */
if( pUpper ){
- int bOk; /* True if value is extracted from pExpr */
+ int n; /* Values extracted from pExpr */
Expr *pExpr = pUpper->pExpr->pRight;
- rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
- if( rc==SQLITE_OK && bOk ){
+ rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nTop, nEq, &n);
+ if( rc==SQLITE_OK && n ){
tRowcnt iNew;
+ u16 mask = WO_GT|WO_LE;
+ if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT);
iUprIdx = whereKeyStats(pParse, p, pRec, 1, a);
- iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
+ iNew = a[0] + ((pUpper->eOperator & mask) ? a[1] : 0);
if( iNew<iUpper ) iUpper = iNew;
nOut--;
pUpper = 0;
@@ -124763,7 +130508,6 @@ static int whereEqualScanEst(
Index *p = pBuilder->pNew->u.btree.pIndex;
int nEq = pBuilder->pNew->u.btree.nEq;
UnpackedRecord *pRec = pBuilder->pRec;
- u8 aff; /* Column affinity */
int rc; /* Subfunction return code */
tRowcnt a[2]; /* Statistics */
int bOk;
@@ -124787,15 +130531,15 @@ static int whereEqualScanEst(
return SQLITE_OK;
}
- aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq-1);
- rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk);
+ rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, 1, nEq-1, &bOk);
pBuilder->pRec = pRec;
if( rc!=SQLITE_OK ) return rc;
if( bOk==0 ) return SQLITE_NOTFOUND;
pBuilder->nRecValid = nEq;
whereKeyStats(pParse, p, pRec, 0, a);
- WHERETRACE(0x10,("equality scan regions: %d\n", (int)a[1]));
+ WHERETRACE(0x10,("equality scan regions %s(%d): %d\n",
+ p->zName, nEq-1, (int)a[1]));
*pnRow = a[1];
return rc;
@@ -124861,14 +130605,29 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm);
}else{
char zType[4];
+ char zLeft[50];
memcpy(zType, "...", 4);
if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E';
if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
+ if( pTerm->eOperator & WO_SINGLE ){
+ sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
+ pTerm->leftCursor, pTerm->u.leftColumn);
+ }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){
+ sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld",
+ pTerm->u.pOrInfo->indexable);
+ }else{
+ sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor);
+ }
sqlite3DebugPrintf(
- "TERM-%-3d %p %s cursor=%-3d prob=%-3d op=0x%03x wtFlags=0x%04x\n",
- iTerm, pTerm, zType, pTerm->leftCursor, pTerm->truthProb,
+ "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x",
+ iTerm, pTerm, zType, zLeft, pTerm->truthProb,
pTerm->eOperator, pTerm->wtFlags);
+ if( pTerm->iField ){
+ sqlite3DebugPrintf(" iField=%d\n", pTerm->iField);
+ }else{
+ sqlite3DebugPrintf("\n");
+ }
sqlite3TreeViewExpr(0, pTerm->pExpr, 0);
}
}
@@ -124876,15 +130635,28 @@ static void whereTermPrint(WhereTerm *pTerm, int iTerm){
#ifdef WHERETRACE_ENABLED
/*
+** Show the complete content of a WhereClause
+*/
+SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
+ int i;
+ for(i=0; i<pWC->nTerm; i++){
+ whereTermPrint(&pWC->a[i], i);
+ }
+}
+#endif
+
+#ifdef WHERETRACE_ENABLED
+/*
** Print a WhereLoop object for debugging purposes
*/
static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
WhereInfo *pWInfo = pWC->pWInfo;
- int nb = 1+(pWInfo->pTabList->nSrc+7)/8;
+ int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
Table *pTab = pItem->pTab;
+ Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
- p->iTab, nb, p->maskSelf, nb, p->prereq);
+ p->iTab, nb, p->maskSelf, nb, p->prereq & mAll);
sqlite3DebugPrintf(" %12s",
pItem->zAlias ? pItem->zAlias : pTab->zName);
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
@@ -124970,7 +130742,7 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
if( p->nLSlot>=n ) return SQLITE_OK;
n = (n+7)&~7;
paNew = sqlite3DbMallocRawNN(db, sizeof(p->aLTerm[0])*n);
- if( paNew==0 ) return SQLITE_NOMEM;
+ if( paNew==0 ) return SQLITE_NOMEM_BKPT;
memcpy(paNew, p->aLTerm, sizeof(p->aLTerm[0])*p->nLSlot);
if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFree(db, p->aLTerm);
p->aLTerm = paNew;
@@ -124985,7 +130757,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
whereLoopClearUnion(db, pTo);
if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
memset(&pTo->u, 0, sizeof(pTo->u));
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ);
memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0]));
@@ -125209,6 +130981,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
WhereLoop **ppPrev, *p;
WhereInfo *pWInfo = pBuilder->pWInfo;
sqlite3 *db = pWInfo->pParse->db;
+ int rc;
/* If pBuilder->pOrSet is defined, then only keep track of the costs
** and prereqs.
@@ -125267,7 +131040,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
if( p==0 ){
/* Allocate a new WhereLoop to add to the end of the list */
*ppPrev = p = sqlite3DbMallocRawNN(db, sizeof(WhereLoop));
- if( p==0 ) return SQLITE_NOMEM;
+ if( p==0 ) return SQLITE_NOMEM_BKPT;
whereLoopInit(p);
p->pNextLoop = 0;
}else{
@@ -125291,14 +131064,14 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
whereLoopDelete(db, pToDel);
}
}
- whereLoopXfer(db, p, pTemplate);
+ rc = whereLoopXfer(db, p, pTemplate);
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
Index *pIndex = p->u.btree.pIndex;
if( pIndex && pIndex->tnum==0 ){
p->u.btree.pIndex = 0;
}
}
- return SQLITE_OK;
+ return rc;
}
/*
@@ -125376,6 +131149,72 @@ static void whereLoopOutputAdjust(
if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce;
}
+/*
+** Term pTerm is a vector range comparison operation. The first comparison
+** in the vector can be optimized using column nEq of the index. This
+** function returns the total number of vector elements that can be used
+** as part of the range comparison.
+**
+** For example, if the query is:
+**
+** WHERE a = ? AND (b, c, d) > (?, ?, ?)
+**
+** and the index:
+**
+** CREATE INDEX ... ON (a, b, c, d, e)
+**
+** then this function would be invoked with nEq=1. The value returned in
+** this case is 3.
+*/
+static int whereRangeVectorLen(
+ Parse *pParse, /* Parsing context */
+ int iCur, /* Cursor open on pIdx */
+ Index *pIdx, /* The index to be used for a inequality constraint */
+ int nEq, /* Number of prior equality constraints on same index */
+ WhereTerm *pTerm /* The vector inequality constraint */
+){
+ int nCmp = sqlite3ExprVectorSize(pTerm->pExpr->pLeft);
+ int i;
+
+ nCmp = MIN(nCmp, (pIdx->nColumn - nEq));
+ for(i=1; i<nCmp; i++){
+ /* Test if comparison i of pTerm is compatible with column (i+nEq)
+ ** of the index. If not, exit the loop. */
+ char aff; /* Comparison affinity */
+ char idxaff = 0; /* Indexed columns affinity */
+ CollSeq *pColl; /* Comparison collation sequence */
+ Expr *pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr;
+ Expr *pRhs = pTerm->pExpr->pRight;
+ if( pRhs->flags & EP_xIsSelect ){
+ pRhs = pRhs->x.pSelect->pEList->a[i].pExpr;
+ }else{
+ pRhs = pRhs->x.pList->a[i].pExpr;
+ }
+
+ /* Check that the LHS of the comparison is a column reference to
+ ** the right column of the right source table. And that the sort
+ ** order of the index column is the same as the sort order of the
+ ** leftmost index column. */
+ if( pLhs->op!=TK_COLUMN
+ || pLhs->iTable!=iCur
+ || pLhs->iColumn!=pIdx->aiColumn[i+nEq]
+ || pIdx->aSortOrder[i+nEq]!=pIdx->aSortOrder[nEq]
+ ){
+ break;
+ }
+
+ testcase( pLhs->iColumn==XN_ROWID );
+ aff = sqlite3CompareAffinity(pRhs, sqlite3ExprAffinity(pLhs));
+ idxaff = sqlite3TableColumnAffinity(pIdx->pTable, pLhs->iColumn);
+ if( aff!=idxaff ) break;
+
+ pColl = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
+ if( pColl==0 ) break;
+ if( sqlite3StrICmp(pColl->zName, pIdx->azColl[i+nEq]) ) break;
+ }
+ return i;
+}
+
/*
** Adjust the cost C by the costMult facter T. This only occurs if
** compiled with -DSQLITE_ENABLE_COSTMULT
@@ -125414,6 +131253,8 @@ static int whereLoopAddBtreeIndex(
Bitmask saved_prereq; /* Original value of pNew->prereq */
u16 saved_nLTerm; /* Original value of pNew->nLTerm */
u16 saved_nEq; /* Original value of pNew->u.btree.nEq */
+ u16 saved_nBtm; /* Original value of pNew->u.btree.nBtm */
+ u16 saved_nTop; /* Original value of pNew->u.btree.nTop */
u16 saved_nSkip; /* Original value of pNew->nSkip */
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
LogEst saved_nOut; /* Original value of pNew->nOut */
@@ -125423,15 +131264,16 @@ static int whereLoopAddBtreeIndex(
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
pNew = pBuilder->pNew;
- if( db->mallocFailed ) return SQLITE_NOMEM;
+ if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
+ WHERETRACE(0x800, ("BEGIN addBtreeIdx(%s), nEq=%d\n",
+ pProbe->zName, pNew->u.btree.nEq));
assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
if( pNew->wsFlags & WHERE_BTM_LIMIT ){
opMask = WO_LT|WO_LE;
- }else if( /*pProbe->tnum<=0 ||*/ (pSrc->fg.jointype & JT_LEFT)!=0 ){
- opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE;
}else{
+ assert( pNew->u.btree.nBtm==0 );
opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS;
}
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
@@ -125439,6 +131281,8 @@ static int whereLoopAddBtreeIndex(
assert( pNew->u.btree.nEq<pProbe->nColumn );
saved_nEq = pNew->u.btree.nEq;
+ saved_nBtm = pNew->u.btree.nBtm;
+ saved_nTop = pNew->u.btree.nTop;
saved_nSkip = pNew->nSkip;
saved_nLTerm = pNew->nLTerm;
saved_wsFlags = pNew->wsFlags;
@@ -125468,8 +131312,22 @@ static int whereLoopAddBtreeIndex(
** to mix with a lower range bound from some other source */
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
+ /* Do not allow IS constraints from the WHERE clause to be used by the
+ ** right table of a LEFT JOIN. Only constraints in the ON clause are
+ ** allowed */
+ if( (pSrc->fg.jointype & JT_LEFT)!=0
+ && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
+ && (eOp & (WO_IS|WO_ISNULL))!=0
+ ){
+ testcase( eOp & WO_IS );
+ testcase( eOp & WO_ISNULL );
+ continue;
+ }
+
pNew->wsFlags = saved_wsFlags;
pNew->u.btree.nEq = saved_nEq;
+ pNew->u.btree.nBtm = saved_nBtm;
+ pNew->u.btree.nTop = saved_nTop;
pNew->nLTerm = saved_nLTerm;
if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
pNew->aLTerm[pNew->nLTerm++] = pTerm;
@@ -125486,14 +131344,23 @@ static int whereLoopAddBtreeIndex(
pNew->wsFlags |= WHERE_COLUMN_IN;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
+ int i;
nIn = 46; assert( 46==sqlite3LogEst(25) );
+
+ /* The expression may actually be of the form (x, y) IN (SELECT...).
+ ** In this case there is a separate term for each of (x) and (y).
+ ** However, the nIn multiplier should only be applied once, not once
+ ** for each such term. The following loop checks that pTerm is the
+ ** first such term in use, and sets nIn back to 0 if it is not. */
+ for(i=0; i<pNew->nLTerm-1; i++){
+ if( pNew->aLTerm[i] && pNew->aLTerm[i]->pExpr==pExpr ) nIn = 0;
+ }
}else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
/* "x IN (value, value, ...)" */
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
+ assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
+ ** changes "x IN (?)" into "x=?". */
}
- assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
- ** changes "x IN (?)" into "x=?". */
-
}else if( eOp & (WO_EQ|WO_IS) ){
int iCol = pProbe->aiColumn[saved_nEq];
pNew->wsFlags |= WHERE_COLUMN_EQ;
@@ -125513,6 +131380,9 @@ static int whereLoopAddBtreeIndex(
testcase( eOp & WO_GT );
testcase( eOp & WO_GE );
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
+ pNew->u.btree.nBtm = whereRangeVectorLen(
+ pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
+ );
pBtm = pTerm;
pTop = 0;
if( pTerm->wtFlags & TERM_LIKEOPT ){
@@ -125525,12 +131395,16 @@ static int whereLoopAddBtreeIndex(
if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
pNew->aLTerm[pNew->nLTerm++] = pTop;
pNew->wsFlags |= WHERE_TOP_LIMIT;
+ pNew->u.btree.nTop = 1;
}
}else{
assert( eOp & (WO_LT|WO_LE) );
testcase( eOp & WO_LT );
testcase( eOp & WO_LE );
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
+ pNew->u.btree.nTop = whereRangeVectorLen(
+ pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
+ );
pTop = pTerm;
pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
pNew->aLTerm[pNew->nLTerm-2] : 0;
@@ -125630,6 +131504,8 @@ static int whereLoopAddBtreeIndex(
}
pNew->prereq = saved_prereq;
pNew->u.btree.nEq = saved_nEq;
+ pNew->u.btree.nBtm = saved_nBtm;
+ pNew->u.btree.nTop = saved_nTop;
pNew->nSkip = saved_nSkip;
pNew->wsFlags = saved_wsFlags;
pNew->nOut = saved_nOut;
@@ -125669,6 +131545,8 @@ static int whereLoopAddBtreeIndex(
pNew->wsFlags = saved_wsFlags;
}
+ WHERETRACE(0x800, ("END addBtreeIdx(%s), nEq=%d, rc=%d\n",
+ pProbe->zName, saved_nEq, rc));
return rc;
}
@@ -125751,7 +131629,7 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
/*
** Add all WhereLoop objects for a single table of the join where the table
-** is idenfied by pBuilder->pNew->iTab. That table is guaranteed to be
+** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
** a b-tree table, not a virtual table.
**
** The costs (WhereLoop.rRun) of the b-tree loops added by this function
@@ -125787,7 +131665,7 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
- Bitmask mExtra /* Extra prerequesites for using this table */
+ Bitmask mPrereq /* Extra prerequesites for using this table */
){
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
@@ -125848,7 +131726,7 @@ static int whereLoopAddBtree(
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/* Automatic indexes */
if( !pBuilder->pOrSet /* Not part of an OR optimization */
- && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0
+ && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
&& pSrc->pIBIndex==0 /* Has no INDEXED BY clause */
&& !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */
@@ -125880,6 +131758,7 @@ static int whereLoopAddBtree(
pNew->rSetup += 24;
}
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
+ if( pNew->rSetup<0 ) pNew->rSetup = 0;
/* TUNING: Each index lookup yields 20 rows in the table. This
** is more than the usual guess of 10 rows, since we have no way
** of knowing how selective the index will ultimately be. It would
@@ -125887,7 +131766,7 @@ static int whereLoopAddBtree(
pNew->nOut = 43; assert( 43==sqlite3LogEst(20) );
pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut);
pNew->wsFlags = WHERE_AUTO_INDEX;
- pNew->prereq = mExtra | pTerm->prereqRight;
+ pNew->prereq = mPrereq | pTerm->prereqRight;
rc = whereLoopInsert(pBuilder, pNew);
}
}
@@ -125904,11 +131783,13 @@ static int whereLoopAddBtree(
}
rSize = pProbe->aiRowLogEst[0];
pNew->u.btree.nEq = 0;
+ pNew->u.btree.nBtm = 0;
+ pNew->u.btree.nTop = 0;
pNew->nSkip = 0;
pNew->nLTerm = 0;
pNew->iSortIdx = 0;
pNew->rSetup = 0;
- pNew->prereq = mExtra;
+ pNew->prereq = mPrereq;
pNew->nOut = rSize;
pNew->u.btree.pIndex = pProbe;
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
@@ -125940,6 +131821,7 @@ static int whereLoopAddBtree(
/* Full scan via index */
if( b
|| !HasRowid(pTab)
+ || pProbe->pPartIdxWhere!=0
|| ( m==0
&& pProbe->bUnordered==0
&& (pProbe->szIdxRow<pTab->szTabRow)
@@ -125952,11 +131834,34 @@ static int whereLoopAddBtree(
/* The cost of visiting the index rows is N*K, where K is
** between 1.1 and 3.0, depending on the relative sizes of the
- ** index and table rows. If this is a non-covering index scan,
- ** also add the cost of visiting table rows (N*3.0). */
+ ** index and table rows. */
pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
if( m!=0 ){
- pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
+ /* If this is a non-covering index scan, add in the cost of
+ ** doing table lookups. The cost will be 3x the number of
+ ** lookups. Take into account WHERE clause terms that can be
+ ** satisfied using just the index, and that do not require a
+ ** table lookup. */
+ LogEst nLookup = rSize + 16; /* Base cost: N*3 */
+ int ii;
+ int iCur = pSrc->iCursor;
+ WhereClause *pWC2 = &pWInfo->sWC;
+ for(ii=0; ii<pWC2->nTerm; ii++){
+ WhereTerm *pTerm = &pWC2->a[ii];
+ if( !sqlite3ExprCoveredByIndex(pTerm->pExpr, iCur, pProbe) ){
+ break;
+ }
+ /* pTerm can be evaluated using just the index. So reduce
+ ** the expected number of table lookups accordingly */
+ if( pTerm->truthProb<=0 ){
+ nLookup += pTerm->truthProb;
+ }else{
+ nLookup--;
+ if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19;
+ }
+ }
+
+ pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup);
}
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize);
@@ -125981,12 +131886,162 @@ static int whereLoopAddBtree(
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Argument pIdxInfo is already populated with all constraints that may
+** be used by the virtual table identified by pBuilder->pNew->iTab. This
+** function marks a subset of those constraints usable, invokes the
+** xBestIndex method and adds the returned plan to pBuilder.
+**
+** A constraint is marked usable if:
+**
+** * Argument mUsable indicates that its prerequisites are available, and
+**
+** * It is not one of the operators specified in the mExclude mask passed
+** as the fourth argument (which in practice is either WO_IN or 0).
+**
+** Argument mPrereq is a mask of tables that must be scanned before the
+** virtual table in question. These are added to the plans prerequisites
+** before it is added to pBuilder.
+**
+** Output parameter *pbIn is set to true if the plan added to pBuilder
+** uses one or more WO_IN terms, or false otherwise.
+*/
+static int whereLoopAddVirtualOne(
+ WhereLoopBuilder *pBuilder,
+ Bitmask mPrereq, /* Mask of tables that must be used. */
+ Bitmask mUsable, /* Mask of usable tables */
+ u16 mExclude, /* Exclude terms using these operators */
+ sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */
+ u16 mNoOmit, /* Do not omit these constraints */
+ int *pbIn /* OUT: True if plan uses an IN(...) op */
+){
+ WhereClause *pWC = pBuilder->pWC;
+ struct sqlite3_index_constraint *pIdxCons;
+ struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage;
+ int i;
+ int mxTerm;
+ int rc = SQLITE_OK;
+ WhereLoop *pNew = pBuilder->pNew;
+ Parse *pParse = pBuilder->pWInfo->pParse;
+ struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab];
+ int nConstraint = pIdxInfo->nConstraint;
+
+ assert( (mUsable & mPrereq)==mPrereq );
+ *pbIn = 0;
+ pNew->prereq = mPrereq;
+
+ /* Set the usable flag on the subset of constraints identified by
+ ** arguments mUsable and mExclude. */
+ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+ for(i=0; i<nConstraint; i++, pIdxCons++){
+ WhereTerm *pTerm = &pWC->a[pIdxCons->iTermOffset];
+ pIdxCons->usable = 0;
+ if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
+ && (pTerm->eOperator & mExclude)==0
+ ){
+ pIdxCons->usable = 1;
+ }
+ }
+
+ /* Initialize the output fields of the sqlite3_index_info structure */
+ memset(pUsage, 0, sizeof(pUsage[0])*nConstraint);
+ assert( pIdxInfo->needToFreeIdxStr==0 );
+ pIdxInfo->idxStr = 0;
+ pIdxInfo->idxNum = 0;
+ pIdxInfo->orderByConsumed = 0;
+ pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
+ pIdxInfo->estimatedRows = 25;
+ pIdxInfo->idxFlags = 0;
+ pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
+
+ /* Invoke the virtual table xBestIndex() method */
+ rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
+ if( rc ) return rc;
+
+ mxTerm = -1;
+ assert( pNew->nLSlot>=nConstraint );
+ for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
+ pNew->u.vtab.omitMask = 0;
+ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
+ for(i=0; i<nConstraint; i++, pIdxCons++){
+ int iTerm;
+ if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){
+ WhereTerm *pTerm;
+ int j = pIdxCons->iTermOffset;
+ if( iTerm>=nConstraint
+ || j<0
+ || j>=pWC->nTerm
+ || pNew->aLTerm[iTerm]!=0
+ || pIdxCons->usable==0
+ ){
+ rc = SQLITE_ERROR;
+ sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName);
+ return rc;
+ }
+ testcase( iTerm==nConstraint-1 );
+ testcase( j==0 );
+ testcase( j==pWC->nTerm-1 );
+ pTerm = &pWC->a[j];
+ pNew->prereq |= pTerm->prereqRight;
+ assert( iTerm<pNew->nLSlot );
+ pNew->aLTerm[iTerm] = pTerm;
+ if( iTerm>mxTerm ) mxTerm = iTerm;
+ testcase( iTerm==15 );
+ testcase( iTerm==16 );
+ if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
+ if( (pTerm->eOperator & WO_IN)!=0 ){
+ /* A virtual table that is constrained by an IN clause may not
+ ** consume the ORDER BY clause because (1) the order of IN terms
+ ** is not necessarily related to the order of output terms and
+ ** (2) Multiple outputs from a single IN value will not merge
+ ** together. */
+ pIdxInfo->orderByConsumed = 0;
+ pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
+ *pbIn = 1; assert( (mExclude & WO_IN)==0 );
+ }
+ }
+ }
+ pNew->u.vtab.omitMask &= ~mNoOmit;
+
+ pNew->nLTerm = mxTerm+1;
+ assert( pNew->nLTerm<=pNew->nLSlot );
+ pNew->u.vtab.idxNum = pIdxInfo->idxNum;
+ pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
+ pIdxInfo->needToFreeIdxStr = 0;
+ pNew->u.vtab.idxStr = pIdxInfo->idxStr;
+ pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
+ pIdxInfo->nOrderBy : 0);
+ pNew->rSetup = 0;
+ pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
+ pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
+
+ /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
+ ** that the scan will visit at most one row. Clear it otherwise. */
+ if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){
+ pNew->wsFlags |= WHERE_ONEROW;
+ }else{
+ pNew->wsFlags &= ~WHERE_ONEROW;
+ }
+ rc = whereLoopInsert(pBuilder, pNew);
+ if( pNew->u.vtab.needFree ){
+ sqlite3_free(pNew->u.vtab.idxStr);
+ pNew->u.vtab.needFree = 0;
+ }
+ WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
+ *pbIn, (sqlite3_uint64)mPrereq,
+ (sqlite3_uint64)(pNew->prereq & ~mPrereq)));
+
+ return rc;
+}
+
+
/*
** Add all WhereLoop objects for a table of the join identified by
** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table.
**
-** If there are no LEFT or CROSS JOIN joins in the query, both mExtra and
-** mUnusable are set to 0. Otherwise, mExtra is a mask of all FROM clause
+** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and
+** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause
** entries that occur before the virtual table in the FROM clause and are
** separated from it by at least one LEFT or CROSS JOIN. Similarly, the
** mUnusable mask contains all FROM clause entries that occur after the
@@ -125997,188 +132052,128 @@ static int whereLoopAddBtree(
**
** ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6;
**
-** then mExtra corresponds to (t1, t2) and mUnusable to (t5, t6).
+** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6).
**
-** All the tables in mExtra must be scanned before the current virtual
+** All the tables in mPrereq must be scanned before the current virtual
** table. So any terms for which all prerequisites are satisfied by
-** mExtra may be specified as "usable" in all calls to xBestIndex.
+** mPrereq may be specified as "usable" in all calls to xBestIndex.
** Conversely, all tables in mUnusable must be scanned after the current
** virtual table, so any terms for which the prerequisites overlap with
** mUnusable should always be configured as "not-usable" for xBestIndex.
*/
static int whereLoopAddVirtual(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
- Bitmask mExtra, /* Tables that must be scanned before this one */
+ Bitmask mPrereq, /* Tables that must be scanned before this one */
Bitmask mUnusable /* Tables that must be scanned after this one */
){
+ int rc = SQLITE_OK; /* Return code */
WhereInfo *pWInfo; /* WHERE analysis context */
Parse *pParse; /* The parsing context */
WhereClause *pWC; /* The WHERE clause */
struct SrcList_item *pSrc; /* The FROM clause term to search */
- Table *pTab;
- sqlite3 *db;
- sqlite3_index_info *pIdxInfo;
- struct sqlite3_index_constraint *pIdxCons;
- struct sqlite3_index_constraint_usage *pUsage;
- WhereTerm *pTerm;
- int i, j;
- int iTerm, mxTerm;
- int nConstraint;
- int seenIn = 0; /* True if an IN operator is seen */
- int seenVar = 0; /* True if a non-constant constraint is seen */
- int iPhase; /* 0: const w/o IN, 1: const, 2: no IN, 2: IN */
+ sqlite3_index_info *p; /* Object to pass to xBestIndex() */
+ int nConstraint; /* Number of constraints in p */
+ int bIn; /* True if plan uses IN(...) operator */
WhereLoop *pNew;
- int rc = SQLITE_OK;
+ Bitmask mBest; /* Tables used by best possible plan */
+ u16 mNoOmit;
- assert( (mExtra & mUnusable)==0 );
+ assert( (mPrereq & mUnusable)==0 );
pWInfo = pBuilder->pWInfo;
pParse = pWInfo->pParse;
- db = pParse->db;
pWC = pBuilder->pWC;
pNew = pBuilder->pNew;
pSrc = &pWInfo->pTabList->a[pNew->iTab];
- pTab = pSrc->pTab;
- assert( IsVirtual(pTab) );
- pIdxInfo = allocateIndexInfo(pParse, pWC, mUnusable, pSrc,pBuilder->pOrderBy);
- if( pIdxInfo==0 ) return SQLITE_NOMEM;
- pNew->prereq = 0;
+ assert( IsVirtual(pSrc->pTab) );
+ p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy,
+ &mNoOmit);
+ if( p==0 ) return SQLITE_NOMEM_BKPT;
pNew->rSetup = 0;
pNew->wsFlags = WHERE_VIRTUALTABLE;
pNew->nLTerm = 0;
pNew->u.vtab.needFree = 0;
- pUsage = pIdxInfo->aConstraintUsage;
- nConstraint = pIdxInfo->nConstraint;
- if( whereLoopResize(db, pNew, nConstraint) ){
- sqlite3DbFree(db, pIdxInfo);
- return SQLITE_NOMEM;
- }
-
- for(iPhase=0; iPhase<=3; iPhase++){
- if( !seenIn && (iPhase&1)!=0 ){
- iPhase++;
- if( iPhase>3 ) break;
- }
- if( !seenVar && iPhase>1 ) break;
- pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
- for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
- j = pIdxCons->iTermOffset;
- pTerm = &pWC->a[j];
- switch( iPhase ){
- case 0: /* Constants without IN operator */
- pIdxCons->usable = 0;
- if( (pTerm->eOperator & WO_IN)!=0 ){
- seenIn = 1;
- }
- if( (pTerm->prereqRight & ~mExtra)!=0 ){
- seenVar = 1;
- }else if( (pTerm->eOperator & WO_IN)==0 ){
- pIdxCons->usable = 1;
- }
- break;
- case 1: /* Constants with IN operators */
- assert( seenIn );
- pIdxCons->usable = (pTerm->prereqRight & ~mExtra)==0;
- break;
- case 2: /* Variables without IN */
- assert( seenVar );
- pIdxCons->usable = (pTerm->eOperator & WO_IN)==0;
- break;
- default: /* Variables with IN */
- assert( seenVar && seenIn );
- pIdxCons->usable = 1;
- break;
+ nConstraint = p->nConstraint;
+ if( whereLoopResize(pParse->db, pNew, nConstraint) ){
+ sqlite3DbFree(pParse->db, p);
+ return SQLITE_NOMEM_BKPT;
+ }
+
+ /* First call xBestIndex() with all constraints usable. */
+ WHERETRACE(0x40, (" VirtualOne: all usable\n"));
+ rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
+
+ /* If the call to xBestIndex() with all terms enabled produced a plan
+ ** that does not require any source tables (IOW: a plan with mBest==0),
+ ** then there is no point in making any further calls to xBestIndex()
+ ** since they will all return the same result (if the xBestIndex()
+ ** implementation is sane). */
+ if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){
+ int seenZero = 0; /* True if a plan with no prereqs seen */
+ int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */
+ Bitmask mPrev = 0;
+ Bitmask mBestNoIn = 0;
+
+ /* If the plan produced by the earlier call uses an IN(...) term, call
+ ** xBestIndex again, this time with IN(...) terms disabled. */
+ if( bIn ){
+ WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n"));
+ rc = whereLoopAddVirtualOne(
+ pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn);
+ assert( bIn==0 );
+ mBestNoIn = pNew->prereq & ~mPrereq;
+ if( mBestNoIn==0 ){
+ seenZero = 1;
+ seenZeroNoIN = 1;
+ }
+ }
+
+ /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq)
+ ** in the set of terms that apply to the current virtual table. */
+ while( rc==SQLITE_OK ){
+ int i;
+ Bitmask mNext = ALLBITS;
+ assert( mNext>0 );
+ for(i=0; i<nConstraint; i++){
+ Bitmask mThis = (
+ pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq
+ );
+ if( mThis>mPrev && mThis<mNext ) mNext = mThis;
+ }
+ mPrev = mNext;
+ if( mNext==ALLBITS ) break;
+ if( mNext==mBest || mNext==mBestNoIn ) continue;
+ WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
+ (sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
+ rc = whereLoopAddVirtualOne(
+ pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn);
+ if( pNew->prereq==mPrereq ){
+ seenZero = 1;
+ if( bIn==0 ) seenZeroNoIN = 1;
}
}
- memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint);
- if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
- pIdxInfo->idxStr = 0;
- pIdxInfo->idxNum = 0;
- pIdxInfo->needToFreeIdxStr = 0;
- pIdxInfo->orderByConsumed = 0;
- pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2;
- pIdxInfo->estimatedRows = 25;
- pIdxInfo->idxFlags = 0;
- pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
- rc = vtabBestIndex(pParse, pTab, pIdxInfo);
- if( rc ) goto whereLoopAddVtab_exit;
- pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
- pNew->prereq = mExtra;
- mxTerm = -1;
- assert( pNew->nLSlot>=nConstraint );
- for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
- pNew->u.vtab.omitMask = 0;
- for(i=0; i<nConstraint; i++, pIdxCons++){
- if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){
- j = pIdxCons->iTermOffset;
- if( iTerm>=nConstraint
- || j<0
- || j>=pWC->nTerm
- || pNew->aLTerm[iTerm]!=0
- ){
- rc = SQLITE_ERROR;
- sqlite3ErrorMsg(pParse, "%s.xBestIndex() malfunction", pTab->zName);
- goto whereLoopAddVtab_exit;
- }
- testcase( iTerm==nConstraint-1 );
- testcase( j==0 );
- testcase( j==pWC->nTerm-1 );
- pTerm = &pWC->a[j];
- pNew->prereq |= pTerm->prereqRight;
- assert( iTerm<pNew->nLSlot );
- pNew->aLTerm[iTerm] = pTerm;
- if( iTerm>mxTerm ) mxTerm = iTerm;
- testcase( iTerm==15 );
- testcase( iTerm==16 );
- if( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<iTerm;
- if( (pTerm->eOperator & WO_IN)!=0 ){
- if( pUsage[i].omit==0 ){
- /* Do not attempt to use an IN constraint if the virtual table
- ** says that the equivalent EQ constraint cannot be safely omitted.
- ** If we do attempt to use such a constraint, some rows might be
- ** repeated in the output. */
- break;
- }
- /* A virtual table that is constrained by an IN clause may not
- ** consume the ORDER BY clause because (1) the order of IN terms
- ** is not necessarily related to the order of output terms and
- ** (2) Multiple outputs from a single IN value will not merge
- ** together. */
- pIdxInfo->orderByConsumed = 0;
- pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
- }
- }
- }
- if( i>=nConstraint ){
- pNew->nLTerm = mxTerm+1;
- assert( pNew->nLTerm<=pNew->nLSlot );
- pNew->u.vtab.idxNum = pIdxInfo->idxNum;
- pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
- pIdxInfo->needToFreeIdxStr = 0;
- pNew->u.vtab.idxStr = pIdxInfo->idxStr;
- pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
- pIdxInfo->nOrderBy : 0);
- pNew->rSetup = 0;
- pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
- pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
- /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated
- ** that the scan will visit at most one row. Clear it otherwise. */
- if( pIdxInfo->idxFlags & SQLITE_INDEX_SCAN_UNIQUE ){
- pNew->wsFlags |= WHERE_ONEROW;
- }else{
- pNew->wsFlags &= ~WHERE_ONEROW;
- }
- whereLoopInsert(pBuilder, pNew);
- if( pNew->u.vtab.needFree ){
- sqlite3_free(pNew->u.vtab.idxStr);
- pNew->u.vtab.needFree = 0;
- }
+ /* If the calls to xBestIndex() in the above loop did not find a plan
+ ** that requires no source tables at all (i.e. one guaranteed to be
+ ** usable), make a call here with all source tables disabled */
+ if( rc==SQLITE_OK && seenZero==0 ){
+ WHERETRACE(0x40, (" VirtualOne: all disabled\n"));
+ rc = whereLoopAddVirtualOne(
+ pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn);
+ if( bIn==0 ) seenZeroNoIN = 1;
}
- }
-whereLoopAddVtab_exit:
- if( pIdxInfo->needToFreeIdxStr ) sqlite3_free(pIdxInfo->idxStr);
- sqlite3DbFree(db, pIdxInfo);
+ /* If the calls to xBestIndex() have so far failed to find a plan
+ ** that requires no source tables at all and does not use an IN(...)
+ ** operator, make a final call to obtain one here. */
+ if( rc==SQLITE_OK && seenZeroNoIN==0 ){
+ WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n"));
+ rc = whereLoopAddVirtualOne(
+ pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn);
+ }
+ }
+
+ if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
+ sqlite3DbFree(pParse->db, p);
return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -126189,7 +132184,7 @@ whereLoopAddVtab_exit:
*/
static int whereLoopAddOr(
WhereLoopBuilder *pBuilder,
- Bitmask mExtra,
+ Bitmask mPrereq,
Bitmask mUnusable
){
WhereInfo *pWInfo = pBuilder->pWInfo;
@@ -126243,21 +132238,19 @@ static int whereLoopAddOr(
WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n",
(int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm));
if( sqlite3WhereTrace & 0x400 ){
- for(i=0; i<sSubBuild.pWC->nTerm; i++){
- whereTermPrint(&sSubBuild.pWC->a[i], i);
- }
+ sqlite3WhereClausePrint(sSubBuild.pWC);
}
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pItem->pTab) ){
- rc = whereLoopAddVirtual(&sSubBuild, mExtra, mUnusable);
+ rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable);
}else
#endif
{
- rc = whereLoopAddBtree(&sSubBuild, mExtra);
+ rc = whereLoopAddBtree(&sSubBuild, mPrereq);
}
if( rc==SQLITE_OK ){
- rc = whereLoopAddOr(&sSubBuild, mExtra, mUnusable);
+ rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
}
assert( rc==SQLITE_OK || sCur.n==0 );
if( sCur.n==0 ){
@@ -126314,7 +132307,7 @@ static int whereLoopAddOr(
*/
static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
WhereInfo *pWInfo = pBuilder->pWInfo;
- Bitmask mExtra = 0;
+ Bitmask mPrereq = 0;
Bitmask mPrior = 0;
int iTab;
SrcList *pTabList = pWInfo->pTabList;
@@ -126335,9 +132328,10 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
/* This condition is true when pItem is the FROM clause term on the
** right-hand-side of a LEFT or CROSS JOIN. */
- mExtra = mPrior;
+ mPrereq = mPrior;
}
priorJointype = pItem->fg.jointype;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pItem->pTab) ){
struct SrcList_item *p;
for(p=&pItem[1]; p<pEnd; p++){
@@ -126345,12 +132339,14 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
}
}
- rc = whereLoopAddVirtual(pBuilder, mExtra, mUnusable);
- }else{
- rc = whereLoopAddBtree(pBuilder, mExtra);
+ rc = whereLoopAddVirtual(pBuilder, mPrereq, mUnusable);
+ }else
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+ {
+ rc = whereLoopAddBtree(pBuilder, mPrereq);
}
if( rc==SQLITE_OK ){
- rc = whereLoopAddOr(pBuilder, mExtra, mUnusable);
+ rc = whereLoopAddOr(pBuilder, mPrereq, mUnusable);
}
mPrior |= pNew->maskSelf;
if( rc || db->mallocFailed ) break;
@@ -126381,7 +132377,7 @@ static i8 wherePathSatisfiesOrderBy(
WhereInfo *pWInfo, /* The WHERE clause */
ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */
WherePath *pPath, /* The WherePath to check */
- u16 wctrlFlags, /* Might contain WHERE_GROUPBY or WHERE_DISTINCTBY */
+ u16 wctrlFlags, /* WHERE_GROUPBY or _DISTINCTBY or _ORDERBY_LIMIT */
u16 nLoop, /* Number of entries in pPath->aLoop[] */
WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */
Bitmask *pRevMask /* OUT: Mask of WhereLoops to run in reverse order */
@@ -126392,6 +132388,7 @@ static i8 wherePathSatisfiesOrderBy(
u8 isOrderDistinct; /* All prior WhereLoops are order-distinct */
u8 distinctColumns; /* True if the loop has UNIQUE NOT NULL columns */
u8 isMatch; /* iColumn matches a term of the ORDER BY clause */
+ u16 eqOpMask; /* Allowed equality operators */
u16 nKeyCol; /* Number of key columns in pIndex */
u16 nColumn; /* Total number of ordered columns in the index */
u16 nOrderBy; /* Number terms in the ORDER BY clause */
@@ -126442,9 +132439,16 @@ static i8 wherePathSatisfiesOrderBy(
obDone = MASKBIT(nOrderBy)-1;
orderDistinctMask = 0;
ready = 0;
+ eqOpMask = WO_EQ | WO_IS | WO_ISNULL;
+ if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN;
for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){
if( iLoop>0 ) ready |= pLoop->maskSelf;
- pLoop = iLoop<nLoop ? pPath->aLoop[iLoop] : pLast;
+ if( iLoop<nLoop ){
+ pLoop = pPath->aLoop[iLoop];
+ if( wctrlFlags & WHERE_ORDERBY_LIMIT ) continue;
+ }else{
+ pLoop = pLast;
+ }
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
if( pLoop->u.vtab.isOrdered ) obSat = obDone;
break;
@@ -126462,8 +132466,16 @@ static i8 wherePathSatisfiesOrderBy(
if( pOBExpr->op!=TK_COLUMN ) continue;
if( pOBExpr->iTable!=iCur ) continue;
pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
- ~ready, WO_EQ|WO_ISNULL|WO_IS, 0);
+ ~ready, eqOpMask, 0);
if( pTerm==0 ) continue;
+ if( pTerm->eOperator==WO_IN ){
+ /* IN terms are only valid for sorting in the ORDER BY LIMIT
+ ** optimization, and then only if they are actually used
+ ** by the query plan */
+ assert( wctrlFlags & WHERE_ORDERBY_LIMIT );
+ for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
+ if( j>=pLoop->nLTerm ) continue;
+ }
if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
const char *z1, *z2;
pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[i].pExpr);
@@ -126500,18 +132512,42 @@ static i8 wherePathSatisfiesOrderBy(
rev = revSet = 0;
distinctColumns = 0;
for(j=0; j<nColumn; j++){
- u8 bOnce; /* True to run the ORDER BY search loop */
+ u8 bOnce = 1; /* True to run the ORDER BY search loop */
- /* Skip over == and IS NULL terms */
- if( j<pLoop->u.btree.nEq
- && pLoop->nSkip==0
- && ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL|WO_IS))!=0
- ){
- if( i & WO_ISNULL ){
- testcase( isOrderDistinct );
- isOrderDistinct = 0;
+ assert( j>=pLoop->u.btree.nEq
+ || (pLoop->aLTerm[j]==0)==(j<pLoop->nSkip)
+ );
+ if( j<pLoop->u.btree.nEq && j>=pLoop->nSkip ){
+ u16 eOp = pLoop->aLTerm[j]->eOperator;
+
+ /* Skip over == and IS and ISNULL terms. (Also skip IN terms when
+ ** doing WHERE_ORDERBY_LIMIT processing).
+ **
+ ** If the current term is a column of an ((?,?) IN (SELECT...))
+ ** expression for which the SELECT returns more than one column,
+ ** check that it is the only column used by this loop. Otherwise,
+ ** if it is one of two or more, none of the columns can be
+ ** considered to match an ORDER BY term. */
+ if( (eOp & eqOpMask)!=0 ){
+ if( eOp & WO_ISNULL ){
+ testcase( isOrderDistinct );
+ isOrderDistinct = 0;
+ }
+ continue;
+ }else if( ALWAYS(eOp & WO_IN) ){
+ /* ALWAYS() justification: eOp is an equality operator due to the
+ ** j<pLoop->u.btree.nEq constraint above. Any equality other
+ ** than WO_IN is captured by the previous "if". So this one
+ ** always has to be WO_IN. */
+ Expr *pX = pLoop->aLTerm[j]->pExpr;
+ for(i=j+1; i<pLoop->u.btree.nEq; i++){
+ if( pLoop->aLTerm[i]->pExpr==pX ){
+ assert( (pLoop->aLTerm[i]->eOperator & WO_IN) );
+ bOnce = 0;
+ break;
+ }
+ }
}
- continue;
}
/* Get the column number in the table (iColumn) and sort order
@@ -126540,7 +132576,6 @@ static i8 wherePathSatisfiesOrderBy(
/* Find the ORDER BY term that corresponds to the j-th column
** of the index and mark that ORDER BY term off
*/
- bOnce = 1;
isMatch = 0;
for(i=0; bOnce && i<nOrderBy; i++){
if( MASKBIT(i) & obSat ) continue;
@@ -126577,7 +132612,7 @@ static i8 wherePathSatisfiesOrderBy(
}
}
if( isMatch ){
- if( iColumn<0 ){
+ if( iColumn==XN_ROWID ){
testcase( distinctColumns==0 );
distinctColumns = 1;
}
@@ -126672,6 +132707,7 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){
** order.
*/
static LogEst whereSortingCost(
+ WhereInfo *pWInfo,
LogEst nRow,
int nOrderBy,
int nSorted
@@ -126692,7 +132728,14 @@ static LogEst whereSortingCost(
LogEst rScale, rSortCost;
assert( nOrderBy>0 && 66==sqlite3LogEst(100) );
rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
- rSortCost = nRow + estLog(nRow) + rScale + 16;
+ rSortCost = nRow + rScale + 16;
+
+ /* Multiple by log(M) where M is the number of output rows.
+ ** Use the LIMIT for M if it is smaller */
+ if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
+ nRow = pWInfo->iLimit;
+ }
+ rSortCost += estLog(nRow);
return rSortCost;
}
@@ -126755,7 +132798,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
nSpace += sizeof(LogEst) * nOrderBy;
pSpace = sqlite3DbMallocRawNN(db, nSpace);
- if( pSpace==0 ) return SQLITE_NOMEM;
+ if( pSpace==0 ) return SQLITE_NOMEM_BKPT;
aTo = (WherePath*)pSpace;
aFrom = aTo+mxChoice;
memset(aFrom, 0, sizeof(aFrom[0]));
@@ -126810,6 +132853,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
+ if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){
+ /* Do not use an automatic index if the this loop is expected
+ ** to run less than 2 times. */
+ assert( 10==sqlite3LogEst(2) );
+ continue;
+ }
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
@@ -126826,7 +132875,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( isOrdered>=0 && isOrdered<nOrderBy ){
if( aSortCost[isOrdered]==0 ){
aSortCost[isOrdered] = whereSortingCost(
- nRowEst, nOrderBy, isOrdered
+ pWInfo, nRowEst, nOrderBy, isOrdered
);
}
rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]);
@@ -127002,9 +133051,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
&& nRowEst
){
Bitmask notUsed;
- int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
+ int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pDistinctSet, pFrom,
WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], &notUsed);
- if( rc==pWInfo->pResultSet->nExpr ){
+ if( rc==pWInfo->pDistinctSet->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
}
@@ -127015,8 +133064,26 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
}
}else{
pWInfo->nOBSat = pFrom->isOrdered;
- if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
pWInfo->revMask = pFrom->revLoop;
+ if( pWInfo->nOBSat<=0 ){
+ pWInfo->nOBSat = 0;
+ if( nLoop>0 ){
+ u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags;
+ if( (wsFlags & WHERE_ONEROW)==0
+ && (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN)
+ ){
+ Bitmask m = 0;
+ int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom,
+ WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m);
+ testcase( wsFlags & WHERE_IPK );
+ testcase( wsFlags & WHERE_COLUMN_IN );
+ if( rc==pWInfo->pOrderBy->nExpr ){
+ pWInfo->bOrderedInnerLoop = 1;
+ pWInfo->revMask = m;
+ }
+ }
+ }
+ }
}
if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
&& pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0
@@ -127062,9 +133129,9 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
int j;
Table *pTab;
Index *pIdx;
-
+
pWInfo = pBuilder->pWInfo;
- if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0;
+ if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
assert( pWInfo->pTabList->nSrc>=1 );
pItem = pWInfo->pTabList->a;
pTab = pItem->pTab;
@@ -127211,7 +133278,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
** is called from an UPDATE or DELETE statement, then pOrderBy is NULL.
**
** The iIdxCur parameter is the cursor number of an index. If
-** WHERE_ONETABLE_ONLY is set, iIdxCur is the cursor number of an index
+** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index
** to use for OR clause processing. The WHERE clause should use this
** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is
** the first cursor in an array of cursors for all indices. iIdxCur should
@@ -127219,13 +133286,14 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
** used.
*/
SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
- Parse *pParse, /* The parser context */
- SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
- Expr *pWhere, /* The WHERE clause */
- ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
- ExprList *pResultSet, /* Result set of the query */
- u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
- int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
+ Parse *pParse, /* The parser context */
+ SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
+ Expr *pWhere, /* The WHERE clause */
+ ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
+ ExprList *pDistinctSet, /* Try not to output two rows that duplicate these */
+ u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
+ int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number
+ ** If WHERE_USE_LIMIT, then the limit amount */
){
int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */
int nTabList; /* Number of elements in pTabList */
@@ -127243,9 +133311,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || (
(wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
- && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0
+ && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
));
+ /* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */
+ assert( (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
+ || (wctrlFlags & WHERE_USE_LIMIT)==0 );
+
/* Variable initialization */
db = pParse->db;
memset(&sWLB, 0, sizeof(sWLB));
@@ -127271,11 +133343,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
/* This function normally generates a nested loop for all tables in
- ** pTabList. But if the WHERE_ONETABLE_ONLY flag is set, then we should
+ ** pTabList. But if the WHERE_OR_SUBCLAUSE flag is set, then we should
** only generate code for the first table in pTabList and assume that
** any cursors associated with subsequent tables are uninitialized.
*/
- nTabList = (wctrlFlags & WHERE_ONETABLE_ONLY) ? 1 : pTabList->nSrc;
+ nTabList = (wctrlFlags & WHERE_OR_SUBCLAUSE) ? 1 : pTabList->nSrc;
/* Allocate and initialize the WhereInfo structure that will become the
** return value. A single allocation is used to store the WhereInfo
@@ -127285,21 +133357,25 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** some architectures. Hence the ROUND8() below.
*/
nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
- pWInfo = sqlite3DbMallocZero(db, nByteWInfo + sizeof(WhereLoop));
+ pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
if( db->mallocFailed ){
sqlite3DbFree(db, pWInfo);
pWInfo = 0;
goto whereBeginError;
}
- pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
- pWInfo->nLevel = nTabList;
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
- pWInfo->pResultSet = pResultSet;
+ pWInfo->pDistinctSet = pDistinctSet;
+ pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
+ pWInfo->nLevel = nTabList;
pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
pWInfo->wctrlFlags = wctrlFlags;
+ pWInfo->iLimit = iAuxArg;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
+ memset(&pWInfo->nOBSat, 0,
+ offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
+ memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */
pMaskSet = &pWInfo->sMaskSet;
sWLB.pWInfo = pWInfo;
@@ -127350,7 +133426,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** Note that bitmasks are created for all pTabList->nSrc tables in
** pTabList, not just the first nTabList tables. nTabList is normally
** equal to pTabList->nSrc but might be shortened to 1 if the
- ** WHERE_ONETABLE_ONLY flag is set.
+ ** WHERE_OR_SUBCLAUSE flag is set.
*/
for(ii=0; ii<pTabList->nSrc; ii++){
createMask(pMaskSet, pTabList->a[ii].iCursor);
@@ -127368,25 +133444,27 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( db->mallocFailed ) goto whereBeginError;
if( wctrlFlags & WHERE_WANT_DISTINCT ){
- if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
+ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pDistinctSet) ){
/* The DISTINCT marking is pointless. Ignore it. */
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}else if( pOrderBy==0 ){
/* Try to ORDER BY the result set to make distinct processing easier */
pWInfo->wctrlFlags |= WHERE_DISTINCTBY;
- pWInfo->pOrderBy = pResultSet;
+ pWInfo->pOrderBy = pDistinctSet;
}
}
/* Construct the WhereLoop objects */
- WHERETRACE(0xffff,("*** Optimizer Start *** (wctrlFlags: 0x%x)\n",
- wctrlFlags));
#if defined(WHERETRACE_ENABLED)
- if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
- int i;
- for(i=0; i<sWLB.pWC->nTerm; i++){
- whereTermPrint(&sWLB.pWC->a[i], i);
+ if( sqlite3WhereTrace & 0xffff ){
+ sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags);
+ if( wctrlFlags & WHERE_USE_LIMIT ){
+ sqlite3DebugPrintf(", limit: %d", iAuxArg);
}
+ sqlite3DebugPrintf(")\n");
+ }
+ if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
+ sqlite3WhereClausePrint(sWLB.pWC);
}
#endif
@@ -127415,7 +133493,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
}
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
- pWInfo->revMask = (Bitmask)(-1);
+ pWInfo->revMask = ALLBITS;
}
if( pParse->nErr || NEVER(db->mallocFailed) ){
goto whereBeginError;
@@ -127448,10 +133526,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
#endif
/* Attempt to omit tables from the join that do not effect the result */
if( pWInfo->nLevel>=2
- && pResultSet!=0
+ && pDistinctSet!=0
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
){
- Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet);
+ Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pDistinctSet);
if( sWLB.pOrderBy ){
tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
}
@@ -127528,7 +133606,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}else
#endif
if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
- && (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
+ && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
int op = OP_OpenRead;
if( pWInfo->eOnePass!=ONEPASS_OFF ){
op = OP_OpenWrite;
@@ -127564,10 +133642,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
Index *pIx = pLoop->u.btree.pIndex;
int iIndexCur;
int op = OP_OpenRead;
- /* iIdxCur is always set if to a positive value if ONEPASS is possible */
- assert( iIdxCur!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
+ /* iAuxArg is always set if to a positive value if ONEPASS is possible */
+ assert( iAuxArg!=0 || (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 );
if( !HasRowid(pTab) && IsPrimaryKeyIndex(pIx)
- && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0
+ && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0
){
/* This is one term of an OR-optimization using the PRIMARY KEY of a
** WITHOUT ROWID table. No need for a separate index */
@@ -127575,7 +133653,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
op = 0;
}else if( pWInfo->eOnePass!=ONEPASS_OFF ){
Index *pJ = pTabItem->pTab->pIndex;
- iIndexCur = iIdxCur;
+ iIndexCur = iAuxArg;
assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
while( ALWAYS(pJ) && pJ!=pIx ){
iIndexCur++;
@@ -127583,9 +133661,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
op = OP_OpenWrite;
pWInfo->aiCurOnePass[1] = iIndexCur;
- }else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
- iIndexCur = iIdxCur;
- if( wctrlFlags & WHERE_REOPEN_IDX ) op = OP_ReopenIdx;
+ }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){
+ iIndexCur = iAuxArg;
+ op = OP_ReopenIdx;
}else{
iIndexCur = pParse->nTab++;
}
@@ -127647,7 +133725,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady);
pWInfo->iContinue = pLevel->addrCont;
- if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){
+ if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){
sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain);
}
}
@@ -127701,10 +133779,12 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
- sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
- VdbeCoverage(v);
- VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
- VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
+ if( pIn->eEndLoopOp!=OP_Noop ){
+ sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
+ VdbeCoverage(v);
+ VdbeCoverageIf(v, pIn->eEndLoopOp==OP_PrevIfOpen);
+ VdbeCoverageIf(v, pIn->eEndLoopOp==OP_NextIfOpen);
+ }
sqlite3VdbeJumpHere(v, pIn->addrInTop-1);
}
}
@@ -127717,24 +133797,21 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
}
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
if( pLevel->addrLikeRep ){
- int op;
- if( sqlite3VdbeGetOp(v, pLevel->addrLikeRep-1)->p1 ){
- op = OP_DecrJumpZero;
- }else{
- op = OP_JumpZeroIncr;
- }
- sqlite3VdbeAddOp2(v, op, pLevel->iLikeRepCntr, pLevel->addrLikeRep);
+ sqlite3VdbeAddOp2(v, OP_DecrJumpZero, (int)(pLevel->iLikeRepCntr>>1),
+ pLevel->addrLikeRep);
VdbeCoverage(v);
}
#endif
if( pLevel->iLeftJoin ){
+ int ws = pLoop->wsFlags;
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
- assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
- || (pLoop->wsFlags & WHERE_INDEXED)!=0 );
- if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 ){
+ assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
+ if( (ws & WHERE_IDX_ONLY)==0 ){
sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
}
- if( pLoop->wsFlags & WHERE_INDEXED ){
+ if( (ws & WHERE_INDEXED)
+ || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx)
+ ){
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
}
if( pLevel->op==OP_Return ){
@@ -127773,27 +133850,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
continue;
}
- /* Close all of the cursors that were opened by sqlite3WhereBegin.
- ** Except, do not close cursors that will be reused by the OR optimization
- ** (WHERE_OMIT_OPEN_CLOSE). And do not close the OP_OpenWrite cursors
- ** created for the ONEPASS optimization.
- */
- if( (pTab->tabFlags & TF_Ephemeral)==0
- && pTab->pSelect==0
- && (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0
- ){
- int ws = pLoop->wsFlags;
- if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){
- sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
- }
- if( (ws & WHERE_INDEXED)!=0
- && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0
- && pLevel->iIdxCur!=pWInfo->aiCurOnePass[1]
- ){
- sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
- }
- }
-
/* If this scan uses an index, make VDBE code substitutions to read data
** from the index instead of from the table where possible. In some cases
** this optimization prevents the table from ever being read, which can
@@ -127912,15 +133968,6 @@ struct LimitVal {
};
/*
-** An instance of this structure is used to store the LIKE,
-** GLOB, NOT LIKE, and NOT GLOB operators.
-*/
-struct LikeOp {
- Token eOperator; /* "like" or "glob" or "regexp" */
- int bNot; /* True if the NOT keyword is present */
-};
-
-/*
** An instance of the following structure describes the event of a
** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT,
** TK_DELETE, or TK_INSTEAD. If the event is of the form
@@ -127932,11 +133979,6 @@ struct LikeOp {
struct TrigEvent { int a; IdList * b; };
/*
-** An instance of this structure holds the ATTACH key and the key type.
-*/
-struct AttachKey { int type; Token key; };
-
-/*
** Disable lookaside memory allocation for objects that might be
** shared across database connections.
*/
@@ -127981,46 +134023,61 @@ static void disableLookaside(Parse *pParse){
** new Expr to populate pOut. Set the span of pOut to be the identifier
** that created the expression.
*/
- static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token *pValue){
- pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, pValue);
- pOut->zStart = pValue->z;
- pOut->zEnd = &pValue->z[pValue->n];
+ static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){
+ Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
+ if( p ){
+ memset(p, 0, sizeof(Expr));
+ p->op = (u8)op;
+ p->flags = EP_Leaf;
+ p->iAgg = -1;
+ p->u.zToken = (char*)&p[1];
+ memcpy(p->u.zToken, t.z, t.n);
+ p->u.zToken[t.n] = 0;
+ if( sqlite3Isquote(p->u.zToken[0]) ){
+ if( p->u.zToken[0]=='"' ) p->flags |= EP_DblQuoted;
+ sqlite3Dequote(p->u.zToken);
+ }
+#if SQLITE_MAX_EXPR_DEPTH>0
+ p->nHeight = 1;
+#endif
+ }
+ pOut->pExpr = p;
+ pOut->zStart = t.z;
+ pOut->zEnd = &t.z[t.n];
}
/* This routine constructs a binary expression node out of two ExprSpan
** objects and uses the result to populate a new ExprSpan object.
*/
static void spanBinaryExpr(
- ExprSpan *pOut, /* Write the result here */
Parse *pParse, /* The parsing context. Errors accumulate here */
int op, /* The binary operation */
- ExprSpan *pLeft, /* The left operand */
+ ExprSpan *pLeft, /* The left operand, and output */
ExprSpan *pRight /* The right operand */
){
- pOut->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0);
- pOut->zStart = pLeft->zStart;
- pOut->zEnd = pRight->zEnd;
+ pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr);
+ pLeft->zEnd = pRight->zEnd;
}
/* If doNot is true, then add a TK_NOT Expr-node wrapper around the
** outside of *ppExpr.
*/
- static void exprNot(Parse *pParse, int doNot, Expr **ppExpr){
- if( doNot ) *ppExpr = sqlite3PExpr(pParse, TK_NOT, *ppExpr, 0, 0);
+ static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){
+ if( doNot ){
+ pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0);
+ }
}
/* Construct an expression node for a unary postfix operator
*/
static void spanUnaryPostfix(
- ExprSpan *pOut, /* Write the new expression node here */
Parse *pParse, /* Parsing context to record errors */
int op, /* The operator */
- ExprSpan *pOperand, /* The operand */
+ ExprSpan *pOperand, /* The operand, and output */
Token *pPostOp /* The operand token for setting the span */
){
- pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
- pOut->zStart = pOperand->zStart;
- pOut->zEnd = &pPostOp->z[pPostOp->n];
+ pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
+ pOperand->zEnd = &pPostOp->z[pPostOp->n];
}
/* A routine to convert a binary TK_IS or TK_ISNOT expression into a
@@ -128043,8 +134100,8 @@ static void disableLookaside(Parse *pParse){
ExprSpan *pOperand, /* The operand */
Token *pPreOp /* The operand token for setting the span */
){
- pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
pOut->zStart = pPreOp->z;
+ pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
pOut->zEnd = pOperand->zEnd;
}
@@ -128129,26 +134186,25 @@ static void disableLookaside(Parse *pParse){
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned char
-#define YYNOCODE 253
+#define YYNOCODE 252
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 70
+#define YYWILDCARD 96
#define sqlite3ParserTOKENTYPE Token
typedef union {
int yyinit;
sqlite3ParserTOKENTYPE yy0;
- int yy4;
- struct TrigEvent yy90;
- ExprSpan yy118;
- TriggerStep* yy203;
- struct {int value; int mask;} yy215;
- SrcList* yy259;
- struct LimitVal yy292;
- Expr* yy314;
- ExprList* yy322;
- struct LikeOp yy342;
- IdList* yy384;
- Select* yy387;
- With* yy451;
+ Expr* yy72;
+ TriggerStep* yy145;
+ ExprList* yy148;
+ SrcList* yy185;
+ ExprSpan yy190;
+ int yy194;
+ Select* yy243;
+ IdList* yy254;
+ With* yy285;
+ struct TrigEvent yy332;
+ struct LimitVal yy354;
+ struct {int value; int mask;} yy497;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
@@ -128158,22 +134214,18 @@ typedef union {
#define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse
#define sqlite3ParserARG_STORE yypParser->pParse = pParse
#define YYFALLBACK 1
-#define YYNSTATE 436
-#define YYNRULE 328
-#define YY_MAX_SHIFT 435
-#define YY_MIN_SHIFTREDUCE 649
-#define YY_MAX_SHIFTREDUCE 976
-#define YY_MIN_REDUCE 977
-#define YY_MAX_REDUCE 1304
-#define YY_ERROR_ACTION 1305
-#define YY_ACCEPT_ACTION 1306
-#define YY_NO_ACTION 1307
+#define YYNSTATE 456
+#define YYNRULE 332
+#define YY_MAX_SHIFT 455
+#define YY_MIN_SHIFTREDUCE 668
+#define YY_MAX_SHIFTREDUCE 999
+#define YY_MIN_REDUCE 1000
+#define YY_MAX_REDUCE 1331
+#define YY_ERROR_ACTION 1332
+#define YY_ACCEPT_ACTION 1333
+#define YY_NO_ACTION 1334
/************* End control #defines *******************************************/
-/* The yyzerominor constant is used to initialize instances of
-** YYMINORTYPE objects to zero. */
-static const YYMINORTYPE yyzerominor = { 0 };
-
/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
@@ -128203,7 +134255,7 @@ static const YYMINORTYPE yyzerominor = { 0 };
**
** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE
** and YY_MAX_REDUCE
-
+**
** N == YY_ERROR_ACTION A syntax error has occurred.
**
** N == YY_ACCEPT_ACTION The parser accepts its input.
@@ -128212,16 +134264,20 @@ static const YYMINORTYPE yyzerominor = { 0 };
** slots in the yy_action[] table.
**
** The action table is constructed as a single large table named yy_action[].
-** Given state S and lookahead X, the action is computed as
+** Given state S and lookahead X, the action is computed as either:
**
-** yy_action[ yy_shift_ofst[S] + X ]
+** (A) N = yy_action[ yy_shift_ofst[S] + X ]
+** (B) N = yy_default[S]
**
-** If the index value yy_shift_ofst[S]+X is out of range or if the value
-** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
-** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
-** and that yy_default[S] should be used instead.
+** The (A) formula is preferred. The B formula is used instead if:
+** (1) The yy_shift_ofst[S]+X value is out of range, or
+** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or
+** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT.
+** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that
+** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X.
+** Hence only tests (1) and (2) need to be evaluated.)
**
-** The formula above is for computing the action when the lookahead is
+** The formulas above are for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
** a reduce action) then the yy_reduce_ofst[] array is used in place of
** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
@@ -128239,446 +134295,463 @@ static const YYMINORTYPE yyzerominor = { 0 };
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (1501)
+#define YY_ACTTAB_COUNT (1567)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 311, 1306, 145, 651, 2, 192, 652, 338, 780, 92,
- /* 10 */ 92, 92, 92, 85, 90, 90, 90, 90, 89, 89,
- /* 20 */ 88, 88, 88, 87, 335, 88, 88, 88, 87, 335,
- /* 30 */ 327, 856, 856, 92, 92, 92, 92, 697, 90, 90,
- /* 40 */ 90, 90, 89, 89, 88, 88, 88, 87, 335, 76,
- /* 50 */ 807, 74, 93, 94, 84, 868, 871, 860, 860, 91,
- /* 60 */ 91, 92, 92, 92, 92, 335, 90, 90, 90, 90,
- /* 70 */ 89, 89, 88, 88, 88, 87, 335, 311, 780, 90,
- /* 80 */ 90, 90, 90, 89, 89, 88, 88, 88, 87, 335,
- /* 90 */ 356, 808, 776, 701, 689, 689, 86, 83, 166, 257,
- /* 100 */ 809, 715, 430, 86, 83, 166, 324, 697, 856, 856,
- /* 110 */ 201, 158, 276, 387, 271, 386, 188, 689, 689, 828,
- /* 120 */ 86, 83, 166, 269, 833, 49, 123, 87, 335, 93,
- /* 130 */ 94, 84, 868, 871, 860, 860, 91, 91, 92, 92,
- /* 140 */ 92, 92, 239, 90, 90, 90, 90, 89, 89, 88,
- /* 150 */ 88, 88, 87, 335, 311, 763, 333, 332, 216, 408,
- /* 160 */ 394, 69, 231, 393, 690, 691, 396, 910, 251, 354,
- /* 170 */ 250, 288, 315, 430, 908, 430, 909, 89, 89, 88,
- /* 180 */ 88, 88, 87, 335, 391, 856, 856, 690, 691, 183,
- /* 190 */ 95, 123, 384, 381, 380, 833, 31, 833, 49, 912,
- /* 200 */ 912, 751, 752, 379, 123, 311, 93, 94, 84, 868,
- /* 210 */ 871, 860, 860, 91, 91, 92, 92, 92, 92, 114,
- /* 220 */ 90, 90, 90, 90, 89, 89, 88, 88, 88, 87,
- /* 230 */ 335, 430, 408, 399, 435, 657, 856, 856, 346, 57,
- /* 240 */ 232, 828, 109, 704, 366, 689, 689, 363, 825, 760,
- /* 250 */ 97, 749, 752, 833, 49, 708, 708, 93, 94, 84,
- /* 260 */ 868, 871, 860, 860, 91, 91, 92, 92, 92, 92,
- /* 270 */ 423, 90, 90, 90, 90, 89, 89, 88, 88, 88,
- /* 280 */ 87, 335, 311, 114, 22, 361, 688, 58, 408, 390,
- /* 290 */ 251, 349, 240, 213, 762, 689, 689, 847, 685, 115,
- /* 300 */ 361, 231, 393, 689, 689, 396, 183, 689, 689, 384,
- /* 310 */ 381, 380, 361, 856, 856, 690, 691, 160, 159, 223,
- /* 320 */ 379, 738, 25, 806, 707, 841, 143, 689, 689, 835,
- /* 330 */ 392, 339, 766, 766, 93, 94, 84, 868, 871, 860,
- /* 340 */ 860, 91, 91, 92, 92, 92, 92, 914, 90, 90,
- /* 350 */ 90, 90, 89, 89, 88, 88, 88, 87, 335, 311,
- /* 360 */ 840, 840, 840, 266, 257, 690, 691, 778, 706, 86,
- /* 370 */ 83, 166, 219, 690, 691, 737, 1, 690, 691, 689,
- /* 380 */ 689, 689, 689, 430, 86, 83, 166, 249, 688, 937,
- /* 390 */ 856, 856, 427, 699, 700, 828, 298, 690, 691, 221,
- /* 400 */ 686, 115, 123, 944, 795, 833, 48, 342, 305, 970,
- /* 410 */ 847, 93, 94, 84, 868, 871, 860, 860, 91, 91,
- /* 420 */ 92, 92, 92, 92, 114, 90, 90, 90, 90, 89,
- /* 430 */ 89, 88, 88, 88, 87, 335, 311, 940, 841, 679,
- /* 440 */ 713, 429, 835, 430, 251, 354, 250, 355, 288, 690,
- /* 450 */ 691, 690, 691, 285, 941, 340, 971, 287, 210, 23,
- /* 460 */ 174, 793, 832, 430, 353, 833, 10, 856, 856, 24,
- /* 470 */ 942, 151, 753, 840, 840, 840, 794, 968, 1290, 321,
- /* 480 */ 398, 1290, 356, 352, 754, 833, 49, 935, 93, 94,
- /* 490 */ 84, 868, 871, 860, 860, 91, 91, 92, 92, 92,
- /* 500 */ 92, 430, 90, 90, 90, 90, 89, 89, 88, 88,
- /* 510 */ 88, 87, 335, 311, 376, 114, 907, 705, 430, 907,
- /* 520 */ 328, 890, 114, 833, 10, 966, 430, 857, 857, 320,
- /* 530 */ 189, 163, 832, 165, 430, 906, 344, 323, 906, 904,
- /* 540 */ 833, 10, 965, 306, 856, 856, 187, 419, 833, 10,
- /* 550 */ 220, 869, 872, 832, 222, 403, 833, 49, 1219, 793,
- /* 560 */ 68, 937, 406, 245, 66, 93, 94, 84, 868, 871,
- /* 570 */ 860, 860, 91, 91, 92, 92, 92, 92, 861, 90,
- /* 580 */ 90, 90, 90, 89, 89, 88, 88, 88, 87, 335,
- /* 590 */ 311, 404, 213, 762, 834, 345, 114, 940, 902, 368,
- /* 600 */ 727, 5, 316, 192, 396, 772, 780, 269, 230, 242,
- /* 610 */ 771, 244, 397, 164, 941, 385, 123, 347, 55, 355,
- /* 620 */ 329, 856, 856, 728, 333, 332, 688, 968, 1291, 724,
- /* 630 */ 942, 1291, 413, 214, 833, 9, 362, 286, 955, 115,
- /* 640 */ 718, 311, 93, 94, 84, 868, 871, 860, 860, 91,
- /* 650 */ 91, 92, 92, 92, 92, 430, 90, 90, 90, 90,
- /* 660 */ 89, 89, 88, 88, 88, 87, 335, 912, 912, 1300,
- /* 670 */ 1300, 758, 856, 856, 325, 966, 780, 833, 35, 747,
- /* 680 */ 720, 334, 699, 700, 977, 652, 338, 243, 745, 920,
- /* 690 */ 920, 369, 187, 93, 94, 84, 868, 871, 860, 860,
- /* 700 */ 91, 91, 92, 92, 92, 92, 114, 90, 90, 90,
- /* 710 */ 90, 89, 89, 88, 88, 88, 87, 335, 311, 430,
- /* 720 */ 954, 430, 112, 310, 430, 693, 317, 698, 400, 430,
- /* 730 */ 793, 359, 430, 1017, 430, 192, 430, 401, 780, 430,
- /* 740 */ 360, 833, 36, 833, 12, 430, 833, 27, 316, 856,
- /* 750 */ 856, 833, 37, 20, 833, 38, 833, 39, 833, 28,
- /* 760 */ 72, 833, 29, 663, 664, 665, 264, 833, 40, 234,
- /* 770 */ 93, 94, 84, 868, 871, 860, 860, 91, 91, 92,
- /* 780 */ 92, 92, 92, 430, 90, 90, 90, 90, 89, 89,
- /* 790 */ 88, 88, 88, 87, 335, 311, 430, 698, 430, 917,
- /* 800 */ 147, 430, 165, 916, 275, 833, 41, 430, 780, 430,
- /* 810 */ 21, 430, 259, 430, 262, 274, 430, 367, 833, 42,
- /* 820 */ 833, 11, 430, 833, 43, 235, 856, 856, 793, 833,
- /* 830 */ 99, 833, 44, 833, 45, 833, 32, 75, 833, 46,
- /* 840 */ 305, 967, 257, 257, 833, 47, 311, 93, 94, 84,
- /* 850 */ 868, 871, 860, 860, 91, 91, 92, 92, 92, 92,
- /* 860 */ 430, 90, 90, 90, 90, 89, 89, 88, 88, 88,
- /* 870 */ 87, 335, 430, 186, 185, 184, 238, 856, 856, 650,
- /* 880 */ 2, 1064, 833, 33, 739, 217, 218, 257, 971, 257,
- /* 890 */ 426, 317, 257, 774, 833, 117, 257, 311, 93, 94,
- /* 900 */ 84, 868, 871, 860, 860, 91, 91, 92, 92, 92,
- /* 910 */ 92, 430, 90, 90, 90, 90, 89, 89, 88, 88,
- /* 920 */ 88, 87, 335, 430, 318, 124, 212, 163, 856, 856,
- /* 930 */ 943, 900, 898, 833, 118, 759, 726, 725, 257, 755,
- /* 940 */ 289, 289, 733, 734, 961, 833, 119, 682, 311, 93,
- /* 950 */ 82, 84, 868, 871, 860, 860, 91, 91, 92, 92,
- /* 960 */ 92, 92, 430, 90, 90, 90, 90, 89, 89, 88,
- /* 970 */ 88, 88, 87, 335, 430, 716, 246, 322, 331, 856,
- /* 980 */ 856, 256, 114, 357, 833, 53, 808, 913, 913, 932,
- /* 990 */ 156, 416, 420, 424, 930, 809, 833, 34, 364, 311,
- /* 1000 */ 253, 94, 84, 868, 871, 860, 860, 91, 91, 92,
- /* 1010 */ 92, 92, 92, 430, 90, 90, 90, 90, 89, 89,
- /* 1020 */ 88, 88, 88, 87, 335, 430, 114, 114, 114, 960,
- /* 1030 */ 856, 856, 307, 258, 830, 833, 100, 191, 252, 377,
- /* 1040 */ 267, 68, 197, 68, 261, 716, 769, 833, 50, 71,
- /* 1050 */ 911, 911, 263, 84, 868, 871, 860, 860, 91, 91,
- /* 1060 */ 92, 92, 92, 92, 430, 90, 90, 90, 90, 89,
- /* 1070 */ 89, 88, 88, 88, 87, 335, 80, 425, 802, 3,
- /* 1080 */ 1214, 191, 430, 265, 336, 336, 833, 101, 741, 80,
- /* 1090 */ 425, 897, 3, 723, 722, 428, 721, 336, 336, 430,
- /* 1100 */ 893, 270, 430, 197, 833, 102, 430, 800, 428, 430,
- /* 1110 */ 695, 430, 843, 111, 414, 430, 784, 409, 430, 831,
- /* 1120 */ 430, 833, 98, 123, 833, 116, 847, 414, 833, 49,
- /* 1130 */ 779, 833, 113, 833, 106, 226, 123, 833, 105, 847,
- /* 1140 */ 833, 103, 833, 104, 791, 411, 77, 78, 290, 412,
- /* 1150 */ 430, 291, 114, 79, 432, 431, 389, 430, 835, 77,
- /* 1160 */ 78, 897, 839, 408, 410, 430, 79, 432, 431, 372,
- /* 1170 */ 703, 835, 833, 52, 430, 80, 425, 430, 3, 833,
- /* 1180 */ 54, 772, 843, 336, 336, 684, 771, 833, 51, 840,
- /* 1190 */ 840, 840, 842, 19, 428, 672, 833, 26, 671, 833,
- /* 1200 */ 30, 673, 840, 840, 840, 842, 19, 207, 661, 278,
- /* 1210 */ 304, 148, 280, 414, 282, 248, 358, 822, 382, 6,
- /* 1220 */ 348, 161, 273, 80, 425, 847, 3, 934, 895, 720,
- /* 1230 */ 894, 336, 336, 296, 157, 415, 241, 284, 674, 958,
- /* 1240 */ 194, 953, 428, 951, 948, 77, 78, 777, 319, 56,
- /* 1250 */ 59, 135, 79, 432, 431, 121, 66, 835, 146, 128,
- /* 1260 */ 350, 414, 819, 130, 351, 131, 132, 133, 375, 173,
- /* 1270 */ 107, 138, 149, 847, 365, 178, 62, 70, 425, 936,
- /* 1280 */ 3, 827, 889, 371, 255, 336, 336, 792, 840, 840,
- /* 1290 */ 840, 842, 19, 77, 78, 915, 428, 208, 179, 144,
- /* 1300 */ 79, 432, 431, 373, 260, 835, 180, 326, 675, 181,
- /* 1310 */ 308, 744, 388, 743, 731, 414, 718, 742, 730, 712,
- /* 1320 */ 402, 309, 711, 272, 788, 65, 710, 847, 709, 277,
- /* 1330 */ 193, 789, 787, 279, 876, 73, 840, 840, 840, 842,
- /* 1340 */ 19, 786, 281, 418, 283, 422, 227, 77, 78, 330,
- /* 1350 */ 228, 229, 96, 767, 79, 432, 431, 407, 67, 835,
- /* 1360 */ 215, 292, 293, 405, 294, 303, 302, 301, 204, 299,
- /* 1370 */ 295, 202, 676, 681, 7, 433, 669, 203, 205, 206,
- /* 1380 */ 125, 110, 313, 434, 667, 666, 658, 168, 224, 237,
- /* 1390 */ 840, 840, 840, 842, 19, 120, 656, 337, 236, 155,
- /* 1400 */ 167, 341, 233, 314, 108, 905, 903, 826, 127, 126,
- /* 1410 */ 756, 170, 129, 172, 247, 928, 134, 136, 171, 60,
- /* 1420 */ 61, 123, 169, 137, 933, 175, 176, 927, 8, 13,
- /* 1430 */ 177, 254, 918, 139, 191, 924, 140, 370, 678, 150,
- /* 1440 */ 374, 182, 274, 268, 141, 122, 63, 14, 378, 15,
- /* 1450 */ 383, 64, 225, 846, 845, 874, 16, 4, 729, 765,
- /* 1460 */ 770, 162, 395, 209, 211, 142, 801, 878, 796, 312,
- /* 1470 */ 71, 68, 875, 873, 939, 190, 417, 938, 17, 195,
- /* 1480 */ 196, 152, 18, 975, 199, 976, 153, 198, 154, 421,
- /* 1490 */ 877, 844, 696, 81, 200, 297, 343, 1019, 1018, 300,
- /* 1500 */ 653,
+ /* 0 */ 325, 832, 351, 825, 5, 203, 203, 819, 99, 100,
+ /* 10 */ 90, 842, 842, 854, 857, 846, 846, 97, 97, 98,
+ /* 20 */ 98, 98, 98, 301, 96, 96, 96, 96, 95, 95,
+ /* 30 */ 94, 94, 94, 93, 351, 325, 977, 977, 824, 824,
+ /* 40 */ 826, 947, 354, 99, 100, 90, 842, 842, 854, 857,
+ /* 50 */ 846, 846, 97, 97, 98, 98, 98, 98, 338, 96,
+ /* 60 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351,
+ /* 70 */ 95, 95, 94, 94, 94, 93, 351, 791, 977, 977,
+ /* 80 */ 325, 94, 94, 94, 93, 351, 792, 75, 99, 100,
+ /* 90 */ 90, 842, 842, 854, 857, 846, 846, 97, 97, 98,
+ /* 100 */ 98, 98, 98, 450, 96, 96, 96, 96, 95, 95,
+ /* 110 */ 94, 94, 94, 93, 351, 1333, 155, 155, 2, 325,
+ /* 120 */ 275, 146, 132, 52, 52, 93, 351, 99, 100, 90,
+ /* 130 */ 842, 842, 854, 857, 846, 846, 97, 97, 98, 98,
+ /* 140 */ 98, 98, 101, 96, 96, 96, 96, 95, 95, 94,
+ /* 150 */ 94, 94, 93, 351, 958, 958, 325, 268, 428, 413,
+ /* 160 */ 411, 61, 752, 752, 99, 100, 90, 842, 842, 854,
+ /* 170 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 60,
+ /* 180 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
+ /* 190 */ 351, 325, 270, 329, 273, 277, 959, 960, 250, 99,
+ /* 200 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97,
+ /* 210 */ 98, 98, 98, 98, 301, 96, 96, 96, 96, 95,
+ /* 220 */ 95, 94, 94, 94, 93, 351, 325, 938, 1326, 698,
+ /* 230 */ 706, 1326, 242, 412, 99, 100, 90, 842, 842, 854,
+ /* 240 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 347,
+ /* 250 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
+ /* 260 */ 351, 325, 938, 1327, 384, 699, 1327, 381, 379, 99,
+ /* 270 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97,
+ /* 280 */ 98, 98, 98, 98, 701, 96, 96, 96, 96, 95,
+ /* 290 */ 95, 94, 94, 94, 93, 351, 325, 92, 89, 178,
+ /* 300 */ 833, 936, 373, 700, 99, 100, 90, 842, 842, 854,
+ /* 310 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 375,
+ /* 320 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
+ /* 330 */ 351, 325, 1276, 947, 354, 818, 936, 739, 739, 99,
+ /* 340 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97,
+ /* 350 */ 98, 98, 98, 98, 230, 96, 96, 96, 96, 95,
+ /* 360 */ 95, 94, 94, 94, 93, 351, 325, 969, 227, 92,
+ /* 370 */ 89, 178, 373, 300, 99, 100, 90, 842, 842, 854,
+ /* 380 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 921,
+ /* 390 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
+ /* 400 */ 351, 325, 449, 447, 447, 447, 147, 737, 737, 99,
+ /* 410 */ 100, 90, 842, 842, 854, 857, 846, 846, 97, 97,
+ /* 420 */ 98, 98, 98, 98, 296, 96, 96, 96, 96, 95,
+ /* 430 */ 95, 94, 94, 94, 93, 351, 325, 419, 231, 958,
+ /* 440 */ 958, 158, 25, 422, 99, 100, 90, 842, 842, 854,
+ /* 450 */ 857, 846, 846, 97, 97, 98, 98, 98, 98, 450,
+ /* 460 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
+ /* 470 */ 351, 443, 224, 224, 420, 958, 958, 962, 325, 52,
+ /* 480 */ 52, 959, 960, 176, 415, 78, 99, 100, 90, 842,
+ /* 490 */ 842, 854, 857, 846, 846, 97, 97, 98, 98, 98,
+ /* 500 */ 98, 379, 96, 96, 96, 96, 95, 95, 94, 94,
+ /* 510 */ 94, 93, 351, 325, 428, 418, 298, 959, 960, 962,
+ /* 520 */ 81, 99, 88, 90, 842, 842, 854, 857, 846, 846,
+ /* 530 */ 97, 97, 98, 98, 98, 98, 717, 96, 96, 96,
+ /* 540 */ 96, 95, 95, 94, 94, 94, 93, 351, 325, 843,
+ /* 550 */ 843, 855, 858, 996, 318, 343, 379, 100, 90, 842,
+ /* 560 */ 842, 854, 857, 846, 846, 97, 97, 98, 98, 98,
+ /* 570 */ 98, 450, 96, 96, 96, 96, 95, 95, 94, 94,
+ /* 580 */ 94, 93, 351, 325, 350, 350, 350, 260, 377, 340,
+ /* 590 */ 929, 52, 52, 90, 842, 842, 854, 857, 846, 846,
+ /* 600 */ 97, 97, 98, 98, 98, 98, 361, 96, 96, 96,
+ /* 610 */ 96, 95, 95, 94, 94, 94, 93, 351, 86, 445,
+ /* 620 */ 847, 3, 1203, 361, 360, 378, 344, 813, 958, 958,
+ /* 630 */ 1300, 86, 445, 729, 3, 212, 169, 287, 405, 282,
+ /* 640 */ 404, 199, 232, 450, 300, 760, 83, 84, 280, 245,
+ /* 650 */ 262, 365, 251, 85, 352, 352, 92, 89, 178, 83,
+ /* 660 */ 84, 242, 412, 52, 52, 448, 85, 352, 352, 246,
+ /* 670 */ 959, 960, 194, 455, 670, 402, 399, 398, 448, 243,
+ /* 680 */ 221, 114, 434, 776, 361, 450, 397, 268, 747, 224,
+ /* 690 */ 224, 132, 132, 198, 832, 434, 452, 451, 428, 427,
+ /* 700 */ 819, 415, 734, 713, 132, 52, 52, 832, 268, 452,
+ /* 710 */ 451, 734, 194, 819, 363, 402, 399, 398, 450, 1271,
+ /* 720 */ 1271, 23, 958, 958, 86, 445, 397, 3, 228, 429,
+ /* 730 */ 895, 824, 824, 826, 827, 19, 203, 720, 52, 52,
+ /* 740 */ 428, 408, 439, 249, 824, 824, 826, 827, 19, 229,
+ /* 750 */ 403, 153, 83, 84, 761, 177, 241, 450, 721, 85,
+ /* 760 */ 352, 352, 120, 157, 959, 960, 58, 977, 409, 355,
+ /* 770 */ 330, 448, 268, 428, 430, 320, 790, 32, 32, 86,
+ /* 780 */ 445, 776, 3, 341, 98, 98, 98, 98, 434, 96,
+ /* 790 */ 96, 96, 96, 95, 95, 94, 94, 94, 93, 351,
+ /* 800 */ 832, 120, 452, 451, 813, 887, 819, 83, 84, 977,
+ /* 810 */ 813, 132, 410, 920, 85, 352, 352, 132, 407, 789,
+ /* 820 */ 958, 958, 92, 89, 178, 917, 448, 262, 370, 261,
+ /* 830 */ 82, 914, 80, 262, 370, 261, 776, 824, 824, 826,
+ /* 840 */ 827, 19, 934, 434, 96, 96, 96, 96, 95, 95,
+ /* 850 */ 94, 94, 94, 93, 351, 832, 74, 452, 451, 958,
+ /* 860 */ 958, 819, 959, 960, 120, 92, 89, 178, 945, 2,
+ /* 870 */ 918, 965, 268, 1, 976, 76, 445, 762, 3, 708,
+ /* 880 */ 901, 901, 387, 958, 958, 757, 919, 371, 740, 778,
+ /* 890 */ 756, 257, 824, 824, 826, 827, 19, 417, 741, 450,
+ /* 900 */ 24, 959, 960, 83, 84, 369, 958, 958, 177, 226,
+ /* 910 */ 85, 352, 352, 885, 315, 314, 313, 215, 311, 10,
+ /* 920 */ 10, 683, 448, 349, 348, 959, 960, 909, 777, 157,
+ /* 930 */ 120, 958, 958, 337, 776, 416, 711, 310, 450, 434,
+ /* 940 */ 450, 321, 450, 791, 103, 200, 175, 450, 959, 960,
+ /* 950 */ 908, 832, 792, 452, 451, 9, 9, 819, 10, 10,
+ /* 960 */ 52, 52, 51, 51, 180, 716, 248, 10, 10, 171,
+ /* 970 */ 170, 167, 339, 959, 960, 247, 984, 702, 702, 450,
+ /* 980 */ 715, 233, 686, 982, 889, 983, 182, 914, 824, 824,
+ /* 990 */ 826, 827, 19, 183, 256, 423, 132, 181, 394, 10,
+ /* 1000 */ 10, 889, 891, 749, 958, 958, 917, 268, 985, 198,
+ /* 1010 */ 985, 349, 348, 425, 415, 299, 817, 832, 326, 825,
+ /* 1020 */ 120, 332, 133, 819, 268, 98, 98, 98, 98, 91,
+ /* 1030 */ 96, 96, 96, 96, 95, 95, 94, 94, 94, 93,
+ /* 1040 */ 351, 157, 810, 371, 382, 359, 959, 960, 358, 268,
+ /* 1050 */ 450, 918, 368, 324, 824, 824, 826, 450, 709, 450,
+ /* 1060 */ 264, 380, 889, 450, 877, 746, 253, 919, 255, 433,
+ /* 1070 */ 36, 36, 234, 450, 234, 120, 269, 37, 37, 12,
+ /* 1080 */ 12, 334, 272, 27, 27, 450, 330, 118, 450, 162,
+ /* 1090 */ 742, 280, 450, 38, 38, 450, 985, 356, 985, 450,
+ /* 1100 */ 709, 1210, 450, 132, 450, 39, 39, 450, 40, 40,
+ /* 1110 */ 450, 362, 41, 41, 450, 42, 42, 450, 254, 28,
+ /* 1120 */ 28, 450, 29, 29, 31, 31, 450, 43, 43, 450,
+ /* 1130 */ 44, 44, 450, 714, 45, 45, 450, 11, 11, 767,
+ /* 1140 */ 450, 46, 46, 450, 268, 450, 105, 105, 450, 47,
+ /* 1150 */ 47, 450, 48, 48, 450, 237, 33, 33, 450, 172,
+ /* 1160 */ 49, 49, 450, 50, 50, 34, 34, 274, 122, 122,
+ /* 1170 */ 450, 123, 123, 450, 124, 124, 450, 898, 56, 56,
+ /* 1180 */ 450, 897, 35, 35, 450, 267, 450, 817, 450, 817,
+ /* 1190 */ 106, 106, 450, 53, 53, 385, 107, 107, 450, 817,
+ /* 1200 */ 108, 108, 817, 450, 104, 104, 121, 121, 119, 119,
+ /* 1210 */ 450, 117, 112, 112, 450, 276, 450, 225, 111, 111,
+ /* 1220 */ 450, 730, 450, 109, 109, 450, 673, 674, 675, 912,
+ /* 1230 */ 110, 110, 317, 998, 55, 55, 57, 57, 692, 331,
+ /* 1240 */ 54, 54, 26, 26, 696, 30, 30, 317, 937, 197,
+ /* 1250 */ 196, 195, 335, 281, 336, 446, 331, 745, 689, 436,
+ /* 1260 */ 440, 444, 120, 72, 386, 223, 175, 345, 757, 933,
+ /* 1270 */ 20, 286, 319, 756, 815, 372, 374, 202, 202, 202,
+ /* 1280 */ 263, 395, 285, 74, 208, 21, 696, 719, 718, 884,
+ /* 1290 */ 120, 120, 120, 120, 120, 754, 278, 828, 77, 74,
+ /* 1300 */ 726, 727, 785, 783, 880, 202, 999, 208, 894, 893,
+ /* 1310 */ 894, 893, 694, 816, 763, 116, 774, 1290, 431, 432,
+ /* 1320 */ 302, 999, 390, 303, 823, 697, 691, 680, 159, 289,
+ /* 1330 */ 679, 884, 681, 952, 291, 218, 293, 7, 316, 828,
+ /* 1340 */ 173, 805, 259, 364, 252, 911, 376, 713, 295, 435,
+ /* 1350 */ 308, 168, 955, 993, 135, 400, 990, 284, 882, 881,
+ /* 1360 */ 205, 928, 926, 59, 333, 62, 144, 156, 130, 72,
+ /* 1370 */ 802, 366, 367, 393, 137, 185, 189, 160, 139, 383,
+ /* 1380 */ 67, 896, 140, 141, 142, 148, 389, 812, 775, 266,
+ /* 1390 */ 219, 190, 154, 391, 913, 876, 271, 406, 191, 322,
+ /* 1400 */ 682, 733, 192, 342, 732, 724, 731, 711, 723, 421,
+ /* 1410 */ 705, 71, 323, 6, 204, 771, 288, 79, 297, 346,
+ /* 1420 */ 772, 704, 290, 283, 703, 770, 292, 294, 967, 239,
+ /* 1430 */ 769, 102, 862, 438, 426, 240, 424, 442, 73, 213,
+ /* 1440 */ 688, 238, 22, 453, 953, 214, 217, 216, 454, 677,
+ /* 1450 */ 676, 671, 753, 125, 115, 235, 126, 669, 353, 166,
+ /* 1460 */ 127, 244, 179, 357, 306, 304, 305, 307, 113, 892,
+ /* 1470 */ 327, 890, 811, 328, 134, 128, 136, 138, 743, 258,
+ /* 1480 */ 907, 184, 143, 129, 910, 186, 63, 64, 145, 187,
+ /* 1490 */ 906, 65, 8, 66, 13, 188, 202, 899, 265, 149,
+ /* 1500 */ 987, 388, 150, 685, 161, 392, 285, 193, 279, 396,
+ /* 1510 */ 151, 401, 68, 14, 15, 722, 69, 236, 831, 131,
+ /* 1520 */ 830, 860, 70, 751, 16, 414, 755, 4, 174, 220,
+ /* 1530 */ 222, 784, 201, 152, 779, 77, 74, 17, 18, 875,
+ /* 1540 */ 861, 859, 916, 864, 915, 207, 206, 942, 163, 437,
+ /* 1550 */ 948, 943, 164, 209, 1002, 441, 863, 165, 210, 829,
+ /* 1560 */ 695, 87, 312, 211, 1292, 1291, 309,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 19, 144, 145, 146, 147, 24, 1, 2, 27, 80,
- /* 10 */ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- /* 20 */ 91, 92, 93, 94, 95, 91, 92, 93, 94, 95,
- /* 30 */ 19, 50, 51, 80, 81, 82, 83, 27, 85, 86,
- /* 40 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 137,
- /* 50 */ 177, 139, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 60 */ 79, 80, 81, 82, 83, 95, 85, 86, 87, 88,
- /* 70 */ 89, 90, 91, 92, 93, 94, 95, 19, 97, 85,
- /* 80 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
- /* 90 */ 152, 33, 212, 173, 27, 28, 223, 224, 225, 152,
- /* 100 */ 42, 181, 152, 223, 224, 225, 95, 97, 50, 51,
- /* 110 */ 99, 100, 101, 102, 103, 104, 105, 27, 28, 59,
- /* 120 */ 223, 224, 225, 112, 174, 175, 66, 94, 95, 71,
- /* 130 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
- /* 140 */ 82, 83, 195, 85, 86, 87, 88, 89, 90, 91,
- /* 150 */ 92, 93, 94, 95, 19, 197, 89, 90, 220, 209,
- /* 160 */ 210, 26, 119, 120, 97, 98, 208, 100, 108, 109,
- /* 170 */ 110, 152, 157, 152, 107, 152, 109, 89, 90, 91,
- /* 180 */ 92, 93, 94, 95, 163, 50, 51, 97, 98, 99,
- /* 190 */ 55, 66, 102, 103, 104, 174, 175, 174, 175, 132,
- /* 200 */ 133, 192, 193, 113, 66, 19, 71, 72, 73, 74,
- /* 210 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 198,
- /* 220 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
- /* 230 */ 95, 152, 209, 210, 148, 149, 50, 51, 100, 53,
- /* 240 */ 154, 59, 156, 174, 229, 27, 28, 232, 163, 163,
- /* 250 */ 22, 192, 193, 174, 175, 27, 28, 71, 72, 73,
- /* 260 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
- /* 270 */ 251, 85, 86, 87, 88, 89, 90, 91, 92, 93,
- /* 280 */ 94, 95, 19, 198, 198, 152, 152, 24, 209, 210,
- /* 290 */ 108, 109, 110, 196, 197, 27, 28, 69, 164, 165,
- /* 300 */ 152, 119, 120, 27, 28, 208, 99, 27, 28, 102,
- /* 310 */ 103, 104, 152, 50, 51, 97, 98, 89, 90, 185,
- /* 320 */ 113, 187, 22, 177, 174, 97, 58, 27, 28, 101,
- /* 330 */ 115, 245, 117, 118, 71, 72, 73, 74, 75, 76,
- /* 340 */ 77, 78, 79, 80, 81, 82, 83, 11, 85, 86,
- /* 350 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 19,
- /* 360 */ 132, 133, 134, 23, 152, 97, 98, 91, 174, 223,
- /* 370 */ 224, 225, 239, 97, 98, 187, 22, 97, 98, 27,
- /* 380 */ 28, 27, 28, 152, 223, 224, 225, 239, 152, 163,
- /* 390 */ 50, 51, 170, 171, 172, 59, 160, 97, 98, 239,
- /* 400 */ 164, 165, 66, 242, 124, 174, 175, 195, 22, 23,
- /* 410 */ 69, 71, 72, 73, 74, 75, 76, 77, 78, 79,
- /* 420 */ 80, 81, 82, 83, 198, 85, 86, 87, 88, 89,
- /* 430 */ 90, 91, 92, 93, 94, 95, 19, 12, 97, 21,
- /* 440 */ 23, 152, 101, 152, 108, 109, 110, 221, 152, 97,
- /* 450 */ 98, 97, 98, 152, 29, 243, 70, 226, 23, 233,
- /* 460 */ 26, 26, 152, 152, 238, 174, 175, 50, 51, 22,
- /* 470 */ 45, 24, 47, 132, 133, 134, 124, 22, 23, 188,
- /* 480 */ 163, 26, 152, 65, 59, 174, 175, 163, 71, 72,
- /* 490 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
- /* 500 */ 83, 152, 85, 86, 87, 88, 89, 90, 91, 92,
- /* 510 */ 93, 94, 95, 19, 19, 198, 152, 23, 152, 152,
- /* 520 */ 209, 103, 198, 174, 175, 70, 152, 50, 51, 219,
- /* 530 */ 213, 214, 152, 98, 152, 171, 172, 188, 171, 172,
- /* 540 */ 174, 175, 248, 249, 50, 51, 51, 251, 174, 175,
- /* 550 */ 220, 74, 75, 152, 188, 152, 174, 175, 140, 124,
- /* 560 */ 26, 163, 188, 16, 130, 71, 72, 73, 74, 75,
- /* 570 */ 76, 77, 78, 79, 80, 81, 82, 83, 101, 85,
- /* 580 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
- /* 590 */ 19, 209, 196, 197, 23, 231, 198, 12, 231, 219,
- /* 600 */ 37, 22, 107, 24, 208, 116, 27, 112, 201, 62,
- /* 610 */ 121, 64, 152, 152, 29, 52, 66, 221, 211, 221,
- /* 620 */ 219, 50, 51, 60, 89, 90, 152, 22, 23, 183,
- /* 630 */ 45, 26, 47, 22, 174, 175, 238, 152, 164, 165,
- /* 640 */ 106, 19, 71, 72, 73, 74, 75, 76, 77, 78,
- /* 650 */ 79, 80, 81, 82, 83, 152, 85, 86, 87, 88,
- /* 660 */ 89, 90, 91, 92, 93, 94, 95, 132, 133, 119,
- /* 670 */ 120, 163, 50, 51, 111, 70, 97, 174, 175, 181,
- /* 680 */ 182, 170, 171, 172, 0, 1, 2, 140, 190, 108,
- /* 690 */ 109, 110, 51, 71, 72, 73, 74, 75, 76, 77,
- /* 700 */ 78, 79, 80, 81, 82, 83, 198, 85, 86, 87,
- /* 710 */ 88, 89, 90, 91, 92, 93, 94, 95, 19, 152,
- /* 720 */ 152, 152, 22, 166, 152, 168, 169, 27, 19, 152,
- /* 730 */ 26, 19, 152, 122, 152, 24, 152, 28, 27, 152,
- /* 740 */ 28, 174, 175, 174, 175, 152, 174, 175, 107, 50,
- /* 750 */ 51, 174, 175, 22, 174, 175, 174, 175, 174, 175,
- /* 760 */ 138, 174, 175, 7, 8, 9, 16, 174, 175, 152,
- /* 770 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 780 */ 81, 82, 83, 152, 85, 86, 87, 88, 89, 90,
- /* 790 */ 91, 92, 93, 94, 95, 19, 152, 97, 152, 31,
- /* 800 */ 24, 152, 98, 35, 101, 174, 175, 152, 97, 152,
- /* 810 */ 79, 152, 62, 152, 64, 112, 152, 49, 174, 175,
- /* 820 */ 174, 175, 152, 174, 175, 152, 50, 51, 124, 174,
- /* 830 */ 175, 174, 175, 174, 175, 174, 175, 138, 174, 175,
- /* 840 */ 22, 23, 152, 152, 174, 175, 19, 71, 72, 73,
- /* 850 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
- /* 860 */ 152, 85, 86, 87, 88, 89, 90, 91, 92, 93,
- /* 870 */ 94, 95, 152, 108, 109, 110, 152, 50, 51, 146,
- /* 880 */ 147, 23, 174, 175, 26, 195, 195, 152, 70, 152,
- /* 890 */ 168, 169, 152, 26, 174, 175, 152, 19, 71, 72,
- /* 900 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
- /* 910 */ 83, 152, 85, 86, 87, 88, 89, 90, 91, 92,
- /* 920 */ 93, 94, 95, 152, 246, 247, 213, 214, 50, 51,
- /* 930 */ 195, 152, 195, 174, 175, 195, 100, 101, 152, 195,
- /* 940 */ 152, 152, 7, 8, 152, 174, 175, 163, 19, 71,
- /* 950 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
- /* 960 */ 82, 83, 152, 85, 86, 87, 88, 89, 90, 91,
- /* 970 */ 92, 93, 94, 95, 152, 27, 152, 189, 189, 50,
- /* 980 */ 51, 195, 198, 152, 174, 175, 33, 132, 133, 152,
- /* 990 */ 123, 163, 163, 163, 152, 42, 174, 175, 152, 19,
- /* 1000 */ 152, 72, 73, 74, 75, 76, 77, 78, 79, 80,
- /* 1010 */ 81, 82, 83, 152, 85, 86, 87, 88, 89, 90,
- /* 1020 */ 91, 92, 93, 94, 95, 152, 198, 198, 198, 23,
- /* 1030 */ 50, 51, 26, 152, 23, 174, 175, 26, 23, 23,
- /* 1040 */ 23, 26, 26, 26, 152, 97, 23, 174, 175, 26,
- /* 1050 */ 132, 133, 152, 73, 74, 75, 76, 77, 78, 79,
- /* 1060 */ 80, 81, 82, 83, 152, 85, 86, 87, 88, 89,
- /* 1070 */ 90, 91, 92, 93, 94, 95, 19, 20, 23, 22,
- /* 1080 */ 23, 26, 152, 152, 27, 28, 174, 175, 152, 19,
- /* 1090 */ 20, 27, 22, 183, 183, 38, 152, 27, 28, 152,
- /* 1100 */ 23, 152, 152, 26, 174, 175, 152, 152, 38, 152,
- /* 1110 */ 23, 152, 27, 26, 57, 152, 215, 163, 152, 152,
- /* 1120 */ 152, 174, 175, 66, 174, 175, 69, 57, 174, 175,
- /* 1130 */ 152, 174, 175, 174, 175, 212, 66, 174, 175, 69,
- /* 1140 */ 174, 175, 174, 175, 152, 152, 89, 90, 152, 193,
- /* 1150 */ 152, 152, 198, 96, 97, 98, 91, 152, 101, 89,
- /* 1160 */ 90, 97, 152, 209, 210, 152, 96, 97, 98, 235,
- /* 1170 */ 152, 101, 174, 175, 152, 19, 20, 152, 22, 174,
- /* 1180 */ 175, 116, 97, 27, 28, 152, 121, 174, 175, 132,
- /* 1190 */ 133, 134, 135, 136, 38, 152, 174, 175, 152, 174,
- /* 1200 */ 175, 152, 132, 133, 134, 135, 136, 234, 152, 212,
- /* 1210 */ 150, 199, 212, 57, 212, 240, 240, 203, 178, 200,
- /* 1220 */ 216, 186, 177, 19, 20, 69, 22, 203, 177, 182,
- /* 1230 */ 177, 27, 28, 202, 200, 228, 216, 216, 155, 39,
- /* 1240 */ 122, 159, 38, 159, 41, 89, 90, 91, 159, 241,
- /* 1250 */ 241, 22, 96, 97, 98, 71, 130, 101, 222, 191,
- /* 1260 */ 18, 57, 203, 194, 159, 194, 194, 194, 18, 158,
- /* 1270 */ 244, 191, 222, 69, 159, 158, 137, 19, 20, 203,
- /* 1280 */ 22, 191, 203, 46, 236, 27, 28, 159, 132, 133,
- /* 1290 */ 134, 135, 136, 89, 90, 237, 38, 159, 158, 22,
- /* 1300 */ 96, 97, 98, 179, 159, 101, 158, 48, 159, 158,
- /* 1310 */ 179, 176, 107, 176, 184, 57, 106, 176, 184, 176,
- /* 1320 */ 125, 179, 178, 176, 218, 107, 176, 69, 176, 217,
- /* 1330 */ 159, 218, 218, 217, 159, 137, 132, 133, 134, 135,
- /* 1340 */ 136, 218, 217, 179, 217, 179, 227, 89, 90, 95,
- /* 1350 */ 230, 230, 129, 207, 96, 97, 98, 126, 128, 101,
- /* 1360 */ 5, 206, 205, 127, 204, 10, 11, 12, 13, 14,
- /* 1370 */ 203, 25, 17, 162, 26, 161, 13, 153, 153, 6,
- /* 1380 */ 247, 180, 250, 151, 151, 151, 151, 32, 180, 34,
- /* 1390 */ 132, 133, 134, 135, 136, 167, 4, 3, 43, 22,
- /* 1400 */ 15, 68, 142, 250, 16, 23, 23, 120, 111, 131,
- /* 1410 */ 20, 56, 123, 125, 16, 1, 123, 131, 63, 79,
- /* 1420 */ 79, 66, 67, 111, 28, 36, 122, 1, 5, 22,
- /* 1430 */ 107, 140, 54, 54, 26, 61, 107, 44, 20, 24,
- /* 1440 */ 19, 105, 112, 23, 22, 40, 22, 22, 53, 22,
- /* 1450 */ 53, 22, 53, 23, 23, 23, 22, 22, 30, 116,
- /* 1460 */ 23, 122, 26, 23, 23, 22, 28, 11, 124, 114,
- /* 1470 */ 26, 26, 23, 23, 23, 36, 24, 23, 36, 26,
- /* 1480 */ 22, 22, 36, 23, 122, 23, 22, 26, 22, 24,
- /* 1490 */ 23, 23, 23, 22, 122, 23, 141, 122, 122, 15,
- /* 1500 */ 1,
+ /* 0 */ 19, 95, 53, 97, 22, 24, 24, 101, 27, 28,
+ /* 10 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ /* 20 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48,
+ /* 30 */ 49, 50, 51, 52, 53, 19, 55, 55, 132, 133,
+ /* 40 */ 134, 1, 2, 27, 28, 29, 30, 31, 32, 33,
+ /* 50 */ 34, 35, 36, 37, 38, 39, 40, 41, 187, 43,
+ /* 60 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ /* 70 */ 47, 48, 49, 50, 51, 52, 53, 61, 97, 97,
+ /* 80 */ 19, 49, 50, 51, 52, 53, 70, 26, 27, 28,
+ /* 90 */ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ /* 100 */ 39, 40, 41, 152, 43, 44, 45, 46, 47, 48,
+ /* 110 */ 49, 50, 51, 52, 53, 144, 145, 146, 147, 19,
+ /* 120 */ 16, 22, 92, 172, 173, 52, 53, 27, 28, 29,
+ /* 130 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ /* 140 */ 40, 41, 81, 43, 44, 45, 46, 47, 48, 49,
+ /* 150 */ 50, 51, 52, 53, 55, 56, 19, 152, 207, 208,
+ /* 160 */ 115, 24, 117, 118, 27, 28, 29, 30, 31, 32,
+ /* 170 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 79,
+ /* 180 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 190 */ 53, 19, 88, 157, 90, 23, 97, 98, 193, 27,
+ /* 200 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ /* 210 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47,
+ /* 220 */ 48, 49, 50, 51, 52, 53, 19, 22, 23, 172,
+ /* 230 */ 23, 26, 119, 120, 27, 28, 29, 30, 31, 32,
+ /* 240 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 187,
+ /* 250 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 260 */ 53, 19, 22, 23, 228, 23, 26, 231, 152, 27,
+ /* 270 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ /* 280 */ 38, 39, 40, 41, 172, 43, 44, 45, 46, 47,
+ /* 290 */ 48, 49, 50, 51, 52, 53, 19, 221, 222, 223,
+ /* 300 */ 23, 96, 152, 172, 27, 28, 29, 30, 31, 32,
+ /* 310 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152,
+ /* 320 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 330 */ 53, 19, 0, 1, 2, 23, 96, 190, 191, 27,
+ /* 340 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ /* 350 */ 38, 39, 40, 41, 238, 43, 44, 45, 46, 47,
+ /* 360 */ 48, 49, 50, 51, 52, 53, 19, 185, 218, 221,
+ /* 370 */ 222, 223, 152, 152, 27, 28, 29, 30, 31, 32,
+ /* 380 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 241,
+ /* 390 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 400 */ 53, 19, 152, 168, 169, 170, 22, 190, 191, 27,
+ /* 410 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ /* 420 */ 38, 39, 40, 41, 152, 43, 44, 45, 46, 47,
+ /* 430 */ 48, 49, 50, 51, 52, 53, 19, 19, 218, 55,
+ /* 440 */ 56, 24, 22, 152, 27, 28, 29, 30, 31, 32,
+ /* 450 */ 33, 34, 35, 36, 37, 38, 39, 40, 41, 152,
+ /* 460 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 470 */ 53, 250, 194, 195, 56, 55, 56, 55, 19, 172,
+ /* 480 */ 173, 97, 98, 152, 206, 138, 27, 28, 29, 30,
+ /* 490 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ /* 500 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50,
+ /* 510 */ 51, 52, 53, 19, 207, 208, 152, 97, 98, 97,
+ /* 520 */ 138, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+ /* 530 */ 36, 37, 38, 39, 40, 41, 181, 43, 44, 45,
+ /* 540 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 30,
+ /* 550 */ 31, 32, 33, 247, 248, 19, 152, 28, 29, 30,
+ /* 560 */ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ /* 570 */ 41, 152, 43, 44, 45, 46, 47, 48, 49, 50,
+ /* 580 */ 51, 52, 53, 19, 168, 169, 170, 238, 19, 53,
+ /* 590 */ 152, 172, 173, 29, 30, 31, 32, 33, 34, 35,
+ /* 600 */ 36, 37, 38, 39, 40, 41, 152, 43, 44, 45,
+ /* 610 */ 46, 47, 48, 49, 50, 51, 52, 53, 19, 20,
+ /* 620 */ 101, 22, 23, 169, 170, 56, 207, 85, 55, 56,
+ /* 630 */ 23, 19, 20, 26, 22, 99, 100, 101, 102, 103,
+ /* 640 */ 104, 105, 238, 152, 152, 210, 47, 48, 112, 152,
+ /* 650 */ 108, 109, 110, 54, 55, 56, 221, 222, 223, 47,
+ /* 660 */ 48, 119, 120, 172, 173, 66, 54, 55, 56, 152,
+ /* 670 */ 97, 98, 99, 148, 149, 102, 103, 104, 66, 154,
+ /* 680 */ 23, 156, 83, 26, 230, 152, 113, 152, 163, 194,
+ /* 690 */ 195, 92, 92, 30, 95, 83, 97, 98, 207, 208,
+ /* 700 */ 101, 206, 179, 180, 92, 172, 173, 95, 152, 97,
+ /* 710 */ 98, 188, 99, 101, 219, 102, 103, 104, 152, 119,
+ /* 720 */ 120, 196, 55, 56, 19, 20, 113, 22, 193, 163,
+ /* 730 */ 11, 132, 133, 134, 135, 136, 24, 65, 172, 173,
+ /* 740 */ 207, 208, 250, 152, 132, 133, 134, 135, 136, 193,
+ /* 750 */ 78, 84, 47, 48, 49, 98, 199, 152, 86, 54,
+ /* 760 */ 55, 56, 196, 152, 97, 98, 209, 55, 163, 244,
+ /* 770 */ 107, 66, 152, 207, 208, 164, 175, 172, 173, 19,
+ /* 780 */ 20, 124, 22, 111, 38, 39, 40, 41, 83, 43,
+ /* 790 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ /* 800 */ 95, 196, 97, 98, 85, 152, 101, 47, 48, 97,
+ /* 810 */ 85, 92, 207, 193, 54, 55, 56, 92, 49, 175,
+ /* 820 */ 55, 56, 221, 222, 223, 12, 66, 108, 109, 110,
+ /* 830 */ 137, 163, 139, 108, 109, 110, 26, 132, 133, 134,
+ /* 840 */ 135, 136, 152, 83, 43, 44, 45, 46, 47, 48,
+ /* 850 */ 49, 50, 51, 52, 53, 95, 26, 97, 98, 55,
+ /* 860 */ 56, 101, 97, 98, 196, 221, 222, 223, 146, 147,
+ /* 870 */ 57, 171, 152, 22, 26, 19, 20, 49, 22, 179,
+ /* 880 */ 108, 109, 110, 55, 56, 116, 73, 219, 75, 124,
+ /* 890 */ 121, 152, 132, 133, 134, 135, 136, 163, 85, 152,
+ /* 900 */ 232, 97, 98, 47, 48, 237, 55, 56, 98, 5,
+ /* 910 */ 54, 55, 56, 193, 10, 11, 12, 13, 14, 172,
+ /* 920 */ 173, 17, 66, 47, 48, 97, 98, 152, 124, 152,
+ /* 930 */ 196, 55, 56, 186, 124, 152, 106, 160, 152, 83,
+ /* 940 */ 152, 164, 152, 61, 22, 211, 212, 152, 97, 98,
+ /* 950 */ 152, 95, 70, 97, 98, 172, 173, 101, 172, 173,
+ /* 960 */ 172, 173, 172, 173, 60, 181, 62, 172, 173, 47,
+ /* 970 */ 48, 123, 186, 97, 98, 71, 100, 55, 56, 152,
+ /* 980 */ 181, 186, 21, 107, 152, 109, 82, 163, 132, 133,
+ /* 990 */ 134, 135, 136, 89, 16, 207, 92, 93, 19, 172,
+ /* 1000 */ 173, 169, 170, 195, 55, 56, 12, 152, 132, 30,
+ /* 1010 */ 134, 47, 48, 186, 206, 225, 152, 95, 114, 97,
+ /* 1020 */ 196, 245, 246, 101, 152, 38, 39, 40, 41, 42,
+ /* 1030 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ /* 1040 */ 53, 152, 163, 219, 152, 141, 97, 98, 193, 152,
+ /* 1050 */ 152, 57, 91, 164, 132, 133, 134, 152, 55, 152,
+ /* 1060 */ 152, 237, 230, 152, 103, 193, 88, 73, 90, 75,
+ /* 1070 */ 172, 173, 183, 152, 185, 196, 152, 172, 173, 172,
+ /* 1080 */ 173, 217, 152, 172, 173, 152, 107, 22, 152, 24,
+ /* 1090 */ 193, 112, 152, 172, 173, 152, 132, 242, 134, 152,
+ /* 1100 */ 97, 140, 152, 92, 152, 172, 173, 152, 172, 173,
+ /* 1110 */ 152, 100, 172, 173, 152, 172, 173, 152, 140, 172,
+ /* 1120 */ 173, 152, 172, 173, 172, 173, 152, 172, 173, 152,
+ /* 1130 */ 172, 173, 152, 152, 172, 173, 152, 172, 173, 213,
+ /* 1140 */ 152, 172, 173, 152, 152, 152, 172, 173, 152, 172,
+ /* 1150 */ 173, 152, 172, 173, 152, 210, 172, 173, 152, 26,
+ /* 1160 */ 172, 173, 152, 172, 173, 172, 173, 152, 172, 173,
+ /* 1170 */ 152, 172, 173, 152, 172, 173, 152, 59, 172, 173,
+ /* 1180 */ 152, 63, 172, 173, 152, 193, 152, 152, 152, 152,
+ /* 1190 */ 172, 173, 152, 172, 173, 77, 172, 173, 152, 152,
+ /* 1200 */ 172, 173, 152, 152, 172, 173, 172, 173, 172, 173,
+ /* 1210 */ 152, 22, 172, 173, 152, 152, 152, 22, 172, 173,
+ /* 1220 */ 152, 152, 152, 172, 173, 152, 7, 8, 9, 163,
+ /* 1230 */ 172, 173, 22, 23, 172, 173, 172, 173, 166, 167,
+ /* 1240 */ 172, 173, 172, 173, 55, 172, 173, 22, 23, 108,
+ /* 1250 */ 109, 110, 217, 152, 217, 166, 167, 163, 163, 163,
+ /* 1260 */ 163, 163, 196, 130, 217, 211, 212, 217, 116, 23,
+ /* 1270 */ 22, 101, 26, 121, 23, 23, 23, 26, 26, 26,
+ /* 1280 */ 23, 23, 112, 26, 26, 37, 97, 100, 101, 55,
+ /* 1290 */ 196, 196, 196, 196, 196, 23, 23, 55, 26, 26,
+ /* 1300 */ 7, 8, 23, 152, 23, 26, 96, 26, 132, 132,
+ /* 1310 */ 134, 134, 23, 152, 152, 26, 152, 122, 152, 191,
+ /* 1320 */ 152, 96, 234, 152, 152, 152, 152, 152, 197, 210,
+ /* 1330 */ 152, 97, 152, 152, 210, 233, 210, 198, 150, 97,
+ /* 1340 */ 184, 201, 239, 214, 214, 201, 239, 180, 214, 227,
+ /* 1350 */ 200, 198, 155, 67, 243, 176, 69, 175, 175, 175,
+ /* 1360 */ 122, 159, 159, 240, 159, 240, 22, 220, 27, 130,
+ /* 1370 */ 201, 18, 159, 18, 189, 158, 158, 220, 192, 159,
+ /* 1380 */ 137, 236, 192, 192, 192, 189, 74, 189, 159, 235,
+ /* 1390 */ 159, 158, 22, 177, 201, 201, 159, 107, 158, 177,
+ /* 1400 */ 159, 174, 158, 76, 174, 182, 174, 106, 182, 125,
+ /* 1410 */ 174, 107, 177, 22, 159, 216, 215, 137, 159, 53,
+ /* 1420 */ 216, 176, 215, 174, 174, 216, 215, 215, 174, 229,
+ /* 1430 */ 216, 129, 224, 177, 126, 229, 127, 177, 128, 25,
+ /* 1440 */ 162, 226, 26, 161, 13, 153, 6, 153, 151, 151,
+ /* 1450 */ 151, 151, 205, 165, 178, 178, 165, 4, 3, 22,
+ /* 1460 */ 165, 142, 15, 94, 202, 204, 203, 201, 16, 23,
+ /* 1470 */ 249, 23, 120, 249, 246, 111, 131, 123, 20, 16,
+ /* 1480 */ 1, 125, 123, 111, 56, 64, 37, 37, 131, 122,
+ /* 1490 */ 1, 37, 5, 37, 22, 107, 26, 80, 140, 80,
+ /* 1500 */ 87, 72, 107, 20, 24, 19, 112, 105, 23, 79,
+ /* 1510 */ 22, 79, 22, 22, 22, 58, 22, 79, 23, 68,
+ /* 1520 */ 23, 23, 26, 116, 22, 26, 23, 22, 122, 23,
+ /* 1530 */ 23, 56, 64, 22, 124, 26, 26, 64, 64, 23,
+ /* 1540 */ 23, 23, 23, 11, 23, 22, 26, 23, 22, 24,
+ /* 1550 */ 1, 23, 22, 26, 251, 24, 23, 22, 122, 23,
+ /* 1560 */ 23, 22, 15, 122, 122, 122, 23,
};
-#define YY_SHIFT_USE_DFLT (-89)
-#define YY_SHIFT_COUNT (435)
-#define YY_SHIFT_MIN (-88)
-#define YY_SHIFT_MAX (1499)
+#define YY_SHIFT_USE_DFLT (1567)
+#define YY_SHIFT_COUNT (455)
+#define YY_SHIFT_MIN (-94)
+#define YY_SHIFT_MAX (1549)
static const short yy_shift_ofst[] = {
- /* 0 */ 5, 1057, 1355, 1070, 1204, 1204, 1204, 90, 60, -19,
- /* 10 */ 58, 58, 186, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
- /* 20 */ 67, 67, 182, 336, 218, 550, 135, 263, 340, 417,
- /* 30 */ 494, 571, 622, 699, 776, 827, 827, 827, 827, 827,
- /* 40 */ 827, 827, 827, 827, 827, 827, 827, 827, 827, 827,
- /* 50 */ 878, 827, 929, 980, 980, 1156, 1204, 1204, 1204, 1204,
- /* 60 */ 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
- /* 70 */ 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204,
- /* 80 */ 1204, 1204, 1204, 1204, 1258, 1204, 1204, 1204, 1204, 1204,
- /* 90 */ 1204, 1204, 1204, 1204, 1204, 1204, 1204, 1204, -71, -47,
- /* 100 */ -47, -47, -47, -47, -6, 88, -66, 218, 218, 418,
- /* 110 */ 495, 535, 535, 33, 43, 10, -30, -89, -89, -89,
- /* 120 */ 11, 425, 425, 268, 455, 605, 218, 218, 218, 218,
- /* 130 */ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
- /* 140 */ 218, 218, 218, 218, 218, 684, 138, 10, 43, 125,
- /* 150 */ 125, 125, 125, 125, 125, -89, -89, -89, 228, 341,
- /* 160 */ 341, 207, 276, 300, 280, 352, 354, 218, 218, 218,
- /* 170 */ 218, 218, 218, 218, 218, 218, 218, 218, 218, 218,
- /* 180 */ 218, 218, 218, 218, 563, 563, 563, 218, 218, 435,
- /* 190 */ 218, 218, 218, 579, 218, 218, 585, 218, 218, 218,
- /* 200 */ 218, 218, 218, 218, 218, 218, 218, 581, 768, 711,
- /* 210 */ 711, 711, 704, 215, 1065, 756, 434, 709, 709, 712,
- /* 220 */ 434, 712, 534, 858, 641, 953, 709, -88, 953, 953,
- /* 230 */ 867, 489, 447, 1200, 1118, 1118, 1203, 1203, 1118, 1229,
- /* 240 */ 1184, 1126, 1242, 1242, 1242, 1242, 1118, 1250, 1126, 1229,
- /* 250 */ 1184, 1184, 1126, 1118, 1250, 1139, 1237, 1118, 1118, 1250,
- /* 260 */ 1277, 1118, 1250, 1118, 1250, 1277, 1205, 1205, 1205, 1259,
- /* 270 */ 1277, 1205, 1210, 1205, 1259, 1205, 1205, 1195, 1218, 1195,
- /* 280 */ 1218, 1195, 1218, 1195, 1218, 1118, 1118, 1198, 1277, 1254,
- /* 290 */ 1254, 1277, 1223, 1231, 1230, 1236, 1126, 1346, 1348, 1363,
- /* 300 */ 1363, 1373, 1373, 1373, 1373, -89, -89, -89, -89, -89,
- /* 310 */ -89, 477, 547, 386, 818, 750, 765, 700, 1006, 731,
- /* 320 */ 1011, 1015, 1016, 1017, 948, 836, 935, 703, 1023, 1055,
- /* 330 */ 1064, 1077, 855, 918, 1087, 1085, 611, 1392, 1394, 1377,
- /* 340 */ 1260, 1385, 1333, 1388, 1382, 1383, 1287, 1278, 1297, 1289,
- /* 350 */ 1390, 1288, 1398, 1414, 1293, 1286, 1340, 1341, 1312, 1396,
- /* 360 */ 1389, 1304, 1426, 1423, 1407, 1323, 1291, 1378, 1408, 1379,
- /* 370 */ 1374, 1393, 1329, 1415, 1418, 1421, 1330, 1336, 1422, 1395,
- /* 380 */ 1424, 1425, 1420, 1427, 1397, 1428, 1429, 1399, 1405, 1430,
- /* 390 */ 1431, 1432, 1343, 1434, 1437, 1435, 1436, 1339, 1440, 1441,
- /* 400 */ 1438, 1439, 1443, 1344, 1444, 1442, 1445, 1446, 1444, 1449,
- /* 410 */ 1450, 1451, 1453, 1454, 1458, 1456, 1460, 1459, 1452, 1461,
- /* 420 */ 1462, 1464, 1465, 1461, 1467, 1466, 1468, 1469, 1471, 1362,
- /* 430 */ 1372, 1375, 1376, 1472, 1484, 1499,
+ /* 0 */ 40, 599, 904, 612, 760, 760, 760, 760, 725, -19,
+ /* 10 */ 16, 16, 100, 760, 760, 760, 760, 760, 760, 760,
+ /* 20 */ 876, 876, 573, 542, 719, 600, 61, 137, 172, 207,
+ /* 30 */ 242, 277, 312, 347, 382, 417, 459, 459, 459, 459,
+ /* 40 */ 459, 459, 459, 459, 459, 459, 459, 459, 459, 459,
+ /* 50 */ 459, 459, 459, 494, 459, 529, 564, 564, 705, 760,
+ /* 60 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760,
+ /* 70 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760,
+ /* 80 */ 760, 760, 760, 760, 760, 760, 760, 760, 760, 760,
+ /* 90 */ 856, 760, 760, 760, 760, 760, 760, 760, 760, 760,
+ /* 100 */ 760, 760, 760, 760, 987, 746, 746, 746, 746, 746,
+ /* 110 */ 801, 23, 32, 949, 961, 979, 964, 964, 949, 73,
+ /* 120 */ 113, -51, 1567, 1567, 1567, 536, 536, 536, 99, 99,
+ /* 130 */ 813, 813, 667, 205, 240, 949, 949, 949, 949, 949,
+ /* 140 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949,
+ /* 150 */ 949, 949, 949, 949, 949, 332, 1011, 422, 422, 113,
+ /* 160 */ 30, 30, 30, 30, 30, 30, 1567, 1567, 1567, 922,
+ /* 170 */ -94, -94, 384, 613, 828, 420, 765, 804, 851, 949,
+ /* 180 */ 949, 949, 949, 949, 949, 949, 949, 949, 949, 949,
+ /* 190 */ 949, 949, 949, 949, 949, 672, 672, 672, 949, 949,
+ /* 200 */ 657, 949, 949, 949, -18, 949, 949, 994, 949, 949,
+ /* 210 */ 949, 949, 949, 949, 949, 949, 949, 949, 772, 1118,
+ /* 220 */ 712, 712, 712, 810, 45, 769, 1219, 1133, 418, 418,
+ /* 230 */ 569, 1133, 569, 830, 607, 663, 882, 418, 693, 882,
+ /* 240 */ 882, 848, 1152, 1065, 1286, 1238, 1238, 1287, 1287, 1238,
+ /* 250 */ 1344, 1341, 1239, 1353, 1353, 1353, 1353, 1238, 1355, 1239,
+ /* 260 */ 1344, 1341, 1341, 1239, 1238, 1355, 1243, 1312, 1238, 1238,
+ /* 270 */ 1355, 1370, 1238, 1355, 1238, 1355, 1370, 1290, 1290, 1290,
+ /* 280 */ 1327, 1370, 1290, 1301, 1290, 1327, 1290, 1290, 1284, 1304,
+ /* 290 */ 1284, 1304, 1284, 1304, 1284, 1304, 1238, 1391, 1238, 1280,
+ /* 300 */ 1370, 1366, 1366, 1370, 1302, 1308, 1310, 1309, 1239, 1414,
+ /* 310 */ 1416, 1431, 1431, 1440, 1440, 1440, 1440, 1567, 1567, 1567,
+ /* 320 */ 1567, 1567, 1567, 1567, 1567, 519, 978, 1210, 1225, 104,
+ /* 330 */ 1141, 1189, 1246, 1248, 1251, 1252, 1253, 1257, 1258, 1273,
+ /* 340 */ 1003, 1187, 1293, 1170, 1272, 1279, 1234, 1281, 1176, 1177,
+ /* 350 */ 1289, 1242, 1195, 1453, 1455, 1437, 1319, 1447, 1369, 1452,
+ /* 360 */ 1446, 1448, 1352, 1345, 1364, 1354, 1458, 1356, 1463, 1479,
+ /* 370 */ 1359, 1357, 1449, 1450, 1454, 1456, 1372, 1428, 1421, 1367,
+ /* 380 */ 1489, 1487, 1472, 1388, 1358, 1417, 1470, 1419, 1413, 1429,
+ /* 390 */ 1395, 1480, 1483, 1486, 1394, 1402, 1488, 1430, 1490, 1491,
+ /* 400 */ 1485, 1492, 1432, 1457, 1494, 1438, 1451, 1495, 1497, 1498,
+ /* 410 */ 1496, 1407, 1502, 1503, 1505, 1499, 1406, 1506, 1507, 1475,
+ /* 420 */ 1468, 1511, 1410, 1509, 1473, 1510, 1474, 1516, 1509, 1517,
+ /* 430 */ 1518, 1519, 1520, 1521, 1523, 1532, 1524, 1526, 1525, 1527,
+ /* 440 */ 1528, 1530, 1531, 1527, 1533, 1535, 1536, 1537, 1539, 1436,
+ /* 450 */ 1441, 1442, 1443, 1543, 1547, 1549,
};
-#define YY_REDUCE_USE_DFLT (-144)
-#define YY_REDUCE_COUNT (310)
-#define YY_REDUCE_MIN (-143)
-#define YY_REDUCE_MAX (1235)
+#define YY_REDUCE_USE_DFLT (-130)
+#define YY_REDUCE_COUNT (324)
+#define YY_REDUCE_MIN (-129)
+#define YY_REDUCE_MAX (1300)
static const short yy_reduce_ofst[] = {
- /* 0 */ -143, 954, 86, 21, -50, 23, 79, 134, 226, -120,
- /* 10 */ -127, 146, 161, 291, 349, 366, 311, 382, 374, 231,
- /* 20 */ 364, 367, 396, 398, 236, 317, -103, -103, -103, -103,
- /* 30 */ -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,
- /* 40 */ -103, -103, -103, -103, -103, -103, -103, -103, -103, -103,
- /* 50 */ -103, -103, -103, -103, -103, 460, 503, 567, 569, 572,
- /* 60 */ 577, 580, 582, 584, 587, 593, 631, 644, 646, 649,
- /* 70 */ 655, 657, 659, 661, 664, 670, 708, 720, 759, 771,
- /* 80 */ 810, 822, 861, 873, 912, 930, 947, 950, 957, 959,
- /* 90 */ 963, 966, 968, 998, 1005, 1013, 1022, 1025, -103, -103,
- /* 100 */ -103, -103, -103, -103, -103, -103, -103, 474, 212, 15,
- /* 110 */ 498, 222, 511, -103, 97, 557, -103, -103, -103, -103,
- /* 120 */ -80, 9, 59, 19, 294, 294, -53, -62, 690, 691,
- /* 130 */ 735, 737, 740, 744, 133, 310, 148, 330, 160, 380,
- /* 140 */ 786, 788, 401, 296, 789, 733, 85, 722, -42, 324,
- /* 150 */ 508, 784, 828, 829, 830, 678, 713, 407, 69, 150,
- /* 160 */ 194, 188, 289, 301, 403, 461, 485, 568, 617, 673,
- /* 170 */ 724, 779, 792, 824, 831, 837, 842, 846, 848, 881,
- /* 180 */ 892, 900, 931, 936, 446, 910, 911, 944, 949, 901,
- /* 190 */ 955, 967, 978, 923, 992, 993, 956, 996, 999, 1010,
- /* 200 */ 289, 1018, 1033, 1043, 1046, 1049, 1056, 934, 973, 997,
- /* 210 */ 1000, 1002, 901, 1012, 1019, 1060, 1014, 1004, 1020, 975,
- /* 220 */ 1024, 976, 1040, 1035, 1047, 1045, 1021, 1007, 1051, 1053,
- /* 230 */ 1031, 1034, 1083, 1026, 1082, 1084, 1008, 1009, 1089, 1036,
- /* 240 */ 1068, 1059, 1069, 1071, 1072, 1073, 1105, 1111, 1076, 1050,
- /* 250 */ 1080, 1090, 1079, 1115, 1117, 1058, 1048, 1128, 1138, 1140,
- /* 260 */ 1124, 1145, 1148, 1149, 1151, 1131, 1135, 1137, 1141, 1130,
- /* 270 */ 1142, 1143, 1144, 1147, 1134, 1150, 1152, 1106, 1112, 1113,
- /* 280 */ 1116, 1114, 1125, 1123, 1127, 1171, 1175, 1119, 1164, 1120,
- /* 290 */ 1121, 1166, 1146, 1155, 1157, 1160, 1167, 1211, 1214, 1224,
- /* 300 */ 1225, 1232, 1233, 1234, 1235, 1132, 1153, 1133, 1201, 1208,
- /* 310 */ 1228,
+ /* 0 */ -29, 566, 525, 605, -49, 307, 491, 533, 668, 435,
+ /* 10 */ 601, 644, 148, 747, 786, 795, 419, 788, 827, 790,
+ /* 20 */ 454, 832, 889, 495, 824, 734, 76, 76, 76, 76,
+ /* 30 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ /* 40 */ 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ /* 50 */ 76, 76, 76, 76, 76, 76, 76, 76, 783, 898,
+ /* 60 */ 905, 907, 911, 921, 933, 936, 940, 943, 947, 950,
+ /* 70 */ 952, 955, 958, 962, 965, 969, 974, 977, 980, 984,
+ /* 80 */ 988, 991, 993, 996, 999, 1002, 1006, 1010, 1018, 1021,
+ /* 90 */ 1024, 1028, 1032, 1034, 1036, 1040, 1046, 1051, 1058, 1062,
+ /* 100 */ 1064, 1068, 1070, 1073, 76, 76, 76, 76, 76, 76,
+ /* 110 */ 76, 76, 76, 855, 36, 523, 235, 416, 777, 76,
+ /* 120 */ 278, 76, 76, 76, 76, 700, 700, 700, 150, 220,
+ /* 130 */ 147, 217, 221, 306, 306, 611, 5, 535, 556, 620,
+ /* 140 */ 720, 872, 897, 116, 864, 349, 1035, 1037, 404, 1047,
+ /* 150 */ 992, -129, 1050, 492, 62, 722, 879, 1072, 1089, 808,
+ /* 160 */ 1066, 1094, 1095, 1096, 1097, 1098, 776, 1054, 557, 57,
+ /* 170 */ 112, 131, 167, 182, 250, 272, 291, 331, 364, 438,
+ /* 180 */ 497, 517, 591, 653, 690, 739, 775, 798, 892, 908,
+ /* 190 */ 924, 930, 1015, 1063, 1069, 355, 784, 799, 981, 1101,
+ /* 200 */ 926, 1151, 1161, 1162, 945, 1164, 1166, 1128, 1168, 1171,
+ /* 210 */ 1172, 250, 1173, 1174, 1175, 1178, 1180, 1181, 1088, 1102,
+ /* 220 */ 1119, 1124, 1126, 926, 1131, 1139, 1188, 1140, 1129, 1130,
+ /* 230 */ 1103, 1144, 1107, 1179, 1156, 1167, 1182, 1134, 1122, 1183,
+ /* 240 */ 1184, 1150, 1153, 1197, 1111, 1202, 1203, 1123, 1125, 1205,
+ /* 250 */ 1147, 1185, 1169, 1186, 1190, 1191, 1192, 1213, 1217, 1193,
+ /* 260 */ 1157, 1196, 1198, 1194, 1220, 1218, 1145, 1154, 1229, 1231,
+ /* 270 */ 1233, 1216, 1237, 1240, 1241, 1244, 1222, 1227, 1230, 1232,
+ /* 280 */ 1223, 1235, 1236, 1245, 1249, 1226, 1250, 1254, 1199, 1201,
+ /* 290 */ 1204, 1207, 1209, 1211, 1214, 1212, 1255, 1208, 1259, 1215,
+ /* 300 */ 1256, 1200, 1206, 1260, 1247, 1261, 1263, 1262, 1266, 1278,
+ /* 310 */ 1282, 1292, 1294, 1297, 1298, 1299, 1300, 1221, 1224, 1228,
+ /* 320 */ 1288, 1291, 1276, 1277, 1295,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 982, 1300, 1300, 1300, 1214, 1214, 1214, 1305, 1300, 1109,
- /* 10 */ 1138, 1138, 1274, 1305, 1305, 1305, 1305, 1305, 1305, 1212,
- /* 20 */ 1305, 1305, 1305, 1300, 1305, 1113, 1144, 1305, 1305, 1305,
- /* 30 */ 1305, 1305, 1305, 1305, 1305, 1273, 1275, 1152, 1151, 1254,
- /* 40 */ 1125, 1149, 1142, 1146, 1215, 1208, 1209, 1207, 1211, 1216,
- /* 50 */ 1305, 1145, 1177, 1192, 1176, 1305, 1305, 1305, 1305, 1305,
- /* 60 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 70 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 80 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 90 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1186, 1191,
- /* 100 */ 1198, 1190, 1187, 1179, 1178, 1180, 1181, 1305, 1305, 1008,
- /* 110 */ 1074, 1305, 1305, 1182, 1305, 1020, 1183, 1195, 1194, 1193,
- /* 120 */ 1015, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 130 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 140 */ 1305, 1305, 1305, 1305, 1305, 982, 1300, 1305, 1305, 1300,
- /* 150 */ 1300, 1300, 1300, 1300, 1300, 1292, 1113, 1103, 1305, 1305,
- /* 160 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1280, 1278,
- /* 170 */ 1305, 1227, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 180 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 190 */ 1305, 1305, 1305, 1109, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 200 */ 1305, 1305, 1305, 1305, 1305, 1305, 988, 1305, 1247, 1109,
- /* 210 */ 1109, 1109, 1111, 1089, 1101, 990, 1148, 1127, 1127, 1259,
- /* 220 */ 1148, 1259, 1045, 1068, 1042, 1138, 1127, 1210, 1138, 1138,
- /* 230 */ 1110, 1101, 1305, 1285, 1118, 1118, 1277, 1277, 1118, 1157,
- /* 240 */ 1078, 1148, 1085, 1085, 1085, 1085, 1118, 1005, 1148, 1157,
- /* 250 */ 1078, 1078, 1148, 1118, 1005, 1253, 1251, 1118, 1118, 1005,
- /* 260 */ 1220, 1118, 1005, 1118, 1005, 1220, 1076, 1076, 1076, 1060,
- /* 270 */ 1220, 1076, 1045, 1076, 1060, 1076, 1076, 1131, 1126, 1131,
- /* 280 */ 1126, 1131, 1126, 1131, 1126, 1118, 1118, 1305, 1220, 1224,
- /* 290 */ 1224, 1220, 1143, 1132, 1141, 1139, 1148, 1011, 1063, 998,
- /* 300 */ 998, 987, 987, 987, 987, 1297, 1297, 1292, 1047, 1047,
- /* 310 */ 1030, 1305, 1305, 1305, 1305, 1305, 1305, 1022, 1305, 1229,
- /* 320 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 330 */ 1305, 1305, 1305, 1305, 1305, 1305, 1164, 1305, 983, 1287,
- /* 340 */ 1305, 1305, 1284, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 350 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 360 */ 1305, 1257, 1305, 1305, 1305, 1305, 1305, 1305, 1250, 1249,
- /* 370 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 380 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305,
- /* 390 */ 1305, 1305, 1092, 1305, 1305, 1305, 1096, 1305, 1305, 1305,
- /* 400 */ 1305, 1305, 1305, 1305, 1140, 1305, 1133, 1305, 1213, 1305,
- /* 410 */ 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1305, 1302,
- /* 420 */ 1305, 1305, 1305, 1301, 1305, 1305, 1305, 1305, 1305, 1166,
- /* 430 */ 1305, 1165, 1169, 1305, 996, 1305,
+ /* 0 */ 1281, 1271, 1271, 1271, 1203, 1203, 1203, 1203, 1271, 1096,
+ /* 10 */ 1125, 1125, 1255, 1332, 1332, 1332, 1332, 1332, 1332, 1202,
+ /* 20 */ 1332, 1332, 1332, 1332, 1271, 1100, 1131, 1332, 1332, 1332,
+ /* 30 */ 1332, 1204, 1205, 1332, 1332, 1332, 1254, 1256, 1141, 1140,
+ /* 40 */ 1139, 1138, 1237, 1112, 1136, 1129, 1133, 1204, 1198, 1199,
+ /* 50 */ 1197, 1201, 1205, 1332, 1132, 1167, 1182, 1166, 1332, 1332,
+ /* 60 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 70 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 80 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 90 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 100 */ 1332, 1332, 1332, 1332, 1176, 1181, 1188, 1180, 1177, 1169,
+ /* 110 */ 1168, 1170, 1171, 1332, 1019, 1067, 1332, 1332, 1332, 1172,
+ /* 120 */ 1332, 1173, 1185, 1184, 1183, 1262, 1289, 1288, 1332, 1332,
+ /* 130 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 140 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 150 */ 1332, 1332, 1332, 1332, 1332, 1281, 1271, 1025, 1025, 1332,
+ /* 160 */ 1271, 1271, 1271, 1271, 1271, 1271, 1267, 1100, 1091, 1332,
+ /* 170 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 180 */ 1259, 1257, 1332, 1218, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 190 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 200 */ 1332, 1332, 1332, 1332, 1096, 1332, 1332, 1332, 1332, 1332,
+ /* 210 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1283, 1332, 1232,
+ /* 220 */ 1096, 1096, 1096, 1098, 1080, 1090, 1004, 1135, 1114, 1114,
+ /* 230 */ 1321, 1135, 1321, 1042, 1303, 1039, 1125, 1114, 1200, 1125,
+ /* 240 */ 1125, 1097, 1090, 1332, 1324, 1105, 1105, 1323, 1323, 1105,
+ /* 250 */ 1146, 1070, 1135, 1076, 1076, 1076, 1076, 1105, 1016, 1135,
+ /* 260 */ 1146, 1070, 1070, 1135, 1105, 1016, 1236, 1318, 1105, 1105,
+ /* 270 */ 1016, 1211, 1105, 1016, 1105, 1016, 1211, 1068, 1068, 1068,
+ /* 280 */ 1057, 1211, 1068, 1042, 1068, 1057, 1068, 1068, 1118, 1113,
+ /* 290 */ 1118, 1113, 1118, 1113, 1118, 1113, 1105, 1206, 1105, 1332,
+ /* 300 */ 1211, 1215, 1215, 1211, 1130, 1119, 1128, 1126, 1135, 1022,
+ /* 310 */ 1060, 1286, 1286, 1282, 1282, 1282, 1282, 1329, 1329, 1267,
+ /* 320 */ 1298, 1298, 1044, 1044, 1298, 1332, 1332, 1332, 1332, 1332,
+ /* 330 */ 1332, 1293, 1332, 1220, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 340 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 350 */ 1332, 1332, 1152, 1332, 1000, 1264, 1332, 1332, 1263, 1332,
+ /* 360 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 370 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1320,
+ /* 380 */ 1332, 1332, 1332, 1332, 1332, 1332, 1235, 1234, 1332, 1332,
+ /* 390 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 400 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332,
+ /* 410 */ 1332, 1082, 1332, 1332, 1332, 1307, 1332, 1332, 1332, 1332,
+ /* 420 */ 1332, 1332, 1332, 1127, 1332, 1120, 1332, 1332, 1311, 1332,
+ /* 430 */ 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1332, 1273,
+ /* 440 */ 1332, 1332, 1332, 1272, 1332, 1332, 1332, 1332, 1332, 1154,
+ /* 450 */ 1332, 1153, 1157, 1332, 1010, 1332,
};
/********** End of lemon-generated parsing tables *****************************/
@@ -128700,74 +134773,100 @@ static const YYACTIONTYPE yy_default[] = {
static const YYCODETYPE yyFallback[] = {
0, /* $ => nothing */
0, /* SEMI => nothing */
- 27, /* EXPLAIN => ID */
- 27, /* QUERY => ID */
- 27, /* PLAN => ID */
- 27, /* BEGIN => ID */
+ 55, /* EXPLAIN => ID */
+ 55, /* QUERY => ID */
+ 55, /* PLAN => ID */
+ 55, /* BEGIN => ID */
0, /* TRANSACTION => nothing */
- 27, /* DEFERRED => ID */
- 27, /* IMMEDIATE => ID */
- 27, /* EXCLUSIVE => ID */
+ 55, /* DEFERRED => ID */
+ 55, /* IMMEDIATE => ID */
+ 55, /* EXCLUSIVE => ID */
0, /* COMMIT => nothing */
- 27, /* END => ID */
- 27, /* ROLLBACK => ID */
- 27, /* SAVEPOINT => ID */
- 27, /* RELEASE => ID */
+ 55, /* END => ID */
+ 55, /* ROLLBACK => ID */
+ 55, /* SAVEPOINT => ID */
+ 55, /* RELEASE => ID */
0, /* TO => nothing */
0, /* TABLE => nothing */
0, /* CREATE => nothing */
- 27, /* IF => ID */
+ 55, /* IF => ID */
0, /* NOT => nothing */
0, /* EXISTS => nothing */
- 27, /* TEMP => ID */
+ 55, /* TEMP => ID */
0, /* LP => nothing */
0, /* RP => nothing */
0, /* AS => nothing */
- 27, /* WITHOUT => ID */
+ 55, /* WITHOUT => ID */
0, /* COMMA => nothing */
+ 0, /* OR => nothing */
+ 0, /* AND => nothing */
+ 0, /* IS => nothing */
+ 55, /* MATCH => ID */
+ 55, /* LIKE_KW => ID */
+ 0, /* BETWEEN => nothing */
+ 0, /* IN => nothing */
+ 0, /* ISNULL => nothing */
+ 0, /* NOTNULL => nothing */
+ 0, /* NE => nothing */
+ 0, /* EQ => nothing */
+ 0, /* GT => nothing */
+ 0, /* LE => nothing */
+ 0, /* LT => nothing */
+ 0, /* GE => nothing */
+ 0, /* ESCAPE => nothing */
+ 0, /* BITAND => nothing */
+ 0, /* BITOR => nothing */
+ 0, /* LSHIFT => nothing */
+ 0, /* RSHIFT => nothing */
+ 0, /* PLUS => nothing */
+ 0, /* MINUS => nothing */
+ 0, /* STAR => nothing */
+ 0, /* SLASH => nothing */
+ 0, /* REM => nothing */
+ 0, /* CONCAT => nothing */
+ 0, /* COLLATE => nothing */
+ 0, /* BITNOT => nothing */
0, /* ID => nothing */
0, /* INDEXED => nothing */
- 27, /* ABORT => ID */
- 27, /* ACTION => ID */
- 27, /* AFTER => ID */
- 27, /* ANALYZE => ID */
- 27, /* ASC => ID */
- 27, /* ATTACH => ID */
- 27, /* BEFORE => ID */
- 27, /* BY => ID */
- 27, /* CASCADE => ID */
- 27, /* CAST => ID */
- 27, /* COLUMNKW => ID */
- 27, /* CONFLICT => ID */
- 27, /* DATABASE => ID */
- 27, /* DESC => ID */
- 27, /* DETACH => ID */
- 27, /* EACH => ID */
- 27, /* FAIL => ID */
- 27, /* FOR => ID */
- 27, /* IGNORE => ID */
- 27, /* INITIALLY => ID */
- 27, /* INSTEAD => ID */
- 27, /* LIKE_KW => ID */
- 27, /* MATCH => ID */
- 27, /* NO => ID */
- 27, /* KEY => ID */
- 27, /* OF => ID */
- 27, /* OFFSET => ID */
- 27, /* PRAGMA => ID */
- 27, /* RAISE => ID */
- 27, /* RECURSIVE => ID */
- 27, /* REPLACE => ID */
- 27, /* RESTRICT => ID */
- 27, /* ROW => ID */
- 27, /* TRIGGER => ID */
- 27, /* VACUUM => ID */
- 27, /* VIEW => ID */
- 27, /* VIRTUAL => ID */
- 27, /* WITH => ID */
- 27, /* REINDEX => ID */
- 27, /* RENAME => ID */
- 27, /* CTIME_KW => ID */
+ 55, /* ABORT => ID */
+ 55, /* ACTION => ID */
+ 55, /* AFTER => ID */
+ 55, /* ANALYZE => ID */
+ 55, /* ASC => ID */
+ 55, /* ATTACH => ID */
+ 55, /* BEFORE => ID */
+ 55, /* BY => ID */
+ 55, /* CASCADE => ID */
+ 55, /* CAST => ID */
+ 55, /* COLUMNKW => ID */
+ 55, /* CONFLICT => ID */
+ 55, /* DATABASE => ID */
+ 55, /* DESC => ID */
+ 55, /* DETACH => ID */
+ 55, /* EACH => ID */
+ 55, /* FAIL => ID */
+ 55, /* FOR => ID */
+ 55, /* IGNORE => ID */
+ 55, /* INITIALLY => ID */
+ 55, /* INSTEAD => ID */
+ 55, /* NO => ID */
+ 55, /* KEY => ID */
+ 55, /* OF => ID */
+ 55, /* OFFSET => ID */
+ 55, /* PRAGMA => ID */
+ 55, /* RAISE => ID */
+ 55, /* RECURSIVE => ID */
+ 55, /* REPLACE => ID */
+ 55, /* RESTRICT => ID */
+ 55, /* ROW => ID */
+ 55, /* TRIGGER => ID */
+ 55, /* VACUUM => ID */
+ 55, /* VIEW => ID */
+ 55, /* VIRTUAL => ID */
+ 55, /* WITH => ID */
+ 55, /* REINDEX => ID */
+ 55, /* RENAME => ID */
+ 55, /* CTIME_KW => ID */
};
#endif /* YYFALLBACK */
@@ -128799,15 +134898,18 @@ typedef struct yyStackEntry yyStackEntry;
/* The state of the parser is completely contained in an instance of
** the following structure */
struct yyParser {
- int yyidx; /* Index of top element in stack */
+ yyStackEntry *yytos; /* Pointer to top element of the stack */
#ifdef YYTRACKMAXSTACKDEPTH
- int yyidxMax; /* Maximum value of yyidx */
+ int yyhwm; /* High-water mark of the stack */
#endif
+#ifndef YYNOERRORRECOVERY
int yyerrcnt; /* Shifts left before out of the error */
+#endif
sqlite3ParserARG_SDECL /* A place to hold %extra_argument */
#if YYSTACKDEPTH<=0
int yystksz; /* Current side of the stack */
yyStackEntry *yystack; /* The parser's stack */
+ yyStackEntry yystk0; /* First stack entry */
#else
yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
#endif
@@ -128856,25 +134958,25 @@ static const char *const yyTokenName[] = {
"ROLLBACK", "SAVEPOINT", "RELEASE", "TO",
"TABLE", "CREATE", "IF", "NOT",
"EXISTS", "TEMP", "LP", "RP",
- "AS", "WITHOUT", "COMMA", "ID",
+ "AS", "WITHOUT", "COMMA", "OR",
+ "AND", "IS", "MATCH", "LIKE_KW",
+ "BETWEEN", "IN", "ISNULL", "NOTNULL",
+ "NE", "EQ", "GT", "LE",
+ "LT", "GE", "ESCAPE", "BITAND",
+ "BITOR", "LSHIFT", "RSHIFT", "PLUS",
+ "MINUS", "STAR", "SLASH", "REM",
+ "CONCAT", "COLLATE", "BITNOT", "ID",
"INDEXED", "ABORT", "ACTION", "AFTER",
"ANALYZE", "ASC", "ATTACH", "BEFORE",
"BY", "CASCADE", "CAST", "COLUMNKW",
"CONFLICT", "DATABASE", "DESC", "DETACH",
"EACH", "FAIL", "FOR", "IGNORE",
- "INITIALLY", "INSTEAD", "LIKE_KW", "MATCH",
- "NO", "KEY", "OF", "OFFSET",
- "PRAGMA", "RAISE", "RECURSIVE", "REPLACE",
- "RESTRICT", "ROW", "TRIGGER", "VACUUM",
- "VIEW", "VIRTUAL", "WITH", "REINDEX",
- "RENAME", "CTIME_KW", "ANY", "OR",
- "AND", "IS", "BETWEEN", "IN",
- "ISNULL", "NOTNULL", "NE", "EQ",
- "GT", "LE", "LT", "GE",
- "ESCAPE", "BITAND", "BITOR", "LSHIFT",
- "RSHIFT", "PLUS", "MINUS", "STAR",
- "SLASH", "REM", "CONCAT", "COLLATE",
- "BITNOT", "STRING", "JOIN_KW", "CONSTRAINT",
+ "INITIALLY", "INSTEAD", "NO", "KEY",
+ "OF", "OFFSET", "PRAGMA", "RAISE",
+ "RECURSIVE", "REPLACE", "RESTRICT", "ROW",
+ "TRIGGER", "VACUUM", "VIEW", "VIRTUAL",
+ "WITH", "REINDEX", "RENAME", "CTIME_KW",
+ "ANY", "STRING", "JOIN_KW", "CONSTRAINT",
"DEFAULT", "NULL", "PRIMARY", "UNIQUE",
"CHECK", "REFERENCES", "AUTOINCR", "ON",
"INSERT", "DELETE", "UPDATE", "SET",
@@ -128883,7 +134985,7 @@ static const char *const yyTokenName[] = {
"VALUES", "DISTINCT", "DOT", "FROM",
"JOIN", "USING", "ORDER", "GROUP",
"HAVING", "LIMIT", "WHERE", "INTO",
- "INTEGER", "FLOAT", "BLOB", "VARIABLE",
+ "FLOAT", "BLOB", "INTEGER", "VARIABLE",
"CASE", "WHEN", "THEN", "ELSE",
"INDEX", "ALTER", "ADD", "error",
"input", "cmdlist", "ecmd", "explain",
@@ -128891,28 +134993,28 @@ static const char *const yyTokenName[] = {
"nm", "savepoint_opt", "create_table", "create_table_args",
"createkw", "temp", "ifnotexists", "dbnm",
"columnlist", "conslist_opt", "table_options", "select",
- "column", "columnid", "type", "carglist",
- "typetoken", "typename", "signed", "plus_num",
- "minus_num", "ccons", "term", "expr",
- "onconf", "sortorder", "autoinc", "eidlist_opt",
- "refargs", "defer_subclause", "refarg", "refact",
- "init_deferred_pred_opt", "conslist", "tconscomma", "tcons",
- "sortlist", "eidlist", "defer_subclause_opt", "orconf",
- "resolvetype", "raisetype", "ifexists", "fullname",
- "selectnowith", "oneselect", "with", "multiselect_op",
- "distinct", "selcollist", "from", "where_opt",
- "groupby_opt", "having_opt", "orderby_opt", "limit_opt",
- "values", "nexprlist", "exprlist", "sclp",
- "as", "seltablist", "stl_prefix", "joinop",
- "indexed_opt", "on_opt", "using_opt", "idlist",
- "setlist", "insert_cmd", "idlist_opt", "likeop",
- "between_op", "in_op", "case_operand", "case_exprlist",
- "case_else", "uniqueflag", "collate", "nmnum",
- "trigger_decl", "trigger_cmd_list", "trigger_time", "trigger_event",
- "foreach_clause", "when_clause", "trigger_cmd", "trnm",
- "tridxby", "database_kw_opt", "key_opt", "add_column_fullname",
- "kwcolumn_opt", "create_vtab", "vtabarglist", "vtabarg",
- "vtabargtoken", "lp", "anylist", "wqlist",
+ "columnname", "carglist", "typetoken", "typename",
+ "signed", "plus_num", "minus_num", "ccons",
+ "term", "expr", "onconf", "sortorder",
+ "autoinc", "eidlist_opt", "refargs", "defer_subclause",
+ "refarg", "refact", "init_deferred_pred_opt", "conslist",
+ "tconscomma", "tcons", "sortlist", "eidlist",
+ "defer_subclause_opt", "orconf", "resolvetype", "raisetype",
+ "ifexists", "fullname", "selectnowith", "oneselect",
+ "with", "multiselect_op", "distinct", "selcollist",
+ "from", "where_opt", "groupby_opt", "having_opt",
+ "orderby_opt", "limit_opt", "values", "nexprlist",
+ "exprlist", "sclp", "as", "seltablist",
+ "stl_prefix", "joinop", "indexed_opt", "on_opt",
+ "using_opt", "idlist", "setlist", "insert_cmd",
+ "idlist_opt", "likeop", "between_op", "in_op",
+ "paren_exprlist", "case_operand", "case_exprlist", "case_else",
+ "uniqueflag", "collate", "nmnum", "trigger_decl",
+ "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause",
+ "when_clause", "trigger_cmd", "trnm", "tridxby",
+ "database_kw_opt", "key_opt", "add_column_fullname", "kwcolumn_opt",
+ "create_vtab", "vtabarglist", "vtabarg", "vtabargtoken",
+ "lp", "anylist", "wqlist",
};
#endif /* NDEBUG */
@@ -128920,358 +135022,372 @@ static const char *const yyTokenName[] = {
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
- /* 0 */ "input ::= cmdlist",
- /* 1 */ "cmdlist ::= cmdlist ecmd",
- /* 2 */ "cmdlist ::= ecmd",
- /* 3 */ "ecmd ::= SEMI",
- /* 4 */ "ecmd ::= explain cmdx SEMI",
- /* 5 */ "explain ::=",
- /* 6 */ "explain ::= EXPLAIN",
- /* 7 */ "explain ::= EXPLAIN QUERY PLAN",
- /* 8 */ "cmdx ::= cmd",
- /* 9 */ "cmd ::= BEGIN transtype trans_opt",
- /* 10 */ "trans_opt ::=",
- /* 11 */ "trans_opt ::= TRANSACTION",
- /* 12 */ "trans_opt ::= TRANSACTION nm",
- /* 13 */ "transtype ::=",
- /* 14 */ "transtype ::= DEFERRED",
- /* 15 */ "transtype ::= IMMEDIATE",
- /* 16 */ "transtype ::= EXCLUSIVE",
- /* 17 */ "cmd ::= COMMIT trans_opt",
- /* 18 */ "cmd ::= END trans_opt",
- /* 19 */ "cmd ::= ROLLBACK trans_opt",
- /* 20 */ "savepoint_opt ::= SAVEPOINT",
- /* 21 */ "savepoint_opt ::=",
- /* 22 */ "cmd ::= SAVEPOINT nm",
- /* 23 */ "cmd ::= RELEASE savepoint_opt nm",
- /* 24 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
- /* 25 */ "cmd ::= create_table create_table_args",
- /* 26 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
- /* 27 */ "createkw ::= CREATE",
- /* 28 */ "ifnotexists ::=",
- /* 29 */ "ifnotexists ::= IF NOT EXISTS",
- /* 30 */ "temp ::= TEMP",
- /* 31 */ "temp ::=",
- /* 32 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
- /* 33 */ "create_table_args ::= AS select",
- /* 34 */ "table_options ::=",
- /* 35 */ "table_options ::= WITHOUT nm",
- /* 36 */ "columnlist ::= columnlist COMMA column",
- /* 37 */ "columnlist ::= column",
- /* 38 */ "column ::= columnid type carglist",
- /* 39 */ "columnid ::= nm",
- /* 40 */ "nm ::= ID|INDEXED",
- /* 41 */ "nm ::= STRING",
- /* 42 */ "nm ::= JOIN_KW",
- /* 43 */ "type ::=",
- /* 44 */ "type ::= typetoken",
- /* 45 */ "typetoken ::= typename",
- /* 46 */ "typetoken ::= typename LP signed RP",
- /* 47 */ "typetoken ::= typename LP signed COMMA signed RP",
- /* 48 */ "typename ::= ID|STRING",
- /* 49 */ "typename ::= typename ID|STRING",
- /* 50 */ "signed ::= plus_num",
- /* 51 */ "signed ::= minus_num",
- /* 52 */ "carglist ::= carglist ccons",
- /* 53 */ "carglist ::=",
- /* 54 */ "ccons ::= CONSTRAINT nm",
- /* 55 */ "ccons ::= DEFAULT term",
- /* 56 */ "ccons ::= DEFAULT LP expr RP",
- /* 57 */ "ccons ::= DEFAULT PLUS term",
- /* 58 */ "ccons ::= DEFAULT MINUS term",
- /* 59 */ "ccons ::= DEFAULT ID|INDEXED",
- /* 60 */ "ccons ::= NULL onconf",
- /* 61 */ "ccons ::= NOT NULL onconf",
- /* 62 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
- /* 63 */ "ccons ::= UNIQUE onconf",
- /* 64 */ "ccons ::= CHECK LP expr RP",
- /* 65 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
- /* 66 */ "ccons ::= defer_subclause",
- /* 67 */ "ccons ::= COLLATE ID|STRING",
- /* 68 */ "autoinc ::=",
- /* 69 */ "autoinc ::= AUTOINCR",
- /* 70 */ "refargs ::=",
- /* 71 */ "refargs ::= refargs refarg",
- /* 72 */ "refarg ::= MATCH nm",
- /* 73 */ "refarg ::= ON INSERT refact",
- /* 74 */ "refarg ::= ON DELETE refact",
- /* 75 */ "refarg ::= ON UPDATE refact",
- /* 76 */ "refact ::= SET NULL",
- /* 77 */ "refact ::= SET DEFAULT",
- /* 78 */ "refact ::= CASCADE",
- /* 79 */ "refact ::= RESTRICT",
- /* 80 */ "refact ::= NO ACTION",
- /* 81 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
- /* 82 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
- /* 83 */ "init_deferred_pred_opt ::=",
- /* 84 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
- /* 85 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
- /* 86 */ "conslist_opt ::=",
- /* 87 */ "conslist_opt ::= COMMA conslist",
- /* 88 */ "conslist ::= conslist tconscomma tcons",
- /* 89 */ "conslist ::= tcons",
- /* 90 */ "tconscomma ::= COMMA",
- /* 91 */ "tconscomma ::=",
- /* 92 */ "tcons ::= CONSTRAINT nm",
- /* 93 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
- /* 94 */ "tcons ::= UNIQUE LP sortlist RP onconf",
- /* 95 */ "tcons ::= CHECK LP expr RP onconf",
- /* 96 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
- /* 97 */ "defer_subclause_opt ::=",
- /* 98 */ "defer_subclause_opt ::= defer_subclause",
- /* 99 */ "onconf ::=",
- /* 100 */ "onconf ::= ON CONFLICT resolvetype",
- /* 101 */ "orconf ::=",
- /* 102 */ "orconf ::= OR resolvetype",
- /* 103 */ "resolvetype ::= raisetype",
- /* 104 */ "resolvetype ::= IGNORE",
- /* 105 */ "resolvetype ::= REPLACE",
- /* 106 */ "cmd ::= DROP TABLE ifexists fullname",
- /* 107 */ "ifexists ::= IF EXISTS",
- /* 108 */ "ifexists ::=",
- /* 109 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
- /* 110 */ "cmd ::= DROP VIEW ifexists fullname",
- /* 111 */ "cmd ::= select",
- /* 112 */ "select ::= with selectnowith",
- /* 113 */ "selectnowith ::= oneselect",
- /* 114 */ "selectnowith ::= selectnowith multiselect_op oneselect",
- /* 115 */ "multiselect_op ::= UNION",
- /* 116 */ "multiselect_op ::= UNION ALL",
- /* 117 */ "multiselect_op ::= EXCEPT|INTERSECT",
- /* 118 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
- /* 119 */ "oneselect ::= values",
- /* 120 */ "values ::= VALUES LP nexprlist RP",
- /* 121 */ "values ::= values COMMA LP exprlist RP",
- /* 122 */ "distinct ::= DISTINCT",
- /* 123 */ "distinct ::= ALL",
- /* 124 */ "distinct ::=",
- /* 125 */ "sclp ::= selcollist COMMA",
- /* 126 */ "sclp ::=",
- /* 127 */ "selcollist ::= sclp expr as",
- /* 128 */ "selcollist ::= sclp STAR",
- /* 129 */ "selcollist ::= sclp nm DOT STAR",
- /* 130 */ "as ::= AS nm",
- /* 131 */ "as ::= ID|STRING",
- /* 132 */ "as ::=",
- /* 133 */ "from ::=",
- /* 134 */ "from ::= FROM seltablist",
- /* 135 */ "stl_prefix ::= seltablist joinop",
- /* 136 */ "stl_prefix ::=",
- /* 137 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
- /* 138 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
- /* 139 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
- /* 140 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
- /* 141 */ "dbnm ::=",
- /* 142 */ "dbnm ::= DOT nm",
- /* 143 */ "fullname ::= nm dbnm",
- /* 144 */ "joinop ::= COMMA|JOIN",
- /* 145 */ "joinop ::= JOIN_KW JOIN",
- /* 146 */ "joinop ::= JOIN_KW nm JOIN",
- /* 147 */ "joinop ::= JOIN_KW nm nm JOIN",
- /* 148 */ "on_opt ::= ON expr",
- /* 149 */ "on_opt ::=",
- /* 150 */ "indexed_opt ::=",
- /* 151 */ "indexed_opt ::= INDEXED BY nm",
- /* 152 */ "indexed_opt ::= NOT INDEXED",
- /* 153 */ "using_opt ::= USING LP idlist RP",
- /* 154 */ "using_opt ::=",
- /* 155 */ "orderby_opt ::=",
- /* 156 */ "orderby_opt ::= ORDER BY sortlist",
- /* 157 */ "sortlist ::= sortlist COMMA expr sortorder",
- /* 158 */ "sortlist ::= expr sortorder",
- /* 159 */ "sortorder ::= ASC",
- /* 160 */ "sortorder ::= DESC",
- /* 161 */ "sortorder ::=",
- /* 162 */ "groupby_opt ::=",
- /* 163 */ "groupby_opt ::= GROUP BY nexprlist",
- /* 164 */ "having_opt ::=",
- /* 165 */ "having_opt ::= HAVING expr",
- /* 166 */ "limit_opt ::=",
- /* 167 */ "limit_opt ::= LIMIT expr",
- /* 168 */ "limit_opt ::= LIMIT expr OFFSET expr",
- /* 169 */ "limit_opt ::= LIMIT expr COMMA expr",
- /* 170 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
- /* 171 */ "where_opt ::=",
- /* 172 */ "where_opt ::= WHERE expr",
- /* 173 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
- /* 174 */ "setlist ::= setlist COMMA nm EQ expr",
- /* 175 */ "setlist ::= nm EQ expr",
- /* 176 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select",
- /* 177 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES",
- /* 178 */ "insert_cmd ::= INSERT orconf",
- /* 179 */ "insert_cmd ::= REPLACE",
- /* 180 */ "idlist_opt ::=",
- /* 181 */ "idlist_opt ::= LP idlist RP",
- /* 182 */ "idlist ::= idlist COMMA nm",
- /* 183 */ "idlist ::= nm",
- /* 184 */ "expr ::= term",
- /* 185 */ "expr ::= LP expr RP",
- /* 186 */ "term ::= NULL",
- /* 187 */ "expr ::= ID|INDEXED",
- /* 188 */ "expr ::= JOIN_KW",
- /* 189 */ "expr ::= nm DOT nm",
- /* 190 */ "expr ::= nm DOT nm DOT nm",
- /* 191 */ "term ::= INTEGER|FLOAT|BLOB",
- /* 192 */ "term ::= STRING",
- /* 193 */ "expr ::= VARIABLE",
- /* 194 */ "expr ::= expr COLLATE ID|STRING",
- /* 195 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 196 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 197 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 198 */ "term ::= CTIME_KW",
- /* 199 */ "expr ::= expr AND expr",
- /* 200 */ "expr ::= expr OR expr",
- /* 201 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 202 */ "expr ::= expr EQ|NE expr",
- /* 203 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 204 */ "expr ::= expr PLUS|MINUS expr",
- /* 205 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 206 */ "expr ::= expr CONCAT expr",
- /* 207 */ "likeop ::= LIKE_KW|MATCH",
- /* 208 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 209 */ "expr ::= expr likeop expr",
- /* 210 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 211 */ "expr ::= expr ISNULL|NOTNULL",
- /* 212 */ "expr ::= expr NOT NULL",
- /* 213 */ "expr ::= expr IS expr",
- /* 214 */ "expr ::= expr IS NOT expr",
- /* 215 */ "expr ::= NOT expr",
- /* 216 */ "expr ::= BITNOT expr",
- /* 217 */ "expr ::= MINUS expr",
- /* 218 */ "expr ::= PLUS expr",
- /* 219 */ "between_op ::= BETWEEN",
- /* 220 */ "between_op ::= NOT BETWEEN",
- /* 221 */ "expr ::= expr between_op expr AND expr",
- /* 222 */ "in_op ::= IN",
- /* 223 */ "in_op ::= NOT IN",
- /* 224 */ "expr ::= expr in_op LP exprlist RP",
- /* 225 */ "expr ::= LP select RP",
- /* 226 */ "expr ::= expr in_op LP select RP",
- /* 227 */ "expr ::= expr in_op nm dbnm",
- /* 228 */ "expr ::= EXISTS LP select RP",
- /* 229 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 230 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 231 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 232 */ "case_else ::= ELSE expr",
- /* 233 */ "case_else ::=",
- /* 234 */ "case_operand ::= expr",
- /* 235 */ "case_operand ::=",
- /* 236 */ "exprlist ::= nexprlist",
- /* 237 */ "exprlist ::=",
- /* 238 */ "nexprlist ::= nexprlist COMMA expr",
- /* 239 */ "nexprlist ::= expr",
- /* 240 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
- /* 241 */ "uniqueflag ::= UNIQUE",
- /* 242 */ "uniqueflag ::=",
- /* 243 */ "eidlist_opt ::=",
- /* 244 */ "eidlist_opt ::= LP eidlist RP",
- /* 245 */ "eidlist ::= eidlist COMMA nm collate sortorder",
- /* 246 */ "eidlist ::= nm collate sortorder",
- /* 247 */ "collate ::=",
- /* 248 */ "collate ::= COLLATE ID|STRING",
- /* 249 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 250 */ "cmd ::= VACUUM",
- /* 251 */ "cmd ::= VACUUM nm",
- /* 252 */ "cmd ::= PRAGMA nm dbnm",
- /* 253 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 254 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 255 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 256 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 257 */ "nmnum ::= plus_num",
- /* 258 */ "nmnum ::= nm",
- /* 259 */ "nmnum ::= ON",
- /* 260 */ "nmnum ::= DELETE",
- /* 261 */ "nmnum ::= DEFAULT",
- /* 262 */ "plus_num ::= PLUS INTEGER|FLOAT",
- /* 263 */ "plus_num ::= INTEGER|FLOAT",
- /* 264 */ "minus_num ::= MINUS INTEGER|FLOAT",
- /* 265 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 266 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 267 */ "trigger_time ::= BEFORE",
- /* 268 */ "trigger_time ::= AFTER",
- /* 269 */ "trigger_time ::= INSTEAD OF",
- /* 270 */ "trigger_time ::=",
- /* 271 */ "trigger_event ::= DELETE|INSERT",
- /* 272 */ "trigger_event ::= UPDATE",
- /* 273 */ "trigger_event ::= UPDATE OF idlist",
- /* 274 */ "foreach_clause ::=",
- /* 275 */ "foreach_clause ::= FOR EACH ROW",
- /* 276 */ "when_clause ::=",
- /* 277 */ "when_clause ::= WHEN expr",
- /* 278 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 279 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 280 */ "trnm ::= nm",
- /* 281 */ "trnm ::= nm DOT nm",
- /* 282 */ "tridxby ::=",
- /* 283 */ "tridxby ::= INDEXED BY nm",
- /* 284 */ "tridxby ::= NOT INDEXED",
- /* 285 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
- /* 286 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select",
- /* 287 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
- /* 288 */ "trigger_cmd ::= select",
- /* 289 */ "expr ::= RAISE LP IGNORE RP",
- /* 290 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 291 */ "raisetype ::= ROLLBACK",
- /* 292 */ "raisetype ::= ABORT",
- /* 293 */ "raisetype ::= FAIL",
- /* 294 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 295 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 296 */ "cmd ::= DETACH database_kw_opt expr",
- /* 297 */ "key_opt ::=",
- /* 298 */ "key_opt ::= KEY expr",
- /* 299 */ "database_kw_opt ::= DATABASE",
- /* 300 */ "database_kw_opt ::=",
- /* 301 */ "cmd ::= REINDEX",
- /* 302 */ "cmd ::= REINDEX nm dbnm",
- /* 303 */ "cmd ::= ANALYZE",
- /* 304 */ "cmd ::= ANALYZE nm dbnm",
- /* 305 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 306 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
- /* 307 */ "add_column_fullname ::= fullname",
- /* 308 */ "kwcolumn_opt ::=",
- /* 309 */ "kwcolumn_opt ::= COLUMNKW",
- /* 310 */ "cmd ::= create_vtab",
- /* 311 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 312 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
- /* 313 */ "vtabarglist ::= vtabarg",
- /* 314 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 315 */ "vtabarg ::=",
- /* 316 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 317 */ "vtabargtoken ::= ANY",
- /* 318 */ "vtabargtoken ::= lp anylist RP",
- /* 319 */ "lp ::= LP",
- /* 320 */ "anylist ::=",
- /* 321 */ "anylist ::= anylist LP anylist RP",
- /* 322 */ "anylist ::= anylist ANY",
- /* 323 */ "with ::=",
- /* 324 */ "with ::= WITH wqlist",
- /* 325 */ "with ::= WITH RECURSIVE wqlist",
- /* 326 */ "wqlist ::= nm eidlist_opt AS LP select RP",
- /* 327 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
+ /* 0 */ "explain ::= EXPLAIN",
+ /* 1 */ "explain ::= EXPLAIN QUERY PLAN",
+ /* 2 */ "cmdx ::= cmd",
+ /* 3 */ "cmd ::= BEGIN transtype trans_opt",
+ /* 4 */ "transtype ::=",
+ /* 5 */ "transtype ::= DEFERRED",
+ /* 6 */ "transtype ::= IMMEDIATE",
+ /* 7 */ "transtype ::= EXCLUSIVE",
+ /* 8 */ "cmd ::= COMMIT trans_opt",
+ /* 9 */ "cmd ::= END trans_opt",
+ /* 10 */ "cmd ::= ROLLBACK trans_opt",
+ /* 11 */ "cmd ::= SAVEPOINT nm",
+ /* 12 */ "cmd ::= RELEASE savepoint_opt nm",
+ /* 13 */ "cmd ::= ROLLBACK trans_opt TO savepoint_opt nm",
+ /* 14 */ "create_table ::= createkw temp TABLE ifnotexists nm dbnm",
+ /* 15 */ "createkw ::= CREATE",
+ /* 16 */ "ifnotexists ::=",
+ /* 17 */ "ifnotexists ::= IF NOT EXISTS",
+ /* 18 */ "temp ::= TEMP",
+ /* 19 */ "temp ::=",
+ /* 20 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
+ /* 21 */ "create_table_args ::= AS select",
+ /* 22 */ "table_options ::=",
+ /* 23 */ "table_options ::= WITHOUT nm",
+ /* 24 */ "columnname ::= nm typetoken",
+ /* 25 */ "typetoken ::=",
+ /* 26 */ "typetoken ::= typename LP signed RP",
+ /* 27 */ "typetoken ::= typename LP signed COMMA signed RP",
+ /* 28 */ "typename ::= typename ID|STRING",
+ /* 29 */ "ccons ::= CONSTRAINT nm",
+ /* 30 */ "ccons ::= DEFAULT term",
+ /* 31 */ "ccons ::= DEFAULT LP expr RP",
+ /* 32 */ "ccons ::= DEFAULT PLUS term",
+ /* 33 */ "ccons ::= DEFAULT MINUS term",
+ /* 34 */ "ccons ::= DEFAULT ID|INDEXED",
+ /* 35 */ "ccons ::= NOT NULL onconf",
+ /* 36 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
+ /* 37 */ "ccons ::= UNIQUE onconf",
+ /* 38 */ "ccons ::= CHECK LP expr RP",
+ /* 39 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
+ /* 40 */ "ccons ::= defer_subclause",
+ /* 41 */ "ccons ::= COLLATE ID|STRING",
+ /* 42 */ "autoinc ::=",
+ /* 43 */ "autoinc ::= AUTOINCR",
+ /* 44 */ "refargs ::=",
+ /* 45 */ "refargs ::= refargs refarg",
+ /* 46 */ "refarg ::= MATCH nm",
+ /* 47 */ "refarg ::= ON INSERT refact",
+ /* 48 */ "refarg ::= ON DELETE refact",
+ /* 49 */ "refarg ::= ON UPDATE refact",
+ /* 50 */ "refact ::= SET NULL",
+ /* 51 */ "refact ::= SET DEFAULT",
+ /* 52 */ "refact ::= CASCADE",
+ /* 53 */ "refact ::= RESTRICT",
+ /* 54 */ "refact ::= NO ACTION",
+ /* 55 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
+ /* 56 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
+ /* 57 */ "init_deferred_pred_opt ::=",
+ /* 58 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
+ /* 59 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
+ /* 60 */ "conslist_opt ::=",
+ /* 61 */ "tconscomma ::= COMMA",
+ /* 62 */ "tcons ::= CONSTRAINT nm",
+ /* 63 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
+ /* 64 */ "tcons ::= UNIQUE LP sortlist RP onconf",
+ /* 65 */ "tcons ::= CHECK LP expr RP onconf",
+ /* 66 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
+ /* 67 */ "defer_subclause_opt ::=",
+ /* 68 */ "onconf ::=",
+ /* 69 */ "onconf ::= ON CONFLICT resolvetype",
+ /* 70 */ "orconf ::=",
+ /* 71 */ "orconf ::= OR resolvetype",
+ /* 72 */ "resolvetype ::= IGNORE",
+ /* 73 */ "resolvetype ::= REPLACE",
+ /* 74 */ "cmd ::= DROP TABLE ifexists fullname",
+ /* 75 */ "ifexists ::= IF EXISTS",
+ /* 76 */ "ifexists ::=",
+ /* 77 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
+ /* 78 */ "cmd ::= DROP VIEW ifexists fullname",
+ /* 79 */ "cmd ::= select",
+ /* 80 */ "select ::= with selectnowith",
+ /* 81 */ "selectnowith ::= selectnowith multiselect_op oneselect",
+ /* 82 */ "multiselect_op ::= UNION",
+ /* 83 */ "multiselect_op ::= UNION ALL",
+ /* 84 */ "multiselect_op ::= EXCEPT|INTERSECT",
+ /* 85 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
+ /* 86 */ "values ::= VALUES LP nexprlist RP",
+ /* 87 */ "values ::= values COMMA LP exprlist RP",
+ /* 88 */ "distinct ::= DISTINCT",
+ /* 89 */ "distinct ::= ALL",
+ /* 90 */ "distinct ::=",
+ /* 91 */ "sclp ::=",
+ /* 92 */ "selcollist ::= sclp expr as",
+ /* 93 */ "selcollist ::= sclp STAR",
+ /* 94 */ "selcollist ::= sclp nm DOT STAR",
+ /* 95 */ "as ::= AS nm",
+ /* 96 */ "as ::=",
+ /* 97 */ "from ::=",
+ /* 98 */ "from ::= FROM seltablist",
+ /* 99 */ "stl_prefix ::= seltablist joinop",
+ /* 100 */ "stl_prefix ::=",
+ /* 101 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
+ /* 102 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
+ /* 103 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
+ /* 104 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
+ /* 105 */ "dbnm ::=",
+ /* 106 */ "dbnm ::= DOT nm",
+ /* 107 */ "fullname ::= nm dbnm",
+ /* 108 */ "joinop ::= COMMA|JOIN",
+ /* 109 */ "joinop ::= JOIN_KW JOIN",
+ /* 110 */ "joinop ::= JOIN_KW nm JOIN",
+ /* 111 */ "joinop ::= JOIN_KW nm nm JOIN",
+ /* 112 */ "on_opt ::= ON expr",
+ /* 113 */ "on_opt ::=",
+ /* 114 */ "indexed_opt ::=",
+ /* 115 */ "indexed_opt ::= INDEXED BY nm",
+ /* 116 */ "indexed_opt ::= NOT INDEXED",
+ /* 117 */ "using_opt ::= USING LP idlist RP",
+ /* 118 */ "using_opt ::=",
+ /* 119 */ "orderby_opt ::=",
+ /* 120 */ "orderby_opt ::= ORDER BY sortlist",
+ /* 121 */ "sortlist ::= sortlist COMMA expr sortorder",
+ /* 122 */ "sortlist ::= expr sortorder",
+ /* 123 */ "sortorder ::= ASC",
+ /* 124 */ "sortorder ::= DESC",
+ /* 125 */ "sortorder ::=",
+ /* 126 */ "groupby_opt ::=",
+ /* 127 */ "groupby_opt ::= GROUP BY nexprlist",
+ /* 128 */ "having_opt ::=",
+ /* 129 */ "having_opt ::= HAVING expr",
+ /* 130 */ "limit_opt ::=",
+ /* 131 */ "limit_opt ::= LIMIT expr",
+ /* 132 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 133 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 134 */ "cmd ::= with DELETE FROM fullname indexed_opt where_opt",
+ /* 135 */ "where_opt ::=",
+ /* 136 */ "where_opt ::= WHERE expr",
+ /* 137 */ "cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt",
+ /* 138 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 139 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
+ /* 140 */ "setlist ::= nm EQ expr",
+ /* 141 */ "setlist ::= LP idlist RP EQ expr",
+ /* 142 */ "cmd ::= with insert_cmd INTO fullname idlist_opt select",
+ /* 143 */ "cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES",
+ /* 144 */ "insert_cmd ::= INSERT orconf",
+ /* 145 */ "insert_cmd ::= REPLACE",
+ /* 146 */ "idlist_opt ::=",
+ /* 147 */ "idlist_opt ::= LP idlist RP",
+ /* 148 */ "idlist ::= idlist COMMA nm",
+ /* 149 */ "idlist ::= nm",
+ /* 150 */ "expr ::= LP expr RP",
+ /* 151 */ "term ::= NULL",
+ /* 152 */ "expr ::= ID|INDEXED",
+ /* 153 */ "expr ::= JOIN_KW",
+ /* 154 */ "expr ::= nm DOT nm",
+ /* 155 */ "expr ::= nm DOT nm DOT nm",
+ /* 156 */ "term ::= FLOAT|BLOB",
+ /* 157 */ "term ::= STRING",
+ /* 158 */ "term ::= INTEGER",
+ /* 159 */ "expr ::= VARIABLE",
+ /* 160 */ "expr ::= expr COLLATE ID|STRING",
+ /* 161 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 162 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
+ /* 163 */ "expr ::= ID|INDEXED LP STAR RP",
+ /* 164 */ "term ::= CTIME_KW",
+ /* 165 */ "expr ::= LP nexprlist COMMA expr RP",
+ /* 166 */ "expr ::= expr AND expr",
+ /* 167 */ "expr ::= expr OR expr",
+ /* 168 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 169 */ "expr ::= expr EQ|NE expr",
+ /* 170 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 171 */ "expr ::= expr PLUS|MINUS expr",
+ /* 172 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 173 */ "expr ::= expr CONCAT expr",
+ /* 174 */ "likeop ::= LIKE_KW|MATCH",
+ /* 175 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 176 */ "expr ::= expr likeop expr",
+ /* 177 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 178 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 179 */ "expr ::= expr NOT NULL",
+ /* 180 */ "expr ::= expr IS expr",
+ /* 181 */ "expr ::= expr IS NOT expr",
+ /* 182 */ "expr ::= NOT expr",
+ /* 183 */ "expr ::= BITNOT expr",
+ /* 184 */ "expr ::= MINUS expr",
+ /* 185 */ "expr ::= PLUS expr",
+ /* 186 */ "between_op ::= BETWEEN",
+ /* 187 */ "between_op ::= NOT BETWEEN",
+ /* 188 */ "expr ::= expr between_op expr AND expr",
+ /* 189 */ "in_op ::= IN",
+ /* 190 */ "in_op ::= NOT IN",
+ /* 191 */ "expr ::= expr in_op LP exprlist RP",
+ /* 192 */ "expr ::= LP select RP",
+ /* 193 */ "expr ::= expr in_op LP select RP",
+ /* 194 */ "expr ::= expr in_op nm dbnm paren_exprlist",
+ /* 195 */ "expr ::= EXISTS LP select RP",
+ /* 196 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 197 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 198 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 199 */ "case_else ::= ELSE expr",
+ /* 200 */ "case_else ::=",
+ /* 201 */ "case_operand ::= expr",
+ /* 202 */ "case_operand ::=",
+ /* 203 */ "exprlist ::=",
+ /* 204 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 205 */ "nexprlist ::= expr",
+ /* 206 */ "paren_exprlist ::=",
+ /* 207 */ "paren_exprlist ::= LP exprlist RP",
+ /* 208 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
+ /* 209 */ "uniqueflag ::= UNIQUE",
+ /* 210 */ "uniqueflag ::=",
+ /* 211 */ "eidlist_opt ::=",
+ /* 212 */ "eidlist_opt ::= LP eidlist RP",
+ /* 213 */ "eidlist ::= eidlist COMMA nm collate sortorder",
+ /* 214 */ "eidlist ::= nm collate sortorder",
+ /* 215 */ "collate ::=",
+ /* 216 */ "collate ::= COLLATE ID|STRING",
+ /* 217 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 218 */ "cmd ::= VACUUM",
+ /* 219 */ "cmd ::= VACUUM nm",
+ /* 220 */ "cmd ::= PRAGMA nm dbnm",
+ /* 221 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 222 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 223 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 224 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 225 */ "plus_num ::= PLUS INTEGER|FLOAT",
+ /* 226 */ "minus_num ::= MINUS INTEGER|FLOAT",
+ /* 227 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 228 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 229 */ "trigger_time ::= BEFORE",
+ /* 230 */ "trigger_time ::= AFTER",
+ /* 231 */ "trigger_time ::= INSTEAD OF",
+ /* 232 */ "trigger_time ::=",
+ /* 233 */ "trigger_event ::= DELETE|INSERT",
+ /* 234 */ "trigger_event ::= UPDATE",
+ /* 235 */ "trigger_event ::= UPDATE OF idlist",
+ /* 236 */ "when_clause ::=",
+ /* 237 */ "when_clause ::= WHEN expr",
+ /* 238 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 239 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 240 */ "trnm ::= nm DOT nm",
+ /* 241 */ "tridxby ::= INDEXED BY nm",
+ /* 242 */ "tridxby ::= NOT INDEXED",
+ /* 243 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt",
+ /* 244 */ "trigger_cmd ::= insert_cmd INTO trnm idlist_opt select",
+ /* 245 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt",
+ /* 246 */ "trigger_cmd ::= select",
+ /* 247 */ "expr ::= RAISE LP IGNORE RP",
+ /* 248 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 249 */ "raisetype ::= ROLLBACK",
+ /* 250 */ "raisetype ::= ABORT",
+ /* 251 */ "raisetype ::= FAIL",
+ /* 252 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 253 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 254 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 255 */ "key_opt ::=",
+ /* 256 */ "key_opt ::= KEY expr",
+ /* 257 */ "cmd ::= REINDEX",
+ /* 258 */ "cmd ::= REINDEX nm dbnm",
+ /* 259 */ "cmd ::= ANALYZE",
+ /* 260 */ "cmd ::= ANALYZE nm dbnm",
+ /* 261 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 262 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
+ /* 263 */ "add_column_fullname ::= fullname",
+ /* 264 */ "cmd ::= create_vtab",
+ /* 265 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 266 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 267 */ "vtabarg ::=",
+ /* 268 */ "vtabargtoken ::= ANY",
+ /* 269 */ "vtabargtoken ::= lp anylist RP",
+ /* 270 */ "lp ::= LP",
+ /* 271 */ "with ::=",
+ /* 272 */ "with ::= WITH wqlist",
+ /* 273 */ "with ::= WITH RECURSIVE wqlist",
+ /* 274 */ "wqlist ::= nm eidlist_opt AS LP select RP",
+ /* 275 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
+ /* 276 */ "input ::= cmdlist",
+ /* 277 */ "cmdlist ::= cmdlist ecmd",
+ /* 278 */ "cmdlist ::= ecmd",
+ /* 279 */ "ecmd ::= SEMI",
+ /* 280 */ "ecmd ::= explain cmdx SEMI",
+ /* 281 */ "explain ::=",
+ /* 282 */ "trans_opt ::=",
+ /* 283 */ "trans_opt ::= TRANSACTION",
+ /* 284 */ "trans_opt ::= TRANSACTION nm",
+ /* 285 */ "savepoint_opt ::= SAVEPOINT",
+ /* 286 */ "savepoint_opt ::=",
+ /* 287 */ "cmd ::= create_table create_table_args",
+ /* 288 */ "columnlist ::= columnlist COMMA columnname carglist",
+ /* 289 */ "columnlist ::= columnname carglist",
+ /* 290 */ "nm ::= ID|INDEXED",
+ /* 291 */ "nm ::= STRING",
+ /* 292 */ "nm ::= JOIN_KW",
+ /* 293 */ "typetoken ::= typename",
+ /* 294 */ "typename ::= ID|STRING",
+ /* 295 */ "signed ::= plus_num",
+ /* 296 */ "signed ::= minus_num",
+ /* 297 */ "carglist ::= carglist ccons",
+ /* 298 */ "carglist ::=",
+ /* 299 */ "ccons ::= NULL onconf",
+ /* 300 */ "conslist_opt ::= COMMA conslist",
+ /* 301 */ "conslist ::= conslist tconscomma tcons",
+ /* 302 */ "conslist ::= tcons",
+ /* 303 */ "tconscomma ::=",
+ /* 304 */ "defer_subclause_opt ::= defer_subclause",
+ /* 305 */ "resolvetype ::= raisetype",
+ /* 306 */ "selectnowith ::= oneselect",
+ /* 307 */ "oneselect ::= values",
+ /* 308 */ "sclp ::= selcollist COMMA",
+ /* 309 */ "as ::= ID|STRING",
+ /* 310 */ "expr ::= term",
+ /* 311 */ "exprlist ::= nexprlist",
+ /* 312 */ "nmnum ::= plus_num",
+ /* 313 */ "nmnum ::= nm",
+ /* 314 */ "nmnum ::= ON",
+ /* 315 */ "nmnum ::= DELETE",
+ /* 316 */ "nmnum ::= DEFAULT",
+ /* 317 */ "plus_num ::= INTEGER|FLOAT",
+ /* 318 */ "foreach_clause ::=",
+ /* 319 */ "foreach_clause ::= FOR EACH ROW",
+ /* 320 */ "trnm ::= nm",
+ /* 321 */ "tridxby ::=",
+ /* 322 */ "database_kw_opt ::= DATABASE",
+ /* 323 */ "database_kw_opt ::=",
+ /* 324 */ "kwcolumn_opt ::=",
+ /* 325 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 326 */ "vtabarglist ::= vtabarg",
+ /* 327 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 328 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 329 */ "anylist ::=",
+ /* 330 */ "anylist ::= anylist LP anylist RP",
+ /* 331 */ "anylist ::= anylist ANY",
};
#endif /* NDEBUG */
#if YYSTACKDEPTH<=0
/*
-** Try to increase the size of the parser stack.
+** Try to increase the size of the parser stack. Return the number
+** of errors. Return 0 on success.
*/
-static void yyGrowStack(yyParser *p){
+static int yyGrowStack(yyParser *p){
int newSize;
+ int idx;
yyStackEntry *pNew;
newSize = p->yystksz*2 + 100;
- pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
+ if( p->yystack==&p->yystk0 ){
+ pNew = malloc(newSize*sizeof(pNew[0]));
+ if( pNew ) pNew[0] = p->yystk0;
+ }else{
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ }
if( pNew ){
p->yystack = pNew;
- p->yystksz = newSize;
+ p->yytos = &p->yystack[idx];
#ifndef NDEBUG
if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
- yyTracePrompt, p->yystksz);
+ fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+ yyTracePrompt, p->yystksz, newSize);
}
#endif
+ p->yystksz = newSize;
}
+ return pNew==0;
}
#endif
@@ -129300,15 +135416,24 @@ SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
yyParser *pParser;
pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
if( pParser ){
- pParser->yyidx = -1;
#ifdef YYTRACKMAXSTACKDEPTH
- pParser->yyidxMax = 0;
+ pParser->yyhwm = 0;
#endif
#if YYSTACKDEPTH<=0
+ pParser->yytos = NULL;
pParser->yystack = NULL;
pParser->yystksz = 0;
- yyGrowStack(pParser);
+ if( yyGrowStack(pParser) ){
+ pParser->yystack = &pParser->yystk0;
+ pParser->yystksz = 1;
+ }
+#endif
+#ifndef YYNOERRORRECOVERY
+ pParser->yyerrcnt = -1;
#endif
+ pParser->yytos = pParser->yystack;
+ pParser->yystack[0].stateno = 0;
+ pParser->yystack[0].major = 0;
}
return pParser;
}
@@ -129339,75 +135464,76 @@ static void yy_destructor(
*/
/********* Begin destructor definitions ***************************************/
case 163: /* select */
- case 196: /* selectnowith */
- case 197: /* oneselect */
- case 208: /* values */
+ case 194: /* selectnowith */
+ case 195: /* oneselect */
+ case 206: /* values */
{
-sqlite3SelectDelete(pParse->db, (yypminor->yy387));
+sqlite3SelectDelete(pParse->db, (yypminor->yy243));
}
break;
- case 174: /* term */
- case 175: /* expr */
+ case 172: /* term */
+ case 173: /* expr */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy118).pExpr);
+sqlite3ExprDelete(pParse->db, (yypminor->yy190).pExpr);
}
break;
- case 179: /* eidlist_opt */
- case 188: /* sortlist */
- case 189: /* eidlist */
- case 201: /* selcollist */
- case 204: /* groupby_opt */
- case 206: /* orderby_opt */
- case 209: /* nexprlist */
- case 210: /* exprlist */
- case 211: /* sclp */
- case 220: /* setlist */
- case 227: /* case_exprlist */
+ case 177: /* eidlist_opt */
+ case 186: /* sortlist */
+ case 187: /* eidlist */
+ case 199: /* selcollist */
+ case 202: /* groupby_opt */
+ case 204: /* orderby_opt */
+ case 207: /* nexprlist */
+ case 208: /* exprlist */
+ case 209: /* sclp */
+ case 218: /* setlist */
+ case 224: /* paren_exprlist */
+ case 226: /* case_exprlist */
{
-sqlite3ExprListDelete(pParse->db, (yypminor->yy322));
+sqlite3ExprListDelete(pParse->db, (yypminor->yy148));
}
break;
- case 195: /* fullname */
- case 202: /* from */
- case 213: /* seltablist */
- case 214: /* stl_prefix */
+ case 193: /* fullname */
+ case 200: /* from */
+ case 211: /* seltablist */
+ case 212: /* stl_prefix */
{
-sqlite3SrcListDelete(pParse->db, (yypminor->yy259));
+sqlite3SrcListDelete(pParse->db, (yypminor->yy185));
}
break;
- case 198: /* with */
- case 251: /* wqlist */
+ case 196: /* with */
+ case 250: /* wqlist */
{
-sqlite3WithDelete(pParse->db, (yypminor->yy451));
+sqlite3WithDelete(pParse->db, (yypminor->yy285));
}
break;
- case 203: /* where_opt */
- case 205: /* having_opt */
- case 217: /* on_opt */
- case 226: /* case_operand */
- case 228: /* case_else */
- case 237: /* when_clause */
- case 242: /* key_opt */
+ case 201: /* where_opt */
+ case 203: /* having_opt */
+ case 215: /* on_opt */
+ case 225: /* case_operand */
+ case 227: /* case_else */
+ case 236: /* when_clause */
+ case 241: /* key_opt */
{
-sqlite3ExprDelete(pParse->db, (yypminor->yy314));
+sqlite3ExprDelete(pParse->db, (yypminor->yy72));
}
break;
- case 218: /* using_opt */
- case 219: /* idlist */
- case 222: /* idlist_opt */
+ case 216: /* using_opt */
+ case 217: /* idlist */
+ case 220: /* idlist_opt */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy384));
+sqlite3IdListDelete(pParse->db, (yypminor->yy254));
}
break;
- case 233: /* trigger_cmd_list */
- case 238: /* trigger_cmd */
+ case 232: /* trigger_cmd_list */
+ case 237: /* trigger_cmd */
{
-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy203));
+sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy145));
}
break;
- case 235: /* trigger_event */
+ case 234: /* trigger_event */
{
-sqlite3IdListDelete(pParse->db, (yypminor->yy90).b);
+sqlite3IdListDelete(pParse->db, (yypminor->yy332).b);
}
break;
/********* End destructor definitions *****************************************/
@@ -129423,8 +135549,9 @@ sqlite3IdListDelete(pParse->db, (yypminor->yy90).b);
*/
static void yy_pop_parser_stack(yyParser *pParser){
yyStackEntry *yytos;
- assert( pParser->yyidx>=0 );
- yytos = &pParser->yystack[pParser->yyidx--];
+ assert( pParser->yytos!=0 );
+ assert( pParser->yytos > pParser->yystack );
+ yytos = pParser->yytos--;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sPopping %s\n",
@@ -129451,9 +135578,9 @@ SQLITE_PRIVATE void sqlite3ParserFree(
#ifndef YYPARSEFREENEVERNULL
if( pParser==0 ) return;
#endif
- while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+ while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
#if YYSTACKDEPTH<=0
- free(pParser->yystack);
+ if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
#endif
(*freeProc)((void*)pParser);
}
@@ -129464,7 +135591,7 @@ SQLITE_PRIVATE void sqlite3ParserFree(
#ifdef YYTRACKMAXSTACKDEPTH
SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){
yyParser *pParser = (yyParser*)p;
- return pParser->yyidxMax;
+ return pParser->yyhwm;
}
#endif
@@ -129472,61 +135599,58 @@ SQLITE_PRIVATE int sqlite3ParserStackPeak(void *p){
** Find the appropriate action for a parser given the terminal
** look-ahead token iLookAhead.
*/
-static int yy_find_shift_action(
+static unsigned int yy_find_shift_action(
yyParser *pParser, /* The parser */
YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
- int stateno = pParser->yystack[pParser->yyidx].stateno;
+ int stateno = pParser->yytos->stateno;
if( stateno>=YY_MIN_REDUCE ) return stateno;
assert( stateno <= YY_SHIFT_COUNT );
do{
i = yy_shift_ofst[stateno];
- if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno];
assert( iLookAhead!=YYNOCODE );
i += iLookAhead;
if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
- if( iLookAhead>0 ){
#ifdef YYFALLBACK
- YYCODETYPE iFallback; /* Fallback token */
- if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
- && (iFallback = yyFallback[iLookAhead])!=0 ){
+ YYCODETYPE iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0 ){
#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
- yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
- }
-#endif
- assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
- iLookAhead = iFallback;
- continue;
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
}
#endif
+ assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
+ iLookAhead = iFallback;
+ continue;
+ }
+#endif
#ifdef YYWILDCARD
- {
- int j = i - iLookAhead + YYWILDCARD;
- if(
+ {
+ int j = i - iLookAhead + YYWILDCARD;
+ if(
#if YY_SHIFT_MIN+YYWILDCARD<0
- j>=0 &&
+ j>=0 &&
#endif
#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
- j<YY_ACTTAB_COUNT &&
+ j<YY_ACTTAB_COUNT &&
#endif
- yy_lookahead[j]==YYWILDCARD
- ){
+ yy_lookahead[j]==YYWILDCARD && iLookAhead>0
+ ){
#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
- yyTracePrompt, yyTokenName[iLookAhead],
- yyTokenName[YYWILDCARD]);
- }
-#endif /* NDEBUG */
- return yy_action[j];
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead],
+ yyTokenName[YYWILDCARD]);
}
+#endif /* NDEBUG */
+ return yy_action[j];
}
-#endif /* YYWILDCARD */
}
+#endif /* YYWILDCARD */
return yy_default[stateno];
}else{
return yy_action[i];
@@ -129568,20 +135692,18 @@ static int yy_find_reduce_action(
/*
** The following routine is called if the stack overflows.
*/
-static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
+static void yyStackOverflow(yyParser *yypParser){
sqlite3ParserARG_FETCH;
- yypParser->yyidx--;
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
}
#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will execute if the parser
** stack every overflows */
/******** Begin %stack_overflow code ******************************************/
- UNUSED_PARAMETER(yypMinor); /* Silence some compiler warnings */
sqlite3ErrorMsg(pParse, "parser stack overflow");
/******** End %stack_overflow code ********************************************/
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
@@ -129595,11 +135717,11 @@ static void yyTraceShift(yyParser *yypParser, int yyNewState){
if( yyTraceFILE ){
if( yyNewState<YYNSTATE ){
fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n",
- yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major],
+ yyTracePrompt,yyTokenName[yypParser->yytos->major],
yyNewState);
}else{
fprintf(yyTraceFILE,"%sShift '%s'\n",
- yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major]);
+ yyTracePrompt,yyTokenName[yypParser->yytos->major]);
}
}
}
@@ -129614,33 +135736,38 @@ static void yy_shift(
yyParser *yypParser, /* The parser to be shifted */
int yyNewState, /* The new state to shift in */
int yyMajor, /* The major token to shift in */
- YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */
+ sqlite3ParserTOKENTYPE yyMinor /* The minor token to shift in */
){
yyStackEntry *yytos;
- yypParser->yyidx++;
+ yypParser->yytos++;
#ifdef YYTRACKMAXSTACKDEPTH
- if( yypParser->yyidx>yypParser->yyidxMax ){
- yypParser->yyidxMax = yypParser->yyidx;
+ if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+ yypParser->yyhwm++;
+ assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
}
#endif
#if YYSTACKDEPTH>0
- if( yypParser->yyidx>=YYSTACKDEPTH ){
- yyStackOverflow(yypParser, yypMinor);
+ if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){
+ yypParser->yytos--;
+ yyStackOverflow(yypParser);
return;
}
#else
- if( yypParser->yyidx>=yypParser->yystksz ){
- yyGrowStack(yypParser);
- if( yypParser->yyidx>=yypParser->yystksz ){
- yyStackOverflow(yypParser, yypMinor);
+ if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
+ if( yyGrowStack(yypParser) ){
+ yypParser->yytos--;
+ yyStackOverflow(yypParser);
return;
}
}
#endif
- yytos = &yypParser->yystack[yypParser->yyidx];
+ if( yyNewState > YY_MAX_SHIFT ){
+ yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+ }
+ yytos = yypParser->yytos;
yytos->stateno = (YYACTIONTYPE)yyNewState;
yytos->major = (YYCODETYPE)yyMajor;
- yytos->minor = *yypMinor;
+ yytos->minor.yy0 = yyMinor;
yyTraceShift(yypParser, yyNewState);
}
@@ -129651,19 +135778,10 @@ static const struct {
YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
unsigned char nrhs; /* Number of right-hand side symbols in the rule */
} yyRuleInfo[] = {
- { 144, 1 },
- { 145, 2 },
- { 145, 1 },
- { 146, 1 },
- { 146, 3 },
- { 147, 0 },
{ 147, 1 },
{ 147, 3 },
{ 148, 1 },
{ 149, 3 },
- { 151, 0 },
- { 151, 1 },
- { 151, 2 },
{ 150, 0 },
{ 150, 1 },
{ 150, 1 },
@@ -129671,12 +135789,9 @@ static const struct {
{ 149, 2 },
{ 149, 2 },
{ 149, 2 },
- { 153, 1 },
- { 153, 0 },
{ 149, 2 },
{ 149, 3 },
{ 149, 5 },
- { 149, 2 },
{ 154, 6 },
{ 156, 1 },
{ 158, 0 },
@@ -129687,219 +135802,199 @@ static const struct {
{ 155, 2 },
{ 162, 0 },
{ 162, 2 },
- { 160, 3 },
- { 160, 1 },
- { 164, 3 },
- { 165, 1 },
- { 152, 1 },
- { 152, 1 },
- { 152, 1 },
+ { 164, 2 },
{ 166, 0 },
- { 166, 1 },
- { 168, 1 },
- { 168, 4 },
- { 168, 6 },
- { 169, 1 },
- { 169, 2 },
- { 170, 1 },
- { 170, 1 },
+ { 166, 4 },
+ { 166, 6 },
{ 167, 2 },
- { 167, 0 },
- { 173, 2 },
- { 173, 2 },
- { 173, 4 },
- { 173, 3 },
- { 173, 3 },
- { 173, 2 },
- { 173, 2 },
- { 173, 3 },
- { 173, 5 },
- { 173, 2 },
- { 173, 4 },
- { 173, 4 },
- { 173, 1 },
- { 173, 2 },
+ { 171, 2 },
+ { 171, 2 },
+ { 171, 4 },
+ { 171, 3 },
+ { 171, 3 },
+ { 171, 2 },
+ { 171, 3 },
+ { 171, 5 },
+ { 171, 2 },
+ { 171, 4 },
+ { 171, 4 },
+ { 171, 1 },
+ { 171, 2 },
+ { 176, 0 },
+ { 176, 1 },
{ 178, 0 },
- { 178, 1 },
- { 180, 0 },
+ { 178, 2 },
{ 180, 2 },
- { 182, 2 },
- { 182, 3 },
- { 182, 3 },
- { 182, 3 },
- { 183, 2 },
- { 183, 2 },
- { 183, 1 },
- { 183, 1 },
- { 183, 2 },
- { 181, 3 },
+ { 180, 3 },
+ { 180, 3 },
+ { 180, 3 },
{ 181, 2 },
- { 184, 0 },
- { 184, 2 },
- { 184, 2 },
+ { 181, 2 },
+ { 181, 1 },
+ { 181, 1 },
+ { 181, 2 },
+ { 179, 3 },
+ { 179, 2 },
+ { 182, 0 },
+ { 182, 2 },
+ { 182, 2 },
{ 161, 0 },
- { 161, 2 },
- { 185, 3 },
- { 185, 1 },
- { 186, 1 },
- { 186, 0 },
- { 187, 2 },
- { 187, 7 },
- { 187, 5 },
- { 187, 5 },
- { 187, 10 },
- { 190, 0 },
+ { 184, 1 },
+ { 185, 2 },
+ { 185, 7 },
+ { 185, 5 },
+ { 185, 5 },
+ { 185, 10 },
+ { 188, 0 },
+ { 174, 0 },
+ { 174, 3 },
+ { 189, 0 },
+ { 189, 2 },
+ { 190, 1 },
{ 190, 1 },
- { 176, 0 },
- { 176, 3 },
- { 191, 0 },
- { 191, 2 },
- { 192, 1 },
- { 192, 1 },
- { 192, 1 },
{ 149, 4 },
- { 194, 2 },
- { 194, 0 },
+ { 192, 2 },
+ { 192, 0 },
{ 149, 9 },
{ 149, 4 },
{ 149, 1 },
{ 163, 2 },
- { 196, 1 },
- { 196, 3 },
- { 199, 1 },
- { 199, 2 },
- { 199, 1 },
- { 197, 9 },
+ { 194, 3 },
+ { 197, 1 },
+ { 197, 2 },
{ 197, 1 },
- { 208, 4 },
- { 208, 5 },
- { 200, 1 },
- { 200, 1 },
+ { 195, 9 },
+ { 206, 4 },
+ { 206, 5 },
+ { 198, 1 },
+ { 198, 1 },
+ { 198, 0 },
+ { 209, 0 },
+ { 199, 3 },
+ { 199, 2 },
+ { 199, 4 },
+ { 210, 2 },
+ { 210, 0 },
{ 200, 0 },
- { 211, 2 },
- { 211, 0 },
- { 201, 3 },
- { 201, 2 },
- { 201, 4 },
+ { 200, 2 },
{ 212, 2 },
- { 212, 1 },
{ 212, 0 },
- { 202, 0 },
- { 202, 2 },
- { 214, 2 },
- { 214, 0 },
- { 213, 7 },
- { 213, 9 },
- { 213, 7 },
- { 213, 7 },
+ { 211, 7 },
+ { 211, 9 },
+ { 211, 7 },
+ { 211, 7 },
{ 159, 0 },
{ 159, 2 },
- { 195, 2 },
- { 215, 1 },
+ { 193, 2 },
+ { 213, 1 },
+ { 213, 2 },
+ { 213, 3 },
+ { 213, 4 },
{ 215, 2 },
- { 215, 3 },
- { 215, 4 },
- { 217, 2 },
- { 217, 0 },
+ { 215, 0 },
+ { 214, 0 },
+ { 214, 3 },
+ { 214, 2 },
+ { 216, 4 },
{ 216, 0 },
- { 216, 3 },
- { 216, 2 },
- { 218, 4 },
- { 218, 0 },
- { 206, 0 },
- { 206, 3 },
- { 188, 4 },
- { 188, 2 },
- { 177, 1 },
- { 177, 1 },
- { 177, 0 },
{ 204, 0 },
{ 204, 3 },
+ { 186, 4 },
+ { 186, 2 },
+ { 175, 1 },
+ { 175, 1 },
+ { 175, 0 },
+ { 202, 0 },
+ { 202, 3 },
+ { 203, 0 },
+ { 203, 2 },
{ 205, 0 },
{ 205, 2 },
- { 207, 0 },
- { 207, 2 },
- { 207, 4 },
- { 207, 4 },
+ { 205, 4 },
+ { 205, 4 },
{ 149, 6 },
- { 203, 0 },
- { 203, 2 },
+ { 201, 0 },
+ { 201, 2 },
{ 149, 8 },
- { 220, 5 },
- { 220, 3 },
+ { 218, 5 },
+ { 218, 7 },
+ { 218, 3 },
+ { 218, 5 },
{ 149, 6 },
{ 149, 7 },
- { 221, 2 },
- { 221, 1 },
- { 222, 0 },
- { 222, 3 },
- { 219, 3 },
+ { 219, 2 },
{ 219, 1 },
- { 175, 1 },
- { 175, 3 },
- { 174, 1 },
- { 175, 1 },
- { 175, 1 },
- { 175, 3 },
- { 175, 5 },
- { 174, 1 },
- { 174, 1 },
- { 175, 1 },
- { 175, 3 },
- { 175, 6 },
- { 175, 5 },
- { 175, 4 },
- { 174, 1 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
- { 175, 3 },
+ { 220, 0 },
+ { 220, 3 },
+ { 217, 3 },
+ { 217, 1 },
+ { 173, 3 },
+ { 172, 1 },
+ { 173, 1 },
+ { 173, 1 },
+ { 173, 3 },
+ { 173, 5 },
+ { 172, 1 },
+ { 172, 1 },
+ { 172, 1 },
+ { 173, 1 },
+ { 173, 3 },
+ { 173, 6 },
+ { 173, 5 },
+ { 173, 4 },
+ { 172, 1 },
+ { 173, 5 },
+ { 173, 3 },
+ { 173, 3 },
+ { 173, 3 },
+ { 173, 3 },
+ { 173, 3 },
+ { 173, 3 },
+ { 173, 3 },
+ { 173, 3 },
+ { 221, 1 },
+ { 221, 2 },
+ { 173, 3 },
+ { 173, 5 },
+ { 173, 2 },
+ { 173, 3 },
+ { 173, 3 },
+ { 173, 4 },
+ { 173, 2 },
+ { 173, 2 },
+ { 173, 2 },
+ { 173, 2 },
+ { 222, 1 },
+ { 222, 2 },
+ { 173, 5 },
{ 223, 1 },
{ 223, 2 },
- { 175, 3 },
- { 175, 5 },
- { 175, 2 },
- { 175, 3 },
- { 175, 3 },
- { 175, 4 },
- { 175, 2 },
- { 175, 2 },
- { 175, 2 },
- { 175, 2 },
- { 224, 1 },
- { 224, 2 },
- { 175, 5 },
+ { 173, 5 },
+ { 173, 3 },
+ { 173, 5 },
+ { 173, 5 },
+ { 173, 4 },
+ { 173, 5 },
+ { 226, 5 },
+ { 226, 4 },
+ { 227, 2 },
+ { 227, 0 },
{ 225, 1 },
- { 225, 2 },
- { 175, 5 },
- { 175, 3 },
- { 175, 5 },
- { 175, 4 },
- { 175, 4 },
- { 175, 5 },
- { 227, 5 },
- { 227, 4 },
- { 228, 2 },
- { 228, 0 },
- { 226, 1 },
- { 226, 0 },
- { 210, 1 },
- { 210, 0 },
- { 209, 3 },
- { 209, 1 },
+ { 225, 0 },
+ { 208, 0 },
+ { 207, 3 },
+ { 207, 1 },
+ { 224, 0 },
+ { 224, 3 },
{ 149, 12 },
- { 229, 1 },
+ { 228, 1 },
+ { 228, 0 },
+ { 177, 0 },
+ { 177, 3 },
+ { 187, 5 },
+ { 187, 3 },
{ 229, 0 },
- { 179, 0 },
- { 179, 3 },
- { 189, 5 },
- { 189, 3 },
- { 230, 0 },
- { 230, 2 },
+ { 229, 2 },
{ 149, 4 },
{ 149, 1 },
{ 149, 2 },
@@ -129908,77 +136003,113 @@ static const struct {
{ 149, 6 },
{ 149, 5 },
{ 149, 6 },
- { 231, 1 },
- { 231, 1 },
- { 231, 1 },
- { 231, 1 },
- { 231, 1 },
- { 171, 2 },
- { 171, 1 },
- { 172, 2 },
+ { 169, 2 },
+ { 170, 2 },
{ 149, 5 },
- { 232, 11 },
+ { 231, 11 },
+ { 233, 1 },
+ { 233, 1 },
+ { 233, 2 },
+ { 233, 0 },
{ 234, 1 },
{ 234, 1 },
- { 234, 2 },
- { 234, 0 },
- { 235, 1 },
- { 235, 1 },
- { 235, 3 },
+ { 234, 3 },
{ 236, 0 },
- { 236, 3 },
- { 237, 0 },
- { 237, 2 },
- { 233, 3 },
- { 233, 2 },
- { 239, 1 },
+ { 236, 2 },
+ { 232, 3 },
+ { 232, 2 },
+ { 238, 3 },
{ 239, 3 },
- { 240, 0 },
- { 240, 3 },
- { 240, 2 },
- { 238, 7 },
- { 238, 5 },
- { 238, 5 },
- { 238, 1 },
- { 175, 4 },
- { 175, 6 },
- { 193, 1 },
- { 193, 1 },
- { 193, 1 },
+ { 239, 2 },
+ { 237, 7 },
+ { 237, 5 },
+ { 237, 5 },
+ { 237, 1 },
+ { 173, 4 },
+ { 173, 6 },
+ { 191, 1 },
+ { 191, 1 },
+ { 191, 1 },
{ 149, 4 },
{ 149, 6 },
{ 149, 3 },
- { 242, 0 },
- { 242, 2 },
- { 241, 1 },
{ 241, 0 },
+ { 241, 2 },
{ 149, 1 },
{ 149, 3 },
{ 149, 1 },
{ 149, 3 },
{ 149, 6 },
- { 149, 6 },
- { 243, 1 },
- { 244, 0 },
- { 244, 1 },
+ { 149, 7 },
+ { 242, 1 },
{ 149, 1 },
{ 149, 4 },
- { 245, 8 },
- { 246, 1 },
- { 246, 3 },
- { 247, 0 },
- { 247, 2 },
+ { 244, 8 },
+ { 246, 0 },
+ { 247, 1 },
+ { 247, 3 },
{ 248, 1 },
- { 248, 3 },
- { 249, 1 },
- { 250, 0 },
- { 250, 4 },
- { 250, 2 },
- { 198, 0 },
- { 198, 2 },
- { 198, 3 },
- { 251, 6 },
- { 251, 8 },
+ { 196, 0 },
+ { 196, 2 },
+ { 196, 3 },
+ { 250, 6 },
+ { 250, 8 },
+ { 144, 1 },
+ { 145, 2 },
+ { 145, 1 },
+ { 146, 1 },
+ { 146, 3 },
+ { 147, 0 },
+ { 151, 0 },
+ { 151, 1 },
+ { 151, 2 },
+ { 153, 1 },
+ { 153, 0 },
+ { 149, 2 },
+ { 160, 4 },
+ { 160, 2 },
+ { 152, 1 },
+ { 152, 1 },
+ { 152, 1 },
+ { 166, 1 },
+ { 167, 1 },
+ { 168, 1 },
+ { 168, 1 },
+ { 165, 2 },
+ { 165, 0 },
+ { 171, 2 },
+ { 161, 2 },
+ { 183, 3 },
+ { 183, 1 },
+ { 184, 0 },
+ { 188, 1 },
+ { 190, 1 },
+ { 194, 1 },
+ { 195, 1 },
+ { 209, 2 },
+ { 210, 1 },
+ { 173, 1 },
+ { 208, 1 },
+ { 230, 1 },
+ { 230, 1 },
+ { 230, 1 },
+ { 230, 1 },
+ { 230, 1 },
+ { 169, 1 },
+ { 235, 0 },
+ { 235, 3 },
+ { 238, 1 },
+ { 239, 0 },
+ { 240, 1 },
+ { 240, 0 },
+ { 243, 0 },
+ { 243, 1 },
+ { 245, 1 },
+ { 245, 3 },
+ { 246, 2 },
+ { 249, 0 },
+ { 249, 4 },
+ { 249, 2 },
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -129989,24 +136120,47 @@ static void yy_accept(yyParser*); /* Forward Declaration */
*/
static void yy_reduce(
yyParser *yypParser, /* The parser */
- int yyruleno /* Number of the rule by which to reduce */
+ unsigned int yyruleno /* Number of the rule by which to reduce */
){
int yygoto; /* The next state */
int yyact; /* The next action */
- YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
yyStackEntry *yymsp; /* The top of the parser's stack */
int yysize; /* Amount to pop the stack */
sqlite3ParserARG_FETCH;
- yymsp = &yypParser->yystack[yypParser->yyidx];
+ yymsp = yypParser->yytos;
#ifndef NDEBUG
- if( yyTraceFILE && yyruleno>=0
- && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+ if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
yysize = yyRuleInfo[yyruleno].nrhs;
fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt,
yyRuleName[yyruleno], yymsp[-yysize].stateno);
}
#endif /* NDEBUG */
- yygotominor = yyzerominor;
+
+ /* Check that the stack is large enough to grow by a single entry
+ ** if the RHS of the rule is empty. This ensures that there is room
+ ** enough on the stack to push the LHS value */
+ if( yyRuleInfo[yyruleno].nrhs==0 ){
+#ifdef YYTRACKMAXSTACKDEPTH
+ if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+ yypParser->yyhwm++;
+ assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
+ }
+#endif
+#if YYSTACKDEPTH>0
+ if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){
+ yyStackOverflow(yypParser);
+ return;
+ }
+#else
+ if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
+ if( yyGrowStack(yypParser) ){
+ yyStackOverflow(yypParser);
+ return;
+ }
+ yymsp = yypParser->yytos;
+ }
+#endif
+ }
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
@@ -130018,322 +136172,288 @@ static void yy_reduce(
** break;
*/
/********** Begin reduce actions **********************************************/
- case 6: /* explain ::= EXPLAIN */
+ YYMINORTYPE yylhsminor;
+ case 0: /* explain ::= EXPLAIN */
{ pParse->explain = 1; }
break;
- case 7: /* explain ::= EXPLAIN QUERY PLAN */
+ case 1: /* explain ::= EXPLAIN QUERY PLAN */
{ pParse->explain = 2; }
break;
- case 8: /* cmdx ::= cmd */
+ case 2: /* cmdx ::= cmd */
{ sqlite3FinishCoding(pParse); }
break;
- case 9: /* cmd ::= BEGIN transtype trans_opt */
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy4);}
+ case 3: /* cmd ::= BEGIN transtype trans_opt */
+{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy194);}
break;
- case 13: /* transtype ::= */
-{yygotominor.yy4 = TK_DEFERRED;}
+ case 4: /* transtype ::= */
+{yymsp[1].minor.yy194 = TK_DEFERRED;}
break;
- case 14: /* transtype ::= DEFERRED */
- case 15: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==15);
- case 16: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==16);
- case 115: /* multiselect_op ::= UNION */ yytestcase(yyruleno==115);
- case 117: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==117);
-{yygotominor.yy4 = yymsp[0].major;}
+ case 5: /* transtype ::= DEFERRED */
+ case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
+ case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
+{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-X*/}
break;
- case 17: /* cmd ::= COMMIT trans_opt */
- case 18: /* cmd ::= END trans_opt */ yytestcase(yyruleno==18);
+ case 8: /* cmd ::= COMMIT trans_opt */
+ case 9: /* cmd ::= END trans_opt */ yytestcase(yyruleno==9);
{sqlite3CommitTransaction(pParse);}
break;
- case 19: /* cmd ::= ROLLBACK trans_opt */
+ case 10: /* cmd ::= ROLLBACK trans_opt */
{sqlite3RollbackTransaction(pParse);}
break;
- case 22: /* cmd ::= SAVEPOINT nm */
+ case 11: /* cmd ::= SAVEPOINT nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &yymsp[0].minor.yy0);
}
break;
- case 23: /* cmd ::= RELEASE savepoint_opt nm */
+ case 12: /* cmd ::= RELEASE savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &yymsp[0].minor.yy0);
}
break;
- case 24: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
+ case 13: /* cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
{
sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &yymsp[0].minor.yy0);
}
break;
- case 26: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
+ case 14: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
{
- sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy4,0,0,yymsp[-2].minor.yy4);
+ sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy194,0,0,yymsp[-2].minor.yy194);
}
break;
- case 27: /* createkw ::= CREATE */
-{
- disableLookaside(pParse);
- yygotominor.yy0 = yymsp[0].minor.yy0;
-}
+ case 15: /* createkw ::= CREATE */
+{disableLookaside(pParse);}
break;
- case 28: /* ifnotexists ::= */
- case 31: /* temp ::= */ yytestcase(yyruleno==31);
- case 34: /* table_options ::= */ yytestcase(yyruleno==34);
- case 68: /* autoinc ::= */ yytestcase(yyruleno==68);
- case 81: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */ yytestcase(yyruleno==81);
- case 83: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==83);
- case 85: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */ yytestcase(yyruleno==85);
- case 97: /* defer_subclause_opt ::= */ yytestcase(yyruleno==97);
- case 108: /* ifexists ::= */ yytestcase(yyruleno==108);
- case 124: /* distinct ::= */ yytestcase(yyruleno==124);
- case 219: /* between_op ::= BETWEEN */ yytestcase(yyruleno==219);
- case 222: /* in_op ::= IN */ yytestcase(yyruleno==222);
- case 247: /* collate ::= */ yytestcase(yyruleno==247);
-{yygotominor.yy4 = 0;}
+ case 16: /* ifnotexists ::= */
+ case 19: /* temp ::= */ yytestcase(yyruleno==19);
+ case 22: /* table_options ::= */ yytestcase(yyruleno==22);
+ case 42: /* autoinc ::= */ yytestcase(yyruleno==42);
+ case 57: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==57);
+ case 67: /* defer_subclause_opt ::= */ yytestcase(yyruleno==67);
+ case 76: /* ifexists ::= */ yytestcase(yyruleno==76);
+ case 90: /* distinct ::= */ yytestcase(yyruleno==90);
+ case 215: /* collate ::= */ yytestcase(yyruleno==215);
+{yymsp[1].minor.yy194 = 0;}
break;
- case 29: /* ifnotexists ::= IF NOT EXISTS */
- case 30: /* temp ::= TEMP */ yytestcase(yyruleno==30);
- case 69: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==69);
- case 84: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */ yytestcase(yyruleno==84);
- case 107: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==107);
- case 220: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==220);
- case 223: /* in_op ::= NOT IN */ yytestcase(yyruleno==223);
- case 248: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==248);
-{yygotominor.yy4 = 1;}
+ case 17: /* ifnotexists ::= IF NOT EXISTS */
+{yymsp[-2].minor.yy194 = 1;}
break;
- case 32: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
+ case 18: /* temp ::= TEMP */
+ case 43: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==43);
+{yymsp[0].minor.yy194 = 1;}
+ break;
+ case 20: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
{
- sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy4,0);
+ sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy194,0);
}
break;
- case 33: /* create_table_args ::= AS select */
+ case 21: /* create_table_args ::= AS select */
{
- sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy387);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
+ sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy243);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243);
}
break;
- case 35: /* table_options ::= WITHOUT nm */
+ case 23: /* table_options ::= WITHOUT nm */
{
if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
- yygotominor.yy4 = TF_WithoutRowid | TF_NoVisibleRowid;
+ yymsp[-1].minor.yy194 = TF_WithoutRowid | TF_NoVisibleRowid;
}else{
- yygotominor.yy4 = 0;
+ yymsp[-1].minor.yy194 = 0;
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
}
}
break;
- case 38: /* column ::= columnid type carglist */
-{
- yygotominor.yy0.z = yymsp[-2].minor.yy0.z;
- yygotominor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-2].minor.yy0.z) + pParse->sLastToken.n;
-}
- break;
- case 39: /* columnid ::= nm */
-{
- sqlite3AddColumn(pParse,&yymsp[0].minor.yy0);
- yygotominor.yy0 = yymsp[0].minor.yy0;
- pParse->constraintName.n = 0;
-}
- break;
- case 40: /* nm ::= ID|INDEXED */
- case 41: /* nm ::= STRING */ yytestcase(yyruleno==41);
- case 42: /* nm ::= JOIN_KW */ yytestcase(yyruleno==42);
- case 45: /* typetoken ::= typename */ yytestcase(yyruleno==45);
- case 48: /* typename ::= ID|STRING */ yytestcase(yyruleno==48);
- case 130: /* as ::= AS nm */ yytestcase(yyruleno==130);
- case 131: /* as ::= ID|STRING */ yytestcase(yyruleno==131);
- case 142: /* dbnm ::= DOT nm */ yytestcase(yyruleno==142);
- case 151: /* indexed_opt ::= INDEXED BY nm */ yytestcase(yyruleno==151);
- case 257: /* nmnum ::= plus_num */ yytestcase(yyruleno==257);
- case 258: /* nmnum ::= nm */ yytestcase(yyruleno==258);
- case 259: /* nmnum ::= ON */ yytestcase(yyruleno==259);
- case 260: /* nmnum ::= DELETE */ yytestcase(yyruleno==260);
- case 261: /* nmnum ::= DEFAULT */ yytestcase(yyruleno==261);
- case 262: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==262);
- case 263: /* plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==263);
- case 264: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==264);
- case 280: /* trnm ::= nm */ yytestcase(yyruleno==280);
-{yygotominor.yy0 = yymsp[0].minor.yy0;}
+ case 24: /* columnname ::= nm typetoken */
+{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
break;
- case 44: /* type ::= typetoken */
-{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy0);}
+ case 25: /* typetoken ::= */
+ case 60: /* conslist_opt ::= */ yytestcase(yyruleno==60);
+ case 96: /* as ::= */ yytestcase(yyruleno==96);
+{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
break;
- case 46: /* typetoken ::= typename LP signed RP */
+ case 26: /* typetoken ::= typename LP signed RP */
{
- yygotominor.yy0.z = yymsp[-3].minor.yy0.z;
- yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
+ yymsp[-3].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy0.z);
}
break;
- case 47: /* typetoken ::= typename LP signed COMMA signed RP */
+ case 27: /* typetoken ::= typename LP signed COMMA signed RP */
{
- yygotominor.yy0.z = yymsp[-5].minor.yy0.z;
- yygotominor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
+ yymsp[-5].minor.yy0.n = (int)(&yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy0.z);
}
break;
- case 49: /* typename ::= typename ID|STRING */
-{yygotominor.yy0.z=yymsp[-1].minor.yy0.z; yygotominor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
+ case 28: /* typename ::= typename ID|STRING */
+{yymsp[-1].minor.yy0.n=yymsp[0].minor.yy0.n+(int)(yymsp[0].minor.yy0.z-yymsp[-1].minor.yy0.z);}
break;
- case 54: /* ccons ::= CONSTRAINT nm */
- case 92: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==92);
+ case 29: /* ccons ::= CONSTRAINT nm */
+ case 62: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==62);
{pParse->constraintName = yymsp[0].minor.yy0;}
break;
- case 55: /* ccons ::= DEFAULT term */
- case 57: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==57);
-{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy118);}
+ case 30: /* ccons ::= DEFAULT term */
+ case 32: /* ccons ::= DEFAULT PLUS term */ yytestcase(yyruleno==32);
+{sqlite3AddDefaultValue(pParse,&yymsp[0].minor.yy190);}
break;
- case 56: /* ccons ::= DEFAULT LP expr RP */
-{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy118);}
+ case 31: /* ccons ::= DEFAULT LP expr RP */
+{sqlite3AddDefaultValue(pParse,&yymsp[-1].minor.yy190);}
break;
- case 58: /* ccons ::= DEFAULT MINUS term */
+ case 33: /* ccons ::= DEFAULT MINUS term */
{
ExprSpan v;
- v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy118.pExpr, 0, 0);
+ v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy190.pExpr, 0);
v.zStart = yymsp[-1].minor.yy0.z;
- v.zEnd = yymsp[0].minor.yy118.zEnd;
+ v.zEnd = yymsp[0].minor.yy190.zEnd;
sqlite3AddDefaultValue(pParse,&v);
}
break;
- case 59: /* ccons ::= DEFAULT ID|INDEXED */
+ case 34: /* ccons ::= DEFAULT ID|INDEXED */
{
ExprSpan v;
- spanExpr(&v, pParse, TK_STRING, &yymsp[0].minor.yy0);
+ spanExpr(&v, pParse, TK_STRING, yymsp[0].minor.yy0);
sqlite3AddDefaultValue(pParse,&v);
}
break;
- case 61: /* ccons ::= NOT NULL onconf */
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy4);}
+ case 35: /* ccons ::= NOT NULL onconf */
+{sqlite3AddNotNull(pParse, yymsp[0].minor.yy194);}
break;
- case 62: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy4,yymsp[0].minor.yy4,yymsp[-2].minor.yy4);}
+ case 36: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
+{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy194,yymsp[0].minor.yy194,yymsp[-2].minor.yy194);}
break;
- case 63: /* ccons ::= UNIQUE onconf */
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy4,0,0,0,0);}
+ case 37: /* ccons ::= UNIQUE onconf */
+{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy194,0,0,0,0,
+ SQLITE_IDXTYPE_UNIQUE);}
break;
- case 64: /* ccons ::= CHECK LP expr RP */
-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy118.pExpr);}
+ case 38: /* ccons ::= CHECK LP expr RP */
+{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy190.pExpr);}
break;
- case 65: /* ccons ::= REFERENCES nm eidlist_opt refargs */
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy4);}
+ case 39: /* ccons ::= REFERENCES nm eidlist_opt refargs */
+{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy148,yymsp[0].minor.yy194);}
break;
- case 66: /* ccons ::= defer_subclause */
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy4);}
+ case 40: /* ccons ::= defer_subclause */
+{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy194);}
break;
- case 67: /* ccons ::= COLLATE ID|STRING */
+ case 41: /* ccons ::= COLLATE ID|STRING */
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
break;
- case 70: /* refargs ::= */
-{ yygotominor.yy4 = OE_None*0x0101; /* EV: R-19803-45884 */}
+ case 44: /* refargs ::= */
+{ yymsp[1].minor.yy194 = OE_None*0x0101; /* EV: R-19803-45884 */}
+ break;
+ case 45: /* refargs ::= refargs refarg */
+{ yymsp[-1].minor.yy194 = (yymsp[-1].minor.yy194 & ~yymsp[0].minor.yy497.mask) | yymsp[0].minor.yy497.value; }
+ break;
+ case 46: /* refarg ::= MATCH nm */
+{ yymsp[-1].minor.yy497.value = 0; yymsp[-1].minor.yy497.mask = 0x000000; }
break;
- case 71: /* refargs ::= refargs refarg */
-{ yygotominor.yy4 = (yymsp[-1].minor.yy4 & ~yymsp[0].minor.yy215.mask) | yymsp[0].minor.yy215.value; }
+ case 47: /* refarg ::= ON INSERT refact */
+{ yymsp[-2].minor.yy497.value = 0; yymsp[-2].minor.yy497.mask = 0x000000; }
break;
- case 72: /* refarg ::= MATCH nm */
- case 73: /* refarg ::= ON INSERT refact */ yytestcase(yyruleno==73);
-{ yygotominor.yy215.value = 0; yygotominor.yy215.mask = 0x000000; }
+ case 48: /* refarg ::= ON DELETE refact */
+{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194; yymsp[-2].minor.yy497.mask = 0x0000ff; }
break;
- case 74: /* refarg ::= ON DELETE refact */
-{ yygotominor.yy215.value = yymsp[0].minor.yy4; yygotominor.yy215.mask = 0x0000ff; }
+ case 49: /* refarg ::= ON UPDATE refact */
+{ yymsp[-2].minor.yy497.value = yymsp[0].minor.yy194<<8; yymsp[-2].minor.yy497.mask = 0x00ff00; }
break;
- case 75: /* refarg ::= ON UPDATE refact */
-{ yygotominor.yy215.value = yymsp[0].minor.yy4<<8; yygotominor.yy215.mask = 0x00ff00; }
+ case 50: /* refact ::= SET NULL */
+{ yymsp[-1].minor.yy194 = OE_SetNull; /* EV: R-33326-45252 */}
break;
- case 76: /* refact ::= SET NULL */
-{ yygotominor.yy4 = OE_SetNull; /* EV: R-33326-45252 */}
+ case 51: /* refact ::= SET DEFAULT */
+{ yymsp[-1].minor.yy194 = OE_SetDflt; /* EV: R-33326-45252 */}
break;
- case 77: /* refact ::= SET DEFAULT */
-{ yygotominor.yy4 = OE_SetDflt; /* EV: R-33326-45252 */}
+ case 52: /* refact ::= CASCADE */
+{ yymsp[0].minor.yy194 = OE_Cascade; /* EV: R-33326-45252 */}
break;
- case 78: /* refact ::= CASCADE */
-{ yygotominor.yy4 = OE_Cascade; /* EV: R-33326-45252 */}
+ case 53: /* refact ::= RESTRICT */
+{ yymsp[0].minor.yy194 = OE_Restrict; /* EV: R-33326-45252 */}
break;
- case 79: /* refact ::= RESTRICT */
-{ yygotominor.yy4 = OE_Restrict; /* EV: R-33326-45252 */}
+ case 54: /* refact ::= NO ACTION */
+{ yymsp[-1].minor.yy194 = OE_None; /* EV: R-33326-45252 */}
break;
- case 80: /* refact ::= NO ACTION */
-{ yygotominor.yy4 = OE_None; /* EV: R-33326-45252 */}
+ case 55: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
+{yymsp[-2].minor.yy194 = 0;}
break;
- case 82: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
- case 98: /* defer_subclause_opt ::= defer_subclause */ yytestcase(yyruleno==98);
- case 100: /* onconf ::= ON CONFLICT resolvetype */ yytestcase(yyruleno==100);
- case 102: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==102);
- case 103: /* resolvetype ::= raisetype */ yytestcase(yyruleno==103);
- case 178: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==178);
-{yygotominor.yy4 = yymsp[0].minor.yy4;}
+ case 56: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
+ case 71: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==71);
+ case 144: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==144);
+{yymsp[-1].minor.yy194 = yymsp[0].minor.yy194;}
break;
- case 86: /* conslist_opt ::= */
-{yygotominor.yy0.n = 0; yygotominor.yy0.z = 0;}
+ case 58: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
+ case 75: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==75);
+ case 187: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==187);
+ case 190: /* in_op ::= NOT IN */ yytestcase(yyruleno==190);
+ case 216: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==216);
+{yymsp[-1].minor.yy194 = 1;}
break;
- case 87: /* conslist_opt ::= COMMA conslist */
-{yygotominor.yy0 = yymsp[-1].minor.yy0;}
+ case 59: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
+{yymsp[-1].minor.yy194 = 0;}
break;
- case 90: /* tconscomma ::= COMMA */
+ case 61: /* tconscomma ::= COMMA */
{pParse->constraintName.n = 0;}
break;
- case 93: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy4,yymsp[-2].minor.yy4,0);}
+ case 63: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
+{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy148,yymsp[0].minor.yy194,yymsp[-2].minor.yy194,0);}
break;
- case 94: /* tcons ::= UNIQUE LP sortlist RP onconf */
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy4,0,0,0,0);}
+ case 64: /* tcons ::= UNIQUE LP sortlist RP onconf */
+{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy148,yymsp[0].minor.yy194,0,0,0,0,
+ SQLITE_IDXTYPE_UNIQUE);}
break;
- case 95: /* tcons ::= CHECK LP expr RP onconf */
-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy118.pExpr);}
+ case 65: /* tcons ::= CHECK LP expr RP onconf */
+{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy190.pExpr);}
break;
- case 96: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
+ case 66: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
{
- sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy4);
- sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy4);
+ sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy148, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[-1].minor.yy194);
+ sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy194);
}
break;
- case 99: /* onconf ::= */
- case 101: /* orconf ::= */ yytestcase(yyruleno==101);
-{yygotominor.yy4 = OE_Default;}
+ case 68: /* onconf ::= */
+ case 70: /* orconf ::= */ yytestcase(yyruleno==70);
+{yymsp[1].minor.yy194 = OE_Default;}
break;
- case 104: /* resolvetype ::= IGNORE */
-{yygotominor.yy4 = OE_Ignore;}
+ case 69: /* onconf ::= ON CONFLICT resolvetype */
+{yymsp[-2].minor.yy194 = yymsp[0].minor.yy194;}
break;
- case 105: /* resolvetype ::= REPLACE */
- case 179: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==179);
-{yygotominor.yy4 = OE_Replace;}
+ case 72: /* resolvetype ::= IGNORE */
+{yymsp[0].minor.yy194 = OE_Ignore;}
break;
- case 106: /* cmd ::= DROP TABLE ifexists fullname */
+ case 73: /* resolvetype ::= REPLACE */
+ case 145: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==145);
+{yymsp[0].minor.yy194 = OE_Replace;}
+ break;
+ case 74: /* cmd ::= DROP TABLE ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy259, 0, yymsp[-1].minor.yy4);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy185, 0, yymsp[-1].minor.yy194);
}
break;
- case 109: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
+ case 77: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
{
- sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy387, yymsp[-7].minor.yy4, yymsp[-5].minor.yy4);
+ sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy148, yymsp[0].minor.yy243, yymsp[-7].minor.yy194, yymsp[-5].minor.yy194);
}
break;
- case 110: /* cmd ::= DROP VIEW ifexists fullname */
+ case 78: /* cmd ::= DROP VIEW ifexists fullname */
{
- sqlite3DropTable(pParse, yymsp[0].minor.yy259, 1, yymsp[-1].minor.yy4);
+ sqlite3DropTable(pParse, yymsp[0].minor.yy185, 1, yymsp[-1].minor.yy194);
}
break;
- case 111: /* cmd ::= select */
+ case 79: /* cmd ::= select */
{
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
- sqlite3Select(pParse, yymsp[0].minor.yy387, &dest);
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy387);
+ sqlite3Select(pParse, yymsp[0].minor.yy243, &dest);
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy243);
}
break;
- case 112: /* select ::= with selectnowith */
+ case 80: /* select ::= with selectnowith */
{
- Select *p = yymsp[0].minor.yy387;
+ Select *p = yymsp[0].minor.yy243;
if( p ){
- p->pWith = yymsp[-1].minor.yy451;
+ p->pWith = yymsp[-1].minor.yy285;
parserDoubleLinkSelect(pParse, p);
}else{
- sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy451);
+ sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy285);
}
- yygotominor.yy387 = p;
+ yymsp[-1].minor.yy243 = p; /*A-overwrites-W*/
}
break;
- case 113: /* selectnowith ::= oneselect */
- case 119: /* oneselect ::= values */ yytestcase(yyruleno==119);
-{yygotominor.yy387 = yymsp[0].minor.yy387;}
- break;
- case 114: /* selectnowith ::= selectnowith multiselect_op oneselect */
+ case 81: /* selectnowith ::= selectnowith multiselect_op oneselect */
{
- Select *pRhs = yymsp[0].minor.yy387;
- Select *pLhs = yymsp[-2].minor.yy387;
+ Select *pRhs = yymsp[0].minor.yy243;
+ Select *pLhs = yymsp[-2].minor.yy243;
if( pRhs && pRhs->pPrior ){
SrcList *pFrom;
Token x;
@@ -130343,23 +136463,30 @@ static void yy_reduce(
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0);
}
if( pRhs ){
- pRhs->op = (u8)yymsp[-1].minor.yy4;
+ pRhs->op = (u8)yymsp[-1].minor.yy194;
pRhs->pPrior = pLhs;
if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
pRhs->selFlags &= ~SF_MultiValue;
- if( yymsp[-1].minor.yy4!=TK_ALL ) pParse->hasCompound = 1;
+ if( yymsp[-1].minor.yy194!=TK_ALL ) pParse->hasCompound = 1;
}else{
sqlite3SelectDelete(pParse->db, pLhs);
}
- yygotominor.yy387 = pRhs;
+ yymsp[-2].minor.yy243 = pRhs;
}
break;
- case 116: /* multiselect_op ::= UNION ALL */
-{yygotominor.yy4 = TK_ALL;}
+ case 82: /* multiselect_op ::= UNION */
+ case 84: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==84);
+{yymsp[0].minor.yy194 = yymsp[0].major; /*A-overwrites-OP*/}
break;
- case 118: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
+ case 83: /* multiselect_op ::= UNION ALL */
+{yymsp[-1].minor.yy194 = TK_ALL;}
+ break;
+ case 85: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
{
- yygotominor.yy387 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy259,yymsp[-4].minor.yy314,yymsp[-3].minor.yy322,yymsp[-2].minor.yy314,yymsp[-1].minor.yy322,yymsp[-7].minor.yy4,yymsp[0].minor.yy292.pLimit,yymsp[0].minor.yy292.pOffset);
+#if SELECTTRACE_ENABLED
+ Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/
+#endif
+ yymsp[-8].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy148,yymsp[-5].minor.yy185,yymsp[-4].minor.yy72,yymsp[-3].minor.yy148,yymsp[-2].minor.yy72,yymsp[-1].minor.yy148,yymsp[-7].minor.yy194,yymsp[0].minor.yy354.pLimit,yymsp[0].minor.yy354.pOffset);
#if SELECTTRACE_ENABLED
/* Populate the Select.zSelName[] string that is used to help with
** query planner debugging, to differentiate between multiple Select
@@ -130370,446 +136497,488 @@ static void yy_reduce(
** comment to be the zSelName value. Otherwise, the label is #N where
** is an integer that is incremented with each SELECT statement seen.
*/
- if( yygotominor.yy387!=0 ){
- const char *z = yymsp[-8].minor.yy0.z+6;
+ if( yymsp[-8].minor.yy243!=0 ){
+ const char *z = s.z+6;
int i;
- sqlite3_snprintf(sizeof(yygotominor.yy387->zSelName), yygotominor.yy387->zSelName, "#%d",
+ sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "#%d",
++pParse->nSelect);
while( z[0]==' ' ) z++;
if( z[0]=='/' && z[1]=='*' ){
z += 2;
while( z[0]==' ' ) z++;
for(i=0; sqlite3Isalnum(z[i]); i++){}
- sqlite3_snprintf(sizeof(yygotominor.yy387->zSelName), yygotominor.yy387->zSelName, "%.*s", i, z);
+ sqlite3_snprintf(sizeof(yymsp[-8].minor.yy243->zSelName), yymsp[-8].minor.yy243->zSelName, "%.*s", i, z);
}
}
#endif /* SELECTRACE_ENABLED */
}
break;
- case 120: /* values ::= VALUES LP nexprlist RP */
+ case 86: /* values ::= VALUES LP nexprlist RP */
{
- yygotominor.yy387 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0,0);
+ yymsp[-3].minor.yy243 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values,0,0);
}
break;
- case 121: /* values ::= values COMMA LP exprlist RP */
+ case 87: /* values ::= values COMMA LP exprlist RP */
{
- Select *pRight, *pLeft = yymsp[-4].minor.yy387;
- pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
+ Select *pRight, *pLeft = yymsp[-4].minor.yy243;
+ pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy148,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
if( pRight ){
pRight->op = TK_ALL;
- pLeft = yymsp[-4].minor.yy387;
pRight->pPrior = pLeft;
- yygotominor.yy387 = pRight;
+ yymsp[-4].minor.yy243 = pRight;
}else{
- yygotominor.yy387 = pLeft;
+ yymsp[-4].minor.yy243 = pLeft;
}
}
break;
- case 122: /* distinct ::= DISTINCT */
-{yygotominor.yy4 = SF_Distinct;}
- break;
- case 123: /* distinct ::= ALL */
-{yygotominor.yy4 = SF_All;}
+ case 88: /* distinct ::= DISTINCT */
+{yymsp[0].minor.yy194 = SF_Distinct;}
break;
- case 125: /* sclp ::= selcollist COMMA */
- case 244: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==244);
-{yygotominor.yy322 = yymsp[-1].minor.yy322;}
+ case 89: /* distinct ::= ALL */
+{yymsp[0].minor.yy194 = SF_All;}
break;
- case 126: /* sclp ::= */
- case 155: /* orderby_opt ::= */ yytestcase(yyruleno==155);
- case 162: /* groupby_opt ::= */ yytestcase(yyruleno==162);
- case 237: /* exprlist ::= */ yytestcase(yyruleno==237);
- case 243: /* eidlist_opt ::= */ yytestcase(yyruleno==243);
-{yygotominor.yy322 = 0;}
+ case 91: /* sclp ::= */
+ case 119: /* orderby_opt ::= */ yytestcase(yyruleno==119);
+ case 126: /* groupby_opt ::= */ yytestcase(yyruleno==126);
+ case 203: /* exprlist ::= */ yytestcase(yyruleno==203);
+ case 206: /* paren_exprlist ::= */ yytestcase(yyruleno==206);
+ case 211: /* eidlist_opt ::= */ yytestcase(yyruleno==211);
+{yymsp[1].minor.yy148 = 0;}
break;
- case 127: /* selcollist ::= sclp expr as */
+ case 92: /* selcollist ::= sclp expr as */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, yymsp[-1].minor.yy118.pExpr);
- if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[0].minor.yy0, 1);
- sqlite3ExprListSetSpan(pParse,yygotominor.yy322,&yymsp[-1].minor.yy118);
+ yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy148, yymsp[-1].minor.yy190.pExpr);
+ if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy148, &yymsp[0].minor.yy0, 1);
+ sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy148,&yymsp[-1].minor.yy190);
}
break;
- case 128: /* selcollist ::= sclp STAR */
+ case 93: /* selcollist ::= sclp STAR */
{
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
- yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy322, p);
+ yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy148, p);
}
break;
- case 129: /* selcollist ::= sclp nm DOT STAR */
+ case 94: /* selcollist ::= sclp nm DOT STAR */
{
- Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, &yymsp[0].minor.yy0);
- Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
- Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, pDot);
+ Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
+ Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
+ Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
+ yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, pDot);
}
break;
- case 132: /* as ::= */
-{yygotominor.yy0.n = 0;}
+ case 95: /* as ::= AS nm */
+ case 106: /* dbnm ::= DOT nm */ yytestcase(yyruleno==106);
+ case 225: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==225);
+ case 226: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==226);
+{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 133: /* from ::= */
-{yygotominor.yy259 = sqlite3DbMallocZero(pParse->db, sizeof(*yygotominor.yy259));}
+ case 97: /* from ::= */
+{yymsp[1].minor.yy185 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy185));}
break;
- case 134: /* from ::= FROM seltablist */
+ case 98: /* from ::= FROM seltablist */
{
- yygotominor.yy259 = yymsp[0].minor.yy259;
- sqlite3SrcListShiftJoinType(yygotominor.yy259);
+ yymsp[-1].minor.yy185 = yymsp[0].minor.yy185;
+ sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy185);
}
break;
- case 135: /* stl_prefix ::= seltablist joinop */
+ case 99: /* stl_prefix ::= seltablist joinop */
{
- yygotominor.yy259 = yymsp[-1].minor.yy259;
- if( ALWAYS(yygotominor.yy259 && yygotominor.yy259->nSrc>0) ) yygotominor.yy259->a[yygotominor.yy259->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy4;
+ if( ALWAYS(yymsp[-1].minor.yy185 && yymsp[-1].minor.yy185->nSrc>0) ) yymsp[-1].minor.yy185->a[yymsp[-1].minor.yy185->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy194;
}
break;
- case 136: /* stl_prefix ::= */
-{yygotominor.yy259 = 0;}
+ case 100: /* stl_prefix ::= */
+{yymsp[1].minor.yy185 = 0;}
break;
- case 137: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
+ case 101: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
{
- yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
- sqlite3SrcListIndexedBy(pParse, yygotominor.yy259, &yymsp[-2].minor.yy0);
+ yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy185, &yymsp[-2].minor.yy0);
}
break;
- case 138: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
+ case 102: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
{
- yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy259,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
- sqlite3SrcListFuncArgs(pParse, yygotominor.yy259, yymsp[-4].minor.yy322);
+ yymsp[-8].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy185,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
+ sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy185, yymsp[-4].minor.yy148);
}
break;
- case 139: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
+ case 103: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
{
- yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy387,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
+ yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy243,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
}
break;
- case 140: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
+ case 104: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
{
- if( yymsp[-6].minor.yy259==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy314==0 && yymsp[0].minor.yy384==0 ){
- yygotominor.yy259 = yymsp[-4].minor.yy259;
- }else if( yymsp[-4].minor.yy259->nSrc==1 ){
- yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
- if( yygotominor.yy259 ){
- struct SrcList_item *pNew = &yygotominor.yy259->a[yygotominor.yy259->nSrc-1];
- struct SrcList_item *pOld = yymsp[-4].minor.yy259->a;
+ if( yymsp[-6].minor.yy185==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy72==0 && yymsp[0].minor.yy254==0 ){
+ yymsp[-6].minor.yy185 = yymsp[-4].minor.yy185;
+ }else if( yymsp[-4].minor.yy185->nSrc==1 ){
+ yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
+ if( yymsp[-6].minor.yy185 ){
+ struct SrcList_item *pNew = &yymsp[-6].minor.yy185->a[yymsp[-6].minor.yy185->nSrc-1];
+ struct SrcList_item *pOld = yymsp[-4].minor.yy185->a;
pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase;
pNew->pSelect = pOld->pSelect;
pOld->zName = pOld->zDatabase = 0;
pOld->pSelect = 0;
}
- sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy259);
+ sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy185);
}else{
Select *pSubquery;
- sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy259);
- pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy259,0,0,0,0,SF_NestedFrom,0,0);
- yygotominor.yy259 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy259,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy314,yymsp[0].minor.yy384);
+ sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy185);
+ pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy185,0,0,0,0,SF_NestedFrom,0,0);
+ yymsp[-6].minor.yy185 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy185,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy72,yymsp[0].minor.yy254);
}
}
break;
- case 141: /* dbnm ::= */
- case 150: /* indexed_opt ::= */ yytestcase(yyruleno==150);
-{yygotominor.yy0.z=0; yygotominor.yy0.n=0;}
+ case 105: /* dbnm ::= */
+ case 114: /* indexed_opt ::= */ yytestcase(yyruleno==114);
+{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
break;
- case 143: /* fullname ::= nm dbnm */
-{yygotominor.yy259 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
+ case 107: /* fullname ::= nm dbnm */
+{yymsp[-1].minor.yy185 = sqlite3SrcListAppend(pParse->db,0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 144: /* joinop ::= COMMA|JOIN */
-{ yygotominor.yy4 = JT_INNER; }
+ case 108: /* joinop ::= COMMA|JOIN */
+{ yymsp[0].minor.yy194 = JT_INNER; }
break;
- case 145: /* joinop ::= JOIN_KW JOIN */
-{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
+ case 109: /* joinop ::= JOIN_KW JOIN */
+{yymsp[-1].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
break;
- case 146: /* joinop ::= JOIN_KW nm JOIN */
-{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); }
+ case 110: /* joinop ::= JOIN_KW nm JOIN */
+{yymsp[-2].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
break;
- case 147: /* joinop ::= JOIN_KW nm nm JOIN */
-{ yygotominor.yy4 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0); }
+ case 111: /* joinop ::= JOIN_KW nm nm JOIN */
+{yymsp[-3].minor.yy194 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
break;
- case 148: /* on_opt ::= ON expr */
- case 165: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==165);
- case 172: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==172);
- case 232: /* case_else ::= ELSE expr */ yytestcase(yyruleno==232);
- case 234: /* case_operand ::= expr */ yytestcase(yyruleno==234);
-{yygotominor.yy314 = yymsp[0].minor.yy118.pExpr;}
+ case 112: /* on_opt ::= ON expr */
+ case 129: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==129);
+ case 136: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==136);
+ case 199: /* case_else ::= ELSE expr */ yytestcase(yyruleno==199);
+{yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr;}
break;
- case 149: /* on_opt ::= */
- case 164: /* having_opt ::= */ yytestcase(yyruleno==164);
- case 171: /* where_opt ::= */ yytestcase(yyruleno==171);
- case 233: /* case_else ::= */ yytestcase(yyruleno==233);
- case 235: /* case_operand ::= */ yytestcase(yyruleno==235);
-{yygotominor.yy314 = 0;}
+ case 113: /* on_opt ::= */
+ case 128: /* having_opt ::= */ yytestcase(yyruleno==128);
+ case 135: /* where_opt ::= */ yytestcase(yyruleno==135);
+ case 200: /* case_else ::= */ yytestcase(yyruleno==200);
+ case 202: /* case_operand ::= */ yytestcase(yyruleno==202);
+{yymsp[1].minor.yy72 = 0;}
break;
- case 152: /* indexed_opt ::= NOT INDEXED */
-{yygotominor.yy0.z=0; yygotominor.yy0.n=1;}
+ case 115: /* indexed_opt ::= INDEXED BY nm */
+{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
break;
- case 153: /* using_opt ::= USING LP idlist RP */
- case 181: /* idlist_opt ::= LP idlist RP */ yytestcase(yyruleno==181);
-{yygotominor.yy384 = yymsp[-1].minor.yy384;}
+ case 116: /* indexed_opt ::= NOT INDEXED */
+{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
break;
- case 154: /* using_opt ::= */
- case 180: /* idlist_opt ::= */ yytestcase(yyruleno==180);
-{yygotominor.yy384 = 0;}
+ case 117: /* using_opt ::= USING LP idlist RP */
+{yymsp[-3].minor.yy254 = yymsp[-1].minor.yy254;}
break;
- case 156: /* orderby_opt ::= ORDER BY sortlist */
- case 163: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==163);
- case 236: /* exprlist ::= nexprlist */ yytestcase(yyruleno==236);
-{yygotominor.yy322 = yymsp[0].minor.yy322;}
+ case 118: /* using_opt ::= */
+ case 146: /* idlist_opt ::= */ yytestcase(yyruleno==146);
+{yymsp[1].minor.yy254 = 0;}
break;
- case 157: /* sortlist ::= sortlist COMMA expr sortorder */
+ case 120: /* orderby_opt ::= ORDER BY sortlist */
+ case 127: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==127);
+{yymsp[-2].minor.yy148 = yymsp[0].minor.yy148;}
+ break;
+ case 121: /* sortlist ::= sortlist COMMA expr sortorder */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322,yymsp[-1].minor.yy118.pExpr);
- sqlite3ExprListSetSortOrder(yygotominor.yy322,yymsp[0].minor.yy4);
+ yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148,yymsp[-1].minor.yy190.pExpr);
+ sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy148,yymsp[0].minor.yy194);
}
break;
- case 158: /* sortlist ::= expr sortorder */
+ case 122: /* sortlist ::= expr sortorder */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy118.pExpr);
- sqlite3ExprListSetSortOrder(yygotominor.yy322,yymsp[0].minor.yy4);
+ yymsp[-1].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy190.pExpr); /*A-overwrites-Y*/
+ sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy148,yymsp[0].minor.yy194);
}
break;
- case 159: /* sortorder ::= ASC */
-{yygotominor.yy4 = SQLITE_SO_ASC;}
+ case 123: /* sortorder ::= ASC */
+{yymsp[0].minor.yy194 = SQLITE_SO_ASC;}
+ break;
+ case 124: /* sortorder ::= DESC */
+{yymsp[0].minor.yy194 = SQLITE_SO_DESC;}
break;
- case 160: /* sortorder ::= DESC */
-{yygotominor.yy4 = SQLITE_SO_DESC;}
+ case 125: /* sortorder ::= */
+{yymsp[1].minor.yy194 = SQLITE_SO_UNDEFINED;}
break;
- case 161: /* sortorder ::= */
-{yygotominor.yy4 = SQLITE_SO_UNDEFINED;}
+ case 130: /* limit_opt ::= */
+{yymsp[1].minor.yy354.pLimit = 0; yymsp[1].minor.yy354.pOffset = 0;}
break;
- case 166: /* limit_opt ::= */
-{yygotominor.yy292.pLimit = 0; yygotominor.yy292.pOffset = 0;}
+ case 131: /* limit_opt ::= LIMIT expr */
+{yymsp[-1].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr; yymsp[-1].minor.yy354.pOffset = 0;}
break;
- case 167: /* limit_opt ::= LIMIT expr */
-{yygotominor.yy292.pLimit = yymsp[0].minor.yy118.pExpr; yygotominor.yy292.pOffset = 0;}
+ case 132: /* limit_opt ::= LIMIT expr OFFSET expr */
+{yymsp[-3].minor.yy354.pLimit = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pOffset = yymsp[0].minor.yy190.pExpr;}
break;
- case 168: /* limit_opt ::= LIMIT expr OFFSET expr */
-{yygotominor.yy292.pLimit = yymsp[-2].minor.yy118.pExpr; yygotominor.yy292.pOffset = yymsp[0].minor.yy118.pExpr;}
+ case 133: /* limit_opt ::= LIMIT expr COMMA expr */
+{yymsp[-3].minor.yy354.pOffset = yymsp[-2].minor.yy190.pExpr; yymsp[-3].minor.yy354.pLimit = yymsp[0].minor.yy190.pExpr;}
break;
- case 169: /* limit_opt ::= LIMIT expr COMMA expr */
-{yygotominor.yy292.pOffset = yymsp[-2].minor.yy118.pExpr; yygotominor.yy292.pLimit = yymsp[0].minor.yy118.pExpr;}
+ case 134: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
+{
+ sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy185, &yymsp[-1].minor.yy0);
+ sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy185,yymsp[0].minor.yy72);
+}
break;
- case 170: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
+ case 137: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
{
- sqlite3WithPush(pParse, yymsp[-5].minor.yy451, 1);
- sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy259, &yymsp[-1].minor.yy0);
- sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy259,yymsp[0].minor.yy314);
+ sqlite3WithPush(pParse, yymsp[-7].minor.yy285, 1);
+ sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy185, &yymsp[-3].minor.yy0);
+ sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy148,"set list");
+ sqlite3Update(pParse,yymsp[-4].minor.yy185,yymsp[-1].minor.yy148,yymsp[0].minor.yy72,yymsp[-5].minor.yy194);
}
break;
- case 173: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
+ case 138: /* setlist ::= setlist COMMA nm EQ expr */
{
- sqlite3WithPush(pParse, yymsp[-7].minor.yy451, 1);
- sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy259, &yymsp[-3].minor.yy0);
- sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy322,"set list");
- sqlite3Update(pParse,yymsp[-4].minor.yy259,yymsp[-1].minor.yy322,yymsp[0].minor.yy314,yymsp[-5].minor.yy4);
+ yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr);
+ sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, 1);
}
break;
- case 174: /* setlist ::= setlist COMMA nm EQ expr */
+ case 139: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy118.pExpr);
- sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[-2].minor.yy0, 1);
+ yymsp[-6].minor.yy148 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy148, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr);
}
break;
- case 175: /* setlist ::= nm EQ expr */
+ case 140: /* setlist ::= nm EQ expr */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy118.pExpr);
- sqlite3ExprListSetName(pParse, yygotominor.yy322, &yymsp[-2].minor.yy0, 1);
+ yylhsminor.yy148 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy190.pExpr);
+ sqlite3ExprListSetName(pParse, yylhsminor.yy148, &yymsp[-2].minor.yy0, 1);
}
+ yymsp[-2].minor.yy148 = yylhsminor.yy148;
break;
- case 176: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
+ case 141: /* setlist ::= LP idlist RP EQ expr */
{
- sqlite3WithPush(pParse, yymsp[-5].minor.yy451, 1);
- sqlite3Insert(pParse, yymsp[-2].minor.yy259, yymsp[0].minor.yy387, yymsp[-1].minor.yy384, yymsp[-4].minor.yy4);
+ yymsp[-4].minor.yy148 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy190.pExpr);
}
break;
- case 177: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
+ case 142: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
{
- sqlite3WithPush(pParse, yymsp[-6].minor.yy451, 1);
- sqlite3Insert(pParse, yymsp[-3].minor.yy259, 0, yymsp[-2].minor.yy384, yymsp[-5].minor.yy4);
+ sqlite3WithPush(pParse, yymsp[-5].minor.yy285, 1);
+ sqlite3Insert(pParse, yymsp[-2].minor.yy185, yymsp[0].minor.yy243, yymsp[-1].minor.yy254, yymsp[-4].minor.yy194);
}
break;
- case 182: /* idlist ::= idlist COMMA nm */
-{yygotominor.yy384 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy384,&yymsp[0].minor.yy0);}
+ case 143: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
+{
+ sqlite3WithPush(pParse, yymsp[-6].minor.yy285, 1);
+ sqlite3Insert(pParse, yymsp[-3].minor.yy185, 0, yymsp[-2].minor.yy254, yymsp[-5].minor.yy194);
+}
break;
- case 183: /* idlist ::= nm */
-{yygotominor.yy384 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0);}
+ case 147: /* idlist_opt ::= LP idlist RP */
+{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;}
break;
- case 184: /* expr ::= term */
-{yygotominor.yy118 = yymsp[0].minor.yy118;}
+ case 148: /* idlist ::= idlist COMMA nm */
+{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);}
break;
- case 185: /* expr ::= LP expr RP */
-{yygotominor.yy118.pExpr = yymsp[-1].minor.yy118.pExpr; spanSet(&yygotominor.yy118,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);}
+ case 149: /* idlist ::= nm */
+{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
break;
- case 186: /* term ::= NULL */
- case 191: /* term ::= INTEGER|FLOAT|BLOB */ yytestcase(yyruleno==191);
- case 192: /* term ::= STRING */ yytestcase(yyruleno==192);
-{spanExpr(&yygotominor.yy118, pParse, yymsp[0].major, &yymsp[0].minor.yy0);}
+ case 150: /* expr ::= LP expr RP */
+{spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/ yymsp[-2].minor.yy190.pExpr = yymsp[-1].minor.yy190.pExpr;}
break;
- case 187: /* expr ::= ID|INDEXED */
- case 188: /* expr ::= JOIN_KW */ yytestcase(yyruleno==188);
-{spanExpr(&yygotominor.yy118, pParse, TK_ID, &yymsp[0].minor.yy0);}
+ case 151: /* term ::= NULL */
+ case 156: /* term ::= FLOAT|BLOB */ yytestcase(yyruleno==156);
+ case 157: /* term ::= STRING */ yytestcase(yyruleno==157);
+{spanExpr(&yymsp[0].minor.yy190,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/}
break;
- case 189: /* expr ::= nm DOT nm */
+ case 152: /* expr ::= ID|INDEXED */
+ case 153: /* expr ::= JOIN_KW */ yytestcase(yyruleno==153);
+{spanExpr(&yymsp[0].minor.yy190,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
+ break;
+ case 154: /* expr ::= nm DOT nm */
+{
+ Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
+ Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
+ spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
+ yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
+}
+ break;
+ case 155: /* expr ::= nm DOT nm DOT nm */
{
- Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
- Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
- spanSet(&yygotominor.yy118,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
+ Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1);
+ Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
+ Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
+ Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
+ spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
+ yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
}
break;
- case 190: /* expr ::= nm DOT nm DOT nm */
+ case 158: /* term ::= INTEGER */
{
- Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-4].minor.yy0);
- Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[-2].minor.yy0);
- Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &yymsp[0].minor.yy0);
- Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
- spanSet(&yygotominor.yy118,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
+ yylhsminor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
+ yylhsminor.yy190.zStart = yymsp[0].minor.yy0.z;
+ yylhsminor.yy190.zEnd = yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n;
+ if( yylhsminor.yy190.pExpr ) yylhsminor.yy190.pExpr->flags |= EP_Leaf;
}
+ yymsp[0].minor.yy190 = yylhsminor.yy190;
break;
- case 193: /* expr ::= VARIABLE */
+ case 159: /* expr ::= VARIABLE */
{
- if( yymsp[0].minor.yy0.n>=2 && yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1]) ){
+ if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
+ u32 n = yymsp[0].minor.yy0.n;
+ spanExpr(&yymsp[0].minor.yy190, pParse, TK_VARIABLE, yymsp[0].minor.yy0);
+ sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy190.pExpr, n);
+ }else{
/* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers
** in the virtual machine. #N is the N-th register. */
+ Token t = yymsp[0].minor.yy0; /*A-overwrites-X*/
+ assert( t.n>=2 );
+ spanSet(&yymsp[0].minor.yy190, &t, &t);
if( pParse->nested==0 ){
- sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &yymsp[0].minor.yy0);
- yygotominor.yy118.pExpr = 0;
+ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
+ yymsp[0].minor.yy190.pExpr = 0;
}else{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &yymsp[0].minor.yy0);
- if( yygotominor.yy118.pExpr ) sqlite3GetInt32(&yymsp[0].minor.yy0.z[1], &yygotominor.yy118.pExpr->iTable);
+ yymsp[0].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
+ if( yymsp[0].minor.yy190.pExpr ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy190.pExpr->iTable);
}
- }else{
- spanExpr(&yygotominor.yy118, pParse, TK_VARIABLE, &yymsp[0].minor.yy0);
- sqlite3ExprAssignVarNumber(pParse, yygotominor.yy118.pExpr);
}
- spanSet(&yygotominor.yy118, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
break;
- case 194: /* expr ::= expr COLLATE ID|STRING */
+ case 160: /* expr ::= expr COLLATE ID|STRING */
{
- yygotominor.yy118.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy118.pExpr, &yymsp[0].minor.yy0, 1);
- yygotominor.yy118.zStart = yymsp[-2].minor.yy118.zStart;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yymsp[-2].minor.yy190.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy190.pExpr, &yymsp[0].minor.yy0, 1);
+ yymsp[-2].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 195: /* expr ::= CAST LP expr AS typetoken RP */
+ case 161: /* expr ::= CAST LP expr AS typetoken RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_CAST, yymsp[-3].minor.yy118.pExpr, 0, &yymsp[-1].minor.yy0);
- spanSet(&yygotominor.yy118,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
+ spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
+ yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
+ sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, 0);
}
break;
- case 196: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+ case 162: /* expr ::= ID|INDEXED LP distinct exprlist RP */
{
- if( yymsp[-1].minor.yy322 && yymsp[-1].minor.yy322->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
+ if( yymsp[-1].minor.yy148 && yymsp[-1].minor.yy148->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
}
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0);
- spanSet(&yygotominor.yy118,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
- if( yymsp[-2].minor.yy4==SF_Distinct && yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->flags |= EP_Distinct;
+ yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy148, &yymsp[-4].minor.yy0);
+ spanSet(&yylhsminor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
+ if( yymsp[-2].minor.yy194==SF_Distinct && yylhsminor.yy190.pExpr ){
+ yylhsminor.yy190.pExpr->flags |= EP_Distinct;
}
}
+ yymsp[-4].minor.yy190 = yylhsminor.yy190;
+ break;
+ case 163: /* expr ::= ID|INDEXED LP STAR RP */
+{
+ yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
+ spanSet(&yylhsminor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+}
+ yymsp[-3].minor.yy190 = yylhsminor.yy190;
break;
- case 197: /* expr ::= ID|INDEXED LP STAR RP */
+ case 164: /* term ::= CTIME_KW */
{
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
- spanSet(&yygotominor.yy118,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
+ yylhsminor.yy190.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
+ spanSet(&yylhsminor.yy190, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
}
+ yymsp[0].minor.yy190 = yylhsminor.yy190;
break;
- case 198: /* term ::= CTIME_KW */
+ case 165: /* expr ::= LP nexprlist COMMA expr RP */
{
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
- spanSet(&yygotominor.yy118, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
+ ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy148, yymsp[-1].minor.yy190.pExpr);
+ yylhsminor.yy190.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
+ if( yylhsminor.yy190.pExpr ){
+ yylhsminor.yy190.pExpr->x.pList = pList;
+ spanSet(&yylhsminor.yy190, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
+ }else{
+ sqlite3ExprListDelete(pParse->db, pList);
+ }
}
+ yymsp[-4].minor.yy190 = yylhsminor.yy190;
break;
- case 199: /* expr ::= expr AND expr */
- case 200: /* expr ::= expr OR expr */ yytestcase(yyruleno==200);
- case 201: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==201);
- case 202: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==202);
- case 203: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==203);
- case 204: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==204);
- case 205: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==205);
- case 206: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==206);
-{spanBinaryExpr(&yygotominor.yy118,pParse,yymsp[-1].major,&yymsp[-2].minor.yy118,&yymsp[0].minor.yy118);}
+ case 166: /* expr ::= expr AND expr */
+ case 167: /* expr ::= expr OR expr */ yytestcase(yyruleno==167);
+ case 168: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==168);
+ case 169: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==169);
+ case 170: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==170);
+ case 171: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==171);
+ case 172: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==172);
+ case 173: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==173);
+{spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);}
break;
- case 207: /* likeop ::= LIKE_KW|MATCH */
-{yygotominor.yy342.eOperator = yymsp[0].minor.yy0; yygotominor.yy342.bNot = 0;}
+ case 174: /* likeop ::= LIKE_KW|MATCH */
+{yymsp[0].minor.yy0=yymsp[0].minor.yy0;/*A-overwrites-X*/}
break;
- case 208: /* likeop ::= NOT LIKE_KW|MATCH */
-{yygotominor.yy342.eOperator = yymsp[0].minor.yy0; yygotominor.yy342.bNot = 1;}
+ case 175: /* likeop ::= NOT LIKE_KW|MATCH */
+{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
break;
- case 209: /* expr ::= expr likeop expr */
+ case 176: /* expr ::= expr likeop expr */
{
ExprList *pList;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy118.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy118.pExpr);
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy342.eOperator);
- exprNot(pParse, yymsp[-1].minor.yy342.bNot, &yygotominor.yy118.pExpr);
- yygotominor.yy118.zStart = yymsp[-2].minor.yy118.zStart;
- yygotominor.yy118.zEnd = yymsp[0].minor.yy118.zEnd;
- if( yygotominor.yy118.pExpr ) yygotominor.yy118.pExpr->flags |= EP_InfixFunc;
+ int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
+ yymsp[-1].minor.yy0.n &= 0x7fffffff;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy190.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy190.pExpr);
+ yymsp[-2].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0);
+ exprNot(pParse, bNot, &yymsp[-2].minor.yy190);
+ yymsp[-2].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd;
+ if( yymsp[-2].minor.yy190.pExpr ) yymsp[-2].minor.yy190.pExpr->flags |= EP_InfixFunc;
}
break;
- case 210: /* expr ::= expr likeop expr ESCAPE expr */
+ case 177: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
- pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy118.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy118.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy118.pExpr);
- yygotominor.yy118.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy342.eOperator);
- exprNot(pParse, yymsp[-3].minor.yy342.bNot, &yygotominor.yy118.pExpr);
- yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart;
- yygotominor.yy118.zEnd = yymsp[0].minor.yy118.zEnd;
- if( yygotominor.yy118.pExpr ) yygotominor.yy118.pExpr->flags |= EP_InfixFunc;
+ int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
+ yymsp[-3].minor.yy0.n &= 0x7fffffff;
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy190.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr);
+ yymsp[-4].minor.yy190.pExpr = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0);
+ exprNot(pParse, bNot, &yymsp[-4].minor.yy190);
+ yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd;
+ if( yymsp[-4].minor.yy190.pExpr ) yymsp[-4].minor.yy190.pExpr->flags |= EP_InfixFunc;
}
break;
- case 211: /* expr ::= expr ISNULL|NOTNULL */
-{spanUnaryPostfix(&yygotominor.yy118,pParse,yymsp[0].major,&yymsp[-1].minor.yy118,&yymsp[0].minor.yy0);}
+ case 178: /* expr ::= expr ISNULL|NOTNULL */
+{spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy190,&yymsp[0].minor.yy0);}
break;
- case 212: /* expr ::= expr NOT NULL */
-{spanUnaryPostfix(&yygotominor.yy118,pParse,TK_NOTNULL,&yymsp[-2].minor.yy118,&yymsp[0].minor.yy0);}
+ case 179: /* expr ::= expr NOT NULL */
+{spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy0);}
break;
- case 213: /* expr ::= expr IS expr */
+ case 180: /* expr ::= expr IS expr */
{
- spanBinaryExpr(&yygotominor.yy118,pParse,TK_IS,&yymsp[-2].minor.yy118,&yymsp[0].minor.yy118);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy118.pExpr, yygotominor.yy118.pExpr, TK_ISNULL);
+ spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy190,&yymsp[0].minor.yy190);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-2].minor.yy190.pExpr, TK_ISNULL);
}
break;
- case 214: /* expr ::= expr IS NOT expr */
+ case 181: /* expr ::= expr IS NOT expr */
{
- spanBinaryExpr(&yygotominor.yy118,pParse,TK_ISNOT,&yymsp[-3].minor.yy118,&yymsp[0].minor.yy118);
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy118.pExpr, yygotominor.yy118.pExpr, TK_NOTNULL);
+ spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy190,&yymsp[0].minor.yy190);
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy190.pExpr, yymsp[-3].minor.yy190.pExpr, TK_NOTNULL);
}
break;
- case 215: /* expr ::= NOT expr */
- case 216: /* expr ::= BITNOT expr */ yytestcase(yyruleno==216);
-{spanUnaryPrefix(&yygotominor.yy118,pParse,yymsp[-1].major,&yymsp[0].minor.yy118,&yymsp[-1].minor.yy0);}
+ case 182: /* expr ::= NOT expr */
+ case 183: /* expr ::= BITNOT expr */ yytestcase(yyruleno==183);
+{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,yymsp[-1].major,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
+ break;
+ case 184: /* expr ::= MINUS expr */
+{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UMINUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
break;
- case 217: /* expr ::= MINUS expr */
-{spanUnaryPrefix(&yygotominor.yy118,pParse,TK_UMINUS,&yymsp[0].minor.yy118,&yymsp[-1].minor.yy0);}
+ case 185: /* expr ::= PLUS expr */
+{spanUnaryPrefix(&yymsp[-1].minor.yy190,pParse,TK_UPLUS,&yymsp[0].minor.yy190,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
break;
- case 218: /* expr ::= PLUS expr */
-{spanUnaryPrefix(&yygotominor.yy118,pParse,TK_UPLUS,&yymsp[0].minor.yy118,&yymsp[-1].minor.yy0);}
+ case 186: /* between_op ::= BETWEEN */
+ case 189: /* in_op ::= IN */ yytestcase(yyruleno==189);
+{yymsp[0].minor.yy194 = 0;}
break;
- case 221: /* expr ::= expr between_op expr AND expr */
+ case 188: /* expr ::= expr between_op expr AND expr */
{
- ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy118.pExpr);
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy118.pExpr);
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy118.pExpr, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pList = pList;
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr);
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy190.pExpr);
+ yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy190.pExpr, 0);
+ if( yymsp[-4].minor.yy190.pExpr ){
+ yymsp[-4].minor.yy190.pExpr->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
- exprNot(pParse, yymsp[-3].minor.yy4, &yygotominor.yy118.pExpr);
- yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart;
- yygotominor.yy118.zEnd = yymsp[0].minor.yy118.zEnd;
+ exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190);
+ yymsp[-4].minor.yy190.zEnd = yymsp[0].minor.yy190.zEnd;
}
break;
- case 224: /* expr ::= expr in_op LP exprlist RP */
+ case 191: /* expr ::= expr in_op LP exprlist RP */
{
- if( yymsp[-1].minor.yy322==0 ){
+ if( yymsp[-1].minor.yy148==0 ){
/* Expressions of the form
**
** expr1 IN ()
@@ -130818,9 +136987,9 @@ static void yy_reduce(
** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1.
*/
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[yymsp[-3].minor.yy4]);
- sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy118.pExpr);
- }else if( yymsp[-1].minor.yy322->nExpr==1 ){
+ sqlite3ExprDelete(pParse->db, yymsp[-4].minor.yy190.pExpr);
+ yymsp[-4].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[yymsp[-3].minor.yy194],1);
+ }else if( yymsp[-1].minor.yy148->nExpr==1 ){
/* Expressions of the form:
**
** expr1 IN (?1)
@@ -130837,423 +137006,419 @@ static void yy_reduce(
** affinity or the collating sequence to use for comparison. Otherwise,
** the semantics would be subtly different from IN or NOT IN.
*/
- Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr;
- yymsp[-1].minor.yy322->a[0].pExpr = 0;
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
+ Expr *pRHS = yymsp[-1].minor.yy148->a[0].pExpr;
+ yymsp[-1].minor.yy148->a[0].pExpr = 0;
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148);
/* pRHS cannot be NULL because a malloc error would have been detected
** before now and control would have never reached this point */
if( ALWAYS(pRHS) ){
pRHS->flags &= ~EP_Collate;
pRHS->flags |= EP_Generic;
}
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy4 ? TK_NE : TK_EQ, yymsp[-4].minor.yy118.pExpr, pRHS, 0);
+ yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, yymsp[-3].minor.yy194 ? TK_NE : TK_EQ, yymsp[-4].minor.yy190.pExpr, pRHS);
}else{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy118.pExpr, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pList = yymsp[-1].minor.yy322;
- sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr);
+ yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0);
+ if( yymsp[-4].minor.yy190.pExpr ){
+ yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy148;
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy148);
}
- exprNot(pParse, yymsp[-3].minor.yy4, &yygotominor.yy118.pExpr);
+ exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190);
}
- yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 225: /* expr ::= LP select RP */
+ case 192: /* expr ::= LP select RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pSelect = yymsp[-1].minor.yy387;
- ExprSetProperty(yygotominor.yy118.pExpr, EP_xIsSelect|EP_Subquery);
- sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr);
- }else{
- sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy387);
- }
- yygotominor.yy118.zStart = yymsp[-2].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ spanSet(&yymsp[-2].minor.yy190,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
+ yymsp[-2].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy190.pExpr, yymsp[-1].minor.yy243);
}
break;
- case 226: /* expr ::= expr in_op LP select RP */
+ case 193: /* expr ::= expr in_op LP select RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy118.pExpr, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pSelect = yymsp[-1].minor.yy387;
- ExprSetProperty(yygotominor.yy118.pExpr, EP_xIsSelect|EP_Subquery);
- sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr);
- }else{
- sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy387);
- }
- exprNot(pParse, yymsp[-3].minor.yy4, &yygotominor.yy118.pExpr);
- yygotominor.yy118.zStart = yymsp[-4].minor.yy118.zStart;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, yymsp[-1].minor.yy243);
+ exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190);
+ yymsp[-4].minor.yy190.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 227: /* expr ::= expr in_op nm dbnm */
+ case 194: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
- SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-3].minor.yy118.pExpr, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
- ExprSetProperty(yygotominor.yy118.pExpr, EP_xIsSelect|EP_Subquery);
- sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr);
- }else{
- sqlite3SrcListDelete(pParse->db, pSrc);
- }
- exprNot(pParse, yymsp[-2].minor.yy4, &yygotominor.yy118.pExpr);
- yygotominor.yy118.zStart = yymsp[-3].minor.yy118.zStart;
- yygotominor.yy118.zEnd = yymsp[0].minor.yy0.z ? &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] : &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n];
+ SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
+ Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
+ if( yymsp[0].minor.yy148 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy148);
+ yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy190.pExpr, 0);
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy190.pExpr, pSelect);
+ exprNot(pParse, yymsp[-3].minor.yy194, &yymsp[-4].minor.yy190);
+ yymsp[-4].minor.yy190.zEnd = yymsp[-1].minor.yy0.z ? &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n] : &yymsp[-2].minor.yy0.z[yymsp[-2].minor.yy0.n];
}
break;
- case 228: /* expr ::= EXISTS LP select RP */
+ case 195: /* expr ::= EXISTS LP select RP */
{
- Expr *p = yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
- if( p ){
- p->x.pSelect = yymsp[-1].minor.yy387;
- ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
- sqlite3ExprSetHeightAndFlags(pParse, p);
- }else{
- sqlite3SelectDelete(pParse->db, yymsp[-1].minor.yy387);
- }
- yygotominor.yy118.zStart = yymsp[-3].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
+ Expr *p;
+ spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
+ p = yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
+ sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy243);
}
break;
- case 229: /* expr ::= CASE case_operand case_exprlist case_else END */
+ case 196: /* expr ::= CASE case_operand case_exprlist case_else END */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy314, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->x.pList = yymsp[-1].minor.yy314 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy314) : yymsp[-2].minor.yy322;
- sqlite3ExprSetHeightAndFlags(pParse, yygotominor.yy118.pExpr);
+ spanSet(&yymsp[-4].minor.yy190,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-C*/
+ yymsp[-4].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy72, 0);
+ if( yymsp[-4].minor.yy190.pExpr ){
+ yymsp[-4].minor.yy190.pExpr->x.pList = yymsp[-1].minor.yy72 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[-1].minor.yy72) : yymsp[-2].minor.yy148;
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy190.pExpr);
}else{
- sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322);
- sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy314);
+ sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy148);
+ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy72);
}
- yygotominor.yy118.zStart = yymsp[-4].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 230: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ case 197: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy118.pExpr);
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yygotominor.yy322, yymsp[0].minor.yy118.pExpr);
+ yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[-2].minor.yy190.pExpr);
+ yymsp[-4].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy148, yymsp[0].minor.yy190.pExpr);
}
break;
- case 231: /* case_exprlist ::= WHEN expr THEN expr */
+ case 198: /* case_exprlist ::= WHEN expr THEN expr */
{
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy118.pExpr);
- yygotominor.yy322 = sqlite3ExprListAppend(pParse,yygotominor.yy322, yymsp[0].minor.yy118.pExpr);
+ yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy190.pExpr);
+ yymsp[-3].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy148, yymsp[0].minor.yy190.pExpr);
}
break;
- case 238: /* nexprlist ::= nexprlist COMMA expr */
-{yygotominor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy118.pExpr);}
+ case 201: /* case_operand ::= expr */
+{yymsp[0].minor.yy72 = yymsp[0].minor.yy190.pExpr; /*A-overwrites-X*/}
break;
- case 239: /* nexprlist ::= expr */
-{yygotominor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy118.pExpr);}
+ case 204: /* nexprlist ::= nexprlist COMMA expr */
+{yymsp[-2].minor.yy148 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy148,yymsp[0].minor.yy190.pExpr);}
break;
- case 240: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ case 205: /* nexprlist ::= expr */
+{yymsp[0].minor.yy148 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy190.pExpr); /*A-overwrites-Y*/}
+ break;
+ case 207: /* paren_exprlist ::= LP exprlist RP */
+ case 212: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==212);
+{yymsp[-2].minor.yy148 = yymsp[-1].minor.yy148;}
+ break;
+ case 208: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
{
sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
- sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy4,
- &yymsp[-11].minor.yy0, yymsp[0].minor.yy314, SQLITE_SO_ASC, yymsp[-8].minor.yy4);
+ sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy148, yymsp[-10].minor.yy194,
+ &yymsp[-11].minor.yy0, yymsp[0].minor.yy72, SQLITE_SO_ASC, yymsp[-8].minor.yy194, SQLITE_IDXTYPE_APPDEF);
}
break;
- case 241: /* uniqueflag ::= UNIQUE */
- case 292: /* raisetype ::= ABORT */ yytestcase(yyruleno==292);
-{yygotominor.yy4 = OE_Abort;}
+ case 209: /* uniqueflag ::= UNIQUE */
+ case 250: /* raisetype ::= ABORT */ yytestcase(yyruleno==250);
+{yymsp[0].minor.yy194 = OE_Abort;}
break;
- case 242: /* uniqueflag ::= */
-{yygotominor.yy4 = OE_None;}
+ case 210: /* uniqueflag ::= */
+{yymsp[1].minor.yy194 = OE_None;}
break;
- case 245: /* eidlist ::= eidlist COMMA nm collate sortorder */
+ case 213: /* eidlist ::= eidlist COMMA nm collate sortorder */
{
- yygotominor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4);
+ yymsp[-4].minor.yy148 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy148, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194);
}
break;
- case 246: /* eidlist ::= nm collate sortorder */
+ case 214: /* eidlist ::= nm collate sortorder */
{
- yygotominor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy4, yymsp[0].minor.yy4);
+ yymsp[-2].minor.yy148 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy194, yymsp[0].minor.yy194); /*A-overwrites-Y*/
}
break;
- case 249: /* cmd ::= DROP INDEX ifexists fullname */
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy259, yymsp[-1].minor.yy4);}
+ case 217: /* cmd ::= DROP INDEX ifexists fullname */
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy185, yymsp[-1].minor.yy194);}
break;
- case 250: /* cmd ::= VACUUM */
- case 251: /* cmd ::= VACUUM nm */ yytestcase(yyruleno==251);
-{sqlite3Vacuum(pParse);}
+ case 218: /* cmd ::= VACUUM */
+{sqlite3Vacuum(pParse,0);}
break;
- case 252: /* cmd ::= PRAGMA nm dbnm */
+ case 219: /* cmd ::= VACUUM nm */
+{sqlite3Vacuum(pParse,&yymsp[0].minor.yy0);}
+ break;
+ case 220: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
- case 253: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+ case 221: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
- case 254: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ case 222: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
- case 255: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+ case 223: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
- case 256: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ case 224: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
break;
- case 265: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ case 227: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
{
Token all;
all.z = yymsp[-3].minor.yy0.z;
all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
- sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy203, &all);
+ sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy145, &all);
}
break;
- case 266: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ case 228: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
- sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy4, yymsp[-4].minor.yy90.a, yymsp[-4].minor.yy90.b, yymsp[-2].minor.yy259, yymsp[0].minor.yy314, yymsp[-10].minor.yy4, yymsp[-8].minor.yy4);
- yygotominor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0);
+ sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy194, yymsp[-4].minor.yy332.a, yymsp[-4].minor.yy332.b, yymsp[-2].minor.yy185, yymsp[0].minor.yy72, yymsp[-10].minor.yy194, yymsp[-8].minor.yy194);
+ yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
}
break;
- case 267: /* trigger_time ::= BEFORE */
- case 270: /* trigger_time ::= */ yytestcase(yyruleno==270);
-{ yygotominor.yy4 = TK_BEFORE; }
+ case 229: /* trigger_time ::= BEFORE */
+{ yymsp[0].minor.yy194 = TK_BEFORE; }
+ break;
+ case 230: /* trigger_time ::= AFTER */
+{ yymsp[0].minor.yy194 = TK_AFTER; }
break;
- case 268: /* trigger_time ::= AFTER */
-{ yygotominor.yy4 = TK_AFTER; }
+ case 231: /* trigger_time ::= INSTEAD OF */
+{ yymsp[-1].minor.yy194 = TK_INSTEAD;}
break;
- case 269: /* trigger_time ::= INSTEAD OF */
-{ yygotominor.yy4 = TK_INSTEAD;}
+ case 232: /* trigger_time ::= */
+{ yymsp[1].minor.yy194 = TK_BEFORE; }
break;
- case 271: /* trigger_event ::= DELETE|INSERT */
- case 272: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==272);
-{yygotominor.yy90.a = yymsp[0].major; yygotominor.yy90.b = 0;}
+ case 233: /* trigger_event ::= DELETE|INSERT */
+ case 234: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==234);
+{yymsp[0].minor.yy332.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy332.b = 0;}
break;
- case 273: /* trigger_event ::= UPDATE OF idlist */
-{yygotominor.yy90.a = TK_UPDATE; yygotominor.yy90.b = yymsp[0].minor.yy384;}
+ case 235: /* trigger_event ::= UPDATE OF idlist */
+{yymsp[-2].minor.yy332.a = TK_UPDATE; yymsp[-2].minor.yy332.b = yymsp[0].minor.yy254;}
break;
- case 276: /* when_clause ::= */
- case 297: /* key_opt ::= */ yytestcase(yyruleno==297);
-{ yygotominor.yy314 = 0; }
+ case 236: /* when_clause ::= */
+ case 255: /* key_opt ::= */ yytestcase(yyruleno==255);
+{ yymsp[1].minor.yy72 = 0; }
break;
- case 277: /* when_clause ::= WHEN expr */
- case 298: /* key_opt ::= KEY expr */ yytestcase(yyruleno==298);
-{ yygotominor.yy314 = yymsp[0].minor.yy118.pExpr; }
+ case 237: /* when_clause ::= WHEN expr */
+ case 256: /* key_opt ::= KEY expr */ yytestcase(yyruleno==256);
+{ yymsp[-1].minor.yy72 = yymsp[0].minor.yy190.pExpr; }
break;
- case 278: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ case 238: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
- assert( yymsp[-2].minor.yy203!=0 );
- yymsp[-2].minor.yy203->pLast->pNext = yymsp[-1].minor.yy203;
- yymsp[-2].minor.yy203->pLast = yymsp[-1].minor.yy203;
- yygotominor.yy203 = yymsp[-2].minor.yy203;
+ assert( yymsp[-2].minor.yy145!=0 );
+ yymsp[-2].minor.yy145->pLast->pNext = yymsp[-1].minor.yy145;
+ yymsp[-2].minor.yy145->pLast = yymsp[-1].minor.yy145;
}
break;
- case 279: /* trigger_cmd_list ::= trigger_cmd SEMI */
+ case 239: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
- assert( yymsp[-1].minor.yy203!=0 );
- yymsp[-1].minor.yy203->pLast = yymsp[-1].minor.yy203;
- yygotominor.yy203 = yymsp[-1].minor.yy203;
+ assert( yymsp[-1].minor.yy145!=0 );
+ yymsp[-1].minor.yy145->pLast = yymsp[-1].minor.yy145;
}
break;
- case 281: /* trnm ::= nm DOT nm */
+ case 240: /* trnm ::= nm DOT nm */
{
- yygotominor.yy0 = yymsp[0].minor.yy0;
+ yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
sqlite3ErrorMsg(pParse,
"qualified table names are not allowed on INSERT, UPDATE, and DELETE "
"statements within triggers");
}
break;
- case 283: /* tridxby ::= INDEXED BY nm */
+ case 241: /* tridxby ::= INDEXED BY nm */
{
sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 284: /* tridxby ::= NOT INDEXED */
+ case 242: /* tridxby ::= NOT INDEXED */
{
sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 285: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
-{ yygotominor.yy203 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy322, yymsp[0].minor.yy314, yymsp[-5].minor.yy4); }
+ case 243: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
+{yymsp[-6].minor.yy145 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy148, yymsp[0].minor.yy72, yymsp[-5].minor.yy194);}
break;
- case 286: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */
-{yygotominor.yy203 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy384, yymsp[0].minor.yy387, yymsp[-4].minor.yy4);}
+ case 244: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */
+{yymsp[-4].minor.yy145 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy254, yymsp[0].minor.yy243, yymsp[-4].minor.yy194);/*A-overwrites-R*/}
break;
- case 287: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
-{yygotominor.yy203 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy314);}
+ case 245: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
+{yymsp[-4].minor.yy145 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy72);}
break;
- case 288: /* trigger_cmd ::= select */
-{yygotominor.yy203 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy387); }
+ case 246: /* trigger_cmd ::= select */
+{yymsp[0].minor.yy145 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy243); /*A-overwrites-X*/}
break;
- case 289: /* expr ::= RAISE LP IGNORE RP */
+ case 247: /* expr ::= RAISE LP IGNORE RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
- if( yygotominor.yy118.pExpr ){
- yygotominor.yy118.pExpr->affinity = OE_Ignore;
+ spanSet(&yymsp[-3].minor.yy190,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
+ yymsp[-3].minor.yy190.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
+ if( yymsp[-3].minor.yy190.pExpr ){
+ yymsp[-3].minor.yy190.pExpr->affinity = OE_Ignore;
}
- yygotominor.yy118.zStart = yymsp[-3].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 290: /* expr ::= RAISE LP raisetype COMMA nm RP */
+ case 248: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
- yygotominor.yy118.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &yymsp[-1].minor.yy0);
- if( yygotominor.yy118.pExpr ) {
- yygotominor.yy118.pExpr->affinity = (char)yymsp[-3].minor.yy4;
+ spanSet(&yymsp[-5].minor.yy190,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
+ yymsp[-5].minor.yy190.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
+ if( yymsp[-5].minor.yy190.pExpr ) {
+ yymsp[-5].minor.yy190.pExpr->affinity = (char)yymsp[-3].minor.yy194;
}
- yygotominor.yy118.zStart = yymsp[-5].minor.yy0.z;
- yygotominor.yy118.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
}
break;
- case 291: /* raisetype ::= ROLLBACK */
-{yygotominor.yy4 = OE_Rollback;}
+ case 249: /* raisetype ::= ROLLBACK */
+{yymsp[0].minor.yy194 = OE_Rollback;}
break;
- case 293: /* raisetype ::= FAIL */
-{yygotominor.yy4 = OE_Fail;}
+ case 251: /* raisetype ::= FAIL */
+{yymsp[0].minor.yy194 = OE_Fail;}
break;
- case 294: /* cmd ::= DROP TRIGGER ifexists fullname */
+ case 252: /* cmd ::= DROP TRIGGER ifexists fullname */
{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy259,yymsp[-1].minor.yy4);
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy185,yymsp[-1].minor.yy194);
}
break;
- case 295: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ case 253: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
- sqlite3Attach(pParse, yymsp[-3].minor.yy118.pExpr, yymsp[-1].minor.yy118.pExpr, yymsp[0].minor.yy314);
+ sqlite3Attach(pParse, yymsp[-3].minor.yy190.pExpr, yymsp[-1].minor.yy190.pExpr, yymsp[0].minor.yy72);
}
break;
- case 296: /* cmd ::= DETACH database_kw_opt expr */
+ case 254: /* cmd ::= DETACH database_kw_opt expr */
{
- sqlite3Detach(pParse, yymsp[0].minor.yy118.pExpr);
+ sqlite3Detach(pParse, yymsp[0].minor.yy190.pExpr);
}
break;
- case 301: /* cmd ::= REINDEX */
+ case 257: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
break;
- case 302: /* cmd ::= REINDEX nm dbnm */
+ case 258: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 303: /* cmd ::= ANALYZE */
+ case 259: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
break;
- case 304: /* cmd ::= ANALYZE nm dbnm */
+ case 260: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 305: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+ case 261: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
- sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy259,&yymsp[0].minor.yy0);
+ sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy185,&yymsp[0].minor.yy0);
}
break;
- case 306: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column */
+ case 262: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
{
- sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy0);
+ yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
+ sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
}
break;
- case 307: /* add_column_fullname ::= fullname */
+ case 263: /* add_column_fullname ::= fullname */
{
disableLookaside(pParse);
- sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy259);
+ sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy185);
}
break;
- case 310: /* cmd ::= create_vtab */
+ case 264: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
break;
- case 311: /* cmd ::= create_vtab LP vtabarglist RP */
+ case 265: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
- case 312: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ case 266: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
- sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy4);
+ sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy194);
}
break;
- case 315: /* vtabarg ::= */
+ case 267: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
break;
- case 317: /* vtabargtoken ::= ANY */
- case 318: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==318);
- case 319: /* lp ::= LP */ yytestcase(yyruleno==319);
+ case 268: /* vtabargtoken ::= ANY */
+ case 269: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==269);
+ case 270: /* lp ::= LP */ yytestcase(yyruleno==270);
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
break;
- case 323: /* with ::= */
-{yygotominor.yy451 = 0;}
+ case 271: /* with ::= */
+{yymsp[1].minor.yy285 = 0;}
break;
- case 324: /* with ::= WITH wqlist */
- case 325: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==325);
-{ yygotominor.yy451 = yymsp[0].minor.yy451; }
+ case 272: /* with ::= WITH wqlist */
+{ yymsp[-1].minor.yy285 = yymsp[0].minor.yy285; }
break;
- case 326: /* wqlist ::= nm eidlist_opt AS LP select RP */
+ case 273: /* with ::= WITH RECURSIVE wqlist */
+{ yymsp[-2].minor.yy285 = yymsp[0].minor.yy285; }
+ break;
+ case 274: /* wqlist ::= nm eidlist_opt AS LP select RP */
{
- yygotominor.yy451 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387);
+ yymsp[-5].minor.yy285 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243); /*A-overwrites-X*/
}
break;
- case 327: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
+ case 275: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
{
- yygotominor.yy451 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy451, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy387);
+ yymsp[-7].minor.yy285 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy285, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy148, yymsp[-1].minor.yy243);
}
break;
default:
- /* (0) input ::= cmdlist */ yytestcase(yyruleno==0);
- /* (1) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==1);
- /* (2) cmdlist ::= ecmd */ yytestcase(yyruleno==2);
- /* (3) ecmd ::= SEMI */ yytestcase(yyruleno==3);
- /* (4) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==4);
- /* (5) explain ::= */ yytestcase(yyruleno==5);
- /* (10) trans_opt ::= */ yytestcase(yyruleno==10);
- /* (11) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==11);
- /* (12) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==12);
- /* (20) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==20);
- /* (21) savepoint_opt ::= */ yytestcase(yyruleno==21);
- /* (25) cmd ::= create_table create_table_args */ yytestcase(yyruleno==25);
- /* (36) columnlist ::= columnlist COMMA column */ yytestcase(yyruleno==36);
- /* (37) columnlist ::= column */ yytestcase(yyruleno==37);
- /* (43) type ::= */ yytestcase(yyruleno==43);
- /* (50) signed ::= plus_num */ yytestcase(yyruleno==50);
- /* (51) signed ::= minus_num */ yytestcase(yyruleno==51);
- /* (52) carglist ::= carglist ccons */ yytestcase(yyruleno==52);
- /* (53) carglist ::= */ yytestcase(yyruleno==53);
- /* (60) ccons ::= NULL onconf */ yytestcase(yyruleno==60);
- /* (88) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==88);
- /* (89) conslist ::= tcons */ yytestcase(yyruleno==89);
- /* (91) tconscomma ::= */ yytestcase(yyruleno==91);
- /* (274) foreach_clause ::= */ yytestcase(yyruleno==274);
- /* (275) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==275);
- /* (282) tridxby ::= */ yytestcase(yyruleno==282);
- /* (299) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==299);
- /* (300) database_kw_opt ::= */ yytestcase(yyruleno==300);
- /* (308) kwcolumn_opt ::= */ yytestcase(yyruleno==308);
- /* (309) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==309);
- /* (313) vtabarglist ::= vtabarg */ yytestcase(yyruleno==313);
- /* (314) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==314);
- /* (316) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==316);
- /* (320) anylist ::= */ yytestcase(yyruleno==320);
- /* (321) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==321);
- /* (322) anylist ::= anylist ANY */ yytestcase(yyruleno==322);
+ /* (276) input ::= cmdlist */ yytestcase(yyruleno==276);
+ /* (277) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==277);
+ /* (278) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=278);
+ /* (279) ecmd ::= SEMI */ yytestcase(yyruleno==279);
+ /* (280) ecmd ::= explain cmdx SEMI */ yytestcase(yyruleno==280);
+ /* (281) explain ::= */ yytestcase(yyruleno==281);
+ /* (282) trans_opt ::= */ yytestcase(yyruleno==282);
+ /* (283) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==283);
+ /* (284) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==284);
+ /* (285) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==285);
+ /* (286) savepoint_opt ::= */ yytestcase(yyruleno==286);
+ /* (287) cmd ::= create_table create_table_args */ yytestcase(yyruleno==287);
+ /* (288) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==288);
+ /* (289) columnlist ::= columnname carglist */ yytestcase(yyruleno==289);
+ /* (290) nm ::= ID|INDEXED */ yytestcase(yyruleno==290);
+ /* (291) nm ::= STRING */ yytestcase(yyruleno==291);
+ /* (292) nm ::= JOIN_KW */ yytestcase(yyruleno==292);
+ /* (293) typetoken ::= typename */ yytestcase(yyruleno==293);
+ /* (294) typename ::= ID|STRING */ yytestcase(yyruleno==294);
+ /* (295) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=295);
+ /* (296) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=296);
+ /* (297) carglist ::= carglist ccons */ yytestcase(yyruleno==297);
+ /* (298) carglist ::= */ yytestcase(yyruleno==298);
+ /* (299) ccons ::= NULL onconf */ yytestcase(yyruleno==299);
+ /* (300) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==300);
+ /* (301) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==301);
+ /* (302) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=302);
+ /* (303) tconscomma ::= */ yytestcase(yyruleno==303);
+ /* (304) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=304);
+ /* (305) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=305);
+ /* (306) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=306);
+ /* (307) oneselect ::= values */ yytestcase(yyruleno==307);
+ /* (308) sclp ::= selcollist COMMA */ yytestcase(yyruleno==308);
+ /* (309) as ::= ID|STRING */ yytestcase(yyruleno==309);
+ /* (310) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=310);
+ /* (311) exprlist ::= nexprlist */ yytestcase(yyruleno==311);
+ /* (312) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=312);
+ /* (313) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=313);
+ /* (314) nmnum ::= ON */ yytestcase(yyruleno==314);
+ /* (315) nmnum ::= DELETE */ yytestcase(yyruleno==315);
+ /* (316) nmnum ::= DEFAULT */ yytestcase(yyruleno==316);
+ /* (317) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==317);
+ /* (318) foreach_clause ::= */ yytestcase(yyruleno==318);
+ /* (319) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==319);
+ /* (320) trnm ::= nm */ yytestcase(yyruleno==320);
+ /* (321) tridxby ::= */ yytestcase(yyruleno==321);
+ /* (322) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==322);
+ /* (323) database_kw_opt ::= */ yytestcase(yyruleno==323);
+ /* (324) kwcolumn_opt ::= */ yytestcase(yyruleno==324);
+ /* (325) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==325);
+ /* (326) vtabarglist ::= vtabarg */ yytestcase(yyruleno==326);
+ /* (327) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==327);
+ /* (328) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==328);
+ /* (329) anylist ::= */ yytestcase(yyruleno==329);
+ /* (330) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==330);
+ /* (331) anylist ::= anylist ANY */ yytestcase(yyruleno==331);
break;
/********** End reduce actions ************************************************/
};
- assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
+ assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
yygoto = yyRuleInfo[yyruleno].lhs;
yysize = yyRuleInfo[yyruleno].nrhs;
- yypParser->yyidx -= yysize;
yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
if( yyact <= YY_MAX_SHIFTREDUCE ){
- if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
- /* If the reduce action popped at least
- ** one element off the stack, then we can push the new element back
- ** onto the stack here, and skip the stack overflow test in yy_shift().
- ** That gives a significant speed improvement. */
- if( yysize ){
- yypParser->yyidx++;
- yymsp -= yysize-1;
- yymsp->stateno = (YYACTIONTYPE)yyact;
- yymsp->major = (YYCODETYPE)yygoto;
- yymsp->minor = yygotominor;
- yyTraceShift(yypParser, yyact);
- }else{
- yy_shift(yypParser,yyact,yygoto,&yygotominor);
+ if( yyact>YY_MAX_SHIFT ){
+ yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
}
+ yymsp -= yysize-1;
+ yypParser->yytos = yymsp;
+ yymsp->stateno = (YYACTIONTYPE)yyact;
+ yymsp->major = (YYCODETYPE)yygoto;
+ yyTraceShift(yypParser, yyact);
}else{
assert( yyact == YY_ACCEPT_ACTION );
+ yypParser->yytos -= yysize;
yy_accept(yypParser);
}
}
@@ -131271,7 +137436,7 @@ static void yy_parse_failed(
fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
}
#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will be executed whenever the
** parser fails */
/************ Begin %parse_failure code ***************************************/
@@ -131286,10 +137451,10 @@ static void yy_parse_failed(
static void yy_syntax_error(
yyParser *yypParser, /* The parser */
int yymajor, /* The major type of the error token */
- YYMINORTYPE yyminor /* The minor type of the error token */
+ sqlite3ParserTOKENTYPE yyminor /* The minor type of the error token */
){
sqlite3ParserARG_FETCH;
-#define TOKEN (yyminor.yy0)
+#define TOKEN yyminor
/************ Begin %syntax_error code ****************************************/
UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */
@@ -131311,7 +137476,10 @@ static void yy_accept(
fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
}
#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
+ assert( yypParser->yytos==yypParser->yystack );
/* Here code is inserted which will be executed whenever the
** parser accepts */
/*********** Begin %parse_accept code *****************************************/
@@ -131345,7 +137513,7 @@ SQLITE_PRIVATE void sqlite3Parser(
sqlite3ParserARG_PDECL /* Optional %extra_argument parameter */
){
YYMINORTYPE yyminorunion;
- int yyact; /* The parser action. */
+ unsigned int yyact; /* The parser action. */
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
int yyendofinput; /* True if we are at the end of input */
#endif
@@ -131354,29 +137522,8 @@ SQLITE_PRIVATE void sqlite3Parser(
#endif
yyParser *yypParser; /* The parser */
- /* (re)initialize the parser, if necessary */
yypParser = (yyParser*)yyp;
- if( yypParser->yyidx<0 ){
-#if YYSTACKDEPTH<=0
- if( yypParser->yystksz <=0 ){
- /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/
- yyminorunion = yyzerominor;
- yyStackOverflow(yypParser, &yyminorunion);
- return;
- }
-#endif
- yypParser->yyidx = 0;
- yypParser->yyerrcnt = -1;
- yypParser->yystack[0].stateno = 0;
- yypParser->yystack[0].major = 0;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sInitialize. Empty stack. State 0\n",
- yyTracePrompt);
- }
-#endif
- }
- yyminorunion.yy0 = yyminor;
+ assert( yypParser->yytos!=0 );
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
yyendofinput = (yymajor==0);
#endif
@@ -131391,14 +137538,16 @@ SQLITE_PRIVATE void sqlite3Parser(
do{
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
if( yyact <= YY_MAX_SHIFTREDUCE ){
- if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
- yy_shift(yypParser,yyact,yymajor,&yyminorunion);
+ yy_shift(yypParser,yyact,yymajor,yyminor);
+#ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt--;
+#endif
yymajor = YYNOCODE;
}else if( yyact <= YY_MAX_REDUCE ){
yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
}else{
assert( yyact == YY_ERROR_ACTION );
+ yyminorunion.yy0 = yyminor;
#ifdef YYERRORSYMBOL
int yymx;
#endif
@@ -131428,9 +137577,9 @@ SQLITE_PRIVATE void sqlite3Parser(
**
*/
if( yypParser->yyerrcnt<0 ){
- yy_syntax_error(yypParser,yymajor,yyminorunion);
+ yy_syntax_error(yypParser,yymajor,yyminor);
}
- yymx = yypParser->yystack[yypParser->yyidx].major;
+ yymx = yypParser->yytos->major;
if( yymx==YYERRORSYMBOL || yyerrorhit ){
#ifndef NDEBUG
if( yyTraceFILE ){
@@ -131438,26 +137587,26 @@ SQLITE_PRIVATE void sqlite3Parser(
yyTracePrompt,yyTokenName[yymajor]);
}
#endif
- yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion);
+ yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
yymajor = YYNOCODE;
}else{
- while(
- yypParser->yyidx >= 0 &&
- yymx != YYERRORSYMBOL &&
- (yyact = yy_find_reduce_action(
- yypParser->yystack[yypParser->yyidx].stateno,
+ while( yypParser->yytos >= yypParser->yystack
+ && yymx != YYERRORSYMBOL
+ && (yyact = yy_find_reduce_action(
+ yypParser->yytos->stateno,
YYERRORSYMBOL)) >= YY_MIN_REDUCE
){
yy_pop_parser_stack(yypParser);
}
- if( yypParser->yyidx < 0 || yymajor==0 ){
+ if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
yymajor = YYNOCODE;
}else if( yymx!=YYERRORSYMBOL ){
- YYMINORTYPE u2;
- u2.YYERRSYMDT = 0;
- yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
}
}
yypParser->yyerrcnt = 3;
@@ -131470,7 +137619,7 @@ SQLITE_PRIVATE void sqlite3Parser(
** Applications can set this macro (for example inside %include) if
** they intend to abandon the parse upon the first syntax error seen.
*/
- yy_syntax_error(yypParser,yymajor,yyminorunion);
+ yy_syntax_error(yypParser,yymajor, yyminor);
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
yymajor = YYNOCODE;
@@ -131485,24 +137634,29 @@ SQLITE_PRIVATE void sqlite3Parser(
** three input tokens have been successfully shifted.
*/
if( yypParser->yyerrcnt<=0 ){
- yy_syntax_error(yypParser,yymajor,yyminorunion);
+ yy_syntax_error(yypParser,yymajor, yyminor);
}
yypParser->yyerrcnt = 3;
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
if( yyendofinput ){
yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
}
yymajor = YYNOCODE;
#endif
}
- }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
+ }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack );
#ifndef NDEBUG
if( yyTraceFILE ){
- int i;
+ yyStackEntry *i;
+ char cDiv = '[';
fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
- for(i=1; i<=yypParser->yyidx; i++)
- fprintf(yyTraceFILE,"%c%s", i==1 ? '[' : ' ',
- yyTokenName[yypParser->yystack[i].major]);
+ for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
+ fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
+ cDiv = ' ';
+ }
fprintf(yyTraceFILE,"]\n");
}
#endif
@@ -131594,13 +137748,13 @@ static const unsigned char aiClass[] = {
/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 2x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
/* 3x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
-/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 12, 17, 20, 10,
+/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10,
/* 5x */ 24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 4, 21, 18, 19, 27,
-/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 7,
+/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 6,
/* 7x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 8, 5, 5, 5, 8, 14, 8,
/* 8x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
/* 9x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
-/* 9x */ 25, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
+/* Ax */ 27, 25, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 27, 27, 27, 27, 27,
/* Cx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
/* Dx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
@@ -132087,7 +138241,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
case CC_BANG: {
if( z[1]!='=' ){
*tokenType = TK_ILLEGAL;
- return 2;
+ return 1;
}else{
*tokenType = TK_NE;
return 2;
@@ -132237,8 +138391,8 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
*tokenType = TK_ID;
return keywordCode((char*)z, i, tokenType);
}
-#ifndef SQLITE_OMIT_BLOB_LITERAL
case CC_X: {
+#ifndef SQLITE_OMIT_BLOB_LITERAL
testcase( z[0]=='x' ); testcase( z[0]=='X' );
if( z[1]=='\'' ){
*tokenType = TK_BLOB;
@@ -132250,10 +138404,10 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
if( z[i] ) i++;
return i;
}
+#endif
/* If it is not a BLOB literal, then it must be an ID, since no
** SQL keywords start with the letter 'x'. Fall through */
}
-#endif
case CC_ID: {
i = 1;
break;
@@ -132297,21 +138451,32 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
pEngine = sqlite3ParserAlloc(sqlite3Malloc);
if( pEngine==0 ){
sqlite3OomFault(db);
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
assert( pParse->pNewTable==0 );
assert( pParse->pNewTrigger==0 );
assert( pParse->nVar==0 );
- assert( pParse->nzVar==0 );
- assert( pParse->azVar==0 );
- while( zSql[i]!=0 ){
+ assert( pParse->pVList==0 );
+ while( 1 ){
assert( i>=0 );
- pParse->sLastToken.z = &zSql[i];
- pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType);
- i += pParse->sLastToken.n;
- if( i>mxSqlLen ){
- pParse->rc = SQLITE_TOOBIG;
- break;
+ if( zSql[i]!=0 ){
+ pParse->sLastToken.z = &zSql[i];
+ pParse->sLastToken.n = sqlite3GetToken((u8*)&zSql[i],&tokenType);
+ i += pParse->sLastToken.n;
+ if( i>mxSqlLen ){
+ pParse->rc = SQLITE_TOOBIG;
+ break;
+ }
+ }else{
+ /* Upon reaching the end of input, call the parser two more times
+ ** with tokens TK_SEMI and 0, in that order. */
+ if( lastTokenParsed==TK_SEMI ){
+ tokenType = 0;
+ }else if( lastTokenParsed==0 ){
+ break;
+ }else{
+ tokenType = TK_SEMI;
+ }
}
if( tokenType>=TK_SPACE ){
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
@@ -132325,23 +138490,13 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
break;
}
}else{
- if( tokenType==TK_SEMI ) pParse->zTail = &zSql[i];
sqlite3Parser(pEngine, tokenType, pParse->sLastToken, pParse);
lastTokenParsed = tokenType;
if( pParse->rc!=SQLITE_OK || db->mallocFailed ) break;
}
}
assert( nErr==0 );
- if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
- assert( zSql[i]==0 );
- if( lastTokenParsed!=TK_SEMI ){
- sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse);
- pParse->zTail = &zSql[i];
- }
- if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){
- sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse);
- }
- }
+ pParse->zTail = &zSql[i];
#ifdef YYTRACKMAXSTACKDEPTH
sqlite3_mutex_enter(sqlite3MallocMutex());
sqlite3StatusHighwater(SQLITE_STATUS_PARSER_STACK,
@@ -132351,7 +138506,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
#endif /* YYDEBUG */
sqlite3ParserFree(pEngine, sqlite3_free);
if( db->mallocFailed ){
- pParse->rc = SQLITE_NOMEM;
+ pParse->rc = SQLITE_NOMEM_BKPT;
}
if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
@@ -132386,10 +138541,9 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
sqlite3DeleteTable(db, pParse->pNewTable);
}
- sqlite3WithDelete(db, pParse->pWithToFree);
+ if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
- for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
- sqlite3DbFree(db, pParse->azVar);
+ sqlite3DbFree(db, pParse->pVList);
while( pParse->pAinc ){
AutoincInfo *p = pParse->pAinc;
pParse->pAinc = p->pNext;
@@ -132509,7 +138663,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];
** to recognize the end of a trigger can be omitted. All we have to do
** is look for a semicolon that is not part of an string or comment.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){
+SQLITE_API int sqlite3_complete(const char *zSql){
u8 state = 0; /* Current state, using numbers defined in header comment */
u8 token; /* Value of the next token */
@@ -132674,7 +138828,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *zSql){
** above, except that the parameter is required to be UTF-16 encoded, not
** UTF-8.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
+SQLITE_API int sqlite3_complete16(const void *zSql){
sqlite3_value *pVal;
char const *zSql8;
int rc;
@@ -132689,7 +138843,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *zSql){
if( zSql8 ){
rc = sqlite3_complete(zSql8);
}else{
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
sqlite3ValueFree(pVal);
return rc & 0xff;
@@ -132834,24 +138988,24 @@ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
** a pointer to the to the sqlite3_version[] string constant.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void){ return sqlite3_version; }
+SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
/* IMPLEMENTATION-OF: R-63124-39300 The sqlite3_sourceid() function returns a
** pointer to a string constant whose value is the same as the
** SQLITE_SOURCE_ID C preprocessor macro.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
+SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
/* IMPLEMENTATION-OF: R-35210-63508 The sqlite3_libversion_number() function
** returns an integer equal to SQLITE_VERSION_NUMBER.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
+SQLITE_API int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
/* IMPLEMENTATION-OF: R-20790-14025 The sqlite3_threadsafe() function returns
** zero if and only if SQLite was compiled with mutexing code omitted due to
** the SQLITE_THREADSAFE compile-time option being set to 0.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
+SQLITE_API int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; }
/*
** When compiling the test fixture or with debugging enabled (on Win32),
@@ -132924,7 +139078,7 @@ SQLITE_API char *sqlite3_data_directory = 0;
** * Recursive calls to this routine from thread X return immediately
** without blocking.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
+SQLITE_API int sqlite3_initialize(void){
MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
int rc; /* Result code */
#ifdef SQLITE_EXTRA_INIT
@@ -132979,7 +139133,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
sqlite3GlobalConfig.pInitMutex =
sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
if( sqlite3GlobalConfig.bCoreMutex && !sqlite3GlobalConfig.pInitMutex ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
}
}
@@ -133010,7 +139164,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
*/
sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex);
if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){
- FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
sqlite3GlobalConfig.inProgress = 1;
#ifdef SQLITE_ENABLE_SQLLOG
{
@@ -133018,8 +139171,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
sqlite3_init_sqllog();
}
#endif
- memset(pHash, 0, sizeof(sqlite3GlobalFunctions));
- sqlite3RegisterGlobalFunctions();
+ memset(&sqlite3BuiltinFunctions, 0, sizeof(sqlite3BuiltinFunctions));
+ sqlite3RegisterBuiltinFunctions();
if( sqlite3GlobalConfig.isPCacheInit==0 ){
rc = sqlite3PcacheInitialize();
}
@@ -133091,7 +139244,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void){
** on when SQLite is already shut down. If SQLite is already shut down
** when this routine is invoked, then this routine is a harmless no-op.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){
+SQLITE_API int sqlite3_shutdown(void){
#ifdef SQLITE_OMIT_WSD
int rc = sqlite3_wsd_init(4096, 24);
if( rc!=SQLITE_OK ){
@@ -133145,7 +139298,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void){
** threadsafe. Failure to heed these warnings can lead to unpredictable
** behavior.
*/
-SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
+SQLITE_API int sqlite3_config(int op, ...){
va_list ap;
int rc = SQLITE_OK;
@@ -133426,6 +139579,11 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int op, ...){
break;
}
+ case SQLITE_CONFIG_STMTJRNL_SPILL: {
+ sqlite3GlobalConfig.nStmtSpill = va_arg(ap, int);
+ break;
+ }
+
default: {
rc = SQLITE_ERROR;
break;
@@ -133505,7 +139663,7 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
/*
** Return the mutex associated with a database connection.
*/
-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){
+SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
@@ -133519,7 +139677,7 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3 *db){
** Free up as much memory as we can from the given database
** connection.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){
+SQLITE_API int sqlite3_db_release_memory(sqlite3 *db){
int i;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -133543,7 +139701,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3 *db){
** Flush any dirty pages in the pager-cache for any attached database
** to disk.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3 *db){
+SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){
int i;
int rc = SQLITE_OK;
int bSeenBusy = 0;
@@ -133572,11 +139730,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3 *db){
/*
** Configuration settings for an individual database connection
*/
-SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
+SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
va_start(ap, op);
switch( op ){
+ case SQLITE_DBCONFIG_MAINDBNAME: {
+ db->aDb[0].zDbSName = va_arg(ap,char*);
+ rc = SQLITE_OK;
+ break;
+ }
case SQLITE_DBCONFIG_LOOKASIDE: {
void *pBuf = va_arg(ap, void*); /* IMP: R-26835-10964 */
int sz = va_arg(ap, int); /* IMP: R-47871-25994 */
@@ -133589,8 +139752,11 @@ SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3 *db, int op, ...){
int op; /* The opcode */
u32 mask; /* Mask of the bit in sqlite3.flags to set/clear */
} aFlagOp[] = {
- { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
- { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
+ { SQLITE_DBCONFIG_ENABLE_FKEY, SQLITE_ForeignKeys },
+ { SQLITE_DBCONFIG_ENABLE_TRIGGER, SQLITE_EnableTrigger },
+ { SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, SQLITE_Fts3Tokenizer },
+ { SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, SQLITE_LoadExtension },
+ { SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, SQLITE_NoCkptOnClose },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -133691,7 +139857,7 @@ static int nocaseCollatingFunc(
/*
** Return the ROWID of the most recent insert
*/
-SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){
+SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
@@ -133704,7 +139870,7 @@ SQLITE_API sqlite_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3 *db){
/*
** Return the number of changes in the most recent call to sqlite3_exec().
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){
+SQLITE_API int sqlite3_changes(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
@@ -133717,7 +139883,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3 *db){
/*
** Return the number of changes since the database handle was opened.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3 *db){
+SQLITE_API int sqlite3_total_changes(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
@@ -133750,7 +139916,7 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){
** with SQLITE_ANY as the encoding.
*/
static void functionDestroy(sqlite3 *db, FuncDef *p){
- FuncDestructor *pDestructor = p->pDestructor;
+ FuncDestructor *pDestructor = p->u.pDestructor;
if( pDestructor ){
pDestructor->nRef--;
if( pDestructor->nRef==0 ){
@@ -133819,6 +139985,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
+ if( db->mTrace & SQLITE_TRACE_CLOSE ){
+ db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
+ }
/* Force xDisconnect calls on all virtual tables */
disconnectAllVtab(db);
@@ -133865,8 +140034,8 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
** unclosed resources, and arranges for deallocation when the last
** prepare statement or sqlite3_backup closes.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
-SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
+SQLITE_API int sqlite3_close(sqlite3 *db){ return sqlite3Close(db,0); }
+SQLITE_API int sqlite3_close_v2(sqlite3 *db){ return sqlite3Close(db,1); }
/*
@@ -133932,18 +140101,17 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
*/
sqlite3ConnectionClosed(db);
- for(j=0; j<ArraySize(db->aFunc.a); j++){
- FuncDef *pNext, *pHash, *p;
- for(p=db->aFunc.a[j]; p; p=pHash){
- pHash = p->pHash;
- while( p ){
- functionDestroy(db, p);
- pNext = p->pNext;
- sqlite3DbFree(db, p);
- p = pNext;
- }
- }
+ for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
+ FuncDef *pNext, *p;
+ p = sqliteHashData(i);
+ do{
+ functionDestroy(db, p);
+ pNext = p->pNext;
+ sqlite3DbFree(db, p);
+ p = pNext;
+ }while( p );
}
+ sqlite3HashClear(&db->aFunc);
for(i=sqliteHashFirst(&db->aCollSeq); i; i=sqliteHashNext(i)){
CollSeq *pColl = (CollSeq *)sqliteHashData(i);
/* Invoke any destructors registered for collation sequence user data. */
@@ -134274,7 +140442,7 @@ SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
** This routine sets the busy callback for an Sqlite database to the
** given callback function with the given argument.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(
+SQLITE_API int sqlite3_busy_handler(
sqlite3 *db,
int (*xBusy)(void*,int),
void *pArg
@@ -134297,7 +140465,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(
** given callback function with the given argument. The progress callback will
** be invoked every nOps opcodes.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(
+SQLITE_API void sqlite3_progress_handler(
sqlite3 *db,
int nOps,
int (*xProgress)(void*),
@@ -134328,7 +140496,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(
** This routine installs a default busy handler that waits for the
** specified number of milliseconds before returning 0.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){
+SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
@@ -134344,9 +140512,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3 *db, int ms){
/*
** Cause any pending operation to stop at its earliest opportunity.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3 *db){
+SQLITE_API void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) ){
+ if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){
(void)SQLITE_MISUSE_BKPT;
return;
}
@@ -134422,7 +140590,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
** is being overridden/deleted but there are no active VMs, allow the
** operation to continue but invalidate all precompiled statements.
*/
- p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
+ p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( db->nVdbeActive ){
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
@@ -134434,10 +140602,10 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
}
}
- p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 1);
+ p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1);
assert(p || db->mallocFailed);
if( !p ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
/* If an older version of the function with a configured destructor is
@@ -134447,7 +140615,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
if( pDestructor ){
pDestructor->nRef++;
}
- p->pDestructor = pDestructor;
+ p->u.pDestructor = pDestructor;
p->funcFlags = (p->funcFlags & SQLITE_FUNC_ENCMASK) | extraFlags;
testcase( p->funcFlags & SQLITE_DETERMINISTIC );
p->xSFunc = xSFunc ? xSFunc : xStep;
@@ -134460,7 +140628,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
/*
** Create new user functions.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
+SQLITE_API int sqlite3_create_function(
sqlite3 *db,
const char *zFunc,
int nArg,
@@ -134474,7 +140642,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
xFinal, 0);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
+SQLITE_API int sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunc,
int nArg,
@@ -134517,7 +140685,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
}
#ifndef SQLITE_OMIT_UTF16
-SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
+SQLITE_API int sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
@@ -134557,12 +140725,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
** A global function must exist in order for name resolution to work
** properly.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
+SQLITE_API int sqlite3_overload_function(
sqlite3 *db,
const char *zName,
int nArg
){
- int nName = sqlite3Strlen30(zName);
int rc = SQLITE_OK;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -134571,7 +140738,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
}
#endif
sqlite3_mutex_enter(db->mutex);
- if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
+ if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
0, sqlite3InvalidFunction, 0, 0, 0);
}
@@ -134589,7 +140756,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(
** trace is a pointer to a function that is invoked at the start of each
** SQL statement.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
+#ifndef SQLITE_OMIT_DEPRECATED
+SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
void *pOld;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -134600,11 +140768,38 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,
#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
- db->xTrace = xTrace;
+ db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
+ db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return pOld;
}
+#endif /* SQLITE_OMIT_DEPRECATED */
+
+/* Register a trace callback using the version-2 interface.
+*/
+SQLITE_API int sqlite3_trace_v2(
+ sqlite3 *db, /* Trace this connection */
+ unsigned mTrace, /* Mask of events to be traced */
+ int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */
+ void *pArg /* Context */
+){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ sqlite3_mutex_enter(db->mutex);
+ if( mTrace==0 ) xTrace = 0;
+ if( xTrace==0 ) mTrace = 0;
+ db->mTrace = mTrace;
+ db->xTrace = xTrace;
+ db->pTraceArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+}
+
+#ifndef SQLITE_OMIT_DEPRECATED
/*
** Register a profile function. The pArg from the previously registered
** profile function is returned.
@@ -134613,7 +140808,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,
** profile is a pointer to a function that is invoked at the conclusion of
** each SQL statement that is run.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
+SQLITE_API void *sqlite3_profile(
sqlite3 *db,
void (*xProfile)(void*,const char*,sqlite_uint64),
void *pArg
@@ -134633,6 +140828,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
sqlite3_mutex_leave(db->mutex);
return pOld;
}
+#endif /* SQLITE_OMIT_DEPRECATED */
#endif /* SQLITE_OMIT_TRACE */
/*
@@ -134640,7 +140836,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_profile(
** If the invoked function returns non-zero, then the commit becomes a
** rollback.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(
+SQLITE_API void *sqlite3_commit_hook(
sqlite3 *db, /* Attach the hook to this database */
int (*xCallback)(void*), /* Function to invoke on each commit */
void *pArg /* Argument to the function */
@@ -134665,7 +140861,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(
** Register a callback to be invoked each time a row is updated,
** inserted or deleted using this database connection.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
+SQLITE_API void *sqlite3_update_hook(
sqlite3 *db, /* Attach the hook to this database */
void (*xCallback)(void*,int,char const *,char const *,sqlite_int64),
void *pArg /* Argument to the function */
@@ -134690,7 +140886,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
** Register a callback to be invoked each time a transaction is rolled
** back by this database connection.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(
+SQLITE_API void *sqlite3_rollback_hook(
sqlite3 *db, /* Attach the hook to this database */
void (*xCallback)(void*), /* Callback function */
void *pArg /* Argument to the function */
@@ -134711,6 +140907,27 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(
return pRet;
}
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
+/*
+** Register a callback to be invoked each time a row is updated,
+** inserted or deleted using this database connection.
+*/
+SQLITE_API void *sqlite3_preupdate_hook(
+ sqlite3 *db, /* Attach the hook to this database */
+ void(*xCallback)( /* Callback function */
+ void*,sqlite3*,int,char const*,char const*,sqlite3_int64,sqlite3_int64),
+ void *pArg /* First callback argument */
+){
+ void *pRet;
+ sqlite3_mutex_enter(db->mutex);
+ pRet = db->pPreUpdateArg;
+ db->xPreUpdateCallback = xCallback;
+ db->pPreUpdateArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
+ return pRet;
+}
+#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
+
#ifndef SQLITE_OMIT_WAL
/*
** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
@@ -134744,7 +140961,7 @@ SQLITE_PRIVATE int sqlite3WalDefaultHook(
** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
** configured by this function.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
+SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
#ifdef SQLITE_OMIT_WAL
UNUSED_PARAMETER(db);
UNUSED_PARAMETER(nFrame);
@@ -134765,7 +140982,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame
** Register a callback to be invoked each time a transaction is written
** into the write-ahead-log by this database connection.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
+SQLITE_API void *sqlite3_wal_hook(
sqlite3 *db, /* Attach the hook to this db handle */
int(*xCallback)(void *, sqlite3*, const char*, int),
void *pArg /* First argument passed to xCallback() */
@@ -134792,7 +141009,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
/*
** Checkpoint database zDb.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
+SQLITE_API int sqlite3_wal_checkpoint_v2(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of attached database (or NULL) */
int eMode, /* SQLITE_CHECKPOINT_* value */
@@ -134836,6 +141053,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
sqlite3Error(db, rc);
}
rc = sqlite3ApiExit(db, rc);
+
+ /* If there are no active statements, clear the interrupt flag at this
+ ** point. */
+ if( db->nVdbeActive==0 ){
+ db->u1.isInterrupted = 0;
+ }
+
sqlite3_mutex_leave(db->mutex);
return rc;
#endif
@@ -134847,7 +141071,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
** to contains a zero-length string, all attached databases are
** checkpointed.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
+SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
/* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to
** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */
return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0);
@@ -134938,17 +141162,17 @@ SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3 *db){
** Return UTF-8 encoded English language explanation of the most recent
** error.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){
+SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
const char *z;
if( !db ){
- return sqlite3ErrStr(SQLITE_NOMEM);
+ return sqlite3ErrStr(SQLITE_NOMEM_BKPT);
}
if( !sqlite3SafetyCheckSickOrOk(db) ){
return sqlite3ErrStr(SQLITE_MISUSE_BKPT);
}
sqlite3_mutex_enter(db->mutex);
if( db->mallocFailed ){
- z = sqlite3ErrStr(SQLITE_NOMEM);
+ z = sqlite3ErrStr(SQLITE_NOMEM_BKPT);
}else{
testcase( db->pErr==0 );
z = (char*)sqlite3_value_text(db->pErr);
@@ -134966,7 +141190,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3 *db){
** Return UTF-16 encoded English language explanation of the most recent
** error.
*/
-SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
+SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){
static const u16 outOfMem[] = {
'o', 'u', 't', ' ', 'o', 'f', ' ', 'm', 'e', 'm', 'o', 'r', 'y', 0
};
@@ -135011,31 +141235,34 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3 *db){
** Return the most recent error code generated by an SQLite routine. If NULL is
** passed to this function, we assume a malloc() failed during sqlite3_open().
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db){
+SQLITE_API int sqlite3_errcode(sqlite3 *db){
if( db && !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
if( !db || db->mallocFailed ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
return db->errCode & db->errMask;
}
-SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db){
+SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
if( db && !sqlite3SafetyCheckSickOrOk(db) ){
return SQLITE_MISUSE_BKPT;
}
if( !db || db->mallocFailed ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}
return db->errCode;
}
+SQLITE_API int sqlite3_system_errno(sqlite3 *db){
+ return db ? db->iSysErrno : 0;
+}
/*
** Return a string that describes the kind of error specified in the
** argument. For now, this simply calls the internal sqlite3ErrStr()
** function.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int rc){
+SQLITE_API const char *sqlite3_errstr(int rc){
return sqlite3ErrStr(rc);
}
@@ -135105,7 +141332,7 @@ static int createCollation(
}
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1);
- if( pColl==0 ) return SQLITE_NOMEM;
+ if( pColl==0 ) return SQLITE_NOMEM_BKPT;
pColl->xCmp = xCompare;
pColl->pUser = pCtx;
pColl->xDel = xDel;
@@ -135153,8 +141380,8 @@ static const int aHardLimit[] = {
#if SQLITE_MAX_VDBE_OP<40
# error SQLITE_MAX_VDBE_OP must be at least 40
#endif
-#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>1000
-# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 1000
+#if SQLITE_MAX_FUNCTION_ARG<0 || SQLITE_MAX_FUNCTION_ARG>127
+# error SQLITE_MAX_FUNCTION_ARG must be between 0 and 127
#endif
#if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>125
# error SQLITE_MAX_ATTACHED must be between 0 and 125
@@ -135183,7 +141410,7 @@ static const int aHardLimit[] = {
** It merely prevents new constructs that exceed the limit
** from forming.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
+SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
int oldLimit;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -135284,7 +141511,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&');
zFile = sqlite3_malloc64(nByte);
- if( !zFile ) return SQLITE_NOMEM;
+ if( !zFile ) return SQLITE_NOMEM_BKPT;
iIn = 5;
#ifdef SQLITE_ALLOW_URI_AUTHORITY
@@ -135335,6 +141562,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
assert( octet>=0 && octet<256 );
if( octet==0 ){
+#ifndef SQLITE_ENABLE_URI_00_ERROR
/* This branch is taken when "%00" appears within the URI. In this
** case we ignore all text in the remainder of the path, name or
** value currently being parsed. So ignore the current character
@@ -135347,6 +141575,12 @@ SQLITE_PRIVATE int sqlite3ParseUri(
iIn++;
}
continue;
+#else
+ /* If ENABLE_URI_00_ERROR is defined, "%00" in a URI is an error. */
+ *pzErrMsg = sqlite3_mprintf("unexpected %%00 in uri");
+ rc = SQLITE_ERROR;
+ goto parse_uri_out;
+#endif
}
c = octet;
}else if( eState==1 && (c=='&' || c=='=') ){
@@ -135450,8 +141684,10 @@ SQLITE_PRIVATE int sqlite3ParseUri(
}else{
zFile = sqlite3_malloc64(nUri+2);
- if( !zFile ) return SQLITE_NOMEM;
- memcpy(zFile, zUri, nUri);
+ if( !zFile ) return SQLITE_NOMEM_BKPT;
+ if( nUri ){
+ memcpy(zFile, zUri, nUri);
+ }
zFile[nUri] = '\0';
zFile[nUri+1] = '\0';
flags &= ~SQLITE_OPEN_URI;
@@ -135607,6 +141843,9 @@ static int openDatabase(
#if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK)
| SQLITE_CellSizeCk
#endif
+#if defined(SQLITE_ENABLE_FTS3_TOKENIZER)
+ | SQLITE_Fts3Tokenizer
+#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -135649,7 +141888,7 @@ static int openDatabase(
flags | SQLITE_OPEN_MAIN_DB);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_IOERR_NOMEM ){
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
sqlite3Error(db, rc);
goto opendb_out;
@@ -135660,13 +141899,13 @@ static int openDatabase(
sqlite3BtreeLeave(db->aDb[0].pBt);
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
- /* The default safety_level for the main database is 'full'; for the temp
- ** database it is 'NONE'. This matches the pager layer defaults.
+ /* The default safety_level for the main database is FULL; for the temp
+ ** database it is OFF. This matches the pager layer defaults.
*/
- db->aDb[0].zName = "main";
- db->aDb[0].safety_level = 3;
- db->aDb[1].zName = "temp";
- db->aDb[1].safety_level = 1;
+ db->aDb[0].zDbSName = "main";
+ db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
+ db->aDb[1].zDbSName = "temp";
+ db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
db->magic = SQLITE_MAGIC_OPEN;
if( db->mallocFailed ){
@@ -135678,12 +141917,21 @@ static int openDatabase(
** is accessed.
*/
sqlite3Error(db, SQLITE_OK);
- sqlite3RegisterBuiltinFunctions(db);
+ sqlite3RegisterPerConnectionBuiltinFunctions(db);
+ rc = sqlite3_errcode(db);
+
+#ifdef SQLITE_ENABLE_FTS5
+ /* Register any built-in FTS5 module before loading the automatic
+ ** extensions. This allows automatic extensions to register FTS5
+ ** tokenizers and auxiliary functions. */
+ if( !db->mallocFailed && rc==SQLITE_OK ){
+ rc = sqlite3Fts5Init(db);
+ }
+#endif
/* Load automatic extensions - extensions that have been registered
** using the sqlite3_automatic_extension() API.
*/
- rc = sqlite3_errcode(db);
if( rc==SQLITE_OK ){
sqlite3AutoLoadExtensions(db);
rc = sqlite3_errcode(db);
@@ -135712,12 +141960,6 @@ static int openDatabase(
}
#endif
-#ifdef SQLITE_ENABLE_FTS5
- if( !db->mallocFailed && rc==SQLITE_OK ){
- rc = sqlite3Fts5Init(db);
- }
-#endif
-
#ifdef SQLITE_ENABLE_ICU
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3IcuInit(db);
@@ -135804,14 +142046,14 @@ opendb_out:
/*
** Open a new database handle.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_open(
+SQLITE_API int sqlite3_open(
const char *zFilename,
sqlite3 **ppDb
){
return openDatabase(zFilename, ppDb,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
}
-SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
+SQLITE_API int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
@@ -135824,7 +142066,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
/*
** Open a new database handle.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_open16(
+SQLITE_API int sqlite3_open16(
const void *zFilename,
sqlite3 **ppDb
){
@@ -135852,7 +142094,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open16(
SCHEMA_ENC(*ppDb) = ENC(*ppDb) = SQLITE_UTF16NATIVE;
}
}else{
- rc = SQLITE_NOMEM;
+ rc = SQLITE_NOMEM_BKPT;
}
sqlite3ValueFree(pVal);
@@ -135863,7 +142105,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open16(
/*
** Register a new collation sequence with the database handle db.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
+SQLITE_API int sqlite3_create_collation(
sqlite3* db,
const char *zName,
int enc,
@@ -135876,7 +142118,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
/*
** Register a new collation sequence with the database handle db.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
+SQLITE_API int sqlite3_create_collation_v2(
sqlite3* db,
const char *zName,
int enc,
@@ -135901,7 +142143,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
/*
** Register a new collation sequence with the database handle db.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
+SQLITE_API int sqlite3_create_collation16(
sqlite3* db,
const void *zName,
int enc,
@@ -135931,7 +142173,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
** Register a collation sequence factory callback with the database handle
** db. Replace any previously installed collation sequence factory.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
+SQLITE_API int sqlite3_collation_needed(
sqlite3 *db,
void *pCollNeededArg,
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
@@ -135952,7 +142194,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
** Register a collation sequence factory callback with the database handle
** db. Replace any previously installed collation sequence factory.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
+SQLITE_API int sqlite3_collation_needed16(
sqlite3 *db,
void *pCollNeededArg,
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
@@ -135974,7 +142216,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
** This function is now an anachronism. It used to be used to recover from a
** malloc() failure, but SQLite now does this automatically.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_global_recover(void){
+SQLITE_API int sqlite3_global_recover(void){
return SQLITE_OK;
}
#endif
@@ -135985,7 +142227,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_global_recover(void){
** by default. Autocommit is disabled by a BEGIN statement and reenabled
** by the next COMMIT or ROLLBACK.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
+SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
(void)SQLITE_MISUSE_BKPT;
@@ -135997,7 +142239,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
/*
** The following routines are substitutes for constants SQLITE_CORRUPT,
-** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_IOERR and possibly other error
+** SQLITE_MISUSE, SQLITE_CANTOPEN, SQLITE_NOMEM and possibly other error
** constants. They serve two purposes:
**
** 1. Serve as a convenient place to set a breakpoint in a debugger
@@ -136006,28 +142248,33 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3 *db){
** 2. Invoke sqlite3_log() to provide the source code location where
** a low-level error is first detected.
*/
+static int reportError(int iErr, int lineno, const char *zType){
+ sqlite3_log(iErr, "%s at line %d of [%.10s]",
+ zType, lineno, 20+sqlite3_sourceid());
+ return iErr;
+}
SQLITE_PRIVATE int sqlite3CorruptError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(SQLITE_CORRUPT,
- "database corruption at line %d of [%.10s]",
- lineno, 20+sqlite3_sourceid());
- return SQLITE_CORRUPT;
+ return reportError(SQLITE_CORRUPT, lineno, "database corruption");
}
SQLITE_PRIVATE int sqlite3MisuseError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(SQLITE_MISUSE,
- "misuse at line %d of [%.10s]",
- lineno, 20+sqlite3_sourceid());
- return SQLITE_MISUSE;
+ return reportError(SQLITE_MISUSE, lineno, "misuse");
}
SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
- sqlite3_log(SQLITE_CANTOPEN,
- "cannot open file at line %d of [%.10s]",
- lineno, 20+sqlite3_sourceid());
- return SQLITE_CANTOPEN;
+ return reportError(SQLITE_CANTOPEN, lineno, "cannot open file");
}
-
+#ifdef SQLITE_DEBUG
+SQLITE_PRIVATE int sqlite3NomemError(int lineno){
+ testcase( sqlite3GlobalConfig.xLog!=0 );
+ return reportError(SQLITE_NOMEM, lineno, "OOM");
+}
+SQLITE_PRIVATE int sqlite3IoerrnomemError(int lineno){
+ testcase( sqlite3GlobalConfig.xLog!=0 );
+ return reportError(SQLITE_IOERR_NOMEM, lineno, "I/O OOM error");
+}
+#endif
#ifndef SQLITE_OMIT_DEPRECATED
/*
@@ -136037,7 +142284,7 @@ SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
** SQLite no longer uses thread-specific data so this routine is now a
** no-op. It is retained for historical compatibility.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_thread_cleanup(void){
+SQLITE_API void sqlite3_thread_cleanup(void){
}
#endif
@@ -136045,7 +142292,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_thread_cleanup(void){
** Return meta information about a specific column of a database table.
** See comment in sqlite3.h (sqlite.h.in) for details.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
+SQLITE_API int sqlite3_table_column_metadata(
sqlite3 *db, /* Connection handle */
const char *zDbName, /* Database name or NULL */
const char *zTableName, /* Table name */
@@ -136121,7 +142368,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
** explicitly declared column. Copy meta information from *pCol.
*/
if( pCol ){
- zDataType = pCol->zType;
+ zDataType = sqlite3ColumnType(pCol,0);
zCollSeq = pCol->zColl;
notnull = pCol->notNull!=0;
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
@@ -136163,7 +142410,7 @@ error_out:
/*
** Sleep for a little while. Return the amount of time slept.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){
+SQLITE_API int sqlite3_sleep(int ms){
sqlite3_vfs *pVfs;
int rc;
pVfs = sqlite3_vfs_find(0);
@@ -136179,7 +142426,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int ms){
/*
** Enable or disable the extended result codes.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int onoff){
+SQLITE_API int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
@@ -136192,7 +142439,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3 *db, int ono
/*
** Invoke the xFileControl method on a particular database.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
+SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
int rc = SQLITE_ERROR;
Btree *pBtree;
@@ -136232,9 +142479,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3 *db, const char *zDbN
/*
** Interface to the testing logic.
*/
-SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
+SQLITE_API int sqlite3_test_control(int op, ...){
int rc = 0;
-#ifdef SQLITE_OMIT_BUILTIN_TEST
+#ifdef SQLITE_UNTESTABLE
UNUSED_PARAMETER(op);
#else
va_list ap;
@@ -136500,6 +142747,15 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
break;
}
+ /* Set the threshold at which OP_Once counters reset back to zero.
+ ** By default this is 0x7ffffffe (over 2 billion), but that value is
+ ** too big to test in a reasonable amount of time, so this control is
+ ** provided to set a small and easily reachable reset value.
+ */
+ case SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD: {
+ sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int);
+ break;
+ }
/* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
**
@@ -136562,7 +142818,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
}
}
va_end(ap);
-#endif /* SQLITE_OMIT_BUILTIN_TEST */
+#endif /* SQLITE_UNTESTABLE */
return rc;
}
@@ -136577,7 +142833,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...){
** parameter if it exists. If the parameter does not exist, this routine
** returns a NULL pointer.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam){
+SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
if( zFilename==0 || zParam==0 ) return 0;
zFilename += sqlite3Strlen30(zFilename) + 1;
while( zFilename[0] ){
@@ -136592,7 +142848,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilenam
/*
** Return a boolean value for a query parameter.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
+SQLITE_API int sqlite3_uri_boolean(const char *zFilename, const char *zParam, int bDflt){
const char *z = sqlite3_uri_parameter(zFilename, zParam);
bDflt = bDflt!=0;
return z ? sqlite3GetBoolean(z, bDflt) : bDflt;
@@ -136601,7 +142857,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFilename, const c
/*
** Return a 64-bit integer value for a query parameter.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(
const char *zFilename, /* Filename as passed to xOpen */
const char *zParam, /* URI parameter sought */
sqlite3_int64 bDflt /* return if parameter is missing */
@@ -136618,22 +142874,15 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(
** Return the Btree pointer identified by zDbName. Return NULL if not found.
*/
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
- int i;
- for(i=0; i<db->nDb; i++){
- if( db->aDb[i].pBt
- && (zDbName==0 || sqlite3StrICmp(zDbName, db->aDb[i].zName)==0)
- ){
- return db->aDb[i].pBt;
- }
- }
- return 0;
+ int iDb = zDbName ? sqlite3FindDbName(db, zDbName) : 0;
+ return iDb<0 ? 0 : db->aDb[iDb].pBt;
}
/*
** Return the filename of the database associated with a database
** connection.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName){
+SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){
Btree *pBt;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
@@ -136649,7 +142898,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha
** Return 1 if database is read-only or 0 if read/write. Return -1 if
** no such database exists.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
+SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
Btree *pBt;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
@@ -136666,14 +142915,13 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
** Obtain a snapshot handle for the snapshot of database zDb currently
** being read by handle db.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_get(
+SQLITE_API int sqlite3_snapshot_get(
sqlite3 *db,
const char *zDb,
sqlite3_snapshot **ppSnapshot
){
int rc = SQLITE_ERROR;
#ifndef SQLITE_OMIT_WAL
- int iDb;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ){
@@ -136682,13 +142930,15 @@ SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_get(
#endif
sqlite3_mutex_enter(db->mutex);
- iDb = sqlite3FindDbName(db, zDb);
- if( iDb==0 || iDb>1 ){
- Btree *pBt = db->aDb[iDb].pBt;
- if( 0==sqlite3BtreeIsInTrans(pBt) ){
- rc = sqlite3BtreeBeginTrans(pBt, 0);
- if( rc==SQLITE_OK ){
- rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
+ if( db->autoCommit==0 ){
+ int iDb = sqlite3FindDbName(db, zDb);
+ if( iDb==0 || iDb>1 ){
+ Btree *pBt = db->aDb[iDb].pBt;
+ if( 0==sqlite3BtreeIsInTrans(pBt) ){
+ rc = sqlite3BtreeBeginTrans(pBt, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
+ }
}
}
}
@@ -136701,7 +142951,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_get(
/*
** Open a read-transaction on the snapshot idendified by pSnapshot.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_open(
+SQLITE_API int sqlite3_snapshot_open(
sqlite3 *db,
const char *zDb,
sqlite3_snapshot *pSnapshot
@@ -136736,9 +142986,41 @@ SQLITE_API int SQLITE_STDCALL sqlite3_snapshot_open(
}
/*
+** Recover as many snapshots as possible from the wal file associated with
+** schema zDb of database db.
+*/
+SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
+ int rc = SQLITE_ERROR;
+ int iDb;
+#ifndef SQLITE_OMIT_WAL
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+
+ sqlite3_mutex_enter(db->mutex);
+ iDb = sqlite3FindDbName(db, zDb);
+ if( iDb==0 || iDb>1 ){
+ Btree *pBt = db->aDb[iDb].pBt;
+ if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
+ rc = sqlite3BtreeBeginTrans(pBt, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
+ sqlite3BtreeCommit(pBt);
+ }
+ }
+ }
+ sqlite3_mutex_leave(db->mutex);
+#endif /* SQLITE_OMIT_WAL */
+ return rc;
+}
+
+/*
** Free a snapshot handle obtained from sqlite3_snapshot_get().
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
+SQLITE_API void sqlite3_snapshot_free(sqlite3_snapshot *pSnapshot){
sqlite3_free(pSnapshot);
}
#endif /* SQLITE_ENABLE_SNAPSHOT */
@@ -136892,7 +143174,7 @@ static void leaveMutex(void){
** on the same "db". If xNotify==0 then any prior callbacks are immediately
** cancelled.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
+SQLITE_API int sqlite3_unlock_notify(
sqlite3 *db,
void (*xNotify)(void **, int),
void *pArg
@@ -143895,7 +150177,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int SQLITE_STDCALL sqlite3_fts3_init(
+SQLITE_API int sqlite3_fts3_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -146857,6 +153139,18 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
/* #include <string.h> */
/*
+** Return true if the two-argument version of fts3_tokenizer()
+** has been activated via a prior call to sqlite3_db_config(db,
+** SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
+*/
+static int fts3TokenizerEnabled(sqlite3_context *context){
+ sqlite3 *db = sqlite3_context_db_handle(context);
+ int isEnabled = 0;
+ sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER,-1,&isEnabled);
+ return isEnabled;
+}
+
+/*
** Implementation of the SQL scalar function for accessing the underlying
** hash table. This function may be called as follows:
**
@@ -146876,7 +153170,7 @@ SQLITE_PRIVATE void sqlite3Fts3PorterTokenizerModule(
** is a blob containing the pointer stored as the hash data corresponding
** to string <key-name> (after the hash-table is updated, if applicable).
*/
-static void scalarFunc(
+static void fts3TokenizerFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
@@ -146894,27 +153188,23 @@ static void scalarFunc(
nName = sqlite3_value_bytes(argv[0])+1;
if( argc==2 ){
-#ifdef SQLITE_ENABLE_FTS3_TOKENIZER
- void *pOld;
- int n = sqlite3_value_bytes(argv[1]);
- if( zName==0 || n!=sizeof(pPtr) ){
- sqlite3_result_error(context, "argument type mismatch", -1);
- return;
- }
- pPtr = *(void **)sqlite3_value_blob(argv[1]);
- pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
- if( pOld==pPtr ){
- sqlite3_result_error(context, "out of memory", -1);
+ if( fts3TokenizerEnabled(context) ){
+ void *pOld;
+ int n = sqlite3_value_bytes(argv[1]);
+ if( zName==0 || n!=sizeof(pPtr) ){
+ sqlite3_result_error(context, "argument type mismatch", -1);
+ return;
+ }
+ pPtr = *(void **)sqlite3_value_blob(argv[1]);
+ pOld = sqlite3Fts3HashInsert(pHash, (void *)zName, nName, pPtr);
+ if( pOld==pPtr ){
+ sqlite3_result_error(context, "out of memory", -1);
+ }
+ }else{
+ sqlite3_result_error(context, "fts3tokenize disabled", -1);
return;
}
-#else
- sqlite3_result_error(context, "fts3tokenize: "
- "disabled - rebuild with -DSQLITE_ENABLE_FTS3_TOKENIZER", -1
- );
- return;
-#endif /* SQLITE_ENABLE_FTS3_TOKENIZER */
- }else
- {
+ }else{
if( zName ){
pPtr = sqlite3Fts3HashFind(pHash, zName, nName);
}
@@ -146925,7 +153215,6 @@ static void scalarFunc(
return;
}
}
-
sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT);
}
@@ -147044,7 +153333,11 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
#ifdef SQLITE_TEST
-#include <tcl.h>
+#if defined(INCLUDE_SQLITE_TCL_H)
+# include "sqlite_tcl.h"
+#else
+# include "tcl.h"
+#endif
/* #include <string.h> */
/*
@@ -147163,7 +153456,6 @@ finish:
Tcl_DecrRefCount(pRet);
}
-#ifdef SQLITE_ENABLE_FTS3_TOKENIZER
static
int registerTokenizer(
sqlite3 *db,
@@ -147185,7 +153477,6 @@ int registerTokenizer(
return sqlite3_finalize(pStmt);
}
-#endif /* SQLITE_ENABLE_FTS3_TOKENIZER */
static
@@ -147258,13 +153549,13 @@ static void intTestFunc(
assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") );
/* Test the storage function */
-#ifdef SQLITE_ENABLE_FTS3_TOKENIZER
- rc = registerTokenizer(db, "nosuchtokenizer", p1);
- assert( rc==SQLITE_OK );
- rc = queryTokenizer(db, "nosuchtokenizer", &p2);
- assert( rc==SQLITE_OK );
- assert( p2==p1 );
-#endif
+ if( fts3TokenizerEnabled(context) ){
+ rc = registerTokenizer(db, "nosuchtokenizer", p1);
+ assert( rc==SQLITE_OK );
+ rc = queryTokenizer(db, "nosuchtokenizer", &p2);
+ assert( rc==SQLITE_OK );
+ assert( p2==p1 );
+ }
sqlite3_result_text(context, "ok", -1, SQLITE_STATIC);
}
@@ -147280,7 +153571,7 @@ static void intTestFunc(
** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
**
** This function adds a scalar function (see header comment above
-** scalarFunc() in this file for details) and, if ENABLE_TABLE is
+** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is
** defined at compilation time, a temporary virtual table (see header
** comment above struct HashTableVtab) to the database schema. Both
** provide read/write access to the contents of *pHash.
@@ -147309,10 +153600,10 @@ SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
#endif
if( SQLITE_OK==rc ){
- rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0);
+ rc = sqlite3_create_function(db, zName, 1, any, p, fts3TokenizerFunc, 0, 0);
}
if( SQLITE_OK==rc ){
- rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
+ rc = sqlite3_create_function(db, zName, 2, any, p, fts3TokenizerFunc, 0, 0);
}
#ifdef SQLITE_TEST
if( SQLITE_OK==rc ){
@@ -148364,7 +154655,8 @@ static int fts3SqlStmt(
** of the oldest level in the db that contains at least ? segments. Or,
** if no level in the FTS index contains more than ? segments, the statement
** returns zero rows. */
-/* 28 */ "SELECT level FROM %Q.'%q_segdir' GROUP BY level HAVING count(*)>=?"
+/* 28 */ "SELECT level, count(*) AS cnt FROM %Q.'%q_segdir' "
+ " GROUP BY level HAVING cnt>=?"
" ORDER BY (level %% 1024) ASC LIMIT 1",
/* Estimate the upper limit on the number of leaf nodes in a new segment
@@ -151225,7 +157517,7 @@ static int fts3SegmentMerge(
** segment. The level of the new segment is equal to the numerically
** greatest segment level currently present in the database for this
** index. The idx of the new segment is always 0. */
- if( csr.nSegment==1 ){
+ if( csr.nSegment==1 && 0==fts3SegReaderIsPending(csr.apSegment[0]) ){
rc = SQLITE_DONE;
goto finished;
}
@@ -152867,10 +159159,11 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
** set nSeg to -1.
*/
rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0);
- sqlite3_bind_int(pFindLevel, 1, nMin);
+ sqlite3_bind_int(pFindLevel, 1, MAX(2, nMin));
if( sqlite3_step(pFindLevel)==SQLITE_ROW ){
iAbsLevel = sqlite3_column_int64(pFindLevel, 0);
- nSeg = nMin;
+ nSeg = sqlite3_column_int(pFindLevel, 1);
+ assert( nSeg>=2 );
}else{
nSeg = -1;
}
@@ -157725,7 +164018,7 @@ static int rtreeFilter(
if( idxNum==1 ){
/* Special case - lookup by rowid. */
RtreeNode *pLeaf; /* Leaf on which the required cell resides */
- RtreeSearchPoint *p; /* Search point for the the leaf */
+ RtreeSearchPoint *p; /* Search point for the leaf */
i64 iRowid = sqlite3_value_int64(argv[0]);
i64 iNode = 0;
rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode);
@@ -157924,7 +164217,7 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
return SQLITE_NOMEM;
}
- nRow = pRtree->nRowEst / (iIdx + 1);
+ nRow = pRtree->nRowEst >> (iIdx/2);
pIdxInfo->estimatedCost = (double)6.0 * (double)nRow;
setEstimatedRows(pIdxInfo, nRow);
@@ -158983,6 +165276,53 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){
}
#endif /* !defined(SQLITE_RTREE_INT_ONLY) */
+/*
+** A constraint has failed while inserting a row into an rtree table.
+** Assuming no OOM error occurs, this function sets the error message
+** (at pRtree->base.zErrMsg) to an appropriate value and returns
+** SQLITE_CONSTRAINT.
+**
+** Parameter iCol is the index of the leftmost column involved in the
+** constraint failure. If it is 0, then the constraint that failed is
+** the unique constraint on the id column. Otherwise, it is the rtree
+** (c1<=c2) constraint on columns iCol and iCol+1 that has failed.
+**
+** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT.
+*/
+static int rtreeConstraintError(Rtree *pRtree, int iCol){
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+ int rc;
+
+ assert( iCol==0 || iCol%2 );
+ zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName);
+ if( zSql ){
+ rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ sqlite3_free(zSql);
+
+ if( rc==SQLITE_OK ){
+ if( iCol==0 ){
+ const char *zCol = sqlite3_column_name(pStmt, 0);
+ pRtree->base.zErrMsg = sqlite3_mprintf(
+ "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol
+ );
+ }else{
+ const char *zCol1 = sqlite3_column_name(pStmt, iCol);
+ const char *zCol2 = sqlite3_column_name(pStmt, iCol+1);
+ pRtree->base.zErrMsg = sqlite3_mprintf(
+ "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2
+ );
+ }
+ }
+
+ sqlite3_finalize(pStmt);
+ return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc);
+}
+
+
/*
** The xUpdate method for rtree module virtual tables.
@@ -159033,7 +165373,7 @@ static int rtreeUpdate(
cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]);
cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]);
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
- rc = SQLITE_CONSTRAINT;
+ rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
}
}
@@ -159044,7 +165384,7 @@ static int rtreeUpdate(
cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
- rc = SQLITE_CONSTRAINT;
+ rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
}
}
@@ -159065,7 +165405,7 @@ static int rtreeUpdate(
if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
rc = rtreeDeleteRowid(pRtree, cell.iRowid);
}else{
- rc = SQLITE_CONSTRAINT;
+ rc = rtreeConstraintError(pRtree, 0);
goto constraint;
}
}
@@ -159148,6 +165488,13 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
int rc;
i64 nRow = 0;
+ rc = sqlite3_table_column_metadata(
+ db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
+ );
+ if( rc!=SQLITE_OK ){
+ pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
+ return rc==SQLITE_ERROR ? SQLITE_OK : rc;
+ }
zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
if( zSql==0 ){
rc = SQLITE_NOMEM;
@@ -159633,7 +165980,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
/*
** Register a new geometry function for use with the r-tree MATCH operator.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
+SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db, /* Register SQL function on this connection */
const char *zGeom, /* Name of the new SQL function */
int (*xGeom)(sqlite3_rtree_geometry*,int,RtreeDValue*,int*), /* Callback */
@@ -159657,7 +166004,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
** Register a new 2nd-generation geometry function for use with the
** r-tree MATCH operator.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
+SQLITE_API int sqlite3_rtree_query_callback(
sqlite3 *db, /* Register SQL function on this connection */
const char *zQueryFunc, /* Name of new SQL function */
int (*xQueryFunc)(sqlite3_rtree_query_info*), /* Callback */
@@ -159682,7 +166029,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_init(
+SQLITE_API int sqlite3_rtree_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -159759,6 +166106,38 @@ static void xFree(void *p){
}
/*
+** This lookup table is used to help decode the first byte of
+** a multi-byte UTF8 character. It is copied here from SQLite source
+** code file utf8.c.
+*/
+static const unsigned char icuUtf8Trans1[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
+};
+
+#define SQLITE_ICU_READ_UTF8(zIn, c) \
+ c = *(zIn++); \
+ if( c>=0xc0 ){ \
+ c = icuUtf8Trans1[c-0xc0]; \
+ while( (*zIn & 0xc0)==0x80 ){ \
+ c = (c<<6) + (0x3f & *(zIn++)); \
+ } \
+ }
+
+#define SQLITE_ICU_SKIP_UTF8(zIn) \
+ assert( *zIn ); \
+ if( *(zIn++)>=0xc0 ){ \
+ while( (*zIn & 0xc0)==0x80 ){zIn++;} \
+ }
+
+
+/*
** Compare two UTF-8 strings for equality where the first string is
** a "LIKE" expression. Return true (1) if they are the same and
** false (0) if they are different.
@@ -159771,16 +166150,14 @@ static int icuLikeCompare(
static const int MATCH_ONE = (UChar32)'_';
static const int MATCH_ALL = (UChar32)'%';
- int iPattern = 0; /* Current byte index in zPattern */
- int iString = 0; /* Current byte index in zString */
-
int prevEscape = 0; /* True if the previous character was uEsc */
- while( zPattern[iPattern]!=0 ){
+ while( 1 ){
/* Read (and consume) the next character from the input pattern. */
UChar32 uPattern;
- U8_NEXT_UNSAFE(zPattern, iPattern, uPattern);
+ SQLITE_ICU_READ_UTF8(zPattern, uPattern);
+ if( uPattern==0 ) break;
/* There are now 4 possibilities:
**
@@ -159797,28 +166174,28 @@ static int icuLikeCompare(
** MATCH_ALL. For each MATCH_ONE, skip one character in the
** test string.
*/
- while( (c=zPattern[iPattern]) == MATCH_ALL || c == MATCH_ONE ){
+ while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
if( c==MATCH_ONE ){
- if( zString[iString]==0 ) return 0;
- U8_FWD_1_UNSAFE(zString, iString);
+ if( *zString==0 ) return 0;
+ SQLITE_ICU_SKIP_UTF8(zString);
}
- iPattern++;
+ zPattern++;
}
- if( zPattern[iPattern]==0 ) return 1;
+ if( *zPattern==0 ) return 1;
- while( zString[iString] ){
- if( icuLikeCompare(&zPattern[iPattern], &zString[iString], uEsc) ){
+ while( *zString ){
+ if( icuLikeCompare(zPattern, zString, uEsc) ){
return 1;
}
- U8_FWD_1_UNSAFE(zString, iString);
+ SQLITE_ICU_SKIP_UTF8(zString);
}
return 0;
}else if( !prevEscape && uPattern==MATCH_ONE ){
/* Case 2. */
- if( zString[iString]==0 ) return 0;
- U8_FWD_1_UNSAFE(zString, iString);
+ if( *zString==0 ) return 0;
+ SQLITE_ICU_SKIP_UTF8(zString);
}else if( !prevEscape && uPattern==uEsc){
/* Case 3. */
@@ -159827,7 +166204,7 @@ static int icuLikeCompare(
}else{
/* Case 4. */
UChar32 uString;
- U8_NEXT_UNSAFE(zString, iString, uString);
+ SQLITE_ICU_READ_UTF8(zString, uString);
uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT);
uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT);
if( uString!=uPattern ){
@@ -159837,7 +166214,7 @@ static int icuLikeCompare(
}
}
- return zString[iString]==0;
+ return *zString==0;
}
/*
@@ -160017,20 +166394,22 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
** of upper() or lower().
**
** lower('I', 'en_us') -> 'i'
-** lower('I', 'tr_tr') -> 'ı' (small dotless i)
+** lower('I', 'tr_tr') -> '\u131' (small dotless i)
**
** http://www.icu-project.org/userguide/posix.html#case_mappings
*/
static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
- const UChar *zInput;
- UChar *zOutput;
- int nInput;
- int nOutput;
-
- UErrorCode status = U_ZERO_ERROR;
+ const UChar *zInput; /* Pointer to input string */
+ UChar *zOutput = 0; /* Pointer to output buffer */
+ int nInput; /* Size of utf-16 input string in bytes */
+ int nOut; /* Size of output buffer in bytes */
+ int cnt;
+ int bToUpper; /* True for toupper(), false for tolower() */
+ UErrorCode status;
const char *zLocale = 0;
assert(nArg==1 || nArg==2);
+ bToUpper = (sqlite3_user_data(p)!=0);
if( nArg==2 ){
zLocale = (const char *)sqlite3_value_text(apArg[1]);
}
@@ -160039,26 +166418,38 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
if( !zInput ){
return;
}
- nInput = sqlite3_value_bytes16(apArg[0]);
-
- nOutput = nInput * 2 + 2;
- zOutput = sqlite3_malloc(nOutput);
- if( !zOutput ){
+ nOut = nInput = sqlite3_value_bytes16(apArg[0]);
+ if( nOut==0 ){
+ sqlite3_result_text16(p, "", 0, SQLITE_STATIC);
return;
}
- if( sqlite3_user_data(p) ){
- u_strToUpper(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
- }else{
- u_strToLower(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
- }
+ for(cnt=0; cnt<2; cnt++){
+ UChar *zNew = sqlite3_realloc(zOutput, nOut);
+ if( zNew==0 ){
+ sqlite3_free(zOutput);
+ sqlite3_result_error_nomem(p);
+ return;
+ }
+ zOutput = zNew;
+ status = U_ZERO_ERROR;
+ if( bToUpper ){
+ nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
+ }else{
+ nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
+ }
- if( !U_SUCCESS(status) ){
- icuFunctionError(p, "u_strToLower()/u_strToUpper", status);
+ if( U_SUCCESS(status) ){
+ sqlite3_result_text16(p, zOutput, nOut, xFree);
+ }else if( status==U_BUFFER_OVERFLOW_ERROR ){
+ assert( cnt==0 );
+ continue;
+ }else{
+ icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status);
+ }
return;
}
-
- sqlite3_result_text16(p, zOutput, -1, xFree);
+ assert( 0 ); /* Unreachable */
}
/*
@@ -160154,20 +166545,20 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
void *pContext; /* sqlite3_user_data() context */
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} scalars[] = {
- {"regexp", 2, SQLITE_ANY, 0, icuRegexpFunc},
+ {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc},
- {"lower", 1, SQLITE_UTF16, 0, icuCaseFunc16},
- {"lower", 2, SQLITE_UTF16, 0, icuCaseFunc16},
- {"upper", 1, SQLITE_UTF16, (void*)1, icuCaseFunc16},
- {"upper", 2, SQLITE_UTF16, (void*)1, icuCaseFunc16},
+ {"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
+ {"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
+ {"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},
+ {"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},
- {"lower", 1, SQLITE_UTF8, 0, icuCaseFunc16},
- {"lower", 2, SQLITE_UTF8, 0, icuCaseFunc16},
- {"upper", 1, SQLITE_UTF8, (void*)1, icuCaseFunc16},
- {"upper", 2, SQLITE_UTF8, (void*)1, icuCaseFunc16},
+ {"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
+ {"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
+ {"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},
+ {"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, (void*)1, icuCaseFunc16},
- {"like", 2, SQLITE_UTF8, 0, icuLikeFunc},
- {"like", 3, SQLITE_UTF8, 0, icuLikeFunc},
+ {"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
+ {"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
{"icu_load_collation", 2, SQLITE_UTF8, (void*)db, icuLoadCollation},
};
@@ -160189,7 +166580,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int SQLITE_STDCALL sqlite3_icu_init(
+SQLITE_API int sqlite3_icu_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -160665,7 +167056,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
** may also be named data<integer>_<target>, where <integer> is any sequence
** of zero or more numeric characters (0-9). This can be significant because
** tables within the RBU database are always processed in order sorted by
-** name. By judicious selection of the the <integer> portion of the names
+** name. By judicious selection of the <integer> portion of the names
** of the RBU tables the user can therefore control the order in which they
** are processed. This can be useful, for example, to ensure that "external
** content" FTS4 tables are updated before their underlying content tables.
@@ -160869,13 +167260,51 @@ typedef struct sqlite3rbu sqlite3rbu;
** not work out of the box with zipvfs. Refer to the comment describing
** the zipvfs_create_vfs() API below for details on using RBU with zipvfs.
*/
-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
+SQLITE_API sqlite3rbu *sqlite3rbu_open(
const char *zTarget,
const char *zRbu,
const char *zState
);
/*
+** Open an RBU handle to perform an RBU vacuum on database file zTarget.
+** An RBU vacuum is similar to SQLite's built-in VACUUM command, except
+** that it can be suspended and resumed like an RBU update.
+**
+** The second argument to this function identifies a database in which
+** to store the state of the RBU vacuum operation if it is suspended. The
+** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum
+** operation, the state database should either not exist or be empty
+** (contain no tables). If an RBU vacuum is suspended by calling
+** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has
+** returned SQLITE_DONE, the vacuum state is stored in the state database.
+** The vacuum can be resumed by calling this function to open a new RBU
+** handle specifying the same target and state databases.
+**
+** If the second argument passed to this function is NULL, then the
+** name of the state database is "<database>-vacuum", where <database>
+** is the name of the target database file. In this case, on UNIX, if the
+** state database is not already present in the file-system, it is created
+** with the same permissions as the target db is made.
+**
+** This function does not delete the state database after an RBU vacuum
+** is completed, even if it created it. However, if the call to
+** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents
+** of the state tables within the state database are zeroed. This way,
+** the next call to sqlite3rbu_vacuum() opens a handle that starts a
+** new RBU vacuum operation.
+**
+** As with sqlite3rbu_open(), Zipvfs users should rever to the comment
+** describing the sqlite3rbu_create_vfs() API function below for
+** a description of the complications associated with using RBU with
+** zipvfs databases.
+*/
+SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
+ const char *zTarget,
+ const char *zState
+);
+
+/*
** Internally, each RBU connection uses a separate SQLite database
** connection to access the target and rbu update databases. This
** API allows the application direct access to these database handles.
@@ -160906,7 +167335,7 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
** Database handles returned by this function remain valid until the next
** call to any sqlite3rbu_xxx() function other than sqlite3rbu_db().
*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu);
+SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
/*
** Do some work towards applying the RBU update to the target db.
@@ -160920,7 +167349,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu*, int bRbu);
** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops
** that immediately return the same value.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu);
+SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
/*
** Force RBU to save its state to disk.
@@ -160932,7 +167361,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *pRbu);
**
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu);
+SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
/*
** Close an RBU handle.
@@ -160952,14 +167381,94 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *pRbu);
** update has been partially applied, or SQLITE_DONE if it has been
** completely applied.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
+SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
/*
** Return the total number of key-value operations (inserts, deletes or
** updates) that have been performed on the target database since the
** current RBU update was started.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu);
+SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
+
+/*
+** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
+** progress indications for the two stages of an RBU update. This API may
+** be useful for driving GUI progress indicators and similar.
+**
+** An RBU update is divided into two stages:
+**
+** * Stage 1, in which changes are accumulated in an oal/wal file, and
+** * Stage 2, in which the contents of the wal file are copied into the
+** main database.
+**
+** The update is visible to non-RBU clients during stage 2. During stage 1
+** non-RBU reader clients may see the original database.
+**
+** If this API is called during stage 2 of the update, output variable
+** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo)
+** to a value between 0 and 10000 to indicate the permyriadage progress of
+** stage 2. A value of 5000 indicates that stage 2 is half finished,
+** 9000 indicates that it is 90% finished, and so on.
+**
+** If this API is called during stage 1 of the update, output variable
+** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The
+** value to which (*pnOne) is set depends on whether or not the RBU
+** database contains an "rbu_count" table. The rbu_count table, if it
+** exists, must contain the same columns as the following:
+**
+** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
+**
+** There must be one row in the table for each source (data_xxx) table within
+** the RBU database. The 'tbl' column should contain the name of the source
+** table. The 'cnt' column should contain the number of rows within the
+** source table.
+**
+** If the rbu_count table is present and populated correctly and this
+** API is called during stage 1, the *pnOne output variable is set to the
+** permyriadage progress of the same stage. If the rbu_count table does
+** not exist, then (*pnOne) is set to -1 during stage 1. If the rbu_count
+** table exists but is not correctly populated, the value of the *pnOne
+** output variable during stage 1 is undefined.
+*/
+SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int *pnTwo);
+
+/*
+** Obtain an indication as to the current stage of an RBU update or vacuum.
+** This function always returns one of the SQLITE_RBU_STATE_XXX constants
+** defined in this file. Return values should be interpreted as follows:
+**
+** SQLITE_RBU_STATE_OAL:
+** RBU is currently building a *-oal file. The next call to sqlite3rbu_step()
+** may either add further data to the *-oal file, or compute data that will
+** be added by a subsequent call.
+**
+** SQLITE_RBU_STATE_MOVE:
+** RBU has finished building the *-oal file. The next call to sqlite3rbu_step()
+** will move the *-oal file to the equivalent *-wal path. If the current
+** operation is an RBU update, then the updated version of the database
+** file will become visible to ordinary SQLite clients following the next
+** call to sqlite3rbu_step().
+**
+** SQLITE_RBU_STATE_CHECKPOINT:
+** RBU is currently performing an incremental checkpoint. The next call to
+** sqlite3rbu_step() will copy a page of data from the *-wal file into
+** the target database file.
+**
+** SQLITE_RBU_STATE_DONE:
+** The RBU operation has finished. Any subsequent calls to sqlite3rbu_step()
+** will immediately return SQLITE_DONE.
+**
+** SQLITE_RBU_STATE_ERROR:
+** An error has occurred. Any subsequent calls to sqlite3rbu_step() will
+** immediately return the SQLite error code associated with the error.
+*/
+#define SQLITE_RBU_STATE_OAL 1
+#define SQLITE_RBU_STATE_MOVE 2
+#define SQLITE_RBU_STATE_CHECKPOINT 3
+#define SQLITE_RBU_STATE_DONE 4
+#define SQLITE_RBU_STATE_ERROR 5
+
+SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
/*
** Create an RBU VFS named zName that accesses the underlying file-system
@@ -161003,7 +167512,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu);
** file-system via "rbu" all the time, even if it only uses RBU functionality
** occasionally.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent);
+SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
/*
** Deregister and destroy an RBU vfs created by an earlier call to
@@ -161013,7 +167522,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
** before all database handles that use it have been closed, the results
** are undefined.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName);
+SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
#if 0
} /* end of the 'extern "C"' block */
@@ -161082,14 +167591,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName);
** RBU_STATE_OALSZ:
** Valid if STAGE==1. The size in bytes of the *-oal file.
*/
-#define RBU_STATE_STAGE 1
-#define RBU_STATE_TBL 2
-#define RBU_STATE_IDX 3
-#define RBU_STATE_ROW 4
-#define RBU_STATE_PROGRESS 5
-#define RBU_STATE_CKPT 6
-#define RBU_STATE_COOKIE 7
-#define RBU_STATE_OALSZ 8
+#define RBU_STATE_STAGE 1
+#define RBU_STATE_TBL 2
+#define RBU_STATE_IDX 3
+#define RBU_STATE_ROW 4
+#define RBU_STATE_PROGRESS 5
+#define RBU_STATE_CKPT 6
+#define RBU_STATE_COOKIE 7
+#define RBU_STATE_OALSZ 8
+#define RBU_STATE_PHASEONESTEP 9
#define RBU_STAGE_OAL 1
#define RBU_STAGE_MOVE 2
@@ -161110,6 +167620,7 @@ typedef struct RbuUpdateStmt RbuUpdateStmt;
#if !defined(SQLITE_AMALGAMATION)
typedef unsigned int u32;
+typedef unsigned short u16;
typedef unsigned char u8;
typedef sqlite3_int64 i64;
#endif
@@ -161123,6 +167634,8 @@ typedef sqlite3_int64 i64;
#define WAL_LOCK_CKPT 1
#define WAL_LOCK_READ0 3
+#define SQLITE_FCNTL_RBUCNT 5149216
+
/*
** A structure to store values read from the rbu_state table in memory.
*/
@@ -161135,6 +167648,7 @@ struct RbuState {
i64 nProgress;
u32 iCookie;
i64 iOalSz;
+ i64 nPhaseOneStep;
};
struct RbuUpdateStmt {
@@ -161179,6 +167693,7 @@ struct RbuObjIter {
int iTnum; /* Root page of current object */
int iPkTnum; /* If eType==EXTERNAL, root of PK index */
int bUnique; /* Current index is unique */
+ int nIndex; /* Number of aux. indexes on table zTbl */
/* Statements created by rbuObjIterPrepareAll() */
int nCol; /* Number of columns in current object */
@@ -161215,10 +167730,11 @@ struct RbuObjIter {
*/
#define RBU_INSERT 1 /* Insert on a main table b-tree */
#define RBU_DELETE 2 /* Delete a row from a main table b-tree */
-#define RBU_IDX_DELETE 3 /* Delete a row from an aux. index b-tree */
-#define RBU_IDX_INSERT 4 /* Insert on an aux. index b-tree */
-#define RBU_UPDATE 5 /* Update a row in a main table b-tree */
+#define RBU_REPLACE 3 /* Delete and then insert a row */
+#define RBU_IDX_DELETE 4 /* Delete a row from an aux. index b-tree */
+#define RBU_IDX_INSERT 5 /* Insert on an aux. index b-tree */
+#define RBU_UPDATE 6 /* Update a row in a main table b-tree */
/*
** A single step of an incremental checkpoint - frame iWalFrame of the wal
@@ -161231,6 +167747,43 @@ struct RbuFrame {
/*
** RBU handle.
+**
+** nPhaseOneStep:
+** If the RBU database contains an rbu_count table, this value is set to
+** a running estimate of the number of b-tree operations required to
+** finish populating the *-oal file. This allows the sqlite3_bp_progress()
+** API to calculate the permyriadage progress of populating the *-oal file
+** using the formula:
+**
+** permyriadage = (10000 * nProgress) / nPhaseOneStep
+**
+** nPhaseOneStep is initialized to the sum of:
+**
+** nRow * (nIndex + 1)
+**
+** for all source tables in the RBU database, where nRow is the number
+** of rows in the source table and nIndex the number of indexes on the
+** corresponding target database table.
+**
+** This estimate is accurate if the RBU update consists entirely of
+** INSERT operations. However, it is inaccurate if:
+**
+** * the RBU update contains any UPDATE operations. If the PK specified
+** for an UPDATE operation does not exist in the target table, then
+** no b-tree operations are required on index b-trees. Or if the
+** specified PK does exist, then (nIndex*2) such operations are
+** required (one delete and one insert on each index b-tree).
+**
+** * the RBU update contains any DELETE operations for which the specified
+** PK does not exist. In this case no operations are required on index
+** b-trees.
+**
+** * the RBU update contains REPLACE operations. These are similar to
+** UPDATE operations.
+**
+** nPhaseOneStep is updated to account for the conditions above during the
+** first pass of each source table. The updated nPhaseOneStep value is
+** stored in the rbu_state table if the RBU update is suspended.
*/
struct sqlite3rbu {
int eStage; /* Value of RBU_STATE_STAGE field */
@@ -161248,6 +167801,7 @@ struct sqlite3rbu {
const char *zVfsName; /* Name of automatically created rbu vfs */
rbu_file *pTargetFd; /* File handle open on target db */
i64 iOalSz;
+ i64 nPhaseOneStep;
/* The following state variables are used as part of the incremental
** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
@@ -161260,6 +167814,10 @@ struct sqlite3rbu {
int pgsz;
u8 *aBuf;
i64 iWalCksum;
+
+ /* Used in RBU vacuum mode only */
+ int nRbu; /* Number of RBU VFS in the stack */
+ rbu_file *pRbuFd; /* Fd for main db of dbRbu */
};
/*
@@ -161285,6 +167843,7 @@ struct rbu_file {
int openFlags; /* Flags this file was opened with */
u32 iCookie; /* Cookie value for main db files */
u8 iWriteVer; /* "write-version" value for main db files */
+ u8 bNolock; /* True to fail EXCLUSIVE locks */
int nShm; /* Number of entries in apShm[] array */
char **apShm; /* Array of mmap'd *-shm regions */
@@ -161295,6 +167854,11 @@ struct rbu_file {
rbu_file *pMainNext; /* Next MAIN_DB file */
};
+/*
+** True for an RBU vacuum handle, or false otherwise.
+*/
+#define rbuIsVacuum(p) ((p)->zTarget==0)
+
/*************************************************************************
** The following three functions, found below:
@@ -161743,8 +168307,11 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
/*
** The implementation of the rbu_target_name() SQL function. This function
-** accepts one argument - the name of a table in the RBU database. If the
-** table name matches the pattern:
+** accepts one or two arguments. The first argument is the name of a table -
+** the name of a table in the RBU database. The second, if it is present, is 1
+** for a view or 0 for a table.
+**
+** For a non-vacuum RBU handle, if the table name matches the pattern:
**
** data[0-9]_<name>
**
@@ -161755,21 +168322,33 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
** "data_t1" -> "t1"
** "data0123_t2" -> "t2"
** "dataAB_t3" -> NULL
+**
+** For an rbu vacuum handle, a copy of the first argument is returned if
+** the second argument is either missing or 0 (not a view).
*/
static void rbuTargetNameFunc(
- sqlite3_context *context,
+ sqlite3_context *pCtx,
int argc,
sqlite3_value **argv
){
+ sqlite3rbu *p = sqlite3_user_data(pCtx);
const char *zIn;
- assert( argc==1 );
+ assert( argc==1 || argc==2 );
zIn = (const char*)sqlite3_value_text(argv[0]);
- if( zIn && strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){
- int i;
- for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++);
- if( zIn[i]=='_' && zIn[i+1] ){
- sqlite3_result_text(context, &zIn[i+1], -1, SQLITE_STATIC);
+ if( zIn ){
+ if( rbuIsVacuum(p) ){
+ if( argc==1 || 0==sqlite3_value_int(argv[1]) ){
+ sqlite3_result_text(pCtx, zIn, -1, SQLITE_STATIC);
+ }
+ }else{
+ if( strlen(zIn)>4 && memcmp("data", zIn, 4)==0 ){
+ int i;
+ for(i=4; zIn[i]>='0' && zIn[i]<='9'; i++);
+ if( zIn[i]=='_' && zIn[i+1] ){
+ sqlite3_result_text(pCtx, &zIn[i+1], -1, SQLITE_STATIC);
+ }
+ }
}
}
}
@@ -161786,11 +168365,14 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
int rc;
memset(pIter, 0, sizeof(RbuObjIter));
- rc = prepareAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
- "SELECT rbu_target_name(name) AS target, name FROM sqlite_master "
+ rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
+ sqlite3_mprintf(
+ "SELECT rbu_target_name(name, type='view') AS target, name "
+ "FROM sqlite_master "
"WHERE type IN ('table', 'view') AND target IS NOT NULL "
+ " %s "
"ORDER BY name"
- );
+ , rbuIsVacuum(p) ? "AND rootpage!=0 AND rootpage IS NOT NULL" : ""));
if( rc==SQLITE_OK ){
rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
@@ -162078,6 +168660,7 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
);
}
+ pIter->nIndex = 0;
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
sqlite3_stmt *pXInfo = 0;
@@ -162091,6 +168674,12 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
}
rbuFinalize(p, pXInfo);
bIndex = 1;
+ pIter->nIndex++;
+ }
+
+ if( pIter->eType==RBU_PK_WITHOUT_ROWID ){
+ /* "PRAGMA index_list" includes the main PK b-tree */
+ pIter->nIndex--;
}
rbuFinalize(p, pList);
@@ -162156,6 +168745,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
pStmt = 0;
if( p->rc==SQLITE_OK
+ && rbuIsVacuum(p)==0
&& bRbuRowid!=(pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
){
p->rc = SQLITE_ERROR;
@@ -162204,6 +168794,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
rbuFinalize(p, pStmt);
rbuObjIterCacheIndexedCols(p, pIter);
assert( pIter->eType!=RBU_PK_VTAB || pIter->abIndexed==0 );
+ assert( pIter->eType!=RBU_PK_VTAB || pIter->nIndex==0 );
}
return p->rc;
@@ -162294,6 +168885,8 @@ static char *rbuObjIterGetIndexCols(
for(i=0; pIter->abTblPk[i]==0; i++);
assert( i<pIter->nTblCol );
zCol = pIter->azTblCol[i];
+ }else if( rbuIsVacuum(p) ){
+ zCol = "_rowid_";
}else{
zCol = "rbu_rowid";
}
@@ -162757,6 +169350,14 @@ static void rbuTmpInsertFunc(
int rc = SQLITE_OK;
int i;
+ assert( sqlite3_value_int(apVal[0])!=0
+ || p->objiter.eType==RBU_PK_EXTERNAL
+ || p->objiter.eType==RBU_PK_NONE
+ );
+ if( sqlite3_value_int(apVal[0])!=0 ){
+ p->nPhaseOneStep += p->objiter.nIndex;
+ }
+
for(i=0; rc==SQLITE_OK && i<nVal; i++){
rc = sqlite3_bind_value(p->objiter.pTmpInsert, i+1, apVal[i]);
}
@@ -162826,7 +169427,7 @@ static int rbuObjIterPrepareAll(
}
/* And to delete index entries */
- if( p->rc==SQLITE_OK ){
+ if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
p->rc = prepareFreeAndCollectError(
p->dbMain, &pIter->pDelete, &p->zErrmsg,
sqlite3_mprintf("DELETE FROM \"rbu_imp_%w\" WHERE %s", zTbl, zWhere)
@@ -162836,6 +169437,15 @@ static int rbuObjIterPrepareAll(
/* Create the SELECT statement to read keys in sorted order */
if( p->rc==SQLITE_OK ){
char *zSql;
+ if( rbuIsVacuum(p) ){
+ zSql = sqlite3_mprintf(
+ "SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s",
+ zCollist,
+ pIter->zDataTbl,
+ zCollist, zLimit
+ );
+ }else
+
if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
zSql = sqlite3_mprintf(
"SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s",
@@ -162844,13 +169454,13 @@ static int rbuObjIterPrepareAll(
);
}else{
zSql = sqlite3_mprintf(
+ "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
+ "UNION ALL "
"SELECT %s, rbu_control FROM '%q' "
"WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
- "UNION ALL "
- "SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
"ORDER BY %s%s",
- zCollist, pIter->zDataTbl,
zCollist, p->zStateDb, pIter->zDataTbl,
+ zCollist, pIter->zDataTbl,
zCollist, zLimit
);
}
@@ -162862,7 +169472,9 @@ static int rbuObjIterPrepareAll(
sqlite3_free(zWhere);
sqlite3_free(zBind);
}else{
- int bRbuRowid = (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE);
+ int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
+ ||(pIter->eType==RBU_PK_NONE)
+ ||(pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p));
const char *zTbl = pIter->zTbl; /* Table this step applies to */
const char *zWrite; /* Imposter table name */
@@ -162889,8 +169501,10 @@ static int rbuObjIterPrepareAll(
);
}
- /* Create the DELETE statement to write to the target PK b-tree */
- if( p->rc==SQLITE_OK ){
+ /* Create the DELETE statement to write to the target PK b-tree.
+ ** Because it only performs INSERT operations, this is not required for
+ ** an rbu vacuum handle. */
+ if( rbuIsVacuum(p)==0 && p->rc==SQLITE_OK ){
p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pDelete, pz,
sqlite3_mprintf(
"DELETE FROM \"%s%w\" WHERE %s", zWrite, zTbl, zWhere
@@ -162898,7 +169512,7 @@ static int rbuObjIterPrepareAll(
);
}
- if( pIter->abIndexed ){
+ if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
const char *zRbuRowid = "";
if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
zRbuRowid = ", rbu_rowid";
@@ -162916,17 +169530,17 @@ static int rbuObjIterPrepareAll(
rbuMPrintfExec(p, p->dbMain,
"CREATE TEMP TRIGGER rbu_delete_tr BEFORE DELETE ON \"%s%w\" "
"BEGIN "
- " SELECT rbu_tmp_insert(2, %s);"
+ " SELECT rbu_tmp_insert(3, %s);"
"END;"
"CREATE TEMP TRIGGER rbu_update1_tr BEFORE UPDATE ON \"%s%w\" "
"BEGIN "
- " SELECT rbu_tmp_insert(2, %s);"
+ " SELECT rbu_tmp_insert(3, %s);"
"END;"
"CREATE TEMP TRIGGER rbu_update2_tr AFTER UPDATE ON \"%s%w\" "
"BEGIN "
- " SELECT rbu_tmp_insert(3, %s);"
+ " SELECT rbu_tmp_insert(4, %s);"
"END;",
zWrite, zTbl, zOldlist,
zWrite, zTbl, zOldlist,
@@ -162948,10 +169562,16 @@ static int rbuObjIterPrepareAll(
/* Create the SELECT statement to read keys from data_xxx */
if( p->rc==SQLITE_OK ){
+ const char *zRbuRowid = "";
+ if( bRbuRowid ){
+ zRbuRowid = rbuIsVacuum(p) ? ",_rowid_ " : ",rbu_rowid";
+ }
p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
sqlite3_mprintf(
- "SELECT %s, rbu_control%s FROM '%q'%s",
- zCollist, (bRbuRowid ? ", rbu_rowid" : ""),
+ "SELECT %s,%s rbu_control%s FROM '%q'%s",
+ zCollist,
+ (rbuIsVacuum(p) ? "0 AS " : ""),
+ zRbuRowid,
pIter->zDataTbl, zLimit
)
);
@@ -163046,11 +169666,15 @@ static int rbuGetUpdateStmt(
return p->rc;
}
-static sqlite3 *rbuOpenDbhandle(sqlite3rbu *p, const char *zName){
+static sqlite3 *rbuOpenDbhandle(
+ sqlite3rbu *p,
+ const char *zName,
+ int bUseVfs
+){
sqlite3 *db = 0;
if( p->rc==SQLITE_OK ){
const int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_URI;
- p->rc = sqlite3_open_v2(zName, &db, flags, p->zVfsName);
+ p->rc = sqlite3_open_v2(zName, &db, flags, bUseVfs ? p->zVfsName : 0);
if( p->rc ){
p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
sqlite3_close(db);
@@ -163061,16 +169685,112 @@ static sqlite3 *rbuOpenDbhandle(sqlite3rbu *p, const char *zName){
}
/*
+** Free an RbuState object allocated by rbuLoadState().
+*/
+static void rbuFreeState(RbuState *p){
+ if( p ){
+ sqlite3_free(p->zTbl);
+ sqlite3_free(p->zIdx);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Allocate an RbuState object and load the contents of the rbu_state
+** table into it. Return a pointer to the new object. It is the
+** responsibility of the caller to eventually free the object using
+** sqlite3_free().
+**
+** If an error occurs, leave an error code and message in the rbu handle
+** and return NULL.
+*/
+static RbuState *rbuLoadState(sqlite3rbu *p){
+ RbuState *pRet = 0;
+ sqlite3_stmt *pStmt = 0;
+ int rc;
+ int rc2;
+
+ pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
+ if( pRet==0 ) return 0;
+
+ rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+ sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
+ );
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ switch( sqlite3_column_int(pStmt, 0) ){
+ case RBU_STATE_STAGE:
+ pRet->eStage = sqlite3_column_int(pStmt, 1);
+ if( pRet->eStage!=RBU_STAGE_OAL
+ && pRet->eStage!=RBU_STAGE_MOVE
+ && pRet->eStage!=RBU_STAGE_CKPT
+ ){
+ p->rc = SQLITE_CORRUPT;
+ }
+ break;
+
+ case RBU_STATE_TBL:
+ pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
+ break;
+
+ case RBU_STATE_IDX:
+ pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
+ break;
+
+ case RBU_STATE_ROW:
+ pRet->nRow = sqlite3_column_int(pStmt, 1);
+ break;
+
+ case RBU_STATE_PROGRESS:
+ pRet->nProgress = sqlite3_column_int64(pStmt, 1);
+ break;
+
+ case RBU_STATE_CKPT:
+ pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
+ break;
+
+ case RBU_STATE_COOKIE:
+ pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
+ break;
+
+ case RBU_STATE_OALSZ:
+ pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
+ break;
+
+ case RBU_STATE_PHASEONESTEP:
+ pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1);
+ break;
+
+ default:
+ rc = SQLITE_CORRUPT;
+ break;
+ }
+ }
+ rc2 = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ) rc = rc2;
+
+ p->rc = rc;
+ return pRet;
+}
+
+
+/*
** Open the database handle and attach the RBU database as "rbu". If an
** error occurs, leave an error code and message in the RBU handle.
*/
static void rbuOpenDatabase(sqlite3rbu *p){
- assert( p->rc==SQLITE_OK );
- assert( p->dbMain==0 && p->dbRbu==0 );
+ assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
+ assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
- p->eStage = 0;
- p->dbMain = rbuOpenDbhandle(p, p->zTarget);
- p->dbRbu = rbuOpenDbhandle(p, p->zRbu);
+ /* Open the RBU database */
+ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
+
+ if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
+ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
+ if( p->zState==0 ){
+ const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
+ p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
+ }
+ }
/* If using separate RBU and state databases, attach the state database to
** the RBU db handle now. */
@@ -163081,6 +169801,96 @@ static void rbuOpenDatabase(sqlite3rbu *p){
memcpy(p->zStateDb, "main", 4);
}
+#if 0
+ if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
+ p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, 0);
+ }
+#endif
+
+ /* If it has not already been created, create the rbu_state table */
+ rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
+
+#if 0
+ if( rbuIsVacuum(p) ){
+ if( p->rc==SQLITE_OK ){
+ int rc2;
+ int bOk = 0;
+ sqlite3_stmt *pCnt = 0;
+ p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
+ "SELECT count(*) FROM stat.sqlite_master"
+ );
+ if( p->rc==SQLITE_OK
+ && sqlite3_step(pCnt)==SQLITE_ROW
+ && 1==sqlite3_column_int(pCnt, 0)
+ ){
+ bOk = 1;
+ }
+ rc2 = sqlite3_finalize(pCnt);
+ if( p->rc==SQLITE_OK ) p->rc = rc2;
+
+ if( p->rc==SQLITE_OK && bOk==0 ){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("invalid state database");
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
+ }
+ }
+ }
+#endif
+
+ if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
+ int bOpen = 0;
+ int rc;
+ p->nRbu = 0;
+ p->pRbuFd = 0;
+ rc = sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
+ if( rc!=SQLITE_NOTFOUND ) p->rc = rc;
+ if( p->eStage>=RBU_STAGE_MOVE ){
+ bOpen = 1;
+ }else{
+ RbuState *pState = rbuLoadState(p);
+ if( pState ){
+ bOpen = (pState->eStage>RBU_STAGE_MOVE);
+ rbuFreeState(pState);
+ }
+ }
+ if( bOpen ) p->dbMain = rbuOpenDbhandle(p, p->zRbu, p->nRbu<=1);
+ }
+
+ p->eStage = 0;
+ if( p->rc==SQLITE_OK && p->dbMain==0 ){
+ if( !rbuIsVacuum(p) ){
+ p->dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
+ }else if( p->pRbuFd->pWalFd ){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("cannot vacuum wal mode database");
+ }else{
+ char *zTarget;
+ char *zExtra = 0;
+ if( strlen(p->zRbu)>=5 && 0==memcmp("file:", p->zRbu, 5) ){
+ zExtra = &p->zRbu[5];
+ while( *zExtra ){
+ if( *zExtra++=='?' ) break;
+ }
+ if( *zExtra=='\0' ) zExtra = 0;
+ }
+
+ zTarget = sqlite3_mprintf("file:%s-vacuum?rbu_memory=1%s%s",
+ sqlite3_db_filename(p->dbRbu, "main"),
+ (zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
+ );
+
+ if( zTarget==0 ){
+ p->rc = SQLITE_NOMEM;
+ return;
+ }
+ p->dbMain = rbuOpenDbhandle(p, zTarget, p->nRbu<=1);
+ sqlite3_free(zTarget);
+ }
+ }
+
if( p->rc==SQLITE_OK ){
p->rc = sqlite3_create_function(p->dbMain,
"rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0
@@ -163095,7 +169905,7 @@ static void rbuOpenDatabase(sqlite3rbu *p){
if( p->rc==SQLITE_OK ){
p->rc = sqlite3_create_function(p->dbRbu,
- "rbu_target_name", 1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
+ "rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
);
}
@@ -163144,9 +169954,9 @@ static void rbuFileSuffix3(const char *zBase, char *z){
#endif
{
int i, sz;
- sz = sqlite3Strlen30(z);
+ sz = (int)strlen(z)&0xffffff;
for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
- if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
+ if( z[i]=='.' && sz>i+4 ) memmove(&z[i+1], &z[sz-3], 4);
}
#endif
}
@@ -163354,9 +170164,15 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
*/
static void rbuMoveOalFile(sqlite3rbu *p){
const char *zBase = sqlite3_db_filename(p->dbMain, "main");
+ const char *zMove = zBase;
+ char *zOal;
+ char *zWal;
- char *zWal = sqlite3_mprintf("%s-wal", zBase);
- char *zOal = sqlite3_mprintf("%s-oal", zBase);
+ if( rbuIsVacuum(p) ){
+ zMove = sqlite3_db_filename(p->dbRbu, "main");
+ }
+ zOal = sqlite3_mprintf("%s-oal", zMove);
+ zWal = sqlite3_mprintf("%s-wal", zMove);
assert( p->eStage==RBU_STAGE_MOVE );
assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
@@ -163377,8 +170193,8 @@ static void rbuMoveOalFile(sqlite3rbu *p){
/* Re-open the databases. */
rbuObjIterFinalize(&p->objiter);
- sqlite3_close(p->dbMain);
sqlite3_close(p->dbRbu);
+ sqlite3_close(p->dbMain);
p->dbMain = 0;
p->dbRbu = 0;
@@ -163444,14 +170260,12 @@ static int rbuStepType(sqlite3rbu *p, const char **pzMask){
switch( sqlite3_column_type(p->objiter.pSelect, iCol) ){
case SQLITE_INTEGER: {
int iVal = sqlite3_column_int(p->objiter.pSelect, iCol);
- if( iVal==0 ){
- res = RBU_INSERT;
- }else if( iVal==1 ){
- res = RBU_DELETE;
- }else if( iVal==2 ){
- res = RBU_IDX_DELETE;
- }else if( iVal==3 ){
- res = RBU_IDX_INSERT;
+ switch( iVal ){
+ case 0: res = RBU_INSERT; break;
+ case 1: res = RBU_DELETE; break;
+ case 2: res = RBU_REPLACE; break;
+ case 3: res = RBU_IDX_DELETE; break;
+ case 4: res = RBU_IDX_INSERT; break;
}
break;
}
@@ -163491,6 +170305,83 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
#endif
/*
+** Argument eType must be one of RBU_INSERT, RBU_DELETE, RBU_IDX_INSERT or
+** RBU_IDX_DELETE. This function performs the work of a single
+** sqlite3rbu_step() call for the type of operation specified by eType.
+*/
+static void rbuStepOneOp(sqlite3rbu *p, int eType){
+ RbuObjIter *pIter = &p->objiter;
+ sqlite3_value *pVal;
+ sqlite3_stmt *pWriter;
+ int i;
+
+ assert( p->rc==SQLITE_OK );
+ assert( eType!=RBU_DELETE || pIter->zIdx==0 );
+ assert( eType==RBU_DELETE || eType==RBU_IDX_DELETE
+ || eType==RBU_INSERT || eType==RBU_IDX_INSERT
+ );
+
+ /* If this is a delete, decrement nPhaseOneStep by nIndex. If the DELETE
+ ** statement below does actually delete a row, nPhaseOneStep will be
+ ** incremented by the same amount when SQL function rbu_tmp_insert()
+ ** is invoked by the trigger. */
+ if( eType==RBU_DELETE ){
+ p->nPhaseOneStep -= p->objiter.nIndex;
+ }
+
+ if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
+ pWriter = pIter->pDelete;
+ }else{
+ pWriter = pIter->pInsert;
+ }
+
+ for(i=0; i<pIter->nCol; i++){
+ /* If this is an INSERT into a table b-tree and the table has an
+ ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
+ ** to write a NULL into the IPK column. That is not permitted. */
+ if( eType==RBU_INSERT
+ && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
+ && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
+ ){
+ p->rc = SQLITE_MISMATCH;
+ p->zErrmsg = sqlite3_mprintf("datatype mismatch");
+ return;
+ }
+
+ if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
+ continue;
+ }
+
+ pVal = sqlite3_column_value(pIter->pSelect, i);
+ p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
+ if( p->rc ) return;
+ }
+ if( pIter->zIdx==0 ){
+ if( pIter->eType==RBU_PK_VTAB
+ || pIter->eType==RBU_PK_NONE
+ || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p))
+ ){
+ /* For a virtual table, or a table with no primary key, the
+ ** SELECT statement is:
+ **
+ ** SELECT <cols>, rbu_control, rbu_rowid FROM ....
+ **
+ ** Hence column_value(pIter->nCol+1).
+ */
+ assertColumnName(pIter->pSelect, pIter->nCol+1,
+ rbuIsVacuum(p) ? "rowid" : "rbu_rowid"
+ );
+ pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
+ p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
+ }
+ }
+ if( p->rc==SQLITE_OK ){
+ sqlite3_step(pWriter);
+ p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
+ }
+}
+
+/*
** This function does the work for an sqlite3rbu_step() call.
**
** The object-iterator (p->objiter) currently points to a valid object,
@@ -163504,78 +170395,36 @@ static void assertColumnName(sqlite3_stmt *pStmt, int iCol, const char *zName){
static int rbuStep(sqlite3rbu *p){
RbuObjIter *pIter = &p->objiter;
const char *zMask = 0;
- int i;
int eType = rbuStepType(p, &zMask);
if( eType ){
+ assert( eType==RBU_INSERT || eType==RBU_DELETE
+ || eType==RBU_REPLACE || eType==RBU_IDX_DELETE
+ || eType==RBU_IDX_INSERT || eType==RBU_UPDATE
+ );
assert( eType!=RBU_UPDATE || pIter->zIdx==0 );
- if( pIter->zIdx==0 && eType==RBU_IDX_DELETE ){
+ if( pIter->zIdx==0 && (eType==RBU_IDX_DELETE || eType==RBU_IDX_INSERT) ){
rbuBadControlError(p);
}
- else if(
- eType==RBU_INSERT
- || eType==RBU_DELETE
- || eType==RBU_IDX_DELETE
- || eType==RBU_IDX_INSERT
- ){
- sqlite3_value *pVal;
- sqlite3_stmt *pWriter;
-
- assert( eType!=RBU_UPDATE );
- assert( eType!=RBU_DELETE || pIter->zIdx==0 );
-
- if( eType==RBU_IDX_DELETE || eType==RBU_DELETE ){
- pWriter = pIter->pDelete;
- }else{
- pWriter = pIter->pInsert;
- }
-
- for(i=0; i<pIter->nCol; i++){
- /* If this is an INSERT into a table b-tree and the table has an
- ** explicit INTEGER PRIMARY KEY, check that this is not an attempt
- ** to write a NULL into the IPK column. That is not permitted. */
- if( eType==RBU_INSERT
- && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
- && sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
- ){
- p->rc = SQLITE_MISMATCH;
- p->zErrmsg = sqlite3_mprintf("datatype mismatch");
- goto step_out;
- }
-
- if( eType==RBU_DELETE && pIter->abTblPk[i]==0 ){
- continue;
- }
-
- pVal = sqlite3_column_value(pIter->pSelect, i);
- p->rc = sqlite3_bind_value(pWriter, i+1, pVal);
- if( p->rc ) goto step_out;
- }
- if( pIter->zIdx==0
- && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
- ){
- /* For a virtual table, or a table with no primary key, the
- ** SELECT statement is:
- **
- ** SELECT <cols>, rbu_control, rbu_rowid FROM ....
- **
- ** Hence column_value(pIter->nCol+1).
- */
- assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
- pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
- p->rc = sqlite3_bind_value(pWriter, pIter->nCol+1, pVal);
- }
- if( p->rc==SQLITE_OK ){
- sqlite3_step(pWriter);
- p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
+ else if( eType==RBU_REPLACE ){
+ if( pIter->zIdx==0 ){
+ p->nPhaseOneStep += p->objiter.nIndex;
+ rbuStepOneOp(p, RBU_DELETE);
}
- }else{
+ if( p->rc==SQLITE_OK ) rbuStepOneOp(p, RBU_INSERT);
+ }
+ else if( eType!=RBU_UPDATE ){
+ rbuStepOneOp(p, eType);
+ }
+ else{
sqlite3_value *pVal;
sqlite3_stmt *pUpdate = 0;
assert( eType==RBU_UPDATE );
+ p->nPhaseOneStep -= p->objiter.nIndex;
rbuGetUpdateStmt(p, pIter, zMask, &pUpdate);
if( pUpdate ){
+ int i;
for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
char c = zMask[pIter->aiSrcOrder[i]];
pVal = sqlite3_column_value(pIter->pSelect, i);
@@ -163598,20 +170447,23 @@ static int rbuStep(sqlite3rbu *p){
}
}
}
-
- step_out:
return p->rc;
}
/*
** Increment the schema cookie of the main database opened by p->dbMain.
+**
+** Or, if this is an RBU vacuum, set the schema cookie of the main db
+** opened by p->dbMain to one more than the schema cookie of the main
+** db opened by p->dbRbu.
*/
static void rbuIncrSchemaCookie(sqlite3rbu *p){
if( p->rc==SQLITE_OK ){
+ sqlite3 *dbread = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
int iCookie = 1000000;
sqlite3_stmt *pStmt;
- p->rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
+ p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg,
"PRAGMA schema_version"
);
if( p->rc==SQLITE_OK ){
@@ -163639,6 +170491,7 @@ static void rbuIncrSchemaCookie(sqlite3rbu *p){
static void rbuSaveState(sqlite3rbu *p, int eStage){
if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
sqlite3_stmt *pInsert = 0;
+ rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
int rc;
assert( p->zErrmsg==0 );
@@ -163652,6 +170505,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
"(%d, %d), "
"(%d, %lld), "
"(%d, %lld), "
+ "(%d, %lld), "
"(%d, %lld) ",
p->zStateDb,
RBU_STATE_STAGE, eStage,
@@ -163660,8 +170514,9 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
RBU_STATE_ROW, p->nStep,
RBU_STATE_PROGRESS, p->nProgress,
RBU_STATE_CKPT, p->iWalCksum,
- RBU_STATE_COOKIE, (i64)p->pTargetFd->iCookie,
- RBU_STATE_OALSZ, p->iOalSz
+ RBU_STATE_COOKIE, (i64)pFd->iCookie,
+ RBU_STATE_OALSZ, p->iOalSz,
+ RBU_STATE_PHASEONESTEP, p->nPhaseOneStep
)
);
assert( pInsert==0 || rc==SQLITE_OK );
@@ -163676,20 +170531,115 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
/*
+** The second argument passed to this function is the name of a PRAGMA
+** setting - "page_size", "auto_vacuum", "user_version" or "application_id".
+** This function executes the following on sqlite3rbu.dbRbu:
+**
+** "PRAGMA main.$zPragma"
+**
+** where $zPragma is the string passed as the second argument, then
+** on sqlite3rbu.dbMain:
+**
+** "PRAGMA main.$zPragma = $val"
+**
+** where $val is the value returned by the first PRAGMA invocation.
+**
+** In short, it copies the value of the specified PRAGMA setting from
+** dbRbu to dbMain.
+*/
+static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
+ if( p->rc==SQLITE_OK ){
+ sqlite3_stmt *pPragma = 0;
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg,
+ sqlite3_mprintf("PRAGMA main.%s", zPragma)
+ );
+ if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){
+ p->rc = rbuMPrintfExec(p, p->dbMain, "PRAGMA main.%s = %d",
+ zPragma, sqlite3_column_int(pPragma, 0)
+ );
+ }
+ rbuFinalize(p, pPragma);
+ }
+}
+
+/*
+** The RBU handle passed as the only argument has just been opened and
+** the state database is empty. If this RBU handle was opened for an
+** RBU vacuum operation, create the schema in the target db.
+*/
+static void rbuCreateTargetSchema(sqlite3rbu *p){
+ sqlite3_stmt *pSql = 0;
+ sqlite3_stmt *pInsert = 0;
+
+ assert( rbuIsVacuum(p) );
+ p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
+ "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
+ " AND name!='sqlite_sequence' "
+ " ORDER BY type DESC"
+ );
+ }
+
+ while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
+ const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
+ p->rc = sqlite3_exec(p->dbMain, zSql, 0, 0, &p->zErrmsg);
+ }
+ rbuFinalize(p, pSql);
+ if( p->rc!=SQLITE_OK ) return;
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
+ "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
+ );
+ }
+
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
+ "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
+ );
+ }
+
+ while( p->rc==SQLITE_OK && sqlite3_step(pSql)==SQLITE_ROW ){
+ int i;
+ for(i=0; i<5; i++){
+ sqlite3_bind_value(pInsert, i+1, sqlite3_column_value(pSql, i));
+ }
+ sqlite3_step(pInsert);
+ p->rc = sqlite3_reset(pInsert);
+ }
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=0",0,0,&p->zErrmsg);
+ }
+
+ rbuFinalize(p, pSql);
+ rbuFinalize(p, pInsert);
+}
+
+/*
** Step the RBU object.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
+SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
if( p ){
switch( p->eStage ){
case RBU_STAGE_OAL: {
RbuObjIter *pIter = &p->objiter;
+
+ /* If this is an RBU vacuum operation and the state table was empty
+ ** when this handle was opened, create the target database schema. */
+ if( rbuIsVacuum(p) && p->nProgress==0 && p->rc==SQLITE_OK ){
+ rbuCreateTargetSchema(p);
+ rbuCopyPragma(p, "user_version");
+ rbuCopyPragma(p, "application_id");
+ }
+
while( p->rc==SQLITE_OK && pIter->zTbl ){
if( pIter->bCleanup ){
/* Clean up the rbu_tmp_xxx table for the previous table. It
** cannot be dropped as there are currently active SQL statements.
** But the contents can be deleted. */
- if( pIter->abIndexed ){
+ if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
rbuMPrintfExec(p, p->dbRbu,
"DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
);
@@ -163777,90 +170727,6 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_step(sqlite3rbu *p){
}
/*
-** Free an RbuState object allocated by rbuLoadState().
-*/
-static void rbuFreeState(RbuState *p){
- if( p ){
- sqlite3_free(p->zTbl);
- sqlite3_free(p->zIdx);
- sqlite3_free(p);
- }
-}
-
-/*
-** Allocate an RbuState object and load the contents of the rbu_state
-** table into it. Return a pointer to the new object. It is the
-** responsibility of the caller to eventually free the object using
-** sqlite3_free().
-**
-** If an error occurs, leave an error code and message in the rbu handle
-** and return NULL.
-*/
-static RbuState *rbuLoadState(sqlite3rbu *p){
- RbuState *pRet = 0;
- sqlite3_stmt *pStmt = 0;
- int rc;
- int rc2;
-
- pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
- if( pRet==0 ) return 0;
-
- rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
- sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
- );
- while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
- switch( sqlite3_column_int(pStmt, 0) ){
- case RBU_STATE_STAGE:
- pRet->eStage = sqlite3_column_int(pStmt, 1);
- if( pRet->eStage!=RBU_STAGE_OAL
- && pRet->eStage!=RBU_STAGE_MOVE
- && pRet->eStage!=RBU_STAGE_CKPT
- ){
- p->rc = SQLITE_CORRUPT;
- }
- break;
-
- case RBU_STATE_TBL:
- pRet->zTbl = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
- break;
-
- case RBU_STATE_IDX:
- pRet->zIdx = rbuStrndup((char*)sqlite3_column_text(pStmt, 1), &rc);
- break;
-
- case RBU_STATE_ROW:
- pRet->nRow = sqlite3_column_int(pStmt, 1);
- break;
-
- case RBU_STATE_PROGRESS:
- pRet->nProgress = sqlite3_column_int64(pStmt, 1);
- break;
-
- case RBU_STATE_CKPT:
- pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
- break;
-
- case RBU_STATE_COOKIE:
- pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);
- break;
-
- case RBU_STATE_OALSZ:
- pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
- break;
-
- default:
- rc = SQLITE_CORRUPT;
- break;
- }
- }
- rc2 = sqlite3_finalize(pStmt);
- if( rc==SQLITE_OK ) rc = rc2;
-
- p->rc = rc;
- return pRet;
-}
-
-/*
** Compare strings z1 and z2, returning 0 if they are identical, or non-zero
** otherwise. Either or both argument may be NULL. Two NULL values are
** considered equal, and NULL is considered distinct from all other values.
@@ -163956,18 +170822,109 @@ static void rbuDeleteVfs(sqlite3rbu *p){
}
/*
-** Open and return a new RBU handle.
+** This user-defined SQL function is invoked with a single argument - the
+** name of a table expected to appear in the target database. It returns
+** the number of auxilliary indexes on the table.
*/
-SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
+static void rbuIndexCntFunc(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx);
+ sqlite3_stmt *pStmt = 0;
+ char *zErrmsg = 0;
+ int rc;
+
+ assert( nVal==1 );
+
+ rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg,
+ sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
+ "WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
+ );
+ if( rc!=SQLITE_OK ){
+ sqlite3_result_error(pCtx, zErrmsg, -1);
+ }else{
+ int nIndex = 0;
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ nIndex = sqlite3_column_int(pStmt, 0);
+ }
+ rc = sqlite3_finalize(pStmt);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_int(pCtx, nIndex);
+ }else{
+ sqlite3_result_error(pCtx, sqlite3_errmsg(p->dbMain), -1);
+ }
+ }
+
+ sqlite3_free(zErrmsg);
+}
+
+/*
+** If the RBU database contains the rbu_count table, use it to initialize
+** the sqlite3rbu.nPhaseOneStep variable. The schema of the rbu_count table
+** is assumed to contain the same columns as:
+**
+** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
+**
+** There should be one row in the table for each data_xxx table in the
+** database. The 'tbl' column should contain the name of a data_xxx table,
+** and the cnt column the number of rows it contains.
+**
+** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
+** for all rows in the rbu_count table, where nIndex is the number of
+** indexes on the corresponding target database table.
+*/
+static void rbuInitPhaseOneSteps(sqlite3rbu *p){
+ if( p->rc==SQLITE_OK ){
+ sqlite3_stmt *pStmt = 0;
+ int bExists = 0; /* True if rbu_count exists */
+
+ p->nPhaseOneStep = -1;
+
+ p->rc = sqlite3_create_function(p->dbRbu,
+ "rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
+ );
+
+ /* Check for the rbu_count table. If it does not exist, or if an error
+ ** occurs, nPhaseOneStep will be left set to -1. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+ "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
+ );
+ }
+ if( p->rc==SQLITE_OK ){
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ bExists = 1;
+ }
+ p->rc = sqlite3_finalize(pStmt);
+ }
+
+ if( p->rc==SQLITE_OK && bExists ){
+ p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
+ "SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
+ "FROM rbu_count"
+ );
+ if( p->rc==SQLITE_OK ){
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ p->nPhaseOneStep = sqlite3_column_int64(pStmt, 0);
+ }
+ p->rc = sqlite3_finalize(pStmt);
+ }
+ }
+ }
+}
+
+
+static sqlite3rbu *openRbuHandle(
const char *zTarget,
const char *zRbu,
const char *zState
){
sqlite3rbu *p;
- size_t nTarget = strlen(zTarget);
+ size_t nTarget = zTarget ? strlen(zTarget) : 0;
size_t nRbu = strlen(zRbu);
- size_t nState = zState ? strlen(zState) : 0;
- size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1+ nState+1;
+ size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1;
p = (sqlite3rbu*)sqlite3_malloc64(nByte);
if( p ){
@@ -163977,22 +170934,23 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
memset(p, 0, sizeof(sqlite3rbu));
rbuCreateVfs(p);
- /* Open the target database */
+ /* Open the target, RBU and state databases */
if( p->rc==SQLITE_OK ){
- p->zTarget = (char*)&p[1];
- memcpy(p->zTarget, zTarget, nTarget+1);
- p->zRbu = &p->zTarget[nTarget+1];
+ char *pCsr = (char*)&p[1];
+ if( zTarget ){
+ p->zTarget = pCsr;
+ memcpy(p->zTarget, zTarget, nTarget+1);
+ pCsr += nTarget+1;
+ }
+ p->zRbu = pCsr;
memcpy(p->zRbu, zRbu, nRbu+1);
+ pCsr += nRbu+1;
if( zState ){
- p->zState = &p->zRbu[nRbu+1];
- memcpy(p->zState, zState, nState+1);
+ p->zState = rbuMPrintf(p, "%s", zState);
}
rbuOpenDatabase(p);
}
- /* If it has not already been created, create the rbu_state table */
- rbuMPrintfExec(p, p->dbRbu, RBU_CREATE_STATE, p->zStateDb);
-
if( p->rc==SQLITE_OK ){
pState = rbuLoadState(p);
assert( pState || p->rc!=SQLITE_OK );
@@ -164000,9 +170958,11 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
if( pState->eStage==0 ){
rbuDeleteOalFile(p);
+ rbuInitPhaseOneSteps(p);
p->eStage = RBU_STAGE_OAL;
}else{
p->eStage = pState->eStage;
+ p->nPhaseOneStep = pState->nPhaseOneStep;
}
p->nProgress = pState->nProgress;
p->iOalSz = pState->iOalSz;
@@ -164020,38 +170980,27 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
}
}
- if( p->rc==SQLITE_OK
+ if( p->rc==SQLITE_OK
&& (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE)
- && pState->eStage!=0 && p->pTargetFd->iCookie!=pState->iCookie
- ){
- /* At this point (pTargetFd->iCookie) contains the value of the
- ** change-counter cookie (the thing that gets incremented when a
- ** transaction is committed in rollback mode) currently stored on
- ** page 1 of the database file. */
- p->rc = SQLITE_BUSY;
- p->zErrmsg = sqlite3_mprintf("database modified during rbu update");
+ && pState->eStage!=0
+ ){
+ rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
+ if( pFd->iCookie!=pState->iCookie ){
+ /* At this point (pTargetFd->iCookie) contains the value of the
+ ** change-counter cookie (the thing that gets incremented when a
+ ** transaction is committed in rollback mode) currently stored on
+ ** page 1 of the database file. */
+ p->rc = SQLITE_BUSY;
+ p->zErrmsg = sqlite3_mprintf("database modified during rbu %s",
+ (rbuIsVacuum(p) ? "vacuum" : "update")
+ );
+ }
}
if( p->rc==SQLITE_OK ){
if( p->eStage==RBU_STAGE_OAL ){
sqlite3 *db = p->dbMain;
-
- /* Open transactions both databases. The *-oal file is opened or
- ** created at this point. */
- p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
- }
-
- /* Check if the main database is a zipvfs db. If it is, set the upper
- ** level pager to use "journal_mode=off". This prevents it from
- ** generating a large journal using a temp file. */
- if( p->rc==SQLITE_OK ){
- int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
- if( frc==SQLITE_OK ){
- p->rc = sqlite3_exec(db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
- }
- }
+ p->rc = sqlite3_exec(p->dbRbu, "BEGIN", 0, 0, &p->zErrmsg);
/* Point the object iterator at the first object */
if( p->rc==SQLITE_OK ){
@@ -164062,12 +171011,34 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
** update finished. */
if( p->rc==SQLITE_OK && p->objiter.zTbl==0 ){
p->rc = SQLITE_DONE;
- }
+ p->eStage = RBU_STAGE_DONE;
+ }else{
+ if( p->rc==SQLITE_OK && pState->eStage==0 && rbuIsVacuum(p) ){
+ rbuCopyPragma(p, "page_size");
+ rbuCopyPragma(p, "auto_vacuum");
+ }
- if( p->rc==SQLITE_OK ){
- rbuSetupOal(p, pState);
- }
+ /* Open transactions both databases. The *-oal file is opened or
+ ** created at this point. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
+ }
+
+ /* Check if the main database is a zipvfs db. If it is, set the upper
+ ** level pager to use "journal_mode=off". This prevents it from
+ ** generating a large journal using a temp file. */
+ if( p->rc==SQLITE_OK ){
+ int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
+ if( frc==SQLITE_OK ){
+ p->rc = sqlite3_exec(
+ db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg);
+ }
+ }
+ if( p->rc==SQLITE_OK ){
+ rbuSetupOal(p, pState);
+ }
+ }
}else if( p->eStage==RBU_STAGE_MOVE ){
/* no-op */
}else if( p->eStage==RBU_STAGE_CKPT ){
@@ -164085,11 +171056,49 @@ SQLITE_API sqlite3rbu *SQLITE_STDCALL sqlite3rbu_open(
return p;
}
+/*
+** Allocate and return an RBU handle with all fields zeroed except for the
+** error code, which is set to SQLITE_MISUSE.
+*/
+static sqlite3rbu *rbuMisuseError(void){
+ sqlite3rbu *pRet;
+ pRet = sqlite3_malloc64(sizeof(sqlite3rbu));
+ if( pRet ){
+ memset(pRet, 0, sizeof(sqlite3rbu));
+ pRet->rc = SQLITE_MISUSE;
+ }
+ return pRet;
+}
+
+/*
+** Open and return a new RBU handle.
+*/
+SQLITE_API sqlite3rbu *sqlite3rbu_open(
+ const char *zTarget,
+ const char *zRbu,
+ const char *zState
+){
+ if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }
+ /* TODO: Check that zTarget and zRbu are non-NULL */
+ return openRbuHandle(zTarget, zRbu, zState);
+}
+
+/*
+** Open a handle to begin or resume an RBU VACUUM operation.
+*/
+SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
+ const char *zTarget,
+ const char *zState
+){
+ if( zTarget==0 ){ return rbuMisuseError(); }
+ /* TODO: Check that both arguments are non-NULL */
+ return openRbuHandle(0, zTarget, zState);
+}
/*
** Return the database handle used by pRbu.
*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
+SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
sqlite3 *db = 0;
if( pRbu ){
db = (bRbu ? pRbu->dbRbu : pRbu->dbMain);
@@ -164105,7 +171114,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3rbu_db(sqlite3rbu *pRbu, int bRbu){
*/
static void rbuEditErrmsg(sqlite3rbu *p){
if( p->rc==SQLITE_CONSTRAINT && p->zErrmsg ){
- int i;
+ unsigned int i;
size_t nErrmsg = strlen(p->zErrmsg);
for(i=0; i<(nErrmsg-8); i++){
if( memcmp(&p->zErrmsg[i], "rbu_imp_", 8)==0 ){
@@ -164121,7 +171130,7 @@ static void rbuEditErrmsg(sqlite3rbu *p){
/*
** Close the RBU handle.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
+SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
int rc;
if( p ){
@@ -164139,9 +171148,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
/* Close any open statement handles. */
rbuObjIterFinalize(&p->objiter);
+ /* If this is an RBU vacuum handle and the vacuum has either finished
+ ** successfully or encountered an error, delete the contents of the
+ ** state table. This causes the next call to sqlite3rbu_vacuum()
+ ** specifying the current target and state databases to start a new
+ ** vacuum from scratch. */
+ if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){
+ int rc2 = sqlite3_exec(p->dbRbu, "DELETE FROM stat.rbu_state", 0, 0, 0);
+ if( p->rc==SQLITE_DONE && rc2!=SQLITE_OK ) p->rc = rc2;
+ }
+
/* Close the open database handle and VFS object. */
- sqlite3_close(p->dbMain);
sqlite3_close(p->dbRbu);
+ sqlite3_close(p->dbMain);
rbuDeleteVfs(p);
sqlite3_free(p->aBuf);
sqlite3_free(p->aFrame);
@@ -164149,6 +171168,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
rbuEditErrmsg(p);
rc = p->rc;
*pzErrmsg = p->zErrmsg;
+ sqlite3_free(p->zState);
sqlite3_free(p);
}else{
rc = SQLITE_NOMEM;
@@ -164162,13 +171182,79 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
** updates) that have been performed on the target database since the
** current RBU update was started.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3rbu_progress(sqlite3rbu *pRbu){
+SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){
return pRbu->nProgress;
}
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_savestate(sqlite3rbu *p){
+/*
+** Return permyriadage progress indications for the two main stages of
+** an RBU update.
+*/
+SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *p, int *pnOne, int *pnTwo){
+ const int MAX_PROGRESS = 10000;
+ switch( p->eStage ){
+ case RBU_STAGE_OAL:
+ if( p->nPhaseOneStep>0 ){
+ *pnOne = (int)(MAX_PROGRESS * (i64)p->nProgress/(i64)p->nPhaseOneStep);
+ }else{
+ *pnOne = -1;
+ }
+ *pnTwo = 0;
+ break;
+
+ case RBU_STAGE_MOVE:
+ *pnOne = MAX_PROGRESS;
+ *pnTwo = 0;
+ break;
+
+ case RBU_STAGE_CKPT:
+ *pnOne = MAX_PROGRESS;
+ *pnTwo = (int)(MAX_PROGRESS * (i64)p->nStep / (i64)p->nFrame);
+ break;
+
+ case RBU_STAGE_DONE:
+ *pnOne = MAX_PROGRESS;
+ *pnTwo = MAX_PROGRESS;
+ break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+/*
+** Return the current state of the RBU vacuum or update operation.
+*/
+SQLITE_API int sqlite3rbu_state(sqlite3rbu *p){
+ int aRes[] = {
+ 0, SQLITE_RBU_STATE_OAL, SQLITE_RBU_STATE_MOVE,
+ 0, SQLITE_RBU_STATE_CHECKPOINT, SQLITE_RBU_STATE_DONE
+ };
+
+ assert( RBU_STAGE_OAL==1 );
+ assert( RBU_STAGE_MOVE==2 );
+ assert( RBU_STAGE_CKPT==4 );
+ assert( RBU_STAGE_DONE==5 );
+ assert( aRes[RBU_STAGE_OAL]==SQLITE_RBU_STATE_OAL );
+ assert( aRes[RBU_STAGE_MOVE]==SQLITE_RBU_STATE_MOVE );
+ assert( aRes[RBU_STAGE_CKPT]==SQLITE_RBU_STATE_CHECKPOINT );
+ assert( aRes[RBU_STAGE_DONE]==SQLITE_RBU_STATE_DONE );
+
+ if( p->rc!=SQLITE_OK && p->rc!=SQLITE_DONE ){
+ return SQLITE_RBU_STATE_ERROR;
+ }else{
+ assert( p->rc!=SQLITE_DONE || p->eStage==RBU_STAGE_DONE );
+ assert( p->eStage==RBU_STAGE_OAL
+ || p->eStage==RBU_STAGE_MOVE
+ || p->eStage==RBU_STAGE_CKPT
+ || p->eStage==RBU_STAGE_DONE
+ );
+ return aRes[p->eStage];
+ }
+}
+
+SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
int rc = p->rc;
-
if( rc==SQLITE_DONE ) return SQLITE_OK;
assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE );
@@ -164308,6 +171394,22 @@ static u32 rbuGetU32(u8 *aBuf){
}
/*
+** Write an unsigned 32-bit value in big-endian format to the supplied
+** buffer.
+*/
+static void rbuPutU32(u8 *aBuf, u32 iVal){
+ aBuf[0] = (iVal >> 24) & 0xFF;
+ aBuf[1] = (iVal >> 16) & 0xFF;
+ aBuf[2] = (iVal >> 8) & 0xFF;
+ aBuf[3] = (iVal >> 0) & 0xFF;
+}
+
+static void rbuPutU16(u8 *aBuf, u16 iVal){
+ aBuf[0] = (iVal >> 8) & 0xFF;
+ aBuf[1] = (iVal >> 0) & 0xFF;
+}
+
+/*
** Read data from an rbuVfs-file.
*/
static int rbuVfsRead(
@@ -164332,6 +171434,35 @@ static int rbuVfsRead(
memset(zBuf, 0, iAmt);
}else{
rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
+#if 1
+ /* If this is being called to read the first page of the target
+ ** database as part of an rbu vacuum operation, synthesize the
+ ** contents of the first page if it does not yet exist. Otherwise,
+ ** SQLite will not check for a *-wal file. */
+ if( pRbu && rbuIsVacuum(pRbu)
+ && rc==SQLITE_IOERR_SHORT_READ && iOfst==0
+ && (p->openFlags & SQLITE_OPEN_MAIN_DB)
+ && pRbu->rc==SQLITE_OK
+ ){
+ sqlite3_file *pFd = (sqlite3_file*)pRbu->pRbuFd;
+ rc = pFd->pMethods->xRead(pFd, zBuf, iAmt, iOfst);
+ if( rc==SQLITE_OK ){
+ u8 *aBuf = (u8*)zBuf;
+ u32 iRoot = rbuGetU32(&aBuf[52]) ? 1 : 0;
+ rbuPutU32(&aBuf[52], iRoot); /* largest root page number */
+ rbuPutU32(&aBuf[36], 0); /* number of free pages */
+ rbuPutU32(&aBuf[32], 0); /* first page on free list trunk */
+ rbuPutU32(&aBuf[28], 1); /* size of db file in pages */
+ rbuPutU32(&aBuf[24], pRbu->pRbuFd->iCookie+1); /* Change counter */
+
+ if( iAmt>100 ){
+ memset(&aBuf[100], 0, iAmt-100);
+ rbuPutU16(&aBuf[105], iAmt & 0xFFFF);
+ aBuf[100] = 0x0D;
+ }
+ }
+ }
+#endif
}
if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
/* These look like magic numbers. But they are stable, as they are part
@@ -164406,7 +171537,20 @@ static int rbuVfsSync(sqlite3_file *pFile, int flags){
*/
static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
rbu_file *p = (rbu_file *)pFile;
- return p->pReal->pMethods->xFileSize(p->pReal, pSize);
+ int rc;
+ rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
+
+ /* If this is an RBU vacuum operation and this is the target database,
+ ** pretend that it has at least one page. Otherwise, SQLite will not
+ ** check for the existance of a *-wal file. rbuVfsRead() contains
+ ** similar logic. */
+ if( rc==SQLITE_OK && *pSize==0
+ && p->pRbu && rbuIsVacuum(p->pRbu)
+ && (p->openFlags & SQLITE_OPEN_MAIN_DB)
+ ){
+ *pSize = 1024;
+ }
+ return rc;
}
/*
@@ -164418,7 +171562,9 @@ static int rbuVfsLock(sqlite3_file *pFile, int eLock){
int rc = SQLITE_OK;
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
- if( pRbu && eLock==SQLITE_LOCK_EXCLUSIVE && pRbu->eStage!=RBU_STAGE_DONE ){
+ if( eLock==SQLITE_LOCK_EXCLUSIVE
+ && (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
+ ){
/* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this
** prevents it from checkpointing the database from sqlite3_close(). */
rc = SQLITE_BUSY;
@@ -164481,6 +171627,12 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
}
return rc;
}
+ else if( op==SQLITE_FCNTL_RBUCNT ){
+ sqlite3rbu *pRbu = (sqlite3rbu*)pArg;
+ pRbu->nRbu++;
+ pRbu->pRbuFd = p;
+ p->bNolock = 1;
+ }
rc = xControl(p->pReal, op, pArg);
if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
@@ -164639,11 +171791,38 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){
static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){
rbu_file *pDb;
sqlite3_mutex_enter(pRbuVfs->mutex);
- for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext);
+ for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){}
sqlite3_mutex_leave(pRbuVfs->mutex);
return pDb;
}
+/*
+** A main database named zName has just been opened. The following
+** function returns a pointer to a buffer owned by SQLite that contains
+** the name of the *-wal file this db connection will use. SQLite
+** happens to pass a pointer to this buffer when using xAccess()
+** or xOpen() to operate on the *-wal file.
+*/
+static const char *rbuMainToWal(const char *zName, int flags){
+ int n = (int)strlen(zName);
+ const char *z = &zName[n];
+ if( flags & SQLITE_OPEN_URI ){
+ int odd = 0;
+ while( 1 ){
+ if( z[0]==0 ){
+ odd = 1 - odd;
+ if( odd && z[1]==0 ) break;
+ }
+ z++;
+ }
+ z += 2;
+ }else{
+ while( *z==0 ) z++;
+ }
+ z += (n + 8 + 1);
+ return z;
+}
+
/*
** Open an rbu file handle.
*/
@@ -164679,6 +171858,7 @@ static int rbuVfsOpen(
rbu_file *pFd = (rbu_file *)pFile;
int rc = SQLITE_OK;
const char *zOpen = zName;
+ int oflags = flags;
memset(pFd, 0, sizeof(rbu_file));
pFd->pReal = (sqlite3_file*)&pFd[1];
@@ -164691,23 +171871,7 @@ static int rbuVfsOpen(
** the name of the *-wal file this db connection will use. SQLite
** happens to pass a pointer to this buffer when using xAccess()
** or xOpen() to operate on the *-wal file. */
- int n = (int)strlen(zName);
- const char *z = &zName[n];
- if( flags & SQLITE_OPEN_URI ){
- int odd = 0;
- while( 1 ){
- if( z[0]==0 ){
- odd = 1 - odd;
- if( odd && z[1]==0 ) break;
- }
- z++;
- }
- z += 2;
- }else{
- while( *z==0 ) z++;
- }
- z += (n + 8 + 1);
- pFd->zWal = z;
+ pFd->zWal = rbuMainToWal(zName, flags);
}
else if( flags & SQLITE_OPEN_WAL ){
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName);
@@ -164717,10 +171881,17 @@ static int rbuVfsOpen(
** code ensures that the string passed to xOpen() is terminated by a
** pair of '\0' bytes in case the VFS attempts to extract a URI
** parameter from it. */
- size_t nCopy = strlen(zName);
- char *zCopy = sqlite3_malloc64(nCopy+2);
+ const char *zBase = zName;
+ size_t nCopy;
+ char *zCopy;
+ if( rbuIsVacuum(pDb->pRbu) ){
+ zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
+ zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI);
+ }
+ nCopy = strlen(zBase);
+ zCopy = sqlite3_malloc64(nCopy+2);
if( zCopy ){
- memcpy(zCopy, zName, nCopy);
+ memcpy(zCopy, zBase, nCopy);
zCopy[nCopy-3] = 'o';
zCopy[nCopy] = '\0';
zCopy[nCopy+1] = '\0';
@@ -164735,8 +171906,17 @@ static int rbuVfsOpen(
}
}
+ if( oflags & SQLITE_OPEN_MAIN_DB
+ && sqlite3_uri_boolean(zName, "rbu_memory", 0)
+ ){
+ assert( oflags & SQLITE_OPEN_MAIN_DB );
+ oflags = SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
+ SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE;
+ zOpen = 0;
+ }
+
if( rc==SQLITE_OK ){
- rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, flags, pOutFlags);
+ rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
}
if( pFd->pReal->pMethods ){
/* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
@@ -164900,7 +172080,7 @@ static int rbuVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
** Deregister and destroy an RBU vfs created by an earlier call to
** sqlite3rbu_create_vfs().
*/
-SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName){
+SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName){
sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
if( pVfs && pVfs->xOpen==rbuVfsOpen ){
sqlite3_mutex_free(((rbu_vfs*)pVfs)->mutex);
@@ -164914,7 +172094,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3rbu_destroy_vfs(const char *zName){
** via existing VFS zParent. The new object is registered as a non-default
** VFS with SQLite before returning.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const char *zParent){
+SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent){
/* Template for VFS */
static sqlite3_vfs vfs_template = {
@@ -165056,10 +172236,10 @@ SQLITE_API int SQLITE_STDCALL sqlite3rbu_create_vfs(const char *zName, const cha
*/
#define VTAB_SCHEMA \
"CREATE TABLE xx( " \
- " name STRING, /* Name of table or index */" \
- " path INTEGER, /* Path to page from root */" \
+ " name TEXT, /* Name of table or index */" \
+ " path TEXT, /* Path to page from root */" \
" pageno INTEGER, /* Page number */" \
- " pagetype STRING, /* 'internal', 'leaf' or 'overflow' */" \
+ " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \
" ncell INTEGER, /* Cells on page (0 for overflow) */" \
" payload INTEGER, /* Bytes of payload on this page */" \
" unused INTEGER, /* Bytes of unused space on this page */" \
@@ -165160,7 +172340,7 @@ static int statConnect(
rc = sqlite3_declare_vtab(db, VTAB_SCHEMA);
if( rc==SQLITE_OK ){
pTab = (StatTable *)sqlite3_malloc64(sizeof(StatTable));
- if( pTab==0 ) rc = SQLITE_NOMEM;
+ if( pTab==0 ) rc = SQLITE_NOMEM_BKPT;
}
assert( rc==SQLITE_OK || pTab==0 );
@@ -165241,7 +172421,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
pCsr = (StatCursor *)sqlite3_malloc64(sizeof(StatCursor));
if( pCsr==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}else{
memset(pCsr, 0, sizeof(StatCursor));
pCsr->base.pVtab = pVTab;
@@ -165347,7 +172527,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt);
sqlite3BtreeLeave(pBt);
p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell));
- if( p->aCell==0 ) return SQLITE_NOMEM;
+ if( p->aCell==0 ) return SQLITE_NOMEM_BKPT;
memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell));
for(i=0; i<p->nCell; i++){
@@ -165380,7 +172560,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
pCell->nOvfl = nOvfl;
pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
- if( pCell->aOvfl==0 ) return SQLITE_NOMEM;
+ if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT;
pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]);
for(j=1; j<nOvfl; j++){
int rc;
@@ -165459,7 +172639,7 @@ statNextRestart:
pCsr->aPage[0].iCell = 0;
pCsr->aPage[0].zPath = z = sqlite3_mprintf("/");
pCsr->iPage = 0;
- if( z==0 ) rc = SQLITE_NOMEM;
+ if( z==0 ) rc = SQLITE_NOMEM_BKPT;
}else{
pCsr->isEof = 1;
return sqlite3_reset(pCsr->pStmt);
@@ -165494,7 +172674,7 @@ statNextRestart:
}
pCell->iOvfl++;
statSizeAndOffset(pCsr);
- return z==0 ? SQLITE_NOMEM : SQLITE_OK;
+ return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK;
}
if( p->iRightChildPg ) break;
p->iCell++;
@@ -165518,7 +172698,7 @@ statNextRestart:
p[1].iCell = 0;
p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell);
p->iCell++;
- if( z==0 ) rc = SQLITE_NOMEM;
+ if( z==0 ) rc = SQLITE_NOMEM_BKPT;
}
@@ -165552,7 +172732,7 @@ statNextRestart:
pCsr->nUnused = p->nUnused;
pCsr->nMxPayload = p->nMxPayload;
pCsr->zPath = z = sqlite3_mprintf("%s", p->zPath);
- if( z==0 ) rc = SQLITE_NOMEM;
+ if( z==0 ) rc = SQLITE_NOMEM_BKPT;
nPayload = 0;
for(i=0; i<p->nCell; i++){
nPayload += p->aCell[i].nLocal;
@@ -165586,7 +172766,7 @@ static int statFilter(
if( pCsr->iDb<0 ){
sqlite3_free(pCursor->pVtab->zErrMsg);
pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase);
- return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+ return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT;
}
}else{
pCsr->iDb = pTab->iDb;
@@ -165600,9 +172780,9 @@ static int statFilter(
" UNION ALL "
"SELECT name, rootpage, type"
" FROM \"%w\".%s WHERE rootpage!=0"
- " ORDER BY name", pTab->db->aDb[pCsr->iDb].zName, zMaster);
+ " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName, zMaster);
if( zSql==0 ){
- return SQLITE_NOMEM;
+ return SQLITE_NOMEM_BKPT;
}else{
rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
sqlite3_free(zSql);
@@ -165654,7 +172834,7 @@ static int statColumn(
default: { /* schema */
sqlite3 *db = sqlite3_context_db_handle(ctx);
int iDb = pCsr->iDb;
- sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC);
+ sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC);
break;
}
}
@@ -165700,6 +172880,4648 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
#endif /* SQLITE_ENABLE_DBSTAT_VTAB */
/************** End of dbstat.c **********************************************/
+/************** Begin file sqlite3session.c **********************************/
+
+#if defined(SQLITE_ENABLE_SESSION) && defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+/* #include "sqlite3session.h" */
+/* #include <assert.h> */
+/* #include <string.h> */
+
+#ifndef SQLITE_AMALGAMATION
+/* # include "sqliteInt.h" */
+/* # include "vdbeInt.h" */
+#endif
+
+typedef struct SessionTable SessionTable;
+typedef struct SessionChange SessionChange;
+typedef struct SessionBuffer SessionBuffer;
+typedef struct SessionInput SessionInput;
+
+/*
+** Minimum chunk size used by streaming versions of functions.
+*/
+#ifndef SESSIONS_STRM_CHUNK_SIZE
+# ifdef SQLITE_TEST
+# define SESSIONS_STRM_CHUNK_SIZE 64
+# else
+# define SESSIONS_STRM_CHUNK_SIZE 1024
+# endif
+#endif
+
+typedef struct SessionHook SessionHook;
+struct SessionHook {
+ void *pCtx;
+ int (*xOld)(void*,int,sqlite3_value**);
+ int (*xNew)(void*,int,sqlite3_value**);
+ int (*xCount)(void*);
+ int (*xDepth)(void*);
+};
+
+/*
+** Session handle structure.
+*/
+struct sqlite3_session {
+ sqlite3 *db; /* Database handle session is attached to */
+ char *zDb; /* Name of database session is attached to */
+ int bEnable; /* True if currently recording */
+ int bIndirect; /* True if all changes are indirect */
+ int bAutoAttach; /* True to auto-attach tables */
+ int rc; /* Non-zero if an error has occurred */
+ void *pFilterCtx; /* First argument to pass to xTableFilter */
+ int (*xTableFilter)(void *pCtx, const char *zTab);
+ sqlite3_session *pNext; /* Next session object on same db. */
+ SessionTable *pTable; /* List of attached tables */
+ SessionHook hook; /* APIs to grab new and old data with */
+};
+
+/*
+** Instances of this structure are used to build strings or binary records.
+*/
+struct SessionBuffer {
+ u8 *aBuf; /* Pointer to changeset buffer */
+ int nBuf; /* Size of buffer aBuf */
+ int nAlloc; /* Size of allocation containing aBuf */
+};
+
+/*
+** An object of this type is used internally as an abstraction for
+** input data. Input data may be supplied either as a single large buffer
+** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
+** sqlite3changeset_start_strm()).
+*/
+struct SessionInput {
+ int bNoDiscard; /* If true, discard no data */
+ int iCurrent; /* Offset in aData[] of current change */
+ int iNext; /* Offset in aData[] of next change */
+ u8 *aData; /* Pointer to buffer containing changeset */
+ int nData; /* Number of bytes in aData */
+
+ SessionBuffer buf; /* Current read buffer */
+ int (*xInput)(void*, void*, int*); /* Input stream call (or NULL) */
+ void *pIn; /* First argument to xInput */
+ int bEof; /* Set to true after xInput finished */
+};
+
+/*
+** Structure for changeset iterators.
+*/
+struct sqlite3_changeset_iter {
+ SessionInput in; /* Input buffer or stream */
+ SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */
+ int bPatchset; /* True if this is a patchset */
+ int rc; /* Iterator error code */
+ sqlite3_stmt *pConflict; /* Points to conflicting row, if any */
+ char *zTab; /* Current table */
+ int nCol; /* Number of columns in zTab */
+ int op; /* Current operation */
+ int bIndirect; /* True if current change was indirect */
+ u8 *abPK; /* Primary key array */
+ sqlite3_value **apValue; /* old.* and new.* values */
+};
+
+/*
+** Each session object maintains a set of the following structures, one
+** for each table the session object is monitoring. The structures are
+** stored in a linked list starting at sqlite3_session.pTable.
+**
+** The keys of the SessionTable.aChange[] hash table are all rows that have
+** been modified in any way since the session object was attached to the
+** table.
+**
+** The data associated with each hash-table entry is a structure containing
+** a subset of the initial values that the modified row contained at the
+** start of the session. Or no initial values if the row was inserted.
+*/
+struct SessionTable {
+ SessionTable *pNext;
+ char *zName; /* Local name of table */
+ int nCol; /* Number of columns in table zName */
+ const char **azCol; /* Column names */
+ u8 *abPK; /* Array of primary key flags */
+ int nEntry; /* Total number of entries in hash table */
+ int nChange; /* Size of apChange[] array */
+ SessionChange **apChange; /* Hash table buckets */
+};
+
+/*
+** RECORD FORMAT:
+**
+** The following record format is similar to (but not compatible with) that
+** used in SQLite database files. This format is used as part of the
+** change-set binary format, and so must be architecture independent.
+**
+** Unlike the SQLite database record format, each field is self-contained -
+** there is no separation of header and data. Each field begins with a
+** single byte describing its type, as follows:
+**
+** 0x00: Undefined value.
+** 0x01: Integer value.
+** 0x02: Real value.
+** 0x03: Text value.
+** 0x04: Blob value.
+** 0x05: SQL NULL value.
+**
+** Note that the above match the definitions of SQLITE_INTEGER, SQLITE_TEXT
+** and so on in sqlite3.h. For undefined and NULL values, the field consists
+** only of the single type byte. For other types of values, the type byte
+** is followed by:
+**
+** Text values:
+** A varint containing the number of bytes in the value (encoded using
+** UTF-8). Followed by a buffer containing the UTF-8 representation
+** of the text value. There is no nul terminator.
+**
+** Blob values:
+** A varint containing the number of bytes in the value, followed by
+** a buffer containing the value itself.
+**
+** Integer values:
+** An 8-byte big-endian integer value.
+**
+** Real values:
+** An 8-byte big-endian IEEE 754-2008 real value.
+**
+** Varint values are encoded in the same way as varints in the SQLite
+** record format.
+**
+** CHANGESET FORMAT:
+**
+** A changeset is a collection of DELETE, UPDATE and INSERT operations on
+** one or more tables. Operations on a single table are grouped together,
+** but may occur in any order (i.e. deletes, updates and inserts are all
+** mixed together).
+**
+** Each group of changes begins with a table header:
+**
+** 1 byte: Constant 0x54 (capital 'T')
+** Varint: Number of columns in the table.
+** nCol bytes: 0x01 for PK columns, 0x00 otherwise.
+** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
+**
+** Followed by one or more changes to the table.
+**
+** 1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
+** 1 byte: The "indirect-change" flag.
+** old.* record: (delete and update only)
+** new.* record: (insert and update only)
+**
+** The "old.*" and "new.*" records, if present, are N field records in the
+** format described above under "RECORD FORMAT", where N is the number of
+** columns in the table. The i'th field of each record is associated with
+** the i'th column of the table, counting from left to right in the order
+** in which columns were declared in the CREATE TABLE statement.
+**
+** The new.* record that is part of each INSERT change contains the values
+** that make up the new row. Similarly, the old.* record that is part of each
+** DELETE change contains the values that made up the row that was deleted
+** from the database. In the changeset format, the records that are part
+** of INSERT or DELETE changes never contain any undefined (type byte 0x00)
+** fields.
+**
+** Within the old.* record associated with an UPDATE change, all fields
+** associated with table columns that are not PRIMARY KEY columns and are
+** not modified by the UPDATE change are set to "undefined". Other fields
+** are set to the values that made up the row before the UPDATE that the
+** change records took place. Within the new.* record, fields associated
+** with table columns modified by the UPDATE change contain the new
+** values. Fields associated with table columns that are not modified
+** are set to "undefined".
+**
+** PATCHSET FORMAT:
+**
+** A patchset is also a collection of changes. It is similar to a changeset,
+** but leaves undefined those fields that are not useful if no conflict
+** resolution is required when applying the changeset.
+**
+** Each group of changes begins with a table header:
+**
+** 1 byte: Constant 0x50 (capital 'P')
+** Varint: Number of columns in the table.
+** nCol bytes: 0x01 for PK columns, 0x00 otherwise.
+** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated.
+**
+** Followed by one or more changes to the table.
+**
+** 1 byte: Either SQLITE_INSERT (0x12), UPDATE (0x17) or DELETE (0x09).
+** 1 byte: The "indirect-change" flag.
+** single record: (PK fields for DELETE, PK and modified fields for UPDATE,
+** full record for INSERT).
+**
+** As in the changeset format, each field of the single record that is part
+** of a patchset change is associated with the correspondingly positioned
+** table column, counting from left to right within the CREATE TABLE
+** statement.
+**
+** For a DELETE change, all fields within the record except those associated
+** with PRIMARY KEY columns are set to "undefined". The PRIMARY KEY fields
+** contain the values identifying the row to delete.
+**
+** For an UPDATE change, all fields except those associated with PRIMARY KEY
+** columns and columns that are modified by the UPDATE are set to "undefined".
+** PRIMARY KEY fields contain the values identifying the table row to update,
+** and fields associated with modified columns contain the new column values.
+**
+** The records associated with INSERT changes are in the same format as for
+** changesets. It is not possible for a record associated with an INSERT
+** change to contain a field set to "undefined".
+*/
+
+/*
+** For each row modified during a session, there exists a single instance of
+** this structure stored in a SessionTable.aChange[] hash table.
+*/
+struct SessionChange {
+ int op; /* One of UPDATE, DELETE, INSERT */
+ int bIndirect; /* True if this change is "indirect" */
+ int nRecord; /* Number of bytes in buffer aRecord[] */
+ u8 *aRecord; /* Buffer containing old.* record */
+ SessionChange *pNext; /* For hash-table collisions */
+};
+
+/*
+** Write a varint with value iVal into the buffer at aBuf. Return the
+** number of bytes written.
+*/
+static int sessionVarintPut(u8 *aBuf, int iVal){
+ return putVarint32(aBuf, iVal);
+}
+
+/*
+** Return the number of bytes required to store value iVal as a varint.
+*/
+static int sessionVarintLen(int iVal){
+ return sqlite3VarintLen(iVal);
+}
+
+/*
+** Read a varint value from aBuf[] into *piVal. Return the number of
+** bytes read.
+*/
+static int sessionVarintGet(u8 *aBuf, int *piVal){
+ return getVarint32(aBuf, *piVal);
+}
+
+/* Load an unaligned and unsigned 32-bit integer */
+#define SESSION_UINT32(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3])
+
+/*
+** Read a 64-bit big-endian integer value from buffer aRec[]. Return
+** the value read.
+*/
+static sqlite3_int64 sessionGetI64(u8 *aRec){
+ u64 x = SESSION_UINT32(aRec);
+ u32 y = SESSION_UINT32(aRec+4);
+ x = (x<<32) + y;
+ return (sqlite3_int64)x;
+}
+
+/*
+** Write a 64-bit big-endian integer value to the buffer aBuf[].
+*/
+static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
+ aBuf[0] = (i>>56) & 0xFF;
+ aBuf[1] = (i>>48) & 0xFF;
+ aBuf[2] = (i>>40) & 0xFF;
+ aBuf[3] = (i>>32) & 0xFF;
+ aBuf[4] = (i>>24) & 0xFF;
+ aBuf[5] = (i>>16) & 0xFF;
+ aBuf[6] = (i>> 8) & 0xFF;
+ aBuf[7] = (i>> 0) & 0xFF;
+}
+
+/*
+** This function is used to serialize the contents of value pValue (see
+** comment titled "RECORD FORMAT" above).
+**
+** If it is non-NULL, the serialized form of the value is written to
+** buffer aBuf. *pnWrite is set to the number of bytes written before
+** returning. Or, if aBuf is NULL, the only thing this function does is
+** set *pnWrite.
+**
+** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
+** within a call to sqlite3_value_text() (may fail if the db is utf-16))
+** SQLITE_NOMEM is returned.
+*/
+static int sessionSerializeValue(
+ u8 *aBuf, /* If non-NULL, write serialized value here */
+ sqlite3_value *pValue, /* Value to serialize */
+ int *pnWrite /* IN/OUT: Increment by bytes written */
+){
+ int nByte; /* Size of serialized value in bytes */
+
+ if( pValue ){
+ int eType; /* Value type (SQLITE_NULL, TEXT etc.) */
+
+ eType = sqlite3_value_type(pValue);
+ if( aBuf ) aBuf[0] = eType;
+
+ switch( eType ){
+ case SQLITE_NULL:
+ nByte = 1;
+ break;
+
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT:
+ if( aBuf ){
+ /* TODO: SQLite does something special to deal with mixed-endian
+ ** floating point values (e.g. ARM7). This code probably should
+ ** too. */
+ u64 i;
+ if( eType==SQLITE_INTEGER ){
+ i = (u64)sqlite3_value_int64(pValue);
+ }else{
+ double r;
+ assert( sizeof(double)==8 && sizeof(u64)==8 );
+ r = sqlite3_value_double(pValue);
+ memcpy(&i, &r, 8);
+ }
+ sessionPutI64(&aBuf[1], i);
+ }
+ nByte = 9;
+ break;
+
+ default: {
+ u8 *z;
+ int n;
+ int nVarint;
+
+ assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
+ if( eType==SQLITE_TEXT ){
+ z = (u8 *)sqlite3_value_text(pValue);
+ }else{
+ z = (u8 *)sqlite3_value_blob(pValue);
+ }
+ n = sqlite3_value_bytes(pValue);
+ if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
+ nVarint = sessionVarintLen(n);
+
+ if( aBuf ){
+ sessionVarintPut(&aBuf[1], n);
+ if( n ) memcpy(&aBuf[nVarint + 1], z, n);
+ }
+
+ nByte = 1 + nVarint + n;
+ break;
+ }
+ }
+ }else{
+ nByte = 1;
+ if( aBuf ) aBuf[0] = '\0';
+ }
+
+ if( pnWrite ) *pnWrite += nByte;
+ return SQLITE_OK;
+}
+
+
+/*
+** This macro is used to calculate hash key values for data structures. In
+** order to use this macro, the entire data structure must be represented
+** as a series of unsigned integers. In order to calculate a hash-key value
+** for a data structure represented as three such integers, the macro may
+** then be used as follows:
+**
+** int hash_key_value;
+** hash_key_value = HASH_APPEND(0, <value 1>);
+** hash_key_value = HASH_APPEND(hash_key_value, <value 2>);
+** hash_key_value = HASH_APPEND(hash_key_value, <value 3>);
+**
+** In practice, the data structures this macro is used for are the primary
+** key values of modified rows.
+*/
+#define HASH_APPEND(hash, add) ((hash) << 3) ^ (hash) ^ (unsigned int)(add)
+
+/*
+** Append the hash of the 64-bit integer passed as the second argument to the
+** hash-key value passed as the first. Return the new hash-key value.
+*/
+static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
+ h = HASH_APPEND(h, i & 0xFFFFFFFF);
+ return HASH_APPEND(h, (i>>32)&0xFFFFFFFF);
+}
+
+/*
+** Append the hash of the blob passed via the second and third arguments to
+** the hash-key value passed as the first. Return the new hash-key value.
+*/
+static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
+ int i;
+ for(i=0; i<n; i++) h = HASH_APPEND(h, z[i]);
+ return h;
+}
+
+/*
+** Append the hash of the data type passed as the second argument to the
+** hash-key value passed as the first. Return the new hash-key value.
+*/
+static unsigned int sessionHashAppendType(unsigned int h, int eType){
+ return HASH_APPEND(h, eType);
+}
+
+/*
+** This function may only be called from within a pre-update callback.
+** It calculates a hash based on the primary key values of the old.* or
+** new.* row currently available and, assuming no error occurs, writes it to
+** *piHash before returning. If the primary key contains one or more NULL
+** values, *pbNullPK is set to true before returning.
+**
+** If an error occurs, an SQLite error code is returned and the final values
+** of *piHash asn *pbNullPK are undefined. Otherwise, SQLITE_OK is returned
+** and the output variables are set as described above.
+*/
+static int sessionPreupdateHash(
+ sqlite3_session *pSession, /* Session object that owns pTab */
+ SessionTable *pTab, /* Session table handle */
+ int bNew, /* True to hash the new.* PK */
+ int *piHash, /* OUT: Hash value */
+ int *pbNullPK /* OUT: True if there are NULL values in PK */
+){
+ unsigned int h = 0; /* Hash value to return */
+ int i; /* Used to iterate through columns */
+
+ assert( *pbNullPK==0 );
+ assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
+ for(i=0; i<pTab->nCol; i++){
+ if( pTab->abPK[i] ){
+ int rc;
+ int eType;
+ sqlite3_value *pVal;
+
+ if( bNew ){
+ rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
+ }else{
+ rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
+ }
+ if( rc!=SQLITE_OK ) return rc;
+
+ eType = sqlite3_value_type(pVal);
+ h = sessionHashAppendType(h, eType);
+ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ i64 iVal;
+ if( eType==SQLITE_INTEGER ){
+ iVal = sqlite3_value_int64(pVal);
+ }else{
+ double rVal = sqlite3_value_double(pVal);
+ assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
+ memcpy(&iVal, &rVal, 8);
+ }
+ h = sessionHashAppendI64(h, iVal);
+ }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+ const u8 *z;
+ int n;
+ if( eType==SQLITE_TEXT ){
+ z = (const u8 *)sqlite3_value_text(pVal);
+ }else{
+ z = (const u8 *)sqlite3_value_blob(pVal);
+ }
+ n = sqlite3_value_bytes(pVal);
+ if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
+ h = sessionHashAppendBlob(h, n, z);
+ }else{
+ assert( eType==SQLITE_NULL );
+ *pbNullPK = 1;
+ }
+ }
+ }
+
+ *piHash = (h % pTab->nChange);
+ return SQLITE_OK;
+}
+
+/*
+** The buffer that the argument points to contains a serialized SQL value.
+** Return the number of bytes of space occupied by the value (including
+** the type byte).
+*/
+static int sessionSerialLen(u8 *a){
+ int e = *a;
+ int n;
+ if( e==0 ) return 1;
+ if( e==SQLITE_NULL ) return 1;
+ if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
+ return sessionVarintGet(&a[1], &n) + 1 + n;
+}
+
+/*
+** Based on the primary key values stored in change aRecord, calculate a
+** hash key. Assume the has table has nBucket buckets. The hash keys
+** calculated by this function are compatible with those calculated by
+** sessionPreupdateHash().
+**
+** The bPkOnly argument is non-zero if the record at aRecord[] is from
+** a patchset DELETE. In this case the non-PK fields are omitted entirely.
+*/
+static unsigned int sessionChangeHash(
+ SessionTable *pTab, /* Table handle */
+ int bPkOnly, /* Record consists of PK fields only */
+ u8 *aRecord, /* Change record */
+ int nBucket /* Assume this many buckets in hash table */
+){
+ unsigned int h = 0; /* Value to return */
+ int i; /* Used to iterate through columns */
+ u8 *a = aRecord; /* Used to iterate through change record */
+
+ for(i=0; i<pTab->nCol; i++){
+ int eType = *a;
+ int isPK = pTab->abPK[i];
+ if( bPkOnly && isPK==0 ) continue;
+
+ /* It is not possible for eType to be SQLITE_NULL here. The session
+ ** module does not record changes for rows with NULL values stored in
+ ** primary key columns. */
+ assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
+ || eType==SQLITE_TEXT || eType==SQLITE_BLOB
+ || eType==SQLITE_NULL || eType==0
+ );
+ assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
+
+ if( isPK ){
+ a++;
+ h = sessionHashAppendType(h, eType);
+ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ h = sessionHashAppendI64(h, sessionGetI64(a));
+ a += 8;
+ }else{
+ int n;
+ a += sessionVarintGet(a, &n);
+ h = sessionHashAppendBlob(h, n, a);
+ a += n;
+ }
+ }else{
+ a += sessionSerialLen(a);
+ }
+ }
+ return (h % nBucket);
+}
+
+/*
+** Arguments aLeft and aRight are pointers to change records for table pTab.
+** This function returns true if the two records apply to the same row (i.e.
+** have the same values stored in the primary key columns), or false
+** otherwise.
+*/
+static int sessionChangeEqual(
+ SessionTable *pTab, /* Table used for PK definition */
+ int bLeftPkOnly, /* True if aLeft[] contains PK fields only */
+ u8 *aLeft, /* Change record */
+ int bRightPkOnly, /* True if aRight[] contains PK fields only */
+ u8 *aRight /* Change record */
+){
+ u8 *a1 = aLeft; /* Cursor to iterate through aLeft */
+ u8 *a2 = aRight; /* Cursor to iterate through aRight */
+ int iCol; /* Used to iterate through table columns */
+
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ if( pTab->abPK[iCol] ){
+ int n1 = sessionSerialLen(a1);
+ int n2 = sessionSerialLen(a2);
+
+ if( pTab->abPK[iCol] && (n1!=n2 || memcmp(a1, a2, n1)) ){
+ return 0;
+ }
+ a1 += n1;
+ a2 += n2;
+ }else{
+ if( bLeftPkOnly==0 ) a1 += sessionSerialLen(a1);
+ if( bRightPkOnly==0 ) a2 += sessionSerialLen(a2);
+ }
+ }
+
+ return 1;
+}
+
+/*
+** Arguments aLeft and aRight both point to buffers containing change
+** records with nCol columns. This function "merges" the two records into
+** a single records which is written to the buffer at *paOut. *paOut is
+** then set to point to one byte after the last byte written before
+** returning.
+**
+** The merging of records is done as follows: For each column, if the
+** aRight record contains a value for the column, copy the value from
+** their. Otherwise, if aLeft contains a value, copy it. If neither
+** record contains a value for a given column, then neither does the
+** output record.
+*/
+static void sessionMergeRecord(
+ u8 **paOut,
+ int nCol,
+ u8 *aLeft,
+ u8 *aRight
+){
+ u8 *a1 = aLeft; /* Cursor used to iterate through aLeft */
+ u8 *a2 = aRight; /* Cursor used to iterate through aRight */
+ u8 *aOut = *paOut; /* Output cursor */
+ int iCol; /* Used to iterate from 0 to nCol */
+
+ for(iCol=0; iCol<nCol; iCol++){
+ int n1 = sessionSerialLen(a1);
+ int n2 = sessionSerialLen(a2);
+ if( *a2 ){
+ memcpy(aOut, a2, n2);
+ aOut += n2;
+ }else{
+ memcpy(aOut, a1, n1);
+ aOut += n1;
+ }
+ a1 += n1;
+ a2 += n2;
+ }
+
+ *paOut = aOut;
+}
+
+/*
+** This is a helper function used by sessionMergeUpdate().
+**
+** When this function is called, both *paOne and *paTwo point to a value
+** within a change record. Before it returns, both have been advanced so
+** as to point to the next value in the record.
+**
+** If, when this function is called, *paTwo points to a valid value (i.e.
+** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paTwo
+** pointer is returned and *pnVal is set to the number of bytes in the
+** serialized value. Otherwise, a copy of *paOne is returned and *pnVal
+** set to the number of bytes in the value at *paOne. If *paOne points
+** to the "no value" placeholder, *pnVal is set to 1. In other words:
+**
+** if( *paTwo is valid ) return *paTwo;
+** return *paOne;
+**
+*/
+static u8 *sessionMergeValue(
+ u8 **paOne, /* IN/OUT: Left-hand buffer pointer */
+ u8 **paTwo, /* IN/OUT: Right-hand buffer pointer */
+ int *pnVal /* OUT: Bytes in returned value */
+){
+ u8 *a1 = *paOne;
+ u8 *a2 = *paTwo;
+ u8 *pRet = 0;
+ int n1;
+
+ assert( a1 );
+ if( a2 ){
+ int n2 = sessionSerialLen(a2);
+ if( *a2 ){
+ *pnVal = n2;
+ pRet = a2;
+ }
+ *paTwo = &a2[n2];
+ }
+
+ n1 = sessionSerialLen(a1);
+ if( pRet==0 ){
+ *pnVal = n1;
+ pRet = a1;
+ }
+ *paOne = &a1[n1];
+
+ return pRet;
+}
+
+/*
+** This function is used by changeset_concat() to merge two UPDATE changes
+** on the same row.
+*/
+static int sessionMergeUpdate(
+ u8 **paOut, /* IN/OUT: Pointer to output buffer */
+ SessionTable *pTab, /* Table change pertains to */
+ int bPatchset, /* True if records are patchset records */
+ u8 *aOldRecord1, /* old.* record for first change */
+ u8 *aOldRecord2, /* old.* record for second change */
+ u8 *aNewRecord1, /* new.* record for first change */
+ u8 *aNewRecord2 /* new.* record for second change */
+){
+ u8 *aOld1 = aOldRecord1;
+ u8 *aOld2 = aOldRecord2;
+ u8 *aNew1 = aNewRecord1;
+ u8 *aNew2 = aNewRecord2;
+
+ u8 *aOut = *paOut;
+ int i;
+
+ if( bPatchset==0 ){
+ int bRequired = 0;
+
+ assert( aOldRecord1 && aNewRecord1 );
+
+ /* Write the old.* vector first. */
+ for(i=0; i<pTab->nCol; i++){
+ int nOld;
+ u8 *aOld;
+ int nNew;
+ u8 *aNew;
+
+ aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
+ aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
+ if( pTab->abPK[i] || nOld!=nNew || memcmp(aOld, aNew, nNew) ){
+ if( pTab->abPK[i]==0 ) bRequired = 1;
+ memcpy(aOut, aOld, nOld);
+ aOut += nOld;
+ }else{
+ *(aOut++) = '\0';
+ }
+ }
+
+ if( !bRequired ) return 0;
+ }
+
+ /* Write the new.* vector */
+ aOld1 = aOldRecord1;
+ aOld2 = aOldRecord2;
+ aNew1 = aNewRecord1;
+ aNew2 = aNewRecord2;
+ for(i=0; i<pTab->nCol; i++){
+ int nOld;
+ u8 *aOld;
+ int nNew;
+ u8 *aNew;
+
+ aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
+ aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
+ if( bPatchset==0
+ && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew)))
+ ){
+ *(aOut++) = '\0';
+ }else{
+ memcpy(aOut, aNew, nNew);
+ aOut += nNew;
+ }
+ }
+
+ *paOut = aOut;
+ return 1;
+}
+
+/*
+** This function is only called from within a pre-update-hook callback.
+** It determines if the current pre-update-hook change affects the same row
+** as the change stored in argument pChange. If so, it returns true. Otherwise
+** if the pre-update-hook does not affect the same row as pChange, it returns
+** false.
+*/
+static int sessionPreupdateEqual(
+ sqlite3_session *pSession, /* Session object that owns SessionTable */
+ SessionTable *pTab, /* Table associated with change */
+ SessionChange *pChange, /* Change to compare to */
+ int op /* Current pre-update operation */
+){
+ int iCol; /* Used to iterate through columns */
+ u8 *a = pChange->aRecord; /* Cursor used to scan change record */
+
+ assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ if( !pTab->abPK[iCol] ){
+ a += sessionSerialLen(a);
+ }else{
+ sqlite3_value *pVal; /* Value returned by preupdate_new/old */
+ int rc; /* Error code from preupdate_new/old */
+ int eType = *a++; /* Type of value from change record */
+
+ /* The following calls to preupdate_new() and preupdate_old() can not
+ ** fail. This is because they cache their return values, and by the
+ ** time control flows to here they have already been called once from
+ ** within sessionPreupdateHash(). The first two asserts below verify
+ ** this (that the method has already been called). */
+ if( op==SQLITE_INSERT ){
+ /* assert( db->pPreUpdate->pNewUnpacked || db->pPreUpdate->aNew ); */
+ rc = pSession->hook.xNew(pSession->hook.pCtx, iCol, &pVal);
+ }else{
+ /* assert( db->pPreUpdate->pUnpacked ); */
+ rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
+ }
+ assert( rc==SQLITE_OK );
+ if( sqlite3_value_type(pVal)!=eType ) return 0;
+
+ /* A SessionChange object never has a NULL value in a PK column */
+ assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
+ || eType==SQLITE_BLOB || eType==SQLITE_TEXT
+ );
+
+ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ i64 iVal = sessionGetI64(a);
+ a += 8;
+ if( eType==SQLITE_INTEGER ){
+ if( sqlite3_value_int64(pVal)!=iVal ) return 0;
+ }else{
+ double rVal;
+ assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
+ memcpy(&rVal, &iVal, 8);
+ if( sqlite3_value_double(pVal)!=rVal ) return 0;
+ }
+ }else{
+ int n;
+ const u8 *z;
+ a += sessionVarintGet(a, &n);
+ if( sqlite3_value_bytes(pVal)!=n ) return 0;
+ if( eType==SQLITE_TEXT ){
+ z = sqlite3_value_text(pVal);
+ }else{
+ z = sqlite3_value_blob(pVal);
+ }
+ if( memcmp(a, z, n) ) return 0;
+ a += n;
+ break;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/*
+** If required, grow the hash table used to store changes on table pTab
+** (part of the session pSession). If a fatal OOM error occurs, set the
+** session object to failed and return SQLITE_ERROR. Otherwise, return
+** SQLITE_OK.
+**
+** It is possible that a non-fatal OOM error occurs in this function. In
+** that case the hash-table does not grow, but SQLITE_OK is returned anyway.
+** Growing the hash table in this case is a performance optimization only,
+** it is not required for correct operation.
+*/
+static int sessionGrowHash(int bPatchset, SessionTable *pTab){
+ if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
+ int i;
+ SessionChange **apNew;
+ int nNew = (pTab->nChange ? pTab->nChange : 128) * 2;
+
+ apNew = (SessionChange **)sqlite3_malloc(sizeof(SessionChange *) * nNew);
+ if( apNew==0 ){
+ if( pTab->nChange==0 ){
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+ }
+ memset(apNew, 0, sizeof(SessionChange *) * nNew);
+
+ for(i=0; i<pTab->nChange; i++){
+ SessionChange *p;
+ SessionChange *pNext;
+ for(p=pTab->apChange[i]; p; p=pNext){
+ int bPkOnly = (p->op==SQLITE_DELETE && bPatchset);
+ int iHash = sessionChangeHash(pTab, bPkOnly, p->aRecord, nNew);
+ pNext = p->pNext;
+ p->pNext = apNew[iHash];
+ apNew[iHash] = p;
+ }
+ }
+
+ sqlite3_free(pTab->apChange);
+ pTab->nChange = nNew;
+ pTab->apChange = apNew;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** This function queries the database for the names of the columns of table
+** zThis, in schema zDb. It is expected that the table has nCol columns. If
+** not, SQLITE_SCHEMA is returned and none of the output variables are
+** populated.
+**
+** Otherwise, if they are not NULL, variable *pnCol is set to the number
+** of columns in the database table and variable *pzTab is set to point to a
+** nul-terminated copy of the table name. *pazCol (if not NULL) is set to
+** point to an array of pointers to column names. And *pabPK (again, if not
+** NULL) is set to point to an array of booleans - true if the corresponding
+** column is part of the primary key.
+**
+** For example, if the table is declared as:
+**
+** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
+**
+** Then the four output variables are populated as follows:
+**
+** *pnCol = 4
+** *pzTab = "tbl1"
+** *pazCol = {"w", "x", "y", "z"}
+** *pabPK = {1, 0, 0, 1}
+**
+** All returned buffers are part of the same single allocation, which must
+** be freed using sqlite3_free() by the caller. If pazCol was not NULL, then
+** pointer *pazCol should be freed to release all memory. Otherwise, pointer
+** *pabPK. It is illegal for both pazCol and pabPK to be NULL.
+*/
+static int sessionTableInfo(
+ sqlite3 *db, /* Database connection */
+ const char *zDb, /* Name of attached database (e.g. "main") */
+ const char *zThis, /* Table name */
+ int *pnCol, /* OUT: number of columns */
+ const char **pzTab, /* OUT: Copy of zThis */
+ const char ***pazCol, /* OUT: Array of column names for table */
+ u8 **pabPK /* OUT: Array of booleans - true for PK col */
+){
+ char *zPragma;
+ sqlite3_stmt *pStmt;
+ int rc;
+ int nByte;
+ int nDbCol = 0;
+ int nThis;
+ int i;
+ u8 *pAlloc = 0;
+ char **azCol = 0;
+ u8 *abPK = 0;
+
+ assert( pazCol && pabPK );
+
+ nThis = sqlite3Strlen30(zThis);
+ zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
+ if( !zPragma ) return SQLITE_NOMEM;
+
+ rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
+ sqlite3_free(zPragma);
+ if( rc!=SQLITE_OK ) return rc;
+
+ nByte = nThis + 1;
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ nByte += sqlite3_column_bytes(pStmt, 1);
+ nDbCol++;
+ }
+ rc = sqlite3_reset(pStmt);
+
+ if( rc==SQLITE_OK ){
+ nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
+ pAlloc = sqlite3_malloc(nByte);
+ if( pAlloc==0 ){
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ azCol = (char **)pAlloc;
+ pAlloc = (u8 *)&azCol[nDbCol];
+ abPK = (u8 *)pAlloc;
+ pAlloc = &abPK[nDbCol];
+ if( pzTab ){
+ memcpy(pAlloc, zThis, nThis+1);
+ *pzTab = (char *)pAlloc;
+ pAlloc += nThis+1;
+ }
+
+ i = 0;
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ int nName = sqlite3_column_bytes(pStmt, 1);
+ const unsigned char *zName = sqlite3_column_text(pStmt, 1);
+ if( zName==0 ) break;
+ memcpy(pAlloc, zName, nName+1);
+ azCol[i] = (char *)pAlloc;
+ pAlloc += nName+1;
+ abPK[i] = sqlite3_column_int(pStmt, 5);
+ i++;
+ }
+ rc = sqlite3_reset(pStmt);
+
+ }
+
+ /* If successful, populate the output variables. Otherwise, zero them and
+ ** free any allocation made. An error code will be returned in this case.
+ */
+ if( rc==SQLITE_OK ){
+ *pazCol = (const char **)azCol;
+ *pabPK = abPK;
+ *pnCol = nDbCol;
+ }else{
+ *pazCol = 0;
+ *pabPK = 0;
+ *pnCol = 0;
+ if( pzTab ) *pzTab = 0;
+ sqlite3_free(azCol);
+ }
+ sqlite3_finalize(pStmt);
+ return rc;
+}
+
+/*
+** This function is only called from within a pre-update handler for a
+** write to table pTab, part of session pSession. If this is the first
+** write to this table, initalize the SessionTable.nCol, azCol[] and
+** abPK[] arrays accordingly.
+**
+** If an error occurs, an error code is stored in sqlite3_session.rc and
+** non-zero returned. Or, if no error occurs but the table has no primary
+** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to
+** indicate that updates on this table should be ignored. SessionTable.abPK
+** is set to NULL in this case.
+*/
+static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
+ if( pTab->nCol==0 ){
+ u8 *abPK;
+ assert( pTab->azCol==0 || pTab->abPK==0 );
+ pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
+ pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
+ );
+ if( pSession->rc==SQLITE_OK ){
+ int i;
+ for(i=0; i<pTab->nCol; i++){
+ if( abPK[i] ){
+ pTab->abPK = abPK;
+ break;
+ }
+ }
+ }
+ }
+ return (pSession->rc || pTab->abPK==0);
+}
+
+/*
+** This function is only called from with a pre-update-hook reporting a
+** change on table pTab (attached to session pSession). The type of change
+** (UPDATE, INSERT, DELETE) is specified by the first argument.
+**
+** Unless one is already present or an error occurs, an entry is added
+** to the changed-rows hash table associated with table pTab.
+*/
+static void sessionPreupdateOneChange(
+ int op, /* One of SQLITE_UPDATE, INSERT, DELETE */
+ sqlite3_session *pSession, /* Session object pTab is attached to */
+ SessionTable *pTab /* Table that change applies to */
+){
+ int iHash;
+ int bNull = 0;
+ int rc = SQLITE_OK;
+
+ if( pSession->rc ) return;
+
+ /* Load table details if required */
+ if( sessionInitTable(pSession, pTab) ) return;
+
+ /* Check the number of columns in this xPreUpdate call matches the
+ ** number of columns in the table. */
+ if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
+ pSession->rc = SQLITE_SCHEMA;
+ return;
+ }
+
+ /* Grow the hash table if required */
+ if( sessionGrowHash(0, pTab) ){
+ pSession->rc = SQLITE_NOMEM;
+ return;
+ }
+
+ /* Calculate the hash-key for this change. If the primary key of the row
+ ** includes a NULL value, exit early. Such changes are ignored by the
+ ** session module. */
+ rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
+ if( rc!=SQLITE_OK ) goto error_out;
+
+ if( bNull==0 ){
+ /* Search the hash table for an existing record for this row. */
+ SessionChange *pC;
+ for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
+ if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
+ }
+
+ if( pC==0 ){
+ /* Create a new change object containing all the old values (if
+ ** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
+ ** values (if this is an INSERT). */
+ SessionChange *pChange; /* New change object */
+ int nByte; /* Number of bytes to allocate */
+ int i; /* Used to iterate through columns */
+
+ assert( rc==SQLITE_OK );
+ pTab->nEntry++;
+
+ /* Figure out how large an allocation is required */
+ nByte = sizeof(SessionChange);
+ for(i=0; i<pTab->nCol; i++){
+ sqlite3_value *p = 0;
+ if( op!=SQLITE_INSERT ){
+ TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
+ assert( trc==SQLITE_OK );
+ }else if( pTab->abPK[i] ){
+ TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
+ assert( trc==SQLITE_OK );
+ }
+
+ /* This may fail if SQLite value p contains a utf-16 string that must
+ ** be converted to utf-8 and an OOM error occurs while doing so. */
+ rc = sessionSerializeValue(0, p, &nByte);
+ if( rc!=SQLITE_OK ) goto error_out;
+ }
+
+ /* Allocate the change object */
+ pChange = (SessionChange *)sqlite3_malloc(nByte);
+ if( !pChange ){
+ rc = SQLITE_NOMEM;
+ goto error_out;
+ }else{
+ memset(pChange, 0, sizeof(SessionChange));
+ pChange->aRecord = (u8 *)&pChange[1];
+ }
+
+ /* Populate the change object. None of the preupdate_old(),
+ ** preupdate_new() or SerializeValue() calls below may fail as all
+ ** required values and encodings have already been cached in memory.
+ ** It is not possible for an OOM to occur in this block. */
+ nByte = 0;
+ for(i=0; i<pTab->nCol; i++){
+ sqlite3_value *p = 0;
+ if( op!=SQLITE_INSERT ){
+ pSession->hook.xOld(pSession->hook.pCtx, i, &p);
+ }else if( pTab->abPK[i] ){
+ pSession->hook.xNew(pSession->hook.pCtx, i, &p);
+ }
+ sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
+ }
+
+ /* Add the change to the hash-table */
+ if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
+ pChange->bIndirect = 1;
+ }
+ pChange->nRecord = nByte;
+ pChange->op = op;
+ pChange->pNext = pTab->apChange[iHash];
+ pTab->apChange[iHash] = pChange;
+
+ }else if( pC->bIndirect ){
+ /* If the existing change is considered "indirect", but this current
+ ** change is "direct", mark the change object as direct. */
+ if( pSession->hook.xDepth(pSession->hook.pCtx)==0
+ && pSession->bIndirect==0
+ ){
+ pC->bIndirect = 0;
+ }
+ }
+ }
+
+ /* If an error has occurred, mark the session object as failed. */
+ error_out:
+ if( rc!=SQLITE_OK ){
+ pSession->rc = rc;
+ }
+}
+
+static int sessionFindTable(
+ sqlite3_session *pSession,
+ const char *zName,
+ SessionTable **ppTab
+){
+ int rc = SQLITE_OK;
+ int nName = sqlite3Strlen30(zName);
+ SessionTable *pRet;
+
+ /* Search for an existing table */
+ for(pRet=pSession->pTable; pRet; pRet=pRet->pNext){
+ if( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ) break;
+ }
+
+ if( pRet==0 && pSession->bAutoAttach ){
+ /* If there is a table-filter configured, invoke it. If it returns 0,
+ ** do not automatically add the new table. */
+ if( pSession->xTableFilter==0
+ || pSession->xTableFilter(pSession->pFilterCtx, zName)
+ ){
+ rc = sqlite3session_attach(pSession, zName);
+ if( rc==SQLITE_OK ){
+ for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext);
+ assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
+ }
+ }
+ }
+
+ assert( rc==SQLITE_OK || pRet==0 );
+ *ppTab = pRet;
+ return rc;
+}
+
+/*
+** The 'pre-update' hook registered by this module with SQLite databases.
+*/
+static void xPreUpdate(
+ void *pCtx, /* Copy of third arg to preupdate_hook() */
+ sqlite3 *db, /* Database handle */
+ int op, /* SQLITE_UPDATE, DELETE or INSERT */
+ char const *zDb, /* Database name */
+ char const *zName, /* Table name */
+ sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */
+ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */
+){
+ sqlite3_session *pSession;
+ int nDb = sqlite3Strlen30(zDb);
+
+ assert( sqlite3_mutex_held(db->mutex) );
+
+ for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
+ SessionTable *pTab;
+
+ /* If this session is attached to a different database ("main", "temp"
+ ** etc.), or if it is not currently enabled, there is nothing to do. Skip
+ ** to the next session object attached to this database. */
+ if( pSession->bEnable==0 ) continue;
+ if( pSession->rc ) continue;
+ if( sqlite3_strnicmp(zDb, pSession->zDb, nDb+1) ) continue;
+
+ pSession->rc = sessionFindTable(pSession, zName, &pTab);
+ if( pTab ){
+ assert( pSession->rc==SQLITE_OK );
+ sessionPreupdateOneChange(op, pSession, pTab);
+ if( op==SQLITE_UPDATE ){
+ sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
+ }
+ }
+ }
+}
+
+/*
+** The pre-update hook implementations.
+*/
+static int sessionPreupdateOld(void *pCtx, int iVal, sqlite3_value **ppVal){
+ return sqlite3_preupdate_old((sqlite3*)pCtx, iVal, ppVal);
+}
+static int sessionPreupdateNew(void *pCtx, int iVal, sqlite3_value **ppVal){
+ return sqlite3_preupdate_new((sqlite3*)pCtx, iVal, ppVal);
+}
+static int sessionPreupdateCount(void *pCtx){
+ return sqlite3_preupdate_count((sqlite3*)pCtx);
+}
+static int sessionPreupdateDepth(void *pCtx){
+ return sqlite3_preupdate_depth((sqlite3*)pCtx);
+}
+
+/*
+** Install the pre-update hooks on the session object passed as the only
+** argument.
+*/
+static void sessionPreupdateHooks(
+ sqlite3_session *pSession
+){
+ pSession->hook.pCtx = (void*)pSession->db;
+ pSession->hook.xOld = sessionPreupdateOld;
+ pSession->hook.xNew = sessionPreupdateNew;
+ pSession->hook.xCount = sessionPreupdateCount;
+ pSession->hook.xDepth = sessionPreupdateDepth;
+}
+
+typedef struct SessionDiffCtx SessionDiffCtx;
+struct SessionDiffCtx {
+ sqlite3_stmt *pStmt;
+ int nOldOff;
+};
+
+/*
+** The diff hook implementations.
+*/
+static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
+ SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
+ *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
+ return SQLITE_OK;
+}
+static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
+ SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
+ *ppVal = sqlite3_column_value(p->pStmt, iVal);
+ return SQLITE_OK;
+}
+static int sessionDiffCount(void *pCtx){
+ SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
+ return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
+}
+static int sessionDiffDepth(void *pCtx){
+ return 0;
+}
+
+/*
+** Install the diff hooks on the session object passed as the only
+** argument.
+*/
+static void sessionDiffHooks(
+ sqlite3_session *pSession,
+ SessionDiffCtx *pDiffCtx
+){
+ pSession->hook.pCtx = (void*)pDiffCtx;
+ pSession->hook.xOld = sessionDiffOld;
+ pSession->hook.xNew = sessionDiffNew;
+ pSession->hook.xCount = sessionDiffCount;
+ pSession->hook.xDepth = sessionDiffDepth;
+}
+
+static char *sessionExprComparePK(
+ int nCol,
+ const char *zDb1, const char *zDb2,
+ const char *zTab,
+ const char **azCol, u8 *abPK
+){
+ int i;
+ const char *zSep = "";
+ char *zRet = 0;
+
+ for(i=0; i<nCol; i++){
+ if( abPK[i] ){
+ zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"=\"%w\".\"%w\".\"%w\"",
+ zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
+ );
+ zSep = " AND ";
+ if( zRet==0 ) break;
+ }
+ }
+
+ return zRet;
+}
+
+static char *sessionExprCompareOther(
+ int nCol,
+ const char *zDb1, const char *zDb2,
+ const char *zTab,
+ const char **azCol, u8 *abPK
+){
+ int i;
+ const char *zSep = "";
+ char *zRet = 0;
+ int bHave = 0;
+
+ for(i=0; i<nCol; i++){
+ if( abPK[i]==0 ){
+ bHave = 1;
+ zRet = sqlite3_mprintf(
+ "%z%s\"%w\".\"%w\".\"%w\" IS NOT \"%w\".\"%w\".\"%w\"",
+ zRet, zSep, zDb1, zTab, azCol[i], zDb2, zTab, azCol[i]
+ );
+ zSep = " OR ";
+ if( zRet==0 ) break;
+ }
+ }
+
+ if( bHave==0 ){
+ assert( zRet==0 );
+ zRet = sqlite3_mprintf("0");
+ }
+
+ return zRet;
+}
+
+static char *sessionSelectFindNew(
+ int nCol,
+ const char *zDb1, /* Pick rows in this db only */
+ const char *zDb2, /* But not in this one */
+ const char *zTbl, /* Table name */
+ const char *zExpr
+){
+ char *zRet = sqlite3_mprintf(
+ "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
+ " SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
+ ")",
+ zDb1, zTbl, zDb2, zTbl, zExpr
+ );
+ return zRet;
+}
+
+static int sessionDiffFindNew(
+ int op,
+ sqlite3_session *pSession,
+ SessionTable *pTab,
+ const char *zDb1,
+ const char *zDb2,
+ char *zExpr
+){
+ int rc = SQLITE_OK;
+ char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr);
+
+ if( zStmt==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ sqlite3_stmt *pStmt;
+ rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
+ if( rc==SQLITE_OK ){
+ SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
+ pDiffCtx->pStmt = pStmt;
+ pDiffCtx->nOldOff = 0;
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ sessionPreupdateOneChange(op, pSession, pTab);
+ }
+ rc = sqlite3_finalize(pStmt);
+ }
+ sqlite3_free(zStmt);
+ }
+
+ return rc;
+}
+
+static int sessionDiffFindModified(
+ sqlite3_session *pSession,
+ SessionTable *pTab,
+ const char *zFrom,
+ const char *zExpr
+){
+ int rc = SQLITE_OK;
+
+ char *zExpr2 = sessionExprCompareOther(pTab->nCol,
+ pSession->zDb, zFrom, pTab->zName, pTab->azCol, pTab->abPK
+ );
+ if( zExpr2==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ char *zStmt = sqlite3_mprintf(
+ "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
+ pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
+ );
+ if( zStmt==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ sqlite3_stmt *pStmt;
+ rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0);
+
+ if( rc==SQLITE_OK ){
+ SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
+ pDiffCtx->pStmt = pStmt;
+ pDiffCtx->nOldOff = pTab->nCol;
+ while( SQLITE_ROW==sqlite3_step(pStmt) ){
+ sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
+ }
+ rc = sqlite3_finalize(pStmt);
+ }
+ sqlite3_free(zStmt);
+ }
+ }
+
+ return rc;
+}
+
+SQLITE_API int sqlite3session_diff(
+ sqlite3_session *pSession,
+ const char *zFrom,
+ const char *zTbl,
+ char **pzErrMsg
+){
+ const char *zDb = pSession->zDb;
+ int rc = pSession->rc;
+ SessionDiffCtx d;
+
+ memset(&d, 0, sizeof(d));
+ sessionDiffHooks(pSession, &d);
+
+ sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
+ if( pzErrMsg ) *pzErrMsg = 0;
+ if( rc==SQLITE_OK ){
+ char *zExpr = 0;
+ sqlite3 *db = pSession->db;
+ SessionTable *pTo; /* Table zTbl */
+
+ /* Locate and if necessary initialize the target table object */
+ rc = sessionFindTable(pSession, zTbl, &pTo);
+ if( pTo==0 ) goto diff_out;
+ if( sessionInitTable(pSession, pTo) ){
+ rc = pSession->rc;
+ goto diff_out;
+ }
+
+ /* Check the table schemas match */
+ if( rc==SQLITE_OK ){
+ int bHasPk = 0;
+ int bMismatch = 0;
+ int nCol; /* Columns in zFrom.zTbl */
+ u8 *abPK;
+ const char **azCol = 0;
+ rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
+ if( rc==SQLITE_OK ){
+ if( pTo->nCol!=nCol ){
+ bMismatch = 1;
+ }else{
+ int i;
+ for(i=0; i<nCol; i++){
+ if( pTo->abPK[i]!=abPK[i] ) bMismatch = 1;
+ if( sqlite3_stricmp(azCol[i], pTo->azCol[i]) ) bMismatch = 1;
+ if( abPK[i] ) bHasPk = 1;
+ }
+ }
+
+ }
+ sqlite3_free((char*)azCol);
+ if( bMismatch ){
+ *pzErrMsg = sqlite3_mprintf("table schemas do not match");
+ rc = SQLITE_SCHEMA;
+ }
+ if( bHasPk==0 ){
+ /* Ignore tables with no primary keys */
+ goto diff_out;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ zExpr = sessionExprComparePK(pTo->nCol,
+ zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK
+ );
+ }
+
+ /* Find new rows */
+ if( rc==SQLITE_OK ){
+ rc = sessionDiffFindNew(SQLITE_INSERT, pSession, pTo, zDb, zFrom, zExpr);
+ }
+
+ /* Find old rows */
+ if( rc==SQLITE_OK ){
+ rc = sessionDiffFindNew(SQLITE_DELETE, pSession, pTo, zFrom, zDb, zExpr);
+ }
+
+ /* Find modified rows */
+ if( rc==SQLITE_OK ){
+ rc = sessionDiffFindModified(pSession, pTo, zFrom, zExpr);
+ }
+
+ sqlite3_free(zExpr);
+ }
+
+ diff_out:
+ sessionPreupdateHooks(pSession);
+ sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+ return rc;
+}
+
+/*
+** Create a session object. This session object will record changes to
+** database zDb attached to connection db.
+*/
+SQLITE_API int sqlite3session_create(
+ sqlite3 *db, /* Database handle */
+ const char *zDb, /* Name of db (e.g. "main") */
+ sqlite3_session **ppSession /* OUT: New session object */
+){
+ sqlite3_session *pNew; /* Newly allocated session object */
+ sqlite3_session *pOld; /* Session object already attached to db */
+ int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */
+
+ /* Zero the output value in case an error occurs. */
+ *ppSession = 0;
+
+ /* Allocate and populate the new session object. */
+ pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
+ if( !pNew ) return SQLITE_NOMEM;
+ memset(pNew, 0, sizeof(sqlite3_session));
+ pNew->db = db;
+ pNew->zDb = (char *)&pNew[1];
+ pNew->bEnable = 1;
+ memcpy(pNew->zDb, zDb, nDb+1);
+ sessionPreupdateHooks(pNew);
+
+ /* Add the new session object to the linked list of session objects
+ ** attached to database handle $db. Do this under the cover of the db
+ ** handle mutex. */
+ sqlite3_mutex_enter(sqlite3_db_mutex(db));
+ pOld = (sqlite3_session*)sqlite3_preupdate_hook(db, xPreUpdate, (void*)pNew);
+ pNew->pNext = pOld;
+ sqlite3_mutex_leave(sqlite3_db_mutex(db));
+
+ *ppSession = pNew;
+ return SQLITE_OK;
+}
+
+/*
+** Free the list of table objects passed as the first argument. The contents
+** of the changed-rows hash tables are also deleted.
+*/
+static void sessionDeleteTable(SessionTable *pList){
+ SessionTable *pNext;
+ SessionTable *pTab;
+
+ for(pTab=pList; pTab; pTab=pNext){
+ int i;
+ pNext = pTab->pNext;
+ for(i=0; i<pTab->nChange; i++){
+ SessionChange *p;
+ SessionChange *pNextChange;
+ for(p=pTab->apChange[i]; p; p=pNextChange){
+ pNextChange = p->pNext;
+ sqlite3_free(p);
+ }
+ }
+ sqlite3_free((char*)pTab->azCol); /* cast works around VC++ bug */
+ sqlite3_free(pTab->apChange);
+ sqlite3_free(pTab);
+ }
+}
+
+/*
+** Delete a session object previously allocated using sqlite3session_create().
+*/
+SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
+ sqlite3 *db = pSession->db;
+ sqlite3_session *pHead;
+ sqlite3_session **pp;
+
+ /* Unlink the session from the linked list of sessions attached to the
+ ** database handle. Hold the db mutex while doing so. */
+ sqlite3_mutex_enter(sqlite3_db_mutex(db));
+ pHead = (sqlite3_session*)sqlite3_preupdate_hook(db, 0, 0);
+ for(pp=&pHead; ALWAYS((*pp)!=0); pp=&((*pp)->pNext)){
+ if( (*pp)==pSession ){
+ *pp = (*pp)->pNext;
+ if( pHead ) sqlite3_preupdate_hook(db, xPreUpdate, (void*)pHead);
+ break;
+ }
+ }
+ sqlite3_mutex_leave(sqlite3_db_mutex(db));
+
+ /* Delete all attached table objects. And the contents of their
+ ** associated hash-tables. */
+ sessionDeleteTable(pSession->pTable);
+
+ /* Free the session object itself. */
+ sqlite3_free(pSession);
+}
+
+/*
+** Set a table filter on a Session Object.
+*/
+SQLITE_API void sqlite3session_table_filter(
+ sqlite3_session *pSession,
+ int(*xFilter)(void*, const char*),
+ void *pCtx /* First argument passed to xFilter */
+){
+ pSession->bAutoAttach = 1;
+ pSession->pFilterCtx = pCtx;
+ pSession->xTableFilter = xFilter;
+}
+
+/*
+** Attach a table to a session. All subsequent changes made to the table
+** while the session object is enabled will be recorded.
+**
+** Only tables that have a PRIMARY KEY defined may be attached. It does
+** not matter if the PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias)
+** or not.
+*/
+SQLITE_API int sqlite3session_attach(
+ sqlite3_session *pSession, /* Session object */
+ const char *zName /* Table name */
+){
+ int rc = SQLITE_OK;
+ sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
+
+ if( !zName ){
+ pSession->bAutoAttach = 1;
+ }else{
+ SessionTable *pTab; /* New table object (if required) */
+ int nName; /* Number of bytes in string zName */
+
+ /* First search for an existing entry. If one is found, this call is
+ ** a no-op. Return early. */
+ nName = sqlite3Strlen30(zName);
+ for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
+ if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
+ }
+
+ if( !pTab ){
+ /* Allocate new SessionTable object. */
+ pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
+ if( !pTab ){
+ rc = SQLITE_NOMEM;
+ }else{
+ /* Populate the new SessionTable object and link it into the list.
+ ** The new object must be linked onto the end of the list, not
+ ** simply added to the start of it in order to ensure that tables
+ ** appear in the correct order when a changeset or patchset is
+ ** eventually generated. */
+ SessionTable **ppTab;
+ memset(pTab, 0, sizeof(SessionTable));
+ pTab->zName = (char *)&pTab[1];
+ memcpy(pTab->zName, zName, nName+1);
+ for(ppTab=&pSession->pTable; *ppTab; ppTab=&(*ppTab)->pNext);
+ *ppTab = pTab;
+ }
+ }
+ }
+
+ sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+ return rc;
+}
+
+/*
+** Ensure that there is room in the buffer to append nByte bytes of data.
+** If not, use sqlite3_realloc() to grow the buffer so that there is.
+**
+** If successful, return zero. Otherwise, if an OOM condition is encountered,
+** set *pRc to SQLITE_NOMEM and return non-zero.
+*/
+static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){
+ if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){
+ u8 *aNew;
+ int nNew = p->nAlloc ? p->nAlloc : 128;
+ do {
+ nNew = nNew*2;
+ }while( nNew<(p->nBuf+nByte) );
+
+ aNew = (u8 *)sqlite3_realloc(p->aBuf, nNew);
+ if( 0==aNew ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ p->aBuf = aNew;
+ p->nAlloc = nNew;
+ }
+ }
+ return (*pRc!=SQLITE_OK);
+}
+
+/*
+** Append the value passed as the second argument to the buffer passed
+** as the first.
+**
+** This function is a no-op if *pRc is non-zero when it is called.
+** Otherwise, if an error occurs, *pRc is set to an SQLite error code
+** before returning.
+*/
+static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
+ int rc = *pRc;
+ if( rc==SQLITE_OK ){
+ int nByte = 0;
+ rc = sessionSerializeValue(0, pVal, &nByte);
+ sessionBufferGrow(p, nByte, &rc);
+ if( rc==SQLITE_OK ){
+ rc = sessionSerializeValue(&p->aBuf[p->nBuf], pVal, 0);
+ p->nBuf += nByte;
+ }else{
+ *pRc = rc;
+ }
+ }
+}
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a single byte to the buffer.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
+ if( 0==sessionBufferGrow(p, 1, pRc) ){
+ p->aBuf[p->nBuf++] = v;
+ }
+}
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a single varint to the buffer.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){
+ if( 0==sessionBufferGrow(p, 9, pRc) ){
+ p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
+ }
+}
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a blob of data to the buffer.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendBlob(
+ SessionBuffer *p,
+ const u8 *aBlob,
+ int nBlob,
+ int *pRc
+){
+ if( nBlob>0 && 0==sessionBufferGrow(p, nBlob, pRc) ){
+ memcpy(&p->aBuf[p->nBuf], aBlob, nBlob);
+ p->nBuf += nBlob;
+ }
+}
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append a string to the buffer. All bytes in the string
+** up to (but not including) the nul-terminator are written to the buffer.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendStr(
+ SessionBuffer *p,
+ const char *zStr,
+ int *pRc
+){
+ int nStr = sqlite3Strlen30(zStr);
+ if( 0==sessionBufferGrow(p, nStr, pRc) ){
+ memcpy(&p->aBuf[p->nBuf], zStr, nStr);
+ p->nBuf += nStr;
+ }
+}
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append the string representation of integer iVal
+** to the buffer. No nul-terminator is written.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendInteger(
+ SessionBuffer *p, /* Buffer to append to */
+ int iVal, /* Value to write the string rep. of */
+ int *pRc /* IN/OUT: Error code */
+){
+ char aBuf[24];
+ sqlite3_snprintf(sizeof(aBuf)-1, aBuf, "%d", iVal);
+ sessionAppendStr(p, aBuf, pRc);
+}
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwise, append the string zStr enclosed in quotes (") and
+** with any embedded quote characters escaped to the buffer. No
+** nul-terminator byte is written.
+**
+** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
+** returning.
+*/
+static void sessionAppendIdent(
+ SessionBuffer *p, /* Buffer to a append to */
+ const char *zStr, /* String to quote, escape and append */
+ int *pRc /* IN/OUT: Error code */
+){
+ int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
+ if( 0==sessionBufferGrow(p, nStr, pRc) ){
+ char *zOut = (char *)&p->aBuf[p->nBuf];
+ const char *zIn = zStr;
+ *zOut++ = '"';
+ while( *zIn ){
+ if( *zIn=='"' ) *zOut++ = '"';
+ *zOut++ = *(zIn++);
+ }
+ *zOut++ = '"';
+ p->nBuf = (int)((u8 *)zOut - p->aBuf);
+ }
+}
+
+/*
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
+** called. Otherwse, it appends the serialized version of the value stored
+** in column iCol of the row that SQL statement pStmt currently points
+** to to the buffer.
+*/
+static void sessionAppendCol(
+ SessionBuffer *p, /* Buffer to append to */
+ sqlite3_stmt *pStmt, /* Handle pointing to row containing value */
+ int iCol, /* Column to read value from */
+ int *pRc /* IN/OUT: Error code */
+){
+ if( *pRc==SQLITE_OK ){
+ int eType = sqlite3_column_type(pStmt, iCol);
+ sessionAppendByte(p, (u8)eType, pRc);
+ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ sqlite3_int64 i;
+ u8 aBuf[8];
+ if( eType==SQLITE_INTEGER ){
+ i = sqlite3_column_int64(pStmt, iCol);
+ }else{
+ double r = sqlite3_column_double(pStmt, iCol);
+ memcpy(&i, &r, 8);
+ }
+ sessionPutI64(aBuf, i);
+ sessionAppendBlob(p, aBuf, 8, pRc);
+ }
+ if( eType==SQLITE_BLOB || eType==SQLITE_TEXT ){
+ u8 *z;
+ int nByte;
+ if( eType==SQLITE_BLOB ){
+ z = (u8 *)sqlite3_column_blob(pStmt, iCol);
+ }else{
+ z = (u8 *)sqlite3_column_text(pStmt, iCol);
+ }
+ nByte = sqlite3_column_bytes(pStmt, iCol);
+ if( z || (eType==SQLITE_BLOB && nByte==0) ){
+ sessionAppendVarint(p, nByte, pRc);
+ sessionAppendBlob(p, z, nByte, pRc);
+ }else{
+ *pRc = SQLITE_NOMEM;
+ }
+ }
+ }
+}
+
+/*
+**
+** This function appends an update change to the buffer (see the comments
+** under "CHANGESET FORMAT" at the top of the file). An update change
+** consists of:
+**
+** 1 byte: SQLITE_UPDATE (0x17)
+** n bytes: old.* record (see RECORD FORMAT)
+** m bytes: new.* record (see RECORD FORMAT)
+**
+** The SessionChange object passed as the third argument contains the
+** values that were stored in the row when the session began (the old.*
+** values). The statement handle passed as the second argument points
+** at the current version of the row (the new.* values).
+**
+** If all of the old.* values are equal to their corresponding new.* value
+** (i.e. nothing has changed), then no data at all is appended to the buffer.
+**
+** Otherwise, the old.* record contains all primary key values and the
+** original values of any fields that have been modified. The new.* record
+** contains the new values of only those fields that have been modified.
+*/
+static int sessionAppendUpdate(
+ SessionBuffer *pBuf, /* Buffer to append to */
+ int bPatchset, /* True for "patchset", 0 for "changeset" */
+ sqlite3_stmt *pStmt, /* Statement handle pointing at new row */
+ SessionChange *p, /* Object containing old values */
+ u8 *abPK /* Boolean array - true for PK columns */
+){
+ int rc = SQLITE_OK;
+ SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
+ int bNoop = 1; /* Set to zero if any values are modified */
+ int nRewind = pBuf->nBuf; /* Set to zero if any values are modified */
+ int i; /* Used to iterate through columns */
+ u8 *pCsr = p->aRecord; /* Used to iterate through old.* values */
+
+ sessionAppendByte(pBuf, SQLITE_UPDATE, &rc);
+ sessionAppendByte(pBuf, p->bIndirect, &rc);
+ for(i=0; i<sqlite3_column_count(pStmt); i++){
+ int bChanged = 0;
+ int nAdvance;
+ int eType = *pCsr;
+ switch( eType ){
+ case SQLITE_NULL:
+ nAdvance = 1;
+ if( sqlite3_column_type(pStmt, i)!=SQLITE_NULL ){
+ bChanged = 1;
+ }
+ break;
+
+ case SQLITE_FLOAT:
+ case SQLITE_INTEGER: {
+ nAdvance = 9;
+ if( eType==sqlite3_column_type(pStmt, i) ){
+ sqlite3_int64 iVal = sessionGetI64(&pCsr[1]);
+ if( eType==SQLITE_INTEGER ){
+ if( iVal==sqlite3_column_int64(pStmt, i) ) break;
+ }else{
+ double dVal;
+ memcpy(&dVal, &iVal, 8);
+ if( dVal==sqlite3_column_double(pStmt, i) ) break;
+ }
+ }
+ bChanged = 1;
+ break;
+ }
+
+ default: {
+ int n;
+ int nHdr = 1 + sessionVarintGet(&pCsr[1], &n);
+ assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
+ nAdvance = nHdr + n;
+ if( eType==sqlite3_column_type(pStmt, i)
+ && n==sqlite3_column_bytes(pStmt, i)
+ && (n==0 || 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), n))
+ ){
+ break;
+ }
+ bChanged = 1;
+ }
+ }
+
+ /* If at least one field has been modified, this is not a no-op. */
+ if( bChanged ) bNoop = 0;
+
+ /* Add a field to the old.* record. This is omitted if this modules is
+ ** currently generating a patchset. */
+ if( bPatchset==0 ){
+ if( bChanged || abPK[i] ){
+ sessionAppendBlob(pBuf, pCsr, nAdvance, &rc);
+ }else{
+ sessionAppendByte(pBuf, 0, &rc);
+ }
+ }
+
+ /* Add a field to the new.* record. Or the only record if currently
+ ** generating a patchset. */
+ if( bChanged || (bPatchset && abPK[i]) ){
+ sessionAppendCol(&buf2, pStmt, i, &rc);
+ }else{
+ sessionAppendByte(&buf2, 0, &rc);
+ }
+
+ pCsr += nAdvance;
+ }
+
+ if( bNoop ){
+ pBuf->nBuf = nRewind;
+ }else{
+ sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, &rc);
+ }
+ sqlite3_free(buf2.aBuf);
+
+ return rc;
+}
+
+/*
+** Append a DELETE change to the buffer passed as the first argument. Use
+** the changeset format if argument bPatchset is zero, or the patchset
+** format otherwise.
+*/
+static int sessionAppendDelete(
+ SessionBuffer *pBuf, /* Buffer to append to */
+ int bPatchset, /* True for "patchset", 0 for "changeset" */
+ SessionChange *p, /* Object containing old values */
+ int nCol, /* Number of columns in table */
+ u8 *abPK /* Boolean array - true for PK columns */
+){
+ int rc = SQLITE_OK;
+
+ sessionAppendByte(pBuf, SQLITE_DELETE, &rc);
+ sessionAppendByte(pBuf, p->bIndirect, &rc);
+
+ if( bPatchset==0 ){
+ sessionAppendBlob(pBuf, p->aRecord, p->nRecord, &rc);
+ }else{
+ int i;
+ u8 *a = p->aRecord;
+ for(i=0; i<nCol; i++){
+ u8 *pStart = a;
+ int eType = *a++;
+
+ switch( eType ){
+ case 0:
+ case SQLITE_NULL:
+ assert( abPK[i]==0 );
+ break;
+
+ case SQLITE_FLOAT:
+ case SQLITE_INTEGER:
+ a += 8;
+ break;
+
+ default: {
+ int n;
+ a += sessionVarintGet(a, &n);
+ a += n;
+ break;
+ }
+ }
+ if( abPK[i] ){
+ sessionAppendBlob(pBuf, pStart, (int)(a-pStart), &rc);
+ }
+ }
+ assert( (a - p->aRecord)==p->nRecord );
+ }
+
+ return rc;
+}
+
+/*
+** Formulate and prepare a SELECT statement to retrieve a row from table
+** zTab in database zDb based on its primary key. i.e.
+**
+** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
+*/
+static int sessionSelectStmt(
+ sqlite3 *db, /* Database handle */
+ const char *zDb, /* Database name */
+ const char *zTab, /* Table name */
+ int nCol, /* Number of columns in table */
+ const char **azCol, /* Names of table columns */
+ u8 *abPK, /* PRIMARY KEY array */
+ sqlite3_stmt **ppStmt /* OUT: Prepared SELECT statement */
+){
+ int rc = SQLITE_OK;
+ int i;
+ const char *zSep = "";
+ SessionBuffer buf = {0, 0, 0};
+
+ sessionAppendStr(&buf, "SELECT * FROM ", &rc);
+ sessionAppendIdent(&buf, zDb, &rc);
+ sessionAppendStr(&buf, ".", &rc);
+ sessionAppendIdent(&buf, zTab, &rc);
+ sessionAppendStr(&buf, " WHERE ", &rc);
+ for(i=0; i<nCol; i++){
+ if( abPK[i] ){
+ sessionAppendStr(&buf, zSep, &rc);
+ sessionAppendIdent(&buf, azCol[i], &rc);
+ sessionAppendStr(&buf, " = ?", &rc);
+ sessionAppendInteger(&buf, i+1, &rc);
+ zSep = " AND ";
+ }
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, ppStmt, 0);
+ }
+ sqlite3_free(buf.aBuf);
+ return rc;
+}
+
+/*
+** Bind the PRIMARY KEY values from the change passed in argument pChange
+** to the SELECT statement passed as the first argument. The SELECT statement
+** is as prepared by function sessionSelectStmt().
+**
+** Return SQLITE_OK if all PK values are successfully bound, or an SQLite
+** error code (e.g. SQLITE_NOMEM) otherwise.
+*/
+static int sessionSelectBind(
+ sqlite3_stmt *pSelect, /* SELECT from sessionSelectStmt() */
+ int nCol, /* Number of columns in table */
+ u8 *abPK, /* PRIMARY KEY array */
+ SessionChange *pChange /* Change structure */
+){
+ int i;
+ int rc = SQLITE_OK;
+ u8 *a = pChange->aRecord;
+
+ for(i=0; i<nCol && rc==SQLITE_OK; i++){
+ int eType = *a++;
+
+ switch( eType ){
+ case 0:
+ case SQLITE_NULL:
+ assert( abPK[i]==0 );
+ break;
+
+ case SQLITE_INTEGER: {
+ if( abPK[i] ){
+ i64 iVal = sessionGetI64(a);
+ rc = sqlite3_bind_int64(pSelect, i+1, iVal);
+ }
+ a += 8;
+ break;
+ }
+
+ case SQLITE_FLOAT: {
+ if( abPK[i] ){
+ double rVal;
+ i64 iVal = sessionGetI64(a);
+ memcpy(&rVal, &iVal, 8);
+ rc = sqlite3_bind_double(pSelect, i+1, rVal);
+ }
+ a += 8;
+ break;
+ }
+
+ case SQLITE_TEXT: {
+ int n;
+ a += sessionVarintGet(a, &n);
+ if( abPK[i] ){
+ rc = sqlite3_bind_text(pSelect, i+1, (char *)a, n, SQLITE_TRANSIENT);
+ }
+ a += n;
+ break;
+ }
+
+ default: {
+ int n;
+ assert( eType==SQLITE_BLOB );
+ a += sessionVarintGet(a, &n);
+ if( abPK[i] ){
+ rc = sqlite3_bind_blob(pSelect, i+1, a, n, SQLITE_TRANSIENT);
+ }
+ a += n;
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+** This function is a no-op if *pRc is set to other than SQLITE_OK when it
+** is called. Otherwise, append a serialized table header (part of the binary
+** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an
+** SQLite error code before returning.
+*/
+static void sessionAppendTableHdr(
+ SessionBuffer *pBuf, /* Append header to this buffer */
+ int bPatchset, /* Use the patchset format if true */
+ SessionTable *pTab, /* Table object to append header for */
+ int *pRc /* IN/OUT: Error code */
+){
+ /* Write a table header */
+ sessionAppendByte(pBuf, (bPatchset ? 'P' : 'T'), pRc);
+ sessionAppendVarint(pBuf, pTab->nCol, pRc);
+ sessionAppendBlob(pBuf, pTab->abPK, pTab->nCol, pRc);
+ sessionAppendBlob(pBuf, (u8 *)pTab->zName, (int)strlen(pTab->zName)+1, pRc);
+}
+
+/*
+** Generate either a changeset (if argument bPatchset is zero) or a patchset
+** (if it is non-zero) based on the current contents of the session object
+** passed as the first argument.
+**
+** If no error occurs, SQLITE_OK is returned and the new changeset/patchset
+** stored in output variables *pnChangeset and *ppChangeset. Or, if an error
+** occurs, an SQLite error code is returned and both output variables set
+** to 0.
+*/
+static int sessionGenerateChangeset(
+ sqlite3_session *pSession, /* Session object */
+ int bPatchset, /* True for patchset, false for changeset */
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut, /* First argument for xOutput */
+ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
+ void **ppChangeset /* OUT: Buffer containing changeset */
+){
+ sqlite3 *db = pSession->db; /* Source database handle */
+ SessionTable *pTab; /* Used to iterate through attached tables */
+ SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */
+ int rc; /* Return code */
+
+ assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0 ) );
+
+ /* Zero the output variables in case an error occurs. If this session
+ ** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
+ ** this call will be a no-op. */
+ if( xOutput==0 ){
+ *pnChangeset = 0;
+ *ppChangeset = 0;
+ }
+
+ if( pSession->rc ) return pSession->rc;
+ rc = sqlite3_exec(pSession->db, "SAVEPOINT changeset", 0, 0, 0);
+ if( rc!=SQLITE_OK ) return rc;
+
+ sqlite3_mutex_enter(sqlite3_db_mutex(db));
+
+ for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
+ if( pTab->nEntry ){
+ const char *zName = pTab->zName;
+ int nCol; /* Number of columns in table */
+ u8 *abPK; /* Primary key array */
+ const char **azCol = 0; /* Table columns */
+ int i; /* Used to iterate through hash buckets */
+ sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */
+ int nRewind = buf.nBuf; /* Initial size of write buffer */
+ int nNoop; /* Size of buffer after writing tbl header */
+
+ /* Check the table schema is still Ok. */
+ rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
+ if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
+ rc = SQLITE_SCHEMA;
+ }
+
+ /* Write a table header */
+ sessionAppendTableHdr(&buf, bPatchset, pTab, &rc);
+
+ /* Build and compile a statement to execute: */
+ if( rc==SQLITE_OK ){
+ rc = sessionSelectStmt(
+ db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
+ }
+
+ nNoop = buf.nBuf;
+ for(i=0; i<pTab->nChange && rc==SQLITE_OK; i++){
+ SessionChange *p; /* Used to iterate through changes */
+
+ for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
+ rc = sessionSelectBind(pSel, nCol, abPK, p);
+ if( rc!=SQLITE_OK ) continue;
+ if( sqlite3_step(pSel)==SQLITE_ROW ){
+ if( p->op==SQLITE_INSERT ){
+ int iCol;
+ sessionAppendByte(&buf, SQLITE_INSERT, &rc);
+ sessionAppendByte(&buf, p->bIndirect, &rc);
+ for(iCol=0; iCol<nCol; iCol++){
+ sessionAppendCol(&buf, pSel, iCol, &rc);
+ }
+ }else{
+ rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
+ }
+ }else if( p->op!=SQLITE_INSERT ){
+ rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_reset(pSel);
+ }
+
+ /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass
+ ** its contents to the xOutput() callback. */
+ if( xOutput
+ && rc==SQLITE_OK
+ && buf.nBuf>nNoop
+ && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE
+ ){
+ rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
+ nNoop = -1;
+ buf.nBuf = 0;
+ }
+
+ }
+ }
+
+ sqlite3_finalize(pSel);
+ if( buf.nBuf==nNoop ){
+ buf.nBuf = nRewind;
+ }
+ sqlite3_free((char*)azCol); /* cast works around VC++ bug */
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ if( xOutput==0 ){
+ *pnChangeset = buf.nBuf;
+ *ppChangeset = buf.aBuf;
+ buf.aBuf = 0;
+ }else if( buf.nBuf>0 ){
+ rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
+ }
+ }
+
+ sqlite3_free(buf.aBuf);
+ sqlite3_exec(db, "RELEASE changeset", 0, 0, 0);
+ sqlite3_mutex_leave(sqlite3_db_mutex(db));
+ return rc;
+}
+
+/*
+** Obtain a changeset object containing all changes recorded by the
+** session object passed as the first argument.
+**
+** It is the responsibility of the caller to eventually free the buffer
+** using sqlite3_free().
+*/
+SQLITE_API int sqlite3session_changeset(
+ sqlite3_session *pSession, /* Session object */
+ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
+ void **ppChangeset /* OUT: Buffer containing changeset */
+){
+ return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
+}
+
+/*
+** Streaming version of sqlite3session_changeset().
+*/
+SQLITE_API int sqlite3session_changeset_strm(
+ sqlite3_session *pSession,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+){
+ return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0);
+}
+
+/*
+** Streaming version of sqlite3session_patchset().
+*/
+SQLITE_API int sqlite3session_patchset_strm(
+ sqlite3_session *pSession,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+){
+ return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0);
+}
+
+/*
+** Obtain a patchset object containing all changes recorded by the
+** session object passed as the first argument.
+**
+** It is the responsibility of the caller to eventually free the buffer
+** using sqlite3_free().
+*/
+SQLITE_API int sqlite3session_patchset(
+ sqlite3_session *pSession, /* Session object */
+ int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
+ void **ppPatchset /* OUT: Buffer containing changeset */
+){
+ return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset);
+}
+
+/*
+** Enable or disable the session object passed as the first argument.
+*/
+SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable){
+ int ret;
+ sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
+ if( bEnable>=0 ){
+ pSession->bEnable = bEnable;
+ }
+ ret = pSession->bEnable;
+ sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+ return ret;
+}
+
+/*
+** Enable or disable the session object passed as the first argument.
+*/
+SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect){
+ int ret;
+ sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
+ if( bIndirect>=0 ){
+ pSession->bIndirect = bIndirect;
+ }
+ ret = pSession->bIndirect;
+ sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+ return ret;
+}
+
+/*
+** Return true if there have been no changes to monitored tables recorded
+** by the session object passed as the only argument.
+*/
+SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession){
+ int ret = 0;
+ SessionTable *pTab;
+
+ sqlite3_mutex_enter(sqlite3_db_mutex(pSession->db));
+ for(pTab=pSession->pTable; pTab && ret==0; pTab=pTab->pNext){
+ ret = (pTab->nEntry>0);
+ }
+ sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db));
+
+ return (ret==0);
+}
+
+/*
+** Do the work for either sqlite3changeset_start() or start_strm().
+*/
+static int sessionChangesetStart(
+ sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int nChangeset, /* Size of buffer pChangeset in bytes */
+ void *pChangeset /* Pointer to buffer containing changeset */
+){
+ sqlite3_changeset_iter *pRet; /* Iterator to return */
+ int nByte; /* Number of bytes to allocate for iterator */
+
+ assert( xInput==0 || (pChangeset==0 && nChangeset==0) );
+
+ /* Zero the output variable in case an error occurs. */
+ *pp = 0;
+
+ /* Allocate and initialize the iterator structure. */
+ nByte = sizeof(sqlite3_changeset_iter);
+ pRet = (sqlite3_changeset_iter *)sqlite3_malloc(nByte);
+ if( !pRet ) return SQLITE_NOMEM;
+ memset(pRet, 0, sizeof(sqlite3_changeset_iter));
+ pRet->in.aData = (u8 *)pChangeset;
+ pRet->in.nData = nChangeset;
+ pRet->in.xInput = xInput;
+ pRet->in.pIn = pIn;
+ pRet->in.bEof = (xInput ? 0 : 1);
+
+ /* Populate the output variable and return success. */
+ *pp = pRet;
+ return SQLITE_OK;
+}
+
+/*
+** Create an iterator used to iterate through the contents of a changeset.
+*/
+SQLITE_API int sqlite3changeset_start(
+ sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
+ int nChangeset, /* Size of buffer pChangeset in bytes */
+ void *pChangeset /* Pointer to buffer containing changeset */
+){
+ return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset);
+}
+
+/*
+** Streaming version of sqlite3changeset_start().
+*/
+SQLITE_API int sqlite3changeset_start_strm(
+ sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn
+){
+ return sessionChangesetStart(pp, xInput, pIn, 0, 0);
+}
+
+/*
+** If the SessionInput object passed as the only argument is a streaming
+** object and the buffer is full, discard some data to free up space.
+*/
+static void sessionDiscardData(SessionInput *pIn){
+ if( pIn->bEof && pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){
+ int nMove = pIn->buf.nBuf - pIn->iNext;
+ assert( nMove>=0 );
+ if( nMove>0 ){
+ memmove(pIn->buf.aBuf, &pIn->buf.aBuf[pIn->iNext], nMove);
+ }
+ pIn->buf.nBuf -= pIn->iNext;
+ pIn->iNext = 0;
+ pIn->nData = pIn->buf.nBuf;
+ }
+}
+
+/*
+** Ensure that there are at least nByte bytes available in the buffer. Or,
+** if there are not nByte bytes remaining in the input, that all available
+** data is in the buffer.
+**
+** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
+*/
+static int sessionInputBuffer(SessionInput *pIn, int nByte){
+ int rc = SQLITE_OK;
+ if( pIn->xInput ){
+ while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){
+ int nNew = SESSIONS_STRM_CHUNK_SIZE;
+
+ if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn);
+ if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){
+ rc = pIn->xInput(pIn->pIn, &pIn->buf.aBuf[pIn->buf.nBuf], &nNew);
+ if( nNew==0 ){
+ pIn->bEof = 1;
+ }else{
+ pIn->buf.nBuf += nNew;
+ }
+ }
+
+ pIn->aData = pIn->buf.aBuf;
+ pIn->nData = pIn->buf.nBuf;
+ }
+ }
+ return rc;
+}
+
+/*
+** When this function is called, *ppRec points to the start of a record
+** that contains nCol values. This function advances the pointer *ppRec
+** until it points to the byte immediately following that record.
+*/
+static void sessionSkipRecord(
+ u8 **ppRec, /* IN/OUT: Record pointer */
+ int nCol /* Number of values in record */
+){
+ u8 *aRec = *ppRec;
+ int i;
+ for(i=0; i<nCol; i++){
+ int eType = *aRec++;
+ if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+ int nByte;
+ aRec += sessionVarintGet((u8*)aRec, &nByte);
+ aRec += nByte;
+ }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ aRec += 8;
+ }
+ }
+
+ *ppRec = aRec;
+}
+
+/*
+** This function sets the value of the sqlite3_value object passed as the
+** first argument to a copy of the string or blob held in the aData[]
+** buffer. SQLITE_OK is returned if successful, or SQLITE_NOMEM if an OOM
+** error occurs.
+*/
+static int sessionValueSetStr(
+ sqlite3_value *pVal, /* Set the value of this object */
+ u8 *aData, /* Buffer containing string or blob data */
+ int nData, /* Size of buffer aData[] in bytes */
+ u8 enc /* String encoding (0 for blobs) */
+){
+ /* In theory this code could just pass SQLITE_TRANSIENT as the final
+ ** argument to sqlite3ValueSetStr() and have the copy created
+ ** automatically. But doing so makes it difficult to detect any OOM
+ ** error. Hence the code to create the copy externally. */
+ u8 *aCopy = sqlite3_malloc(nData+1);
+ if( aCopy==0 ) return SQLITE_NOMEM;
+ memcpy(aCopy, aData, nData);
+ sqlite3ValueSetStr(pVal, nData, (char*)aCopy, enc, sqlite3_free);
+ return SQLITE_OK;
+}
+
+/*
+** Deserialize a single record from a buffer in memory. See "RECORD FORMAT"
+** for details.
+**
+** When this function is called, *paChange points to the start of the record
+** to deserialize. Assuming no error occurs, *paChange is set to point to
+** one byte after the end of the same record before this function returns.
+** If the argument abPK is NULL, then the record contains nCol values. Or,
+** if abPK is other than NULL, then the record contains only the PK fields
+** (in other words, it is a patchset DELETE record).
+**
+** If successful, each element of the apOut[] array (allocated by the caller)
+** is set to point to an sqlite3_value object containing the value read
+** from the corresponding position in the record. If that value is not
+** included in the record (i.e. because the record is part of an UPDATE change
+** and the field was not modified), the corresponding element of apOut[] is
+** set to NULL.
+**
+** It is the responsibility of the caller to free all sqlite_value structures
+** using sqlite3_free().
+**
+** If an error occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
+** The apOut[] array may have been partially populated in this case.
+*/
+static int sessionReadRecord(
+ SessionInput *pIn, /* Input data */
+ int nCol, /* Number of values in record */
+ u8 *abPK, /* Array of primary key flags, or NULL */
+ sqlite3_value **apOut /* Write values to this array */
+){
+ int i; /* Used to iterate through columns */
+ int rc = SQLITE_OK;
+
+ for(i=0; i<nCol && rc==SQLITE_OK; i++){
+ int eType = 0; /* Type of value (SQLITE_NULL, TEXT etc.) */
+ if( abPK && abPK[i]==0 ) continue;
+ rc = sessionInputBuffer(pIn, 9);
+ if( rc==SQLITE_OK ){
+ eType = pIn->aData[pIn->iNext++];
+ }
+
+ assert( apOut[i]==0 );
+ if( eType ){
+ apOut[i] = sqlite3ValueNew(0);
+ if( !apOut[i] ) rc = SQLITE_NOMEM;
+ }
+
+ if( rc==SQLITE_OK ){
+ u8 *aVal = &pIn->aData[pIn->iNext];
+ if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+ int nByte;
+ pIn->iNext += sessionVarintGet(aVal, &nByte);
+ rc = sessionInputBuffer(pIn, nByte);
+ if( rc==SQLITE_OK ){
+ u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
+ rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
+ }
+ pIn->iNext += nByte;
+ }
+ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ sqlite3_int64 v = sessionGetI64(aVal);
+ if( eType==SQLITE_INTEGER ){
+ sqlite3VdbeMemSetInt64(apOut[i], v);
+ }else{
+ double d;
+ memcpy(&d, &v, 8);
+ sqlite3VdbeMemSetDouble(apOut[i], d);
+ }
+ pIn->iNext += 8;
+ }
+ }
+ }
+
+ return rc;
+}
+
+/*
+** The input pointer currently points to the second byte of a table-header.
+** Specifically, to the following:
+**
+** + number of columns in table (varint)
+** + array of PK flags (1 byte per column),
+** + table name (nul terminated).
+**
+** This function ensures that all of the above is present in the input
+** buffer (i.e. that it can be accessed without any calls to xInput()).
+** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
+** The input pointer is not moved.
+*/
+static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
+ int rc = SQLITE_OK;
+ int nCol = 0;
+ int nRead = 0;
+
+ rc = sessionInputBuffer(pIn, 9);
+ if( rc==SQLITE_OK ){
+ nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol);
+ rc = sessionInputBuffer(pIn, nRead+nCol+100);
+ nRead += nCol;
+ }
+
+ while( rc==SQLITE_OK ){
+ while( (pIn->iNext + nRead)<pIn->nData && pIn->aData[pIn->iNext + nRead] ){
+ nRead++;
+ }
+ if( (pIn->iNext + nRead)<pIn->nData ) break;
+ rc = sessionInputBuffer(pIn, nRead + 100);
+ }
+ *pnByte = nRead+1;
+ return rc;
+}
+
+/*
+** The input pointer currently points to the first byte of the first field
+** of a record consisting of nCol columns. This function ensures the entire
+** record is buffered. It does not move the input pointer.
+**
+** If successful, SQLITE_OK is returned and *pnByte is set to the size of
+** the record in bytes. Otherwise, an SQLite error code is returned. The
+** final value of *pnByte is undefined in this case.
+*/
+static int sessionChangesetBufferRecord(
+ SessionInput *pIn, /* Input data */
+ int nCol, /* Number of columns in record */
+ int *pnByte /* OUT: Size of record in bytes */
+){
+ int rc = SQLITE_OK;
+ int nByte = 0;
+ int i;
+ for(i=0; rc==SQLITE_OK && i<nCol; i++){
+ int eType;
+ rc = sessionInputBuffer(pIn, nByte + 10);
+ if( rc==SQLITE_OK ){
+ eType = pIn->aData[pIn->iNext + nByte++];
+ if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+ int n;
+ nByte += sessionVarintGet(&pIn->aData[pIn->iNext+nByte], &n);
+ nByte += n;
+ rc = sessionInputBuffer(pIn, nByte);
+ }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ nByte += 8;
+ }
+ }
+ }
+ *pnByte = nByte;
+ return rc;
+}
+
+/*
+** The input pointer currently points to the second byte of a table-header.
+** Specifically, to the following:
+**
+** + number of columns in table (varint)
+** + array of PK flags (1 byte per column),
+** + table name (nul terminated).
+**
+** This function decodes the table-header and populates the p->nCol,
+** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is
+** also allocated or resized according to the new value of p->nCol. The
+** input pointer is left pointing to the byte following the table header.
+**
+** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code
+** is returned and the final values of the various fields enumerated above
+** are undefined.
+*/
+static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
+ int rc;
+ int nCopy;
+ assert( p->rc==SQLITE_OK );
+
+ rc = sessionChangesetBufferTblhdr(&p->in, &nCopy);
+ if( rc==SQLITE_OK ){
+ int nByte;
+ int nVarint;
+ nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol);
+ nCopy -= nVarint;
+ p->in.iNext += nVarint;
+ nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
+ p->tblhdr.nBuf = 0;
+ sessionBufferGrow(&p->tblhdr, nByte, &rc);
+ }
+
+ if( rc==SQLITE_OK ){
+ int iPK = sizeof(sqlite3_value*)*p->nCol*2;
+ memset(p->tblhdr.aBuf, 0, iPK);
+ memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
+ p->in.iNext += nCopy;
+ }
+
+ p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
+ p->abPK = (u8*)&p->apValue[p->nCol*2];
+ p->zTab = (char*)&p->abPK[p->nCol];
+ return (p->rc = rc);
+}
+
+/*
+** Advance the changeset iterator to the next change.
+**
+** If both paRec and pnRec are NULL, then this function works like the public
+** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
+** sqlite3changeset_new() and old() APIs may be used to query for values.
+**
+** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
+** record is written to *paRec before returning and the number of bytes in
+** the record to *pnRec.
+**
+** Either way, this function returns SQLITE_ROW if the iterator is
+** successfully advanced to the next change in the changeset, an SQLite
+** error code if an error occurs, or SQLITE_DONE if there are no further
+** changes in the changeset.
+*/
+static int sessionChangesetNext(
+ sqlite3_changeset_iter *p, /* Changeset iterator */
+ u8 **paRec, /* If non-NULL, store record pointer here */
+ int *pnRec /* If non-NULL, store size of record here */
+){
+ int i;
+ u8 op;
+
+ assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
+
+ /* If the iterator is in the error-state, return immediately. */
+ if( p->rc!=SQLITE_OK ) return p->rc;
+
+ /* Free the current contents of p->apValue[], if any. */
+ if( p->apValue ){
+ for(i=0; i<p->nCol*2; i++){
+ sqlite3ValueFree(p->apValue[i]);
+ }
+ memset(p->apValue, 0, sizeof(sqlite3_value*)*p->nCol*2);
+ }
+
+ /* Make sure the buffer contains at least 10 bytes of input data, or all
+ ** remaining data if there are less than 10 bytes available. This is
+ ** sufficient either for the 'T' or 'P' byte and the varint that follows
+ ** it, or for the two single byte values otherwise. */
+ p->rc = sessionInputBuffer(&p->in, 2);
+ if( p->rc!=SQLITE_OK ) return p->rc;
+
+ /* If the iterator is already at the end of the changeset, return DONE. */
+ if( p->in.iNext>=p->in.nData ){
+ return SQLITE_DONE;
+ }
+
+ sessionDiscardData(&p->in);
+ p->in.iCurrent = p->in.iNext;
+
+ op = p->in.aData[p->in.iNext++];
+ if( op=='T' || op=='P' ){
+ p->bPatchset = (op=='P');
+ if( sessionChangesetReadTblhdr(p) ) return p->rc;
+ if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
+ p->in.iCurrent = p->in.iNext;
+ op = p->in.aData[p->in.iNext++];
+ }
+
+ p->op = op;
+ p->bIndirect = p->in.aData[p->in.iNext++];
+ if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
+ return (p->rc = SQLITE_CORRUPT_BKPT);
+ }
+
+ if( paRec ){
+ int nVal; /* Number of values to buffer */
+ if( p->bPatchset==0 && op==SQLITE_UPDATE ){
+ nVal = p->nCol * 2;
+ }else if( p->bPatchset && op==SQLITE_DELETE ){
+ nVal = 0;
+ for(i=0; i<p->nCol; i++) if( p->abPK[i] ) nVal++;
+ }else{
+ nVal = p->nCol;
+ }
+ p->rc = sessionChangesetBufferRecord(&p->in, nVal, pnRec);
+ if( p->rc!=SQLITE_OK ) return p->rc;
+ *paRec = &p->in.aData[p->in.iNext];
+ p->in.iNext += *pnRec;
+ }else{
+
+ /* If this is an UPDATE or DELETE, read the old.* record. */
+ if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
+ u8 *abPK = p->bPatchset ? p->abPK : 0;
+ p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue);
+ if( p->rc!=SQLITE_OK ) return p->rc;
+ }
+
+ /* If this is an INSERT or UPDATE, read the new.* record. */
+ if( p->op!=SQLITE_DELETE ){
+ p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]);
+ if( p->rc!=SQLITE_OK ) return p->rc;
+ }
+
+ if( p->bPatchset && p->op==SQLITE_UPDATE ){
+ /* If this is an UPDATE that is part of a patchset, then all PK and
+ ** modified fields are present in the new.* record. The old.* record
+ ** is currently completely empty. This block shifts the PK fields from
+ ** new.* to old.*, to accommodate the code that reads these arrays. */
+ for(i=0; i<p->nCol; i++){
+ assert( p->apValue[i]==0 );
+ assert( p->abPK[i]==0 || p->apValue[i+p->nCol] );
+ if( p->abPK[i] ){
+ p->apValue[i] = p->apValue[i+p->nCol];
+ p->apValue[i+p->nCol] = 0;
+ }
+ }
+ }
+ }
+
+ return SQLITE_ROW;
+}
+
+/*
+** Advance an iterator created by sqlite3changeset_start() to the next
+** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
+** or SQLITE_CORRUPT.
+**
+** This function may not be called on iterators passed to a conflict handler
+** callback by changeset_apply().
+*/
+SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *p){
+ return sessionChangesetNext(p, 0, 0);
+}
+
+/*
+** The following function extracts information on the current change
+** from a changeset iterator. It may only be called after changeset_next()
+** has returned SQLITE_ROW.
+*/
+SQLITE_API int sqlite3changeset_op(
+ sqlite3_changeset_iter *pIter, /* Iterator handle */
+ const char **pzTab, /* OUT: Pointer to table name */
+ int *pnCol, /* OUT: Number of columns in table */
+ int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */
+ int *pbIndirect /* OUT: True if change is indirect */
+){
+ *pOp = pIter->op;
+ *pnCol = pIter->nCol;
+ *pzTab = pIter->zTab;
+ if( pbIndirect ) *pbIndirect = pIter->bIndirect;
+ return SQLITE_OK;
+}
+
+/*
+** Return information regarding the PRIMARY KEY and number of columns in
+** the database table affected by the change that pIter currently points
+** to. This function may only be called after changeset_next() returns
+** SQLITE_ROW.
+*/
+SQLITE_API int sqlite3changeset_pk(
+ sqlite3_changeset_iter *pIter, /* Iterator object */
+ unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */
+ int *pnCol /* OUT: Number of entries in output array */
+){
+ *pabPK = pIter->abPK;
+ if( pnCol ) *pnCol = pIter->nCol;
+ return SQLITE_OK;
+}
+
+/*
+** This function may only be called while the iterator is pointing to an
+** SQLITE_UPDATE or SQLITE_DELETE change (see sqlite3changeset_op()).
+** Otherwise, SQLITE_MISUSE is returned.
+**
+** It sets *ppValue to point to an sqlite3_value structure containing the
+** iVal'th value in the old.* record. Or, if that particular value is not
+** included in the record (because the change is an UPDATE and the field
+** was not modified and is not a PK column), set *ppValue to NULL.
+**
+** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
+** not modified. Otherwise, SQLITE_OK.
+*/
+SQLITE_API int sqlite3changeset_old(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int iVal, /* Index of old.* value to retrieve */
+ sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */
+){
+ if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_DELETE ){
+ return SQLITE_MISUSE;
+ }
+ if( iVal<0 || iVal>=pIter->nCol ){
+ return SQLITE_RANGE;
+ }
+ *ppValue = pIter->apValue[iVal];
+ return SQLITE_OK;
+}
+
+/*
+** This function may only be called while the iterator is pointing to an
+** SQLITE_UPDATE or SQLITE_INSERT change (see sqlite3changeset_op()).
+** Otherwise, SQLITE_MISUSE is returned.
+**
+** It sets *ppValue to point to an sqlite3_value structure containing the
+** iVal'th value in the new.* record. Or, if that particular value is not
+** included in the record (because the change is an UPDATE and the field
+** was not modified), set *ppValue to NULL.
+**
+** If value iVal is out-of-range, SQLITE_RANGE is returned and *ppValue is
+** not modified. Otherwise, SQLITE_OK.
+*/
+SQLITE_API int sqlite3changeset_new(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int iVal, /* Index of new.* value to retrieve */
+ sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */
+){
+ if( pIter->op!=SQLITE_UPDATE && pIter->op!=SQLITE_INSERT ){
+ return SQLITE_MISUSE;
+ }
+ if( iVal<0 || iVal>=pIter->nCol ){
+ return SQLITE_RANGE;
+ }
+ *ppValue = pIter->apValue[pIter->nCol+iVal];
+ return SQLITE_OK;
+}
+
+/*
+** The following two macros are used internally. They are similar to the
+** sqlite3changeset_new() and sqlite3changeset_old() functions, except that
+** they omit all error checking and return a pointer to the requested value.
+*/
+#define sessionChangesetNew(pIter, iVal) (pIter)->apValue[(pIter)->nCol+(iVal)]
+#define sessionChangesetOld(pIter, iVal) (pIter)->apValue[(iVal)]
+
+/*
+** This function may only be called with a changeset iterator that has been
+** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT
+** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
+**
+** If successful, *ppValue is set to point to an sqlite3_value structure
+** containing the iVal'th value of the conflicting record.
+**
+** If value iVal is out-of-range or some other error occurs, an SQLite error
+** code is returned. Otherwise, SQLITE_OK.
+*/
+SQLITE_API int sqlite3changeset_conflict(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int iVal, /* Index of conflict record value to fetch */
+ sqlite3_value **ppValue /* OUT: Value from conflicting row */
+){
+ if( !pIter->pConflict ){
+ return SQLITE_MISUSE;
+ }
+ if( iVal<0 || iVal>=sqlite3_column_count(pIter->pConflict) ){
+ return SQLITE_RANGE;
+ }
+ *ppValue = sqlite3_column_value(pIter->pConflict, iVal);
+ return SQLITE_OK;
+}
+
+/*
+** This function may only be called with an iterator passed to an
+** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
+** it sets the output variable to the total number of known foreign key
+** violations in the destination database and returns SQLITE_OK.
+**
+** In all other cases this function returns SQLITE_MISUSE.
+*/
+SQLITE_API int sqlite3changeset_fk_conflicts(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int *pnOut /* OUT: Number of FK violations */
+){
+ if( pIter->pConflict || pIter->apValue ){
+ return SQLITE_MISUSE;
+ }
+ *pnOut = pIter->nCol;
+ return SQLITE_OK;
+}
+
+
+/*
+** Finalize an iterator allocated with sqlite3changeset_start().
+**
+** This function may not be called on iterators passed to a conflict handler
+** callback by changeset_apply().
+*/
+SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *p){
+ int rc = SQLITE_OK;
+ if( p ){
+ int i; /* Used to iterate through p->apValue[] */
+ rc = p->rc;
+ if( p->apValue ){
+ for(i=0; i<p->nCol*2; i++) sqlite3ValueFree(p->apValue[i]);
+ }
+ sqlite3_free(p->tblhdr.aBuf);
+ sqlite3_free(p->in.buf.aBuf);
+ sqlite3_free(p);
+ }
+ return rc;
+}
+
+static int sessionChangesetInvert(
+ SessionInput *pInput, /* Input changeset */
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut,
+ int *pnInverted, /* OUT: Number of bytes in output changeset */
+ void **ppInverted /* OUT: Inverse of pChangeset */
+){
+ int rc = SQLITE_OK; /* Return value */
+ SessionBuffer sOut; /* Output buffer */
+ int nCol = 0; /* Number of cols in current table */
+ u8 *abPK = 0; /* PK array for current table */
+ sqlite3_value **apVal = 0; /* Space for values for UPDATE inversion */
+ SessionBuffer sPK = {0, 0, 0}; /* PK array for current table */
+
+ /* Initialize the output buffer */
+ memset(&sOut, 0, sizeof(SessionBuffer));
+
+ /* Zero the output variables in case an error occurs. */
+ if( ppInverted ){
+ *ppInverted = 0;
+ *pnInverted = 0;
+ }
+
+ while( 1 ){
+ u8 eType;
+
+ /* Test for EOF. */
+ if( (rc = sessionInputBuffer(pInput, 2)) ) goto finished_invert;
+ if( pInput->iNext>=pInput->nData ) break;
+ eType = pInput->aData[pInput->iNext];
+
+ switch( eType ){
+ case 'T': {
+ /* A 'table' record consists of:
+ **
+ ** * A constant 'T' character,
+ ** * Number of columns in said table (a varint),
+ ** * An array of nCol bytes (sPK),
+ ** * A nul-terminated table name.
+ */
+ int nByte;
+ int nVar;
+ pInput->iNext++;
+ if( (rc = sessionChangesetBufferTblhdr(pInput, &nByte)) ){
+ goto finished_invert;
+ }
+ nVar = sessionVarintGet(&pInput->aData[pInput->iNext], &nCol);
+ sPK.nBuf = 0;
+ sessionAppendBlob(&sPK, &pInput->aData[pInput->iNext+nVar], nCol, &rc);
+ sessionAppendByte(&sOut, eType, &rc);
+ sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
+ if( rc ) goto finished_invert;
+
+ pInput->iNext += nByte;
+ sqlite3_free(apVal);
+ apVal = 0;
+ abPK = sPK.aBuf;
+ break;
+ }
+
+ case SQLITE_INSERT:
+ case SQLITE_DELETE: {
+ int nByte;
+ int bIndirect = pInput->aData[pInput->iNext+1];
+ int eType2 = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
+ pInput->iNext += 2;
+ assert( rc==SQLITE_OK );
+ rc = sessionChangesetBufferRecord(pInput, nCol, &nByte);
+ sessionAppendByte(&sOut, eType2, &rc);
+ sessionAppendByte(&sOut, bIndirect, &rc);
+ sessionAppendBlob(&sOut, &pInput->aData[pInput->iNext], nByte, &rc);
+ pInput->iNext += nByte;
+ if( rc ) goto finished_invert;
+ break;
+ }
+
+ case SQLITE_UPDATE: {
+ int iCol;
+
+ if( 0==apVal ){
+ apVal = (sqlite3_value **)sqlite3_malloc(sizeof(apVal[0])*nCol*2);
+ if( 0==apVal ){
+ rc = SQLITE_NOMEM;
+ goto finished_invert;
+ }
+ memset(apVal, 0, sizeof(apVal[0])*nCol*2);
+ }
+
+ /* Write the header for the new UPDATE change. Same as the original. */
+ sessionAppendByte(&sOut, eType, &rc);
+ sessionAppendByte(&sOut, pInput->aData[pInput->iNext+1], &rc);
+
+ /* Read the old.* and new.* records for the update change. */
+ pInput->iNext += 2;
+ rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]);
+ if( rc==SQLITE_OK ){
+ rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]);
+ }
+
+ /* Write the new old.* record. Consists of the PK columns from the
+ ** original old.* record, and the other values from the original
+ ** new.* record. */
+ for(iCol=0; iCol<nCol; iCol++){
+ sqlite3_value *pVal = apVal[iCol + (abPK[iCol] ? 0 : nCol)];
+ sessionAppendValue(&sOut, pVal, &rc);
+ }
+
+ /* Write the new new.* record. Consists of a copy of all values
+ ** from the original old.* record, except for the PK columns, which
+ ** are set to "undefined". */
+ for(iCol=0; iCol<nCol; iCol++){
+ sqlite3_value *pVal = (abPK[iCol] ? 0 : apVal[iCol]);
+ sessionAppendValue(&sOut, pVal, &rc);
+ }
+
+ for(iCol=0; iCol<nCol*2; iCol++){
+ sqlite3ValueFree(apVal[iCol]);
+ }
+ memset(apVal, 0, sizeof(apVal[0])*nCol*2);
+ if( rc!=SQLITE_OK ){
+ goto finished_invert;
+ }
+
+ break;
+ }
+
+ default:
+ rc = SQLITE_CORRUPT_BKPT;
+ goto finished_invert;
+ }
+
+ assert( rc==SQLITE_OK );
+ if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
+ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
+ sOut.nBuf = 0;
+ if( rc!=SQLITE_OK ) goto finished_invert;
+ }
+ }
+
+ assert( rc==SQLITE_OK );
+ if( pnInverted ){
+ *pnInverted = sOut.nBuf;
+ *ppInverted = sOut.aBuf;
+ sOut.aBuf = 0;
+ }else if( sOut.nBuf>0 ){
+ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
+ }
+
+ finished_invert:
+ sqlite3_free(sOut.aBuf);
+ sqlite3_free(apVal);
+ sqlite3_free(sPK.aBuf);
+ return rc;
+}
+
+
+/*
+** Invert a changeset object.
+*/
+SQLITE_API int sqlite3changeset_invert(
+ int nChangeset, /* Number of bytes in input */
+ const void *pChangeset, /* Input changeset */
+ int *pnInverted, /* OUT: Number of bytes in output changeset */
+ void **ppInverted /* OUT: Inverse of pChangeset */
+){
+ SessionInput sInput;
+
+ /* Set up the input stream */
+ memset(&sInput, 0, sizeof(SessionInput));
+ sInput.nData = nChangeset;
+ sInput.aData = (u8*)pChangeset;
+
+ return sessionChangesetInvert(&sInput, 0, 0, pnInverted, ppInverted);
+}
+
+/*
+** Streaming version of sqlite3changeset_invert().
+*/
+SQLITE_API int sqlite3changeset_invert_strm(
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+){
+ SessionInput sInput;
+ int rc;
+
+ /* Set up the input stream */
+ memset(&sInput, 0, sizeof(SessionInput));
+ sInput.xInput = xInput;
+ sInput.pIn = pIn;
+
+ rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0);
+ sqlite3_free(sInput.buf.aBuf);
+ return rc;
+}
+
+typedef struct SessionApplyCtx SessionApplyCtx;
+struct SessionApplyCtx {
+ sqlite3 *db;
+ sqlite3_stmt *pDelete; /* DELETE statement */
+ sqlite3_stmt *pUpdate; /* UPDATE statement */
+ sqlite3_stmt *pInsert; /* INSERT statement */
+ sqlite3_stmt *pSelect; /* SELECT statement */
+ int nCol; /* Size of azCol[] and abPK[] arrays */
+ const char **azCol; /* Array of column names */
+ u8 *abPK; /* Boolean array - true if column is in PK */
+
+ int bDeferConstraints; /* True to defer constraints */
+ SessionBuffer constraints; /* Deferred constraints are stored here */
+};
+
+/*
+** Formulate a statement to DELETE a row from database db. Assuming a table
+** structure like this:
+**
+** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
+**
+** The DELETE statement looks like this:
+**
+** DELETE FROM x WHERE a = :1 AND c = :3 AND (:5 OR b IS :2 AND d IS :4)
+**
+** Variable :5 (nCol+1) is a boolean. It should be set to 0 if we require
+** matching b and d values, or 1 otherwise. The second case comes up if the
+** conflict handler is invoked with NOTFOUND and returns CHANGESET_REPLACE.
+**
+** If successful, SQLITE_OK is returned and SessionApplyCtx.pDelete is left
+** pointing to the prepared version of the SQL statement.
+*/
+static int sessionDeleteRow(
+ sqlite3 *db, /* Database handle */
+ const char *zTab, /* Table name */
+ SessionApplyCtx *p /* Session changeset-apply context */
+){
+ int i;
+ const char *zSep = "";
+ int rc = SQLITE_OK;
+ SessionBuffer buf = {0, 0, 0};
+ int nPk = 0;
+
+ sessionAppendStr(&buf, "DELETE FROM ", &rc);
+ sessionAppendIdent(&buf, zTab, &rc);
+ sessionAppendStr(&buf, " WHERE ", &rc);
+
+ for(i=0; i<p->nCol; i++){
+ if( p->abPK[i] ){
+ nPk++;
+ sessionAppendStr(&buf, zSep, &rc);
+ sessionAppendIdent(&buf, p->azCol[i], &rc);
+ sessionAppendStr(&buf, " = ?", &rc);
+ sessionAppendInteger(&buf, i+1, &rc);
+ zSep = " AND ";
+ }
+ }
+
+ if( nPk<p->nCol ){
+ sessionAppendStr(&buf, " AND (?", &rc);
+ sessionAppendInteger(&buf, p->nCol+1, &rc);
+ sessionAppendStr(&buf, " OR ", &rc);
+
+ zSep = "";
+ for(i=0; i<p->nCol; i++){
+ if( !p->abPK[i] ){
+ sessionAppendStr(&buf, zSep, &rc);
+ sessionAppendIdent(&buf, p->azCol[i], &rc);
+ sessionAppendStr(&buf, " IS ?", &rc);
+ sessionAppendInteger(&buf, i+1, &rc);
+ zSep = "AND ";
+ }
+ }
+ sessionAppendStr(&buf, ")", &rc);
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pDelete, 0);
+ }
+ sqlite3_free(buf.aBuf);
+
+ return rc;
+}
+
+/*
+** Formulate and prepare a statement to UPDATE a row from database db.
+** Assuming a table structure like this:
+**
+** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
+**
+** The UPDATE statement looks like this:
+**
+** UPDATE x SET
+** a = CASE WHEN ?2 THEN ?3 ELSE a END,
+** b = CASE WHEN ?5 THEN ?6 ELSE b END,
+** c = CASE WHEN ?8 THEN ?9 ELSE c END,
+** d = CASE WHEN ?11 THEN ?12 ELSE d END
+** WHERE a = ?1 AND c = ?7 AND (?13 OR
+** (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND
+** )
+**
+** For each column in the table, there are three variables to bind:
+**
+** ?(i*3+1) The old.* value of the column, if any.
+** ?(i*3+2) A boolean flag indicating that the value is being modified.
+** ?(i*3+3) The new.* value of the column, if any.
+**
+** Also, a boolean flag that, if set to true, causes the statement to update
+** a row even if the non-PK values do not match. This is required if the
+** conflict-handler is invoked with CHANGESET_DATA and returns
+** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
+**
+** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
+** pointing to the prepared version of the SQL statement.
+*/
+static int sessionUpdateRow(
+ sqlite3 *db, /* Database handle */
+ const char *zTab, /* Table name */
+ SessionApplyCtx *p /* Session changeset-apply context */
+){
+ int rc = SQLITE_OK;
+ int i;
+ const char *zSep = "";
+ SessionBuffer buf = {0, 0, 0};
+
+ /* Append "UPDATE tbl SET " */
+ sessionAppendStr(&buf, "UPDATE ", &rc);
+ sessionAppendIdent(&buf, zTab, &rc);
+ sessionAppendStr(&buf, " SET ", &rc);
+
+ /* Append the assignments */
+ for(i=0; i<p->nCol; i++){
+ sessionAppendStr(&buf, zSep, &rc);
+ sessionAppendIdent(&buf, p->azCol[i], &rc);
+ sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
+ sessionAppendInteger(&buf, i*3+2, &rc);
+ sessionAppendStr(&buf, " THEN ?", &rc);
+ sessionAppendInteger(&buf, i*3+3, &rc);
+ sessionAppendStr(&buf, " ELSE ", &rc);
+ sessionAppendIdent(&buf, p->azCol[i], &rc);
+ sessionAppendStr(&buf, " END", &rc);
+ zSep = ", ";
+ }
+
+ /* Append the PK part of the WHERE clause */
+ sessionAppendStr(&buf, " WHERE ", &rc);
+ for(i=0; i<p->nCol; i++){
+ if( p->abPK[i] ){
+ sessionAppendIdent(&buf, p->azCol[i], &rc);
+ sessionAppendStr(&buf, " = ?", &rc);
+ sessionAppendInteger(&buf, i*3+1, &rc);
+ sessionAppendStr(&buf, " AND ", &rc);
+ }
+ }
+
+ /* Append the non-PK part of the WHERE clause */
+ sessionAppendStr(&buf, " (?", &rc);
+ sessionAppendInteger(&buf, p->nCol*3+1, &rc);
+ sessionAppendStr(&buf, " OR 1", &rc);
+ for(i=0; i<p->nCol; i++){
+ if( !p->abPK[i] ){
+ sessionAppendStr(&buf, " AND (?", &rc);
+ sessionAppendInteger(&buf, i*3+2, &rc);
+ sessionAppendStr(&buf, "=0 OR ", &rc);
+ sessionAppendIdent(&buf, p->azCol[i], &rc);
+ sessionAppendStr(&buf, " IS ?", &rc);
+ sessionAppendInteger(&buf, i*3+1, &rc);
+ sessionAppendStr(&buf, ")", &rc);
+ }
+ }
+ sessionAppendStr(&buf, ")", &rc);
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
+ }
+ sqlite3_free(buf.aBuf);
+
+ return rc;
+}
+
+/*
+** Formulate and prepare an SQL statement to query table zTab by primary
+** key. Assuming the following table structure:
+**
+** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
+**
+** The SELECT statement looks like this:
+**
+** SELECT * FROM x WHERE a = ?1 AND c = ?3
+**
+** If successful, SQLITE_OK is returned and SessionApplyCtx.pSelect is left
+** pointing to the prepared version of the SQL statement.
+*/
+static int sessionSelectRow(
+ sqlite3 *db, /* Database handle */
+ const char *zTab, /* Table name */
+ SessionApplyCtx *p /* Session changeset-apply context */
+){
+ return sessionSelectStmt(
+ db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
+}
+
+/*
+** Formulate and prepare an INSERT statement to add a record to table zTab.
+** For example:
+**
+** INSERT INTO main."zTab" VALUES(?1, ?2, ?3 ...);
+**
+** If successful, SQLITE_OK is returned and SessionApplyCtx.pInsert is left
+** pointing to the prepared version of the SQL statement.
+*/
+static int sessionInsertRow(
+ sqlite3 *db, /* Database handle */
+ const char *zTab, /* Table name */
+ SessionApplyCtx *p /* Session changeset-apply context */
+){
+ int rc = SQLITE_OK;
+ int i;
+ SessionBuffer buf = {0, 0, 0};
+
+ sessionAppendStr(&buf, "INSERT INTO main.", &rc);
+ sessionAppendIdent(&buf, zTab, &rc);
+ sessionAppendStr(&buf, " VALUES(?", &rc);
+ for(i=1; i<p->nCol; i++){
+ sessionAppendStr(&buf, ", ?", &rc);
+ }
+ sessionAppendStr(&buf, ")", &rc);
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pInsert, 0);
+ }
+ sqlite3_free(buf.aBuf);
+ return rc;
+}
+
+/*
+** A wrapper around sqlite3_bind_value() that detects an extra problem.
+** See comments in the body of this function for details.
+*/
+static int sessionBindValue(
+ sqlite3_stmt *pStmt, /* Statement to bind value to */
+ int i, /* Parameter number to bind to */
+ sqlite3_value *pVal /* Value to bind */
+){
+ int eType = sqlite3_value_type(pVal);
+ /* COVERAGE: The (pVal->z==0) branch is never true using current versions
+ ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either
+ ** the (pVal->z) variable remains as it was or the type of the value is
+ ** set to SQLITE_NULL. */
+ if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){
+ /* This condition occurs when an earlier OOM in a call to
+ ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within
+ ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */
+ return SQLITE_NOMEM;
+ }
+ return sqlite3_bind_value(pStmt, i, pVal);
+}
+
+/*
+** Iterator pIter must point to an SQLITE_INSERT entry. This function
+** transfers new.* values from the current iterator entry to statement
+** pStmt. The table being inserted into has nCol columns.
+**
+** New.* value $i from the iterator is bound to variable ($i+1) of
+** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
+** are transfered to the statement. Otherwise, if abPK is not NULL, it points
+** to an array nCol elements in size. In this case only those values for
+** which abPK[$i] is true are read from the iterator and bound to the
+** statement.
+**
+** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
+*/
+static int sessionBindRow(
+ sqlite3_changeset_iter *pIter, /* Iterator to read values from */
+ int(*xValue)(sqlite3_changeset_iter *, int, sqlite3_value **),
+ int nCol, /* Number of columns */
+ u8 *abPK, /* If not NULL, bind only if true */
+ sqlite3_stmt *pStmt /* Bind values to this statement */
+){
+ int i;
+ int rc = SQLITE_OK;
+
+ /* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the
+ ** argument iterator points to a suitable entry. Make sure that xValue
+ ** is one of these to guarantee that it is safe to ignore the return
+ ** in the code below. */
+ assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );
+
+ for(i=0; rc==SQLITE_OK && i<nCol; i++){
+ if( !abPK || abPK[i] ){
+ sqlite3_value *pVal;
+ (void)xValue(pIter, i, &pVal);
+ rc = sessionBindValue(pStmt, i+1, pVal);
+ }
+ }
+ return rc;
+}
+
+/*
+** SQL statement pSelect is as generated by the sessionSelectRow() function.
+** This function binds the primary key values from the change that changeset
+** iterator pIter points to to the SELECT and attempts to seek to the table
+** entry. If a row is found, the SELECT statement left pointing at the row
+** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
+** has occured, the statement is reset and SQLITE_OK is returned. If an
+** error occurs, the statement is reset and an SQLite error code is returned.
+**
+** If this function returns SQLITE_ROW, the caller must eventually reset()
+** statement pSelect. If any other value is returned, the statement does
+** not require a reset().
+**
+** If the iterator currently points to an INSERT record, bind values from the
+** new.* record to the SELECT statement. Or, if it points to a DELETE or
+** UPDATE, bind values from the old.* record.
+*/
+static int sessionSeekToRow(
+ sqlite3 *db, /* Database handle */
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ u8 *abPK, /* Primary key flags array */
+ sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */
+){
+ int rc; /* Return code */
+ int nCol; /* Number of columns in table */
+ int op; /* Changset operation (SQLITE_UPDATE etc.) */
+ const char *zDummy; /* Unused */
+
+ sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
+ rc = sessionBindRow(pIter,
+ op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
+ nCol, abPK, pSelect
+ );
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_step(pSelect);
+ if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
+ }
+
+ return rc;
+}
+
+/*
+** Invoke the conflict handler for the change that the changeset iterator
+** currently points to.
+**
+** Argument eType must be either CHANGESET_DATA or CHANGESET_CONFLICT.
+** If argument pbReplace is NULL, then the type of conflict handler invoked
+** depends solely on eType, as follows:
+**
+** eType value Value passed to xConflict
+** -------------------------------------------------
+** CHANGESET_DATA CHANGESET_NOTFOUND
+** CHANGESET_CONFLICT CHANGESET_CONSTRAINT
+**
+** Or, if pbReplace is not NULL, then an attempt is made to find an existing
+** record with the same primary key as the record about to be deleted, updated
+** or inserted. If such a record can be found, it is available to the conflict
+** handler as the "conflicting" record. In this case the type of conflict
+** handler invoked is as follows:
+**
+** eType value PK Record found? Value passed to xConflict
+** ----------------------------------------------------------------
+** CHANGESET_DATA Yes CHANGESET_DATA
+** CHANGESET_DATA No CHANGESET_NOTFOUND
+** CHANGESET_CONFLICT Yes CHANGESET_CONFLICT
+** CHANGESET_CONFLICT No CHANGESET_CONSTRAINT
+**
+** If pbReplace is not NULL, and a record with a matching PK is found, and
+** the conflict handler function returns SQLITE_CHANGESET_REPLACE, *pbReplace
+** is set to non-zero before returning SQLITE_OK.
+**
+** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
+** returned. Or, if the conflict handler returns an invalid value,
+** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
+** this function returns SQLITE_OK.
+*/
+static int sessionConflictHandler(
+ int eType, /* Either CHANGESET_DATA or CONFLICT */
+ SessionApplyCtx *p, /* changeset_apply() context */
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int(*xConflict)(void *, int, sqlite3_changeset_iter*),
+ void *pCtx, /* First argument for conflict handler */
+ int *pbReplace /* OUT: Set to true if PK row is found */
+){
+ int res = 0; /* Value returned by conflict handler */
+ int rc;
+ int nCol;
+ int op;
+ const char *zDummy;
+
+ sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
+
+ assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA );
+ assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT );
+ assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND );
+
+ /* Bind the new.* PRIMARY KEY values to the SELECT statement. */
+ if( pbReplace ){
+ rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
+ }else{
+ rc = SQLITE_OK;
+ }
+
+ if( rc==SQLITE_ROW ){
+ /* There exists another row with the new.* primary key. */
+ pIter->pConflict = p->pSelect;
+ res = xConflict(pCtx, eType, pIter);
+ pIter->pConflict = 0;
+ rc = sqlite3_reset(p->pSelect);
+ }else if( rc==SQLITE_OK ){
+ if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
+ /* Instead of invoking the conflict handler, append the change blob
+ ** to the SessionApplyCtx.constraints buffer. */
+ u8 *aBlob = &pIter->in.aData[pIter->in.iCurrent];
+ int nBlob = pIter->in.iNext - pIter->in.iCurrent;
+ sessionAppendBlob(&p->constraints, aBlob, nBlob, &rc);
+ res = SQLITE_CHANGESET_OMIT;
+ }else{
+ /* No other row with the new.* primary key. */
+ res = xConflict(pCtx, eType+1, pIter);
+ if( res==SQLITE_CHANGESET_REPLACE ) rc = SQLITE_MISUSE;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ switch( res ){
+ case SQLITE_CHANGESET_REPLACE:
+ assert( pbReplace );
+ *pbReplace = 1;
+ break;
+
+ case SQLITE_CHANGESET_OMIT:
+ break;
+
+ case SQLITE_CHANGESET_ABORT:
+ rc = SQLITE_ABORT;
+ break;
+
+ default:
+ rc = SQLITE_MISUSE;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Attempt to apply the change that the iterator passed as the first argument
+** currently points to to the database. If a conflict is encountered, invoke
+** the conflict handler callback.
+**
+** If argument pbRetry is NULL, then ignore any CHANGESET_DATA conflict. If
+** one is encountered, update or delete the row with the matching primary key
+** instead. Or, if pbRetry is not NULL and a CHANGESET_DATA conflict occurs,
+** invoke the conflict handler. If it returns CHANGESET_REPLACE, set *pbRetry
+** to true before returning. In this case the caller will invoke this function
+** again, this time with pbRetry set to NULL.
+**
+** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is
+** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
+** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
+** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
+** before retrying. In this case the caller attempts to remove the conflicting
+** row before invoking this function again, this time with pbReplace set
+** to NULL.
+**
+** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
+** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is
+** returned.
+*/
+static int sessionApplyOneOp(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ SessionApplyCtx *p, /* changeset_apply() context */
+ int(*xConflict)(void *, int, sqlite3_changeset_iter *),
+ void *pCtx, /* First argument for the conflict handler */
+ int *pbReplace, /* OUT: True to remove PK row and retry */
+ int *pbRetry /* OUT: True to retry. */
+){
+ const char *zDummy;
+ int op;
+ int nCol;
+ int rc = SQLITE_OK;
+
+ assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
+ assert( p->azCol && p->abPK );
+ assert( !pbReplace || *pbReplace==0 );
+
+ sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
+
+ if( op==SQLITE_DELETE ){
+
+ /* Bind values to the DELETE statement. If conflict handling is required,
+ ** bind values for all columns and set bound variable (nCol+1) to true.
+ ** Or, if conflict handling is not required, bind just the PK column
+ ** values and, if it exists, set (nCol+1) to false. Conflict handling
+ ** is not required if:
+ **
+ ** * this is a patchset, or
+ ** * (pbRetry==0), or
+ ** * all columns of the table are PK columns (in this case there is
+ ** no (nCol+1) variable to bind to).
+ */
+ u8 *abPK = (pIter->bPatchset ? p->abPK : 0);
+ rc = sessionBindRow(pIter, sqlite3changeset_old, nCol, abPK, p->pDelete);
+ if( rc==SQLITE_OK && sqlite3_bind_parameter_count(p->pDelete)>nCol ){
+ rc = sqlite3_bind_int(p->pDelete, nCol+1, (pbRetry==0 || abPK));
+ }
+ if( rc!=SQLITE_OK ) return rc;
+
+ sqlite3_step(p->pDelete);
+ rc = sqlite3_reset(p->pDelete);
+ if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
+ rc = sessionConflictHandler(
+ SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
+ );
+ }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
+ rc = sessionConflictHandler(
+ SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
+ );
+ }
+
+ }else if( op==SQLITE_UPDATE ){
+ int i;
+
+ /* Bind values to the UPDATE statement. */
+ for(i=0; rc==SQLITE_OK && i<nCol; i++){
+ sqlite3_value *pOld = sessionChangesetOld(pIter, i);
+ sqlite3_value *pNew = sessionChangesetNew(pIter, i);
+
+ sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
+ if( pOld ){
+ rc = sessionBindValue(p->pUpdate, i*3+1, pOld);
+ }
+ if( rc==SQLITE_OK && pNew ){
+ rc = sessionBindValue(p->pUpdate, i*3+3, pNew);
+ }
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset);
+ }
+ if( rc!=SQLITE_OK ) return rc;
+
+ /* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
+ ** the result will be SQLITE_OK with 0 rows modified. */
+ sqlite3_step(p->pUpdate);
+ rc = sqlite3_reset(p->pUpdate);
+
+ if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
+ /* A NOTFOUND or DATA error. Search the table to see if it contains
+ ** a row with a matching primary key. If so, this is a DATA conflict.
+ ** Otherwise, if there is no primary key match, it is a NOTFOUND. */
+
+ rc = sessionConflictHandler(
+ SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
+ );
+
+ }else if( (rc&0xff)==SQLITE_CONSTRAINT ){
+ /* This is always a CONSTRAINT conflict. */
+ rc = sessionConflictHandler(
+ SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0
+ );
+ }
+
+ }else{
+ assert( op==SQLITE_INSERT );
+ rc = sessionBindRow(pIter, sqlite3changeset_new, nCol, 0, p->pInsert);
+ if( rc!=SQLITE_OK ) return rc;
+
+ sqlite3_step(p->pInsert);
+ rc = sqlite3_reset(p->pInsert);
+ if( (rc&0xff)==SQLITE_CONSTRAINT ){
+ rc = sessionConflictHandler(
+ SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, pbReplace
+ );
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Attempt to apply the change that the iterator passed as the first argument
+** currently points to to the database. If a conflict is encountered, invoke
+** the conflict handler callback.
+**
+** The difference between this function and sessionApplyOne() is that this
+** function handles the case where the conflict-handler is invoked and
+** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be
+** retried in some manner.
+*/
+static int sessionApplyOneWithRetry(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ sqlite3_changeset_iter *pIter, /* Changeset iterator to read change from */
+ SessionApplyCtx *pApply, /* Apply context */
+ int(*xConflict)(void*, int, sqlite3_changeset_iter*),
+ void *pCtx /* First argument passed to xConflict */
+){
+ int bReplace = 0;
+ int bRetry = 0;
+ int rc;
+
+ rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, &bReplace, &bRetry);
+ assert( rc==SQLITE_OK || (bRetry==0 && bReplace==0) );
+
+ /* If the bRetry flag is set, the change has not been applied due to an
+ ** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
+ ** a row with the correct PK is present in the db, but one or more other
+ ** fields do not contain the expected values) and the conflict handler
+ ** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
+ ** but pass NULL as the final argument so that sessionApplyOneOp() ignores
+ ** the SQLITE_CHANGESET_DATA problem. */
+ if( bRetry ){
+ assert( pIter->op==SQLITE_UPDATE || pIter->op==SQLITE_DELETE );
+ rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
+ }
+
+ /* If the bReplace flag is set, the change is an INSERT that has not
+ ** been performed because the database already contains a row with the
+ ** specified primary key and the conflict handler returned
+ ** SQLITE_CHANGESET_REPLACE. In this case remove the conflicting row
+ ** before reattempting the INSERT. */
+ else if( bReplace ){
+ assert( pIter->op==SQLITE_INSERT );
+ rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sessionBindRow(pIter,
+ sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
+ sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_step(pApply->pDelete);
+ rc = sqlite3_reset(pApply->pDelete);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sessionApplyOneOp(pIter, pApply, xConflict, pCtx, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(db, "RELEASE replace_op", 0, 0, 0);
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Retry the changes accumulated in the pApply->constraints buffer.
+*/
+static int sessionRetryConstraints(
+ sqlite3 *db,
+ int bPatchset,
+ const char *zTab,
+ SessionApplyCtx *pApply,
+ int(*xConflict)(void*, int, sqlite3_changeset_iter*),
+ void *pCtx /* First argument passed to xConflict */
+){
+ int rc = SQLITE_OK;
+
+ while( pApply->constraints.nBuf ){
+ sqlite3_changeset_iter *pIter2 = 0;
+ SessionBuffer cons = pApply->constraints;
+ memset(&pApply->constraints, 0, sizeof(SessionBuffer));
+
+ rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf);
+ if( rc==SQLITE_OK ){
+ int nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
+ int rc2;
+ pIter2->bPatchset = bPatchset;
+ pIter2->zTab = (char*)zTab;
+ pIter2->nCol = pApply->nCol;
+ pIter2->abPK = pApply->abPK;
+ sessionBufferGrow(&pIter2->tblhdr, nByte, &rc);
+ pIter2->apValue = (sqlite3_value**)pIter2->tblhdr.aBuf;
+ if( rc==SQLITE_OK ) memset(pIter2->apValue, 0, nByte);
+
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter2) ){
+ rc = sessionApplyOneWithRetry(db, pIter2, pApply, xConflict, pCtx);
+ }
+
+ rc2 = sqlite3changeset_finalize(pIter2);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
+ assert( pApply->bDeferConstraints || pApply->constraints.nBuf==0 );
+
+ sqlite3_free(cons.aBuf);
+ if( rc!=SQLITE_OK ) break;
+ if( pApply->constraints.nBuf>=cons.nBuf ){
+ /* No progress was made on the last round. */
+ pApply->bDeferConstraints = 0;
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Argument pIter is a changeset iterator that has been initialized, but
+** not yet passed to sqlite3changeset_next(). This function applies the
+** changeset to the main database attached to handle "db". The supplied
+** conflict handler callback is invoked to resolve any conflicts encountered
+** while applying the change.
+*/
+static int sessionChangesetApply(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ sqlite3_changeset_iter *pIter, /* Changeset to apply */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of fifth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx /* First argument passed to xConflict */
+){
+ int schemaMismatch = 0;
+ int rc; /* Return code */
+ const char *zTab = 0; /* Name of current table */
+ int nTab = 0; /* Result of sqlite3Strlen30(zTab) */
+ SessionApplyCtx sApply; /* changeset_apply() context object */
+ int bPatchset;
+
+ assert( xConflict!=0 );
+
+ pIter->in.bNoDiscard = 1;
+ memset(&sApply, 0, sizeof(sApply));
+ sqlite3_mutex_enter(sqlite3_db_mutex(db));
+ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(db, "PRAGMA defer_foreign_keys = 1", 0, 0, 0);
+ }
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3changeset_next(pIter) ){
+ int nCol;
+ int op;
+ const char *zNew;
+
+ sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
+
+ if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
+ u8 *abPK;
+
+ rc = sessionRetryConstraints(
+ db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx
+ );
+ if( rc!=SQLITE_OK ) break;
+
+ sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
+ sqlite3_finalize(sApply.pDelete);
+ sqlite3_finalize(sApply.pUpdate);
+ sqlite3_finalize(sApply.pInsert);
+ sqlite3_finalize(sApply.pSelect);
+ memset(&sApply, 0, sizeof(sApply));
+ sApply.db = db;
+ sApply.bDeferConstraints = 1;
+
+ /* If an xFilter() callback was specified, invoke it now. If the
+ ** xFilter callback returns zero, skip this table. If it returns
+ ** non-zero, proceed. */
+ schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew)));
+ if( schemaMismatch ){
+ zTab = sqlite3_mprintf("%s", zNew);
+ if( zTab==0 ){
+ rc = SQLITE_NOMEM;
+ break;
+ }
+ nTab = (int)strlen(zTab);
+ sApply.azCol = (const char **)zTab;
+ }else{
+ sqlite3changeset_pk(pIter, &abPK, 0);
+ rc = sessionTableInfo(
+ db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
+ );
+ if( rc!=SQLITE_OK ) break;
+
+ if( sApply.nCol==0 ){
+ schemaMismatch = 1;
+ sqlite3_log(SQLITE_SCHEMA,
+ "sqlite3changeset_apply(): no such table: %s", zTab
+ );
+ }
+ else if( sApply.nCol!=nCol ){
+ schemaMismatch = 1;
+ sqlite3_log(SQLITE_SCHEMA,
+ "sqlite3changeset_apply(): table %s has %d columns, expected %d",
+ zTab, sApply.nCol, nCol
+ );
+ }
+ else if( memcmp(sApply.abPK, abPK, nCol)!=0 ){
+ schemaMismatch = 1;
+ sqlite3_log(SQLITE_SCHEMA, "sqlite3changeset_apply(): "
+ "primary key mismatch for table %s", zTab
+ );
+ }
+ else if(
+ (rc = sessionSelectRow(db, zTab, &sApply))
+ || (rc = sessionUpdateRow(db, zTab, &sApply))
+ || (rc = sessionDeleteRow(db, zTab, &sApply))
+ || (rc = sessionInsertRow(db, zTab, &sApply))
+ ){
+ break;
+ }
+ nTab = sqlite3Strlen30(zTab);
+ }
+ }
+
+ /* If there is a schema mismatch on the current table, proceed to the
+ ** next change. A log message has already been issued. */
+ if( schemaMismatch ) continue;
+
+ rc = sessionApplyOneWithRetry(db, pIter, &sApply, xConflict, pCtx);
+ }
+
+ bPatchset = pIter->bPatchset;
+ if( rc==SQLITE_OK ){
+ rc = sqlite3changeset_finalize(pIter);
+ }else{
+ sqlite3changeset_finalize(pIter);
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = sessionRetryConstraints(db, bPatchset, zTab, &sApply, xConflict, pCtx);
+ }
+
+ if( rc==SQLITE_OK ){
+ int nFk, notUsed;
+ sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, &notUsed, 0);
+ if( nFk!=0 ){
+ int res = SQLITE_CHANGESET_ABORT;
+ sqlite3_changeset_iter sIter;
+ memset(&sIter, 0, sizeof(sIter));
+ sIter.nCol = nFk;
+ res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter);
+ if( res!=SQLITE_CHANGESET_OMIT ){
+ rc = SQLITE_CONSTRAINT;
+ }
+ }
+ }
+ sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0);
+
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
+ }else{
+ sqlite3_exec(db, "ROLLBACK TO changeset_apply", 0, 0, 0);
+ sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
+ }
+
+ sqlite3_finalize(sApply.pInsert);
+ sqlite3_finalize(sApply.pDelete);
+ sqlite3_finalize(sApply.pUpdate);
+ sqlite3_finalize(sApply.pSelect);
+ sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
+ sqlite3_free((char*)sApply.constraints.aBuf);
+ sqlite3_mutex_leave(sqlite3_db_mutex(db));
+ return rc;
+}
+
+/*
+** Apply the changeset passed via pChangeset/nChangeset to the main database
+** attached to handle "db". Invoke the supplied conflict handler callback
+** to resolve any conflicts encountered while applying the change.
+*/
+SQLITE_API int sqlite3changeset_apply(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int nChangeset, /* Size of changeset in bytes */
+ void *pChangeset, /* Changeset blob */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of fifth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx /* First argument passed to xConflict */
+){
+ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
+ int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
+ if( rc==SQLITE_OK ){
+ rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
+ }
+ return rc;
+}
+
+/*
+** Apply the changeset passed via xInput/pIn to the main database
+** attached to handle "db". Invoke the supplied conflict handler callback
+** to resolve any conflicts encountered while applying the change.
+*/
+SQLITE_API int sqlite3changeset_apply_strm(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
+ void *pIn, /* First arg for xInput */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx /* First argument passed to xConflict */
+){
+ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
+ int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
+ if( rc==SQLITE_OK ){
+ rc = sessionChangesetApply(db, pIter, xFilter, xConflict, pCtx);
+ }
+ return rc;
+}
+
+/*
+** sqlite3_changegroup handle.
+*/
+struct sqlite3_changegroup {
+ int rc; /* Error code */
+ int bPatch; /* True to accumulate patchsets */
+ SessionTable *pList; /* List of tables in current patch */
+};
+
+/*
+** This function is called to merge two changes to the same row together as
+** part of an sqlite3changeset_concat() operation. A new change object is
+** allocated and a pointer to it stored in *ppNew.
+*/
+static int sessionChangeMerge(
+ SessionTable *pTab, /* Table structure */
+ int bPatchset, /* True for patchsets */
+ SessionChange *pExist, /* Existing change */
+ int op2, /* Second change operation */
+ int bIndirect, /* True if second change is indirect */
+ u8 *aRec, /* Second change record */
+ int nRec, /* Number of bytes in aRec */
+ SessionChange **ppNew /* OUT: Merged change */
+){
+ SessionChange *pNew = 0;
+
+ if( !pExist ){
+ pNew = (SessionChange *)sqlite3_malloc(sizeof(SessionChange) + nRec);
+ if( !pNew ){
+ return SQLITE_NOMEM;
+ }
+ memset(pNew, 0, sizeof(SessionChange));
+ pNew->op = op2;
+ pNew->bIndirect = bIndirect;
+ pNew->nRecord = nRec;
+ pNew->aRecord = (u8*)&pNew[1];
+ memcpy(pNew->aRecord, aRec, nRec);
+ }else{
+ int op1 = pExist->op;
+
+ /*
+ ** op1=INSERT, op2=INSERT -> Unsupported. Discard op2.
+ ** op1=INSERT, op2=UPDATE -> INSERT.
+ ** op1=INSERT, op2=DELETE -> (none)
+ **
+ ** op1=UPDATE, op2=INSERT -> Unsupported. Discard op2.
+ ** op1=UPDATE, op2=UPDATE -> UPDATE.
+ ** op1=UPDATE, op2=DELETE -> DELETE.
+ **
+ ** op1=DELETE, op2=INSERT -> UPDATE.
+ ** op1=DELETE, op2=UPDATE -> Unsupported. Discard op2.
+ ** op1=DELETE, op2=DELETE -> Unsupported. Discard op2.
+ */
+ if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT)
+ || (op1==SQLITE_UPDATE && op2==SQLITE_INSERT)
+ || (op1==SQLITE_DELETE && op2==SQLITE_UPDATE)
+ || (op1==SQLITE_DELETE && op2==SQLITE_DELETE)
+ ){
+ pNew = pExist;
+ }else if( op1==SQLITE_INSERT && op2==SQLITE_DELETE ){
+ sqlite3_free(pExist);
+ assert( pNew==0 );
+ }else{
+ u8 *aExist = pExist->aRecord;
+ int nByte;
+ u8 *aCsr;
+
+ /* Allocate a new SessionChange object. Ensure that the aRecord[]
+ ** buffer of the new object is large enough to hold any record that
+ ** may be generated by combining the input records. */
+ nByte = sizeof(SessionChange) + pExist->nRecord + nRec;
+ pNew = (SessionChange *)sqlite3_malloc(nByte);
+ if( !pNew ){
+ sqlite3_free(pExist);
+ return SQLITE_NOMEM;
+ }
+ memset(pNew, 0, sizeof(SessionChange));
+ pNew->bIndirect = (bIndirect && pExist->bIndirect);
+ aCsr = pNew->aRecord = (u8 *)&pNew[1];
+
+ if( op1==SQLITE_INSERT ){ /* INSERT + UPDATE */
+ u8 *a1 = aRec;
+ assert( op2==SQLITE_UPDATE );
+ pNew->op = SQLITE_INSERT;
+ if( bPatchset==0 ) sessionSkipRecord(&a1, pTab->nCol);
+ sessionMergeRecord(&aCsr, pTab->nCol, aExist, a1);
+ }else if( op1==SQLITE_DELETE ){ /* DELETE + INSERT */
+ assert( op2==SQLITE_INSERT );
+ pNew->op = SQLITE_UPDATE;
+ if( bPatchset ){
+ memcpy(aCsr, aRec, nRec);
+ aCsr += nRec;
+ }else{
+ if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aExist, 0,aRec,0) ){
+ sqlite3_free(pNew);
+ pNew = 0;
+ }
+ }
+ }else if( op2==SQLITE_UPDATE ){ /* UPDATE + UPDATE */
+ u8 *a1 = aExist;
+ u8 *a2 = aRec;
+ assert( op1==SQLITE_UPDATE );
+ if( bPatchset==0 ){
+ sessionSkipRecord(&a1, pTab->nCol);
+ sessionSkipRecord(&a2, pTab->nCol);
+ }
+ pNew->op = SQLITE_UPDATE;
+ if( 0==sessionMergeUpdate(&aCsr, pTab, bPatchset, aRec, aExist,a1,a2) ){
+ sqlite3_free(pNew);
+ pNew = 0;
+ }
+ }else{ /* UPDATE + DELETE */
+ assert( op1==SQLITE_UPDATE && op2==SQLITE_DELETE );
+ pNew->op = SQLITE_DELETE;
+ if( bPatchset ){
+ memcpy(aCsr, aRec, nRec);
+ aCsr += nRec;
+ }else{
+ sessionMergeRecord(&aCsr, pTab->nCol, aRec, aExist);
+ }
+ }
+
+ if( pNew ){
+ pNew->nRecord = (int)(aCsr - pNew->aRecord);
+ }
+ sqlite3_free(pExist);
+ }
+ }
+
+ *ppNew = pNew;
+ return SQLITE_OK;
+}
+
+/*
+** Add all changes in the changeset traversed by the iterator passed as
+** the first argument to the changegroup hash tables.
+*/
+static int sessionChangesetToHash(
+ sqlite3_changeset_iter *pIter, /* Iterator to read from */
+ sqlite3_changegroup *pGrp /* Changegroup object to add changeset to */
+){
+ u8 *aRec;
+ int nRec;
+ int rc = SQLITE_OK;
+ SessionTable *pTab = 0;
+
+
+ while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec) ){
+ const char *zNew;
+ int nCol;
+ int op;
+ int iHash;
+ int bIndirect;
+ SessionChange *pChange;
+ SessionChange *pExist = 0;
+ SessionChange **pp;
+
+ if( pGrp->pList==0 ){
+ pGrp->bPatch = pIter->bPatchset;
+ }else if( pIter->bPatchset!=pGrp->bPatch ){
+ rc = SQLITE_ERROR;
+ break;
+ }
+
+ sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);
+ if( !pTab || sqlite3_stricmp(zNew, pTab->zName) ){
+ /* Search the list for a matching table */
+ int nNew = (int)strlen(zNew);
+ u8 *abPK;
+
+ sqlite3changeset_pk(pIter, &abPK, 0);
+ for(pTab = pGrp->pList; pTab; pTab=pTab->pNext){
+ if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
+ }
+ if( !pTab ){
+ SessionTable **ppTab;
+
+ pTab = sqlite3_malloc(sizeof(SessionTable) + nCol + nNew+1);
+ if( !pTab ){
+ rc = SQLITE_NOMEM;
+ break;
+ }
+ memset(pTab, 0, sizeof(SessionTable));
+ pTab->nCol = nCol;
+ pTab->abPK = (u8*)&pTab[1];
+ memcpy(pTab->abPK, abPK, nCol);
+ pTab->zName = (char*)&pTab->abPK[nCol];
+ memcpy(pTab->zName, zNew, nNew+1);
+
+ /* The new object must be linked on to the end of the list, not
+ ** simply added to the start of it. This is to ensure that the
+ ** tables within the output of sqlite3changegroup_output() are in
+ ** the right order. */
+ for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
+ *ppTab = pTab;
+ }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
+ rc = SQLITE_SCHEMA;
+ break;
+ }
+ }
+
+ if( sessionGrowHash(pIter->bPatchset, pTab) ){
+ rc = SQLITE_NOMEM;
+ break;
+ }
+ iHash = sessionChangeHash(
+ pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
+ );
+
+ /* Search for existing entry. If found, remove it from the hash table.
+ ** Code below may link it back in.
+ */
+ for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
+ int bPkOnly1 = 0;
+ int bPkOnly2 = 0;
+ if( pIter->bPatchset ){
+ bPkOnly1 = (*pp)->op==SQLITE_DELETE;
+ bPkOnly2 = op==SQLITE_DELETE;
+ }
+ if( sessionChangeEqual(pTab, bPkOnly1, (*pp)->aRecord, bPkOnly2, aRec) ){
+ pExist = *pp;
+ *pp = (*pp)->pNext;
+ pTab->nEntry--;
+ break;
+ }
+ }
+
+ rc = sessionChangeMerge(pTab,
+ pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
+ );
+ if( rc ) break;
+ if( pChange ){
+ pChange->pNext = pTab->apChange[iHash];
+ pTab->apChange[iHash] = pChange;
+ pTab->nEntry++;
+ }
+ }
+
+ if( rc==SQLITE_OK ) rc = pIter->rc;
+ return rc;
+}
+
+/*
+** Serialize a changeset (or patchset) based on all changesets (or patchsets)
+** added to the changegroup object passed as the first argument.
+**
+** If xOutput is not NULL, then the changeset/patchset is returned to the
+** user via one or more calls to xOutput, as with the other streaming
+** interfaces.
+**
+** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a
+** buffer containing the output changeset before this function returns. In
+** this case (*pnOut) is set to the size of the output buffer in bytes. It
+** is the responsibility of the caller to free the output buffer using
+** sqlite3_free() when it is no longer required.
+**
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an SQLite
+** error code. If an error occurs and xOutput is NULL, (*ppOut) and (*pnOut)
+** are both set to 0 before returning.
+*/
+static int sessionChangegroupOutput(
+ sqlite3_changegroup *pGrp,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut,
+ int *pnOut,
+ void **ppOut
+){
+ int rc = SQLITE_OK;
+ SessionBuffer buf = {0, 0, 0};
+ SessionTable *pTab;
+ assert( xOutput==0 || (ppOut==0 && pnOut==0) );
+
+ /* Create the serialized output changeset based on the contents of the
+ ** hash tables attached to the SessionTable objects in list p->pList.
+ */
+ for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
+ int i;
+ if( pTab->nEntry==0 ) continue;
+
+ sessionAppendTableHdr(&buf, pGrp->bPatch, pTab, &rc);
+ for(i=0; i<pTab->nChange; i++){
+ SessionChange *p;
+ for(p=pTab->apChange[i]; p; p=p->pNext){
+ sessionAppendByte(&buf, p->op, &rc);
+ sessionAppendByte(&buf, p->bIndirect, &rc);
+ sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
+ }
+ }
+
+ if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){
+ rc = xOutput(pOut, buf.aBuf, buf.nBuf);
+ buf.nBuf = 0;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ if( xOutput ){
+ if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
+ }else{
+ *ppOut = buf.aBuf;
+ *pnOut = buf.nBuf;
+ buf.aBuf = 0;
+ }
+ }
+ sqlite3_free(buf.aBuf);
+
+ return rc;
+}
+
+/*
+** Allocate a new, empty, sqlite3_changegroup.
+*/
+SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){
+ int rc = SQLITE_OK; /* Return code */
+ sqlite3_changegroup *p; /* New object */
+ p = (sqlite3_changegroup*)sqlite3_malloc(sizeof(sqlite3_changegroup));
+ if( p==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(p, 0, sizeof(sqlite3_changegroup));
+ }
+ *pp = p;
+ return rc;
+}
+
+/*
+** Add the changeset currently stored in buffer pData, size nData bytes,
+** to changeset-group p.
+*/
+SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup *pGrp, int nData, void *pData){
+ sqlite3_changeset_iter *pIter; /* Iterator opened on pData/nData */
+ int rc; /* Return code */
+
+ rc = sqlite3changeset_start(&pIter, nData, pData);
+ if( rc==SQLITE_OK ){
+ rc = sessionChangesetToHash(pIter, pGrp);
+ }
+ sqlite3changeset_finalize(pIter);
+ return rc;
+}
+
+/*
+** Obtain a buffer containing a changeset representing the concatenation
+** of all changesets added to the group so far.
+*/
+SQLITE_API int sqlite3changegroup_output(
+ sqlite3_changegroup *pGrp,
+ int *pnData,
+ void **ppData
+){
+ return sessionChangegroupOutput(pGrp, 0, 0, pnData, ppData);
+}
+
+/*
+** Streaming versions of changegroup_add().
+*/
+SQLITE_API int sqlite3changegroup_add_strm(
+ sqlite3_changegroup *pGrp,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn
+){
+ sqlite3_changeset_iter *pIter; /* Iterator opened on pData/nData */
+ int rc; /* Return code */
+
+ rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
+ if( rc==SQLITE_OK ){
+ rc = sessionChangesetToHash(pIter, pGrp);
+ }
+ sqlite3changeset_finalize(pIter);
+ return rc;
+}
+
+/*
+** Streaming versions of changegroup_output().
+*/
+SQLITE_API int sqlite3changegroup_output_strm(
+ sqlite3_changegroup *pGrp,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+){
+ return sessionChangegroupOutput(pGrp, xOutput, pOut, 0, 0);
+}
+
+/*
+** Delete a changegroup object.
+*/
+SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
+ if( pGrp ){
+ sessionDeleteTable(pGrp->pList);
+ sqlite3_free(pGrp);
+ }
+}
+
+/*
+** Combine two changesets together.
+*/
+SQLITE_API int sqlite3changeset_concat(
+ int nLeft, /* Number of bytes in lhs input */
+ void *pLeft, /* Lhs input changeset */
+ int nRight /* Number of bytes in rhs input */,
+ void *pRight, /* Rhs input changeset */
+ int *pnOut, /* OUT: Number of bytes in output changeset */
+ void **ppOut /* OUT: changeset (left <concat> right) */
+){
+ sqlite3_changegroup *pGrp;
+ int rc;
+
+ rc = sqlite3changegroup_new(&pGrp);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3changegroup_add(pGrp, nLeft, pLeft);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3changegroup_add(pGrp, nRight, pRight);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
+ }
+ sqlite3changegroup_delete(pGrp);
+
+ return rc;
+}
+
+/*
+** Streaming version of sqlite3changeset_concat().
+*/
+SQLITE_API int sqlite3changeset_concat_strm(
+ int (*xInputA)(void *pIn, void *pData, int *pnData),
+ void *pInA,
+ int (*xInputB)(void *pIn, void *pData, int *pnData),
+ void *pInB,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+){
+ sqlite3_changegroup *pGrp;
+ int rc;
+
+ rc = sqlite3changegroup_new(&pGrp);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3changegroup_add_strm(pGrp, xInputA, pInA);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3changegroup_add_strm(pGrp, xInputB, pInB);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3changegroup_output_strm(pGrp, xOutput, pOut);
+ }
+ sqlite3changegroup_delete(pGrp);
+
+ return rc;
+}
+
+#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */
+
+/************** End of sqlite3session.c **************************************/
/************** Begin file json1.c *******************************************/
/*
** 2015-08-12
@@ -165752,13 +177574,15 @@ SQLITE_EXTENSION_INIT1
#ifdef sqlite3Isdigit
/* Use the SQLite core versions if this routine is part of the
** SQLite amalgamation */
-# define safe_isdigit(x) sqlite3Isdigit(x)
-# define safe_isalnum(x) sqlite3Isalnum(x)
+# define safe_isdigit(x) sqlite3Isdigit(x)
+# define safe_isalnum(x) sqlite3Isalnum(x)
+# define safe_isxdigit(x) sqlite3Isxdigit(x)
#else
/* Use the standard library for separate compilation */
#include <ctype.h> /* amalgamator: keep */
-# define safe_isdigit(x) isdigit((unsigned char)(x))
-# define safe_isalnum(x) isalnum((unsigned char)(x))
+# define safe_isdigit(x) isdigit((unsigned char)(x))
+# define safe_isalnum(x) isalnum((unsigned char)(x))
+# define safe_isxdigit(x) isxdigit((unsigned char)(x))
#endif
/*
@@ -166296,12 +178120,13 @@ static void jsonReturn(
c = z[++i];
if( c=='u' ){
u32 v = 0, k;
- for(k=0; k<4 && i<n-2; i++, k++){
+ for(k=0; k<4; i++, k++){
+ assert( i<n-2 );
c = z[i+1];
- if( c>='0' && c<='9' ) v = v*16 + c - '0';
- else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10;
- else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10;
- else break;
+ assert( safe_isxdigit(c) );
+ if( c<='9' ) v = v*16 + c - '0';
+ else if( c<='F' ) v = v*16 + c - 'A' + 10;
+ else v = v*16 + c - 'a' + 10;
}
if( v==0 ) break;
if( v<=0x7f ){
@@ -166406,6 +178231,15 @@ static int jsonParseAddNode(
}
/*
+** Return true if z[] begins with 4 (or more) hexadecimal digits
+*/
+static int jsonIs4Hex(const char *z){
+ int i;
+ for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
+ return 1;
+}
+
+/*
** Parse a single JSON value which begins at pParse->zJson[i]. Return the
** index of the first character past the end of the value parsed.
**
@@ -166479,8 +178313,13 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
if( c==0 ) return -1;
if( c=='\\' ){
c = pParse->zJson[++j];
- if( c==0 ) return -1;
- jnFlags = JNODE_ESCAPE;
+ if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
+ || c=='n' || c=='r' || c=='t'
+ || (c=='u' && jsonIs4Hex(pParse->zJson+j+1)) ){
+ jnFlags = JNODE_ESCAPE;
+ }else{
+ return -1;
+ }
}else if( c=='"' ){
break;
}
@@ -166915,6 +178754,26 @@ static void jsonTest1Func(
****************************************************************************/
/*
+** Implementation of the json_QUOTE(VALUE) function. Return a JSON value
+** corresponding to the SQL value input. Mostly this means putting
+** double-quotes around strings and returning the unquoted string "null"
+** when given a NULL input.
+*/
+static void jsonQuoteFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonString jx;
+ UNUSED_PARAM(argc);
+
+ jsonInit(&jx, ctx);
+ jsonAppendValue(&jx, argv[0]);
+ jsonResult(&jx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+}
+
+/*
** Implementation of the json_array(VALUE,...) function. Return a JSON
** array that contains all values given in arguments. Or if any argument
** is a BLOB, throw an error.
@@ -167328,7 +179187,7 @@ static void jsonObjectFinal(sqlite3_context *ctx){
if( pStr ){
jsonAppendChar(pStr, '}');
if( pStr->bErr ){
- if( pStr->bErr==0 ) sqlite3_result_error_nomem(ctx);
+ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
assert( pStr->bStatic );
}else{
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
@@ -167606,9 +179465,9 @@ static int jsonEachColumn(
/* For json_each() path and root are the same so fall through
** into the root case */
}
- case JEACH_ROOT: {
+ default: {
const char *zRoot = p->zRoot;
- if( zRoot==0 ) zRoot = "$";
+ if( zRoot==0 ) zRoot = "$";
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
break;
}
@@ -167827,6 +179686,7 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
{ "json_extract", -1, 0, jsonExtractFunc },
{ "json_insert", -1, 0, jsonSetFunc },
{ "json_object", -1, 0, jsonObjectFunc },
+ { "json_quote", 1, 0, jsonQuoteFunc },
{ "json_remove", -1, 0, jsonRemoveFunc },
{ "json_replace", -1, 0, jsonReplaceFunc },
{ "json_set", -1, 1, jsonSetFunc },
@@ -167882,7 +179742,7 @@ SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int SQLITE_STDCALL sqlite3_json_init(
+SQLITE_API int sqlite3_json_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -168052,11 +179912,13 @@ struct Fts5PhraseIter {
** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
**
** with $p set to a phrase equivalent to the phrase iPhrase of the
-** current query is executed. For each row visited, the callback function
-** passed as the fourth argument is invoked. The context and API objects
-** passed to the callback function may be used to access the properties of
-** each matched row. Invoking Api.xUserData() returns a copy of the pointer
-** passed as the third argument to pUserData.
+** current query is executed. Any column filter that applies to
+** phrase iPhrase of the current query is included in $p. For each
+** row visited, the callback function passed as the fourth argument
+** is invoked. The context and API objects passed to the callback
+** function may be used to access the properties of each matched row.
+** Invoking Api.xUserData() returns a copy of the pointer passed as
+** the third argument to pUserData.
**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
@@ -168225,7 +180087,7 @@ struct Fts5ExtensionApi {
** behaviour. The structure methods are expected to function as follows:
**
** xCreate:
-** This function is used to allocate and inititalize a tokenizer instance.
+** This function is used to allocate and initialize a tokenizer instance.
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
@@ -168485,7 +180347,6 @@ struct fts5_api {
#endif /* _FTS5_H */
-
/*
** 2014 May 31
**
@@ -168535,6 +180396,10 @@ typedef sqlite3_uint64 u64;
#endif
+/* Truncate very long tokens to this many bytes. Hard limit is
+** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
+** field that occurs at the start of each leaf page (see fts5_index.c). */
+#define FTS5_MAX_TOKEN_SIZE 32768
/*
** Maximum number of prefix indexes on single FTS5 table. This must be
@@ -168660,6 +180525,7 @@ struct Fts5Config {
int pgsz; /* Approximate page size used in %_data */
int nAutomerge; /* 'automerge' setting */
int nCrisisMerge; /* Maximum allowed segments per level */
+ int nUsermerge; /* 'usermerge' setting */
int nHashSize; /* Bytes of memory for in-memory hash */
char *zRank; /* Name of rank function */
char *zRankArgs; /* Arguments to rank function */
@@ -168967,6 +180833,7 @@ static int sqlite3Fts5IndexReads(Fts5Index *p);
static int sqlite3Fts5IndexReinit(Fts5Index *p);
static int sqlite3Fts5IndexOptimize(Fts5Index *p);
static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge);
+static int sqlite3Fts5IndexReset(Fts5Index *p);
static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
@@ -169109,6 +180976,7 @@ static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);
static int sqlite3Fts5StorageRebuild(Fts5Storage *p);
static int sqlite3Fts5StorageOptimize(Fts5Storage *p);
static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
+static int sqlite3Fts5StorageReset(Fts5Storage *p);
/*
** End of interface to code in fts5_storage.c.
@@ -169167,7 +181035,6 @@ static int sqlite3Fts5ExprPopulatePoslists(
Fts5Config*, Fts5Expr*, Fts5PoslistPopulator*, int, const char*, int
);
static void sqlite3Fts5ExprCheckPoslists(Fts5Expr*, i64);
-static void sqlite3Fts5ExprClearEof(Fts5Expr*);
static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
@@ -169188,6 +181055,12 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
Fts5ExprNearset *pNear
);
+static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
+ Fts5Parse *pParse,
+ Fts5ExprNode *pLeft,
+ Fts5ExprNode *pRight
+);
+
static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
Fts5Parse *pParse,
Fts5ExprPhrase *pPhrase,
@@ -169213,6 +181086,7 @@ static void sqlite3Fts5ParseNodeFree(Fts5ExprNode*);
static void sqlite3Fts5ParseSetDistance(Fts5Parse*, Fts5ExprNearset*, Fts5Token*);
static void sqlite3Fts5ParseSetColset(Fts5Parse*, Fts5ExprNearset*, Fts5Colset*);
+static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse*, Fts5Colset*);
static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p);
static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
@@ -169270,12 +181144,13 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
#define FTS5_COLON 5
#define FTS5_LP 6
#define FTS5_RP 7
-#define FTS5_LCP 8
-#define FTS5_RCP 9
-#define FTS5_STRING 10
-#define FTS5_COMMA 11
-#define FTS5_PLUS 12
-#define FTS5_STAR 13
+#define FTS5_MINUS 8
+#define FTS5_LCP 9
+#define FTS5_RCP 10
+#define FTS5_STRING 11
+#define FTS5_COMMA 12
+#define FTS5_PLUS 13
+#define FTS5_STAR 14
/*
** 2000-05-29
@@ -169389,17 +181264,17 @@ static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
#endif
/************* Begin control #defines *****************************************/
#define fts5YYCODETYPE unsigned char
-#define fts5YYNOCODE 27
+#define fts5YYNOCODE 28
#define fts5YYACTIONTYPE unsigned char
#define sqlite3Fts5ParserFTS5TOKENTYPE Fts5Token
typedef union {
int fts5yyinit;
sqlite3Fts5ParserFTS5TOKENTYPE fts5yy0;
- Fts5Colset* fts5yy3;
- Fts5ExprPhrase* fts5yy11;
- Fts5ExprNode* fts5yy18;
- int fts5yy20;
- Fts5ExprNearset* fts5yy26;
+ int fts5yy4;
+ Fts5Colset* fts5yy11;
+ Fts5ExprNode* fts5yy24;
+ Fts5ExprNearset* fts5yy46;
+ Fts5ExprPhrase* fts5yy53;
} fts5YYMINORTYPE;
#ifndef fts5YYSTACKDEPTH
#define fts5YYSTACKDEPTH 100
@@ -169408,22 +181283,18 @@ typedef union {
#define sqlite3Fts5ParserARG_PDECL ,Fts5Parse *pParse
#define sqlite3Fts5ParserARG_FETCH Fts5Parse *pParse = fts5yypParser->pParse
#define sqlite3Fts5ParserARG_STORE fts5yypParser->pParse = pParse
-#define fts5YYNSTATE 26
-#define fts5YYNRULE 24
-#define fts5YY_MAX_SHIFT 25
-#define fts5YY_MIN_SHIFTREDUCE 40
-#define fts5YY_MAX_SHIFTREDUCE 63
-#define fts5YY_MIN_REDUCE 64
-#define fts5YY_MAX_REDUCE 87
-#define fts5YY_ERROR_ACTION 88
-#define fts5YY_ACCEPT_ACTION 89
-#define fts5YY_NO_ACTION 90
+#define fts5YYNSTATE 29
+#define fts5YYNRULE 26
+#define fts5YY_MAX_SHIFT 28
+#define fts5YY_MIN_SHIFTREDUCE 45
+#define fts5YY_MAX_SHIFTREDUCE 70
+#define fts5YY_MIN_REDUCE 71
+#define fts5YY_MAX_REDUCE 96
+#define fts5YY_ERROR_ACTION 97
+#define fts5YY_ACCEPT_ACTION 98
+#define fts5YY_NO_ACTION 99
/************* End control #defines *******************************************/
-/* The fts5yyzerominor constant is used to initialize instances of
-** fts5YYMINORTYPE objects to zero. */
-static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
-
/* Define the fts5yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
@@ -169453,7 +181324,7 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
**
** N between fts5YY_MIN_REDUCE Reduce by rule N-fts5YY_MIN_REDUCE
** and fts5YY_MAX_REDUCE
-
+**
** N == fts5YY_ERROR_ACTION A syntax error has occurred.
**
** N == fts5YY_ACCEPT_ACTION The parser accepts its input.
@@ -169462,16 +181333,20 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
** slots in the fts5yy_action[] table.
**
** The action table is constructed as a single large table named fts5yy_action[].
-** Given state S and lookahead X, the action is computed as
+** Given state S and lookahead X, the action is computed as either:
**
-** fts5yy_action[ fts5yy_shift_ofst[S] + X ]
+** (A) N = fts5yy_action[ fts5yy_shift_ofst[S] + X ]
+** (B) N = fts5yy_default[S]
**
-** If the index value fts5yy_shift_ofst[S]+X is out of range or if the value
-** fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X or if fts5yy_shift_ofst[S]
-** is equal to fts5YY_SHIFT_USE_DFLT, it means that the action is not in the table
-** and that fts5yy_default[S] should be used instead.
+** The (A) formula is preferred. The B formula is used instead if:
+** (1) The fts5yy_shift_ofst[S]+X value is out of range, or
+** (2) fts5yy_lookahead[fts5yy_shift_ofst[S]+X] is not equal to X, or
+** (3) fts5yy_shift_ofst[S] equal fts5YY_SHIFT_USE_DFLT.
+** (Implementation note: fts5YY_SHIFT_USE_DFLT is chosen so that
+** fts5YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X.
+** Hence only tests (1) and (2) need to be evaluated.)
**
-** The formula above is for computing the action when the lookahead is
+** The formulas above are for computing the action when the lookahead is
** a terminal symbol. If the lookahead is a non-terminal (as occurs after
** a reduce action) then the fts5yy_reduce_ofst[] array is used in place of
** the fts5yy_shift_ofst[] array and fts5YY_REDUCE_USE_DFLT is used in place of
@@ -169489,48 +181364,50 @@ static const fts5YYMINORTYPE fts5yyzerominor = { 0 };
** fts5yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define fts5YY_ACTTAB_COUNT (78)
+#define fts5YY_ACTTAB_COUNT (85)
static const fts5YYACTIONTYPE fts5yy_action[] = {
- /* 0 */ 89, 15, 46, 5, 48, 24, 12, 19, 23, 14,
- /* 10 */ 46, 5, 48, 24, 20, 21, 23, 43, 46, 5,
- /* 20 */ 48, 24, 6, 18, 23, 17, 46, 5, 48, 24,
- /* 30 */ 75, 7, 23, 25, 46, 5, 48, 24, 62, 47,
- /* 40 */ 23, 48, 24, 7, 11, 23, 9, 3, 4, 2,
- /* 50 */ 62, 50, 52, 44, 64, 3, 4, 2, 49, 4,
- /* 60 */ 2, 1, 23, 11, 16, 9, 12, 2, 10, 61,
- /* 70 */ 53, 59, 62, 60, 22, 13, 55, 8,
+ /* 0 */ 98, 16, 51, 5, 53, 27, 83, 7, 26, 15,
+ /* 10 */ 51, 5, 53, 27, 13, 69, 26, 48, 51, 5,
+ /* 20 */ 53, 27, 19, 11, 26, 9, 20, 51, 5, 53,
+ /* 30 */ 27, 13, 22, 26, 28, 51, 5, 53, 27, 68,
+ /* 40 */ 1, 26, 19, 11, 17, 9, 52, 10, 53, 27,
+ /* 50 */ 23, 24, 26, 54, 3, 4, 2, 26, 6, 21,
+ /* 60 */ 49, 71, 3, 4, 2, 7, 56, 59, 55, 59,
+ /* 70 */ 4, 2, 12, 69, 58, 60, 18, 67, 62, 69,
+ /* 80 */ 25, 66, 8, 14, 2,
};
static const fts5YYCODETYPE fts5yy_lookahead[] = {
- /* 0 */ 15, 16, 17, 18, 19, 20, 10, 11, 23, 16,
- /* 10 */ 17, 18, 19, 20, 23, 24, 23, 16, 17, 18,
- /* 20 */ 19, 20, 22, 23, 23, 16, 17, 18, 19, 20,
- /* 30 */ 5, 6, 23, 16, 17, 18, 19, 20, 13, 17,
- /* 40 */ 23, 19, 20, 6, 8, 23, 10, 1, 2, 3,
- /* 50 */ 13, 9, 10, 7, 0, 1, 2, 3, 19, 2,
- /* 60 */ 3, 6, 23, 8, 21, 10, 10, 3, 10, 25,
- /* 70 */ 10, 10, 13, 25, 12, 10, 7, 5,
+ /* 0 */ 16, 17, 18, 19, 20, 21, 5, 6, 24, 17,
+ /* 10 */ 18, 19, 20, 21, 11, 14, 24, 17, 18, 19,
+ /* 20 */ 20, 21, 8, 9, 24, 11, 17, 18, 19, 20,
+ /* 30 */ 21, 11, 12, 24, 17, 18, 19, 20, 21, 26,
+ /* 40 */ 6, 24, 8, 9, 22, 11, 18, 11, 20, 21,
+ /* 50 */ 24, 25, 24, 20, 1, 2, 3, 24, 23, 24,
+ /* 60 */ 7, 0, 1, 2, 3, 6, 10, 11, 10, 11,
+ /* 70 */ 2, 3, 9, 14, 11, 11, 22, 26, 7, 14,
+ /* 80 */ 13, 11, 5, 11, 3,
};
-#define fts5YY_SHIFT_USE_DFLT (-5)
-#define fts5YY_SHIFT_COUNT (25)
-#define fts5YY_SHIFT_MIN (-4)
-#define fts5YY_SHIFT_MAX (72)
-static const signed char fts5yy_shift_ofst[] = {
- /* 0 */ 55, 55, 55, 55, 55, 36, -4, 56, 58, 25,
- /* 10 */ 37, 60, 59, 59, 46, 54, 42, 57, 62, 61,
- /* 20 */ 62, 69, 65, 62, 72, 64,
+#define fts5YY_SHIFT_USE_DFLT (85)
+#define fts5YY_SHIFT_COUNT (28)
+#define fts5YY_SHIFT_MIN (0)
+#define fts5YY_SHIFT_MAX (81)
+static const unsigned char fts5yy_shift_ofst[] = {
+ /* 0 */ 34, 34, 34, 34, 34, 14, 20, 3, 36, 1,
+ /* 10 */ 59, 64, 64, 65, 65, 53, 61, 56, 58, 63,
+ /* 20 */ 68, 67, 70, 67, 71, 72, 67, 77, 81,
};
-#define fts5YY_REDUCE_USE_DFLT (-16)
-#define fts5YY_REDUCE_COUNT (13)
-#define fts5YY_REDUCE_MIN (-15)
-#define fts5YY_REDUCE_MAX (48)
+#define fts5YY_REDUCE_USE_DFLT (-17)
+#define fts5YY_REDUCE_COUNT (14)
+#define fts5YY_REDUCE_MIN (-16)
+#define fts5YY_REDUCE_MAX (54)
static const signed char fts5yy_reduce_ofst[] = {
- /* 0 */ -15, -7, 1, 9, 17, 22, -9, 0, 39, 44,
- /* 10 */ 44, 43, 44, 48,
+ /* 0 */ -16, -8, 0, 9, 17, 28, 26, 35, 33, 13,
+ /* 10 */ 13, 22, 54, 13, 51,
};
static const fts5YYACTIONTYPE fts5yy_default[] = {
- /* 0 */ 88, 88, 88, 88, 88, 69, 82, 88, 88, 87,
- /* 10 */ 87, 88, 87, 87, 88, 88, 88, 66, 80, 88,
- /* 20 */ 81, 88, 88, 78, 88, 65,
+ /* 0 */ 97, 97, 97, 97, 97, 76, 91, 97, 97, 96,
+ /* 10 */ 96, 97, 97, 96, 96, 97, 97, 97, 97, 97,
+ /* 20 */ 73, 89, 97, 90, 97, 97, 87, 97, 72,
};
/********** End of lemon-generated parsing tables *****************************/
@@ -169581,15 +181458,18 @@ typedef struct fts5yyStackEntry fts5yyStackEntry;
/* The state of the parser is completely contained in an instance of
** the following structure */
struct fts5yyParser {
- int fts5yyidx; /* Index of top element in stack */
+ fts5yyStackEntry *fts5yytos; /* Pointer to top element of the stack */
#ifdef fts5YYTRACKMAXSTACKDEPTH
- int fts5yyidxMax; /* Maximum value of fts5yyidx */
+ int fts5yyhwm; /* High-water mark of the stack */
#endif
+#ifndef fts5YYNOERRORRECOVERY
int fts5yyerrcnt; /* Shifts left before out of the error */
+#endif
sqlite3Fts5ParserARG_SDECL /* A place to hold %extra_argument */
#if fts5YYSTACKDEPTH<=0
int fts5yystksz; /* Current side of the stack */
fts5yyStackEntry *fts5yystack; /* The parser's stack */
+ fts5yyStackEntry fts5yystk0; /* First stack entry */
#else
fts5yyStackEntry fts5yystack[fts5YYSTACKDEPTH]; /* The parser's stack */
#endif
@@ -169634,11 +181514,11 @@ static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){
static const char *const fts5yyTokenName[] = {
"$", "OR", "AND", "NOT",
"TERM", "COLON", "LP", "RP",
- "LCP", "RCP", "STRING", "COMMA",
- "PLUS", "STAR", "error", "input",
- "expr", "cnearset", "exprlist", "nearset",
- "colset", "colsetlist", "nearphrases", "phrase",
- "neardist_opt", "star_opt",
+ "MINUS", "LCP", "RCP", "STRING",
+ "COMMA", "PLUS", "STAR", "error",
+ "input", "expr", "cnearset", "exprlist",
+ "nearset", "colset", "colsetlist", "nearphrases",
+ "phrase", "neardist_opt", "star_opt",
};
#endif /* NDEBUG */
@@ -169656,44 +181536,56 @@ static const char *const fts5yyRuleName[] = {
/* 7 */ "exprlist ::= exprlist cnearset",
/* 8 */ "cnearset ::= nearset",
/* 9 */ "cnearset ::= colset COLON nearset",
- /* 10 */ "colset ::= LCP colsetlist RCP",
- /* 11 */ "colset ::= STRING",
- /* 12 */ "colsetlist ::= colsetlist STRING",
- /* 13 */ "colsetlist ::= STRING",
- /* 14 */ "nearset ::= phrase",
- /* 15 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
- /* 16 */ "nearphrases ::= phrase",
- /* 17 */ "nearphrases ::= nearphrases phrase",
- /* 18 */ "neardist_opt ::=",
- /* 19 */ "neardist_opt ::= COMMA STRING",
- /* 20 */ "phrase ::= phrase PLUS STRING star_opt",
- /* 21 */ "phrase ::= STRING star_opt",
- /* 22 */ "star_opt ::= STAR",
- /* 23 */ "star_opt ::=",
+ /* 10 */ "colset ::= MINUS LCP colsetlist RCP",
+ /* 11 */ "colset ::= LCP colsetlist RCP",
+ /* 12 */ "colset ::= STRING",
+ /* 13 */ "colset ::= MINUS STRING",
+ /* 14 */ "colsetlist ::= colsetlist STRING",
+ /* 15 */ "colsetlist ::= STRING",
+ /* 16 */ "nearset ::= phrase",
+ /* 17 */ "nearset ::= STRING LP nearphrases neardist_opt RP",
+ /* 18 */ "nearphrases ::= phrase",
+ /* 19 */ "nearphrases ::= nearphrases phrase",
+ /* 20 */ "neardist_opt ::=",
+ /* 21 */ "neardist_opt ::= COMMA STRING",
+ /* 22 */ "phrase ::= phrase PLUS STRING star_opt",
+ /* 23 */ "phrase ::= STRING star_opt",
+ /* 24 */ "star_opt ::= STAR",
+ /* 25 */ "star_opt ::=",
};
#endif /* NDEBUG */
#if fts5YYSTACKDEPTH<=0
/*
-** Try to increase the size of the parser stack.
+** Try to increase the size of the parser stack. Return the number
+** of errors. Return 0 on success.
*/
-static void fts5yyGrowStack(fts5yyParser *p){
+static int fts5yyGrowStack(fts5yyParser *p){
int newSize;
+ int idx;
fts5yyStackEntry *pNew;
newSize = p->fts5yystksz*2 + 100;
- pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
+ idx = p->fts5yytos ? (int)(p->fts5yytos - p->fts5yystack) : 0;
+ if( p->fts5yystack==&p->fts5yystk0 ){
+ pNew = malloc(newSize*sizeof(pNew[0]));
+ if( pNew ) pNew[0] = p->fts5yystk0;
+ }else{
+ pNew = realloc(p->fts5yystack, newSize*sizeof(pNew[0]));
+ }
if( pNew ){
p->fts5yystack = pNew;
- p->fts5yystksz = newSize;
+ p->fts5yytos = &p->fts5yystack[idx];
#ifndef NDEBUG
if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sStack grows to %d entries!\n",
- fts5yyTracePrompt, p->fts5yystksz);
+ fprintf(fts5yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+ fts5yyTracePrompt, p->fts5yystksz, newSize);
}
#endif
+ p->fts5yystksz = newSize;
}
+ return pNew==0;
}
#endif
@@ -169722,15 +181614,24 @@ static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE)){
fts5yyParser *pParser;
pParser = (fts5yyParser*)(*mallocProc)( (fts5YYMALLOCARGTYPE)sizeof(fts5yyParser) );
if( pParser ){
- pParser->fts5yyidx = -1;
#ifdef fts5YYTRACKMAXSTACKDEPTH
- pParser->fts5yyidxMax = 0;
+ pParser->fts5yyhwm = 0;
#endif
#if fts5YYSTACKDEPTH<=0
+ pParser->fts5yytos = NULL;
pParser->fts5yystack = NULL;
pParser->fts5yystksz = 0;
- fts5yyGrowStack(pParser);
+ if( fts5yyGrowStack(pParser) ){
+ pParser->fts5yystack = &pParser->fts5yystk0;
+ pParser->fts5yystksz = 1;
+ }
+#endif
+#ifndef fts5YYNOERRORRECOVERY
+ pParser->fts5yyerrcnt = -1;
#endif
+ pParser->fts5yytos = pParser->fts5yystack;
+ pParser->fts5yystack[0].stateno = 0;
+ pParser->fts5yystack[0].major = 0;
}
return pParser;
}
@@ -169760,33 +181661,33 @@ static void fts5yy_destructor(
** inside the C code.
*/
/********* Begin destructor definitions ***************************************/
- case 15: /* input */
+ case 16: /* input */
{
(void)pParse;
}
break;
- case 16: /* expr */
- case 17: /* cnearset */
- case 18: /* exprlist */
+ case 17: /* expr */
+ case 18: /* cnearset */
+ case 19: /* exprlist */
{
- sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy18));
+ sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24));
}
break;
- case 19: /* nearset */
- case 22: /* nearphrases */
+ case 20: /* nearset */
+ case 23: /* nearphrases */
{
- sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy26));
+ sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46));
}
break;
- case 20: /* colset */
- case 21: /* colsetlist */
+ case 21: /* colset */
+ case 22: /* colsetlist */
{
- sqlite3_free((fts5yypminor->fts5yy3));
+ sqlite3_free((fts5yypminor->fts5yy11));
}
break;
- case 23: /* phrase */
+ case 24: /* phrase */
{
- sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy11));
+ sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53));
}
break;
/********* End destructor definitions *****************************************/
@@ -169802,8 +181703,9 @@ static void fts5yy_destructor(
*/
static void fts5yy_pop_parser_stack(fts5yyParser *pParser){
fts5yyStackEntry *fts5yytos;
- assert( pParser->fts5yyidx>=0 );
- fts5yytos = &pParser->fts5yystack[pParser->fts5yyidx--];
+ assert( pParser->fts5yytos!=0 );
+ assert( pParser->fts5yytos > pParser->fts5yystack );
+ fts5yytos = pParser->fts5yytos--;
#ifndef NDEBUG
if( fts5yyTraceFILE ){
fprintf(fts5yyTraceFILE,"%sPopping %s\n",
@@ -169830,9 +181732,9 @@ static void sqlite3Fts5ParserFree(
#ifndef fts5YYPARSEFREENEVERNULL
if( pParser==0 ) return;
#endif
- while( pParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(pParser);
+ while( pParser->fts5yytos>pParser->fts5yystack ) fts5yy_pop_parser_stack(pParser);
#if fts5YYSTACKDEPTH<=0
- free(pParser->fts5yystack);
+ if( pParser->fts5yystack!=&pParser->fts5yystk0 ) free(pParser->fts5yystack);
#endif
(*freeProc)((void*)pParser);
}
@@ -169843,7 +181745,7 @@ static void sqlite3Fts5ParserFree(
#ifdef fts5YYTRACKMAXSTACKDEPTH
static int sqlite3Fts5ParserStackPeak(void *p){
fts5yyParser *pParser = (fts5yyParser*)p;
- return pParser->fts5yyidxMax;
+ return pParser->fts5yyhwm;
}
#endif
@@ -169851,61 +181753,58 @@ static int sqlite3Fts5ParserStackPeak(void *p){
** Find the appropriate action for a parser given the terminal
** look-ahead token iLookAhead.
*/
-static int fts5yy_find_shift_action(
+static unsigned int fts5yy_find_shift_action(
fts5yyParser *pParser, /* The parser */
fts5YYCODETYPE iLookAhead /* The look-ahead token */
){
int i;
- int stateno = pParser->fts5yystack[pParser->fts5yyidx].stateno;
+ int stateno = pParser->fts5yytos->stateno;
if( stateno>=fts5YY_MIN_REDUCE ) return stateno;
assert( stateno <= fts5YY_SHIFT_COUNT );
do{
i = fts5yy_shift_ofst[stateno];
- if( i==fts5YY_SHIFT_USE_DFLT ) return fts5yy_default[stateno];
assert( iLookAhead!=fts5YYNOCODE );
i += iLookAhead;
if( i<0 || i>=fts5YY_ACTTAB_COUNT || fts5yy_lookahead[i]!=iLookAhead ){
- if( iLookAhead>0 ){
#ifdef fts5YYFALLBACK
- fts5YYCODETYPE iFallback; /* Fallback token */
- if( iLookAhead<sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])
- && (iFallback = fts5yyFallback[iLookAhead])!=0 ){
+ fts5YYCODETYPE iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(fts5yyFallback)/sizeof(fts5yyFallback[0])
+ && (iFallback = fts5yyFallback[iLookAhead])!=0 ){
#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE, "%sFALLBACK %s => %s\n",
- fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]);
- }
-#endif
- assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
- iLookAhead = iFallback;
- continue;
+ if( fts5yyTraceFILE ){
+ fprintf(fts5yyTraceFILE, "%sFALLBACK %s => %s\n",
+ fts5yyTracePrompt, fts5yyTokenName[iLookAhead], fts5yyTokenName[iFallback]);
}
#endif
+ assert( fts5yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
+ iLookAhead = iFallback;
+ continue;
+ }
+#endif
#ifdef fts5YYWILDCARD
- {
- int j = i - iLookAhead + fts5YYWILDCARD;
- if(
+ {
+ int j = i - iLookAhead + fts5YYWILDCARD;
+ if(
#if fts5YY_SHIFT_MIN+fts5YYWILDCARD<0
- j>=0 &&
+ j>=0 &&
#endif
#if fts5YY_SHIFT_MAX+fts5YYWILDCARD>=fts5YY_ACTTAB_COUNT
- j<fts5YY_ACTTAB_COUNT &&
+ j<fts5YY_ACTTAB_COUNT &&
#endif
- fts5yy_lookahead[j]==fts5YYWILDCARD
- ){
+ fts5yy_lookahead[j]==fts5YYWILDCARD && iLookAhead>0
+ ){
#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n",
- fts5yyTracePrompt, fts5yyTokenName[iLookAhead],
- fts5yyTokenName[fts5YYWILDCARD]);
- }
-#endif /* NDEBUG */
- return fts5yy_action[j];
+ if( fts5yyTraceFILE ){
+ fprintf(fts5yyTraceFILE, "%sWILDCARD %s => %s\n",
+ fts5yyTracePrompt, fts5yyTokenName[iLookAhead],
+ fts5yyTokenName[fts5YYWILDCARD]);
}
+#endif /* NDEBUG */
+ return fts5yy_action[j];
}
-#endif /* fts5YYWILDCARD */
}
+#endif /* fts5YYWILDCARD */
return fts5yy_default[stateno];
}else{
return fts5yy_action[i];
@@ -169947,20 +181846,18 @@ static int fts5yy_find_reduce_action(
/*
** The following routine is called if the stack overflows.
*/
-static void fts5yyStackOverflow(fts5yyParser *fts5yypParser, fts5YYMINORTYPE *fts5yypMinor){
+static void fts5yyStackOverflow(fts5yyParser *fts5yypParser){
sqlite3Fts5ParserARG_FETCH;
- fts5yypParser->fts5yyidx--;
#ifndef NDEBUG
if( fts5yyTraceFILE ){
fprintf(fts5yyTraceFILE,"%sStack Overflow!\n",fts5yyTracePrompt);
}
#endif
- while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
+ while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser);
/* Here code is inserted which will execute if the parser
** stack every overflows */
/******** Begin %stack_overflow code ******************************************/
- UNUSED_PARAM(fts5yypMinor); /* Silence a compiler warning */
sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow");
/******** End %stack_overflow code ********************************************/
sqlite3Fts5ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
@@ -169974,11 +181871,11 @@ static void fts5yyTraceShift(fts5yyParser *fts5yypParser, int fts5yyNewState){
if( fts5yyTraceFILE ){
if( fts5yyNewState<fts5YYNSTATE ){
fprintf(fts5yyTraceFILE,"%sShift '%s', go to state %d\n",
- fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major],
+ fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major],
fts5yyNewState);
}else{
fprintf(fts5yyTraceFILE,"%sShift '%s'\n",
- fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major]);
+ fts5yyTracePrompt,fts5yyTokenName[fts5yypParser->fts5yytos->major]);
}
}
}
@@ -169993,33 +181890,38 @@ static void fts5yy_shift(
fts5yyParser *fts5yypParser, /* The parser to be shifted */
int fts5yyNewState, /* The new state to shift in */
int fts5yyMajor, /* The major token to shift in */
- fts5YYMINORTYPE *fts5yypMinor /* Pointer to the minor token to shift in */
+ sqlite3Fts5ParserFTS5TOKENTYPE fts5yyMinor /* The minor token to shift in */
){
fts5yyStackEntry *fts5yytos;
- fts5yypParser->fts5yyidx++;
+ fts5yypParser->fts5yytos++;
#ifdef fts5YYTRACKMAXSTACKDEPTH
- if( fts5yypParser->fts5yyidx>fts5yypParser->fts5yyidxMax ){
- fts5yypParser->fts5yyidxMax = fts5yypParser->fts5yyidx;
+ if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){
+ fts5yypParser->fts5yyhwm++;
+ assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) );
}
#endif
#if fts5YYSTACKDEPTH>0
- if( fts5yypParser->fts5yyidx>=fts5YYSTACKDEPTH ){
- fts5yyStackOverflow(fts5yypParser, fts5yypMinor);
+ if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH] ){
+ fts5yypParser->fts5yytos--;
+ fts5yyStackOverflow(fts5yypParser);
return;
}
#else
- if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
- fts5yyGrowStack(fts5yypParser);
- if( fts5yypParser->fts5yyidx>=fts5yypParser->fts5yystksz ){
- fts5yyStackOverflow(fts5yypParser, fts5yypMinor);
+ if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz] ){
+ if( fts5yyGrowStack(fts5yypParser) ){
+ fts5yypParser->fts5yytos--;
+ fts5yyStackOverflow(fts5yypParser);
return;
}
}
#endif
- fts5yytos = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
+ if( fts5yyNewState > fts5YY_MAX_SHIFT ){
+ fts5yyNewState += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
+ }
+ fts5yytos = fts5yypParser->fts5yytos;
fts5yytos->stateno = (fts5YYACTIONTYPE)fts5yyNewState;
fts5yytos->major = (fts5YYCODETYPE)fts5yyMajor;
- fts5yytos->minor = *fts5yypMinor;
+ fts5yytos->minor.fts5yy0 = fts5yyMinor;
fts5yyTraceShift(fts5yypParser, fts5yyNewState);
}
@@ -170030,30 +181932,32 @@ static const struct {
fts5YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
unsigned char nrhs; /* Number of right-hand side symbols in the rule */
} fts5yyRuleInfo[] = {
- { 15, 1 },
- { 16, 3 },
- { 16, 3 },
- { 16, 3 },
- { 16, 3 },
{ 16, 1 },
- { 18, 1 },
- { 18, 2 },
- { 17, 1 },
{ 17, 3 },
- { 20, 3 },
- { 20, 1 },
- { 21, 2 },
- { 21, 1 },
+ { 17, 3 },
+ { 17, 3 },
+ { 17, 3 },
+ { 17, 1 },
{ 19, 1 },
- { 19, 5 },
- { 22, 1 },
+ { 19, 2 },
+ { 18, 1 },
+ { 18, 3 },
+ { 21, 4 },
+ { 21, 3 },
+ { 21, 1 },
+ { 21, 2 },
{ 22, 2 },
- { 24, 0 },
- { 24, 2 },
- { 23, 4 },
+ { 22, 1 },
+ { 20, 1 },
+ { 20, 5 },
+ { 23, 1 },
{ 23, 2 },
- { 25, 1 },
{ 25, 0 },
+ { 25, 2 },
+ { 24, 4 },
+ { 24, 2 },
+ { 26, 1 },
+ { 26, 0 },
};
static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */
@@ -170064,24 +181968,47 @@ static void fts5yy_accept(fts5yyParser*); /* Forward Declaration */
*/
static void fts5yy_reduce(
fts5yyParser *fts5yypParser, /* The parser */
- int fts5yyruleno /* Number of the rule by which to reduce */
+ unsigned int fts5yyruleno /* Number of the rule by which to reduce */
){
int fts5yygoto; /* The next state */
int fts5yyact; /* The next action */
- fts5YYMINORTYPE fts5yygotominor; /* The LHS of the rule reduced */
fts5yyStackEntry *fts5yymsp; /* The top of the parser's stack */
int fts5yysize; /* Amount to pop the stack */
sqlite3Fts5ParserARG_FETCH;
- fts5yymsp = &fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx];
+ fts5yymsp = fts5yypParser->fts5yytos;
#ifndef NDEBUG
- if( fts5yyTraceFILE && fts5yyruleno>=0
- && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
+ if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
fprintf(fts5yyTraceFILE, "%sReduce [%s], go to state %d.\n", fts5yyTracePrompt,
fts5yyRuleName[fts5yyruleno], fts5yymsp[-fts5yysize].stateno);
}
#endif /* NDEBUG */
- fts5yygotominor = fts5yyzerominor;
+
+ /* Check that the stack is large enough to grow by a single entry
+ ** if the RHS of the rule is empty. This ensures that there is room
+ ** enough on the stack to push the LHS value */
+ if( fts5yyRuleInfo[fts5yyruleno].nrhs==0 ){
+#ifdef fts5YYTRACKMAXSTACKDEPTH
+ if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){
+ fts5yypParser->fts5yyhwm++;
+ assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack));
+ }
+#endif
+#if fts5YYSTACKDEPTH>0
+ if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5YYSTACKDEPTH-1] ){
+ fts5yyStackOverflow(fts5yypParser);
+ return;
+ }
+#else
+ if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){
+ if( fts5yyGrowStack(fts5yypParser) ){
+ fts5yyStackOverflow(fts5yypParser);
+ return;
+ }
+ fts5yymsp = fts5yypParser->fts5yytos;
+ }
+#endif
+ }
switch( fts5yyruleno ){
/* Beginning here are the reduction cases. A typical example
@@ -170093,133 +182020,154 @@ static void fts5yy_reduce(
** break;
*/
/********** Begin reduce actions **********************************************/
+ fts5YYMINORTYPE fts5yylhsminor;
case 0: /* input ::= expr */
-{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy18); }
+{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy24); }
break;
case 1: /* expr ::= expr AND expr */
{
- fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
}
+ fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
case 2: /* expr ::= expr OR expr */
{
- fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_OR, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
}
+ fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
case 3: /* expr ::= expr NOT expr */
{
- fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_NOT, fts5yymsp[-2].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24, 0);
}
+ fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
case 4: /* expr ::= LP expr RP */
-{fts5yygotominor.fts5yy18 = fts5yymsp[-1].minor.fts5yy18;}
+{fts5yymsp[-2].minor.fts5yy24 = fts5yymsp[-1].minor.fts5yy24;}
break;
case 5: /* expr ::= exprlist */
case 6: /* exprlist ::= cnearset */ fts5yytestcase(fts5yyruleno==6);
-{fts5yygotominor.fts5yy18 = fts5yymsp[0].minor.fts5yy18;}
+{fts5yylhsminor.fts5yy24 = fts5yymsp[0].minor.fts5yy24;}
+ fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
case 7: /* exprlist ::= exprlist cnearset */
{
- fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_AND, fts5yymsp[-1].minor.fts5yy18, fts5yymsp[0].minor.fts5yy18, 0);
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseImplicitAnd(pParse, fts5yymsp[-1].minor.fts5yy24, fts5yymsp[0].minor.fts5yy24);
}
+ fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
case 8: /* cnearset ::= nearset */
{
- fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26);
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
}
+ fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
break;
case 9: /* cnearset ::= colset COLON nearset */
{
- sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy26, fts5yymsp[-2].minor.fts5yy3);
- fts5yygotominor.fts5yy18 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy26);
+ sqlite3Fts5ParseSetColset(pParse, fts5yymsp[0].minor.fts5yy46, fts5yymsp[-2].minor.fts5yy11);
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
+}
+ fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
+ break;
+ case 10: /* colset ::= MINUS LCP colsetlist RCP */
+{
+ fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
}
break;
- case 10: /* colset ::= LCP colsetlist RCP */
-{ fts5yygotominor.fts5yy3 = fts5yymsp[-1].minor.fts5yy3; }
+ case 11: /* colset ::= LCP colsetlist RCP */
+{ fts5yymsp[-2].minor.fts5yy11 = fts5yymsp[-1].minor.fts5yy11; }
+ break;
+ case 12: /* colset ::= STRING */
+{
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+}
+ fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
break;
- case 11: /* colset ::= STRING */
+ case 13: /* colset ::= MINUS STRING */
{
- fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+ fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+ fts5yymsp[-1].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
}
break;
- case 12: /* colsetlist ::= colsetlist STRING */
+ case 14: /* colsetlist ::= colsetlist STRING */
{
- fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy3, &fts5yymsp[0].minor.fts5yy0); }
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); }
+ fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
break;
- case 13: /* colsetlist ::= STRING */
+ case 15: /* colsetlist ::= STRING */
{
- fts5yygotominor.fts5yy3 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
}
+ fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
break;
- case 14: /* nearset ::= phrase */
-{ fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11); }
+ case 16: /* nearset ::= phrase */
+{ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53); }
+ fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 15: /* nearset ::= STRING LP nearphrases neardist_opt RP */
+ case 17: /* nearset ::= STRING LP nearphrases neardist_opt RP */
{
sqlite3Fts5ParseNear(pParse, &fts5yymsp[-4].minor.fts5yy0);
- sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy26, &fts5yymsp[-1].minor.fts5yy0);
- fts5yygotominor.fts5yy26 = fts5yymsp[-2].minor.fts5yy26;
+ sqlite3Fts5ParseSetDistance(pParse, fts5yymsp[-2].minor.fts5yy46, &fts5yymsp[-1].minor.fts5yy0);
+ fts5yylhsminor.fts5yy46 = fts5yymsp[-2].minor.fts5yy46;
}
+ fts5yymsp[-4].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 16: /* nearphrases ::= phrase */
+ case 18: /* nearphrases ::= phrase */
{
- fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy11);
+ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53);
}
+ fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 17: /* nearphrases ::= nearphrases phrase */
+ case 19: /* nearphrases ::= nearphrases phrase */
{
- fts5yygotominor.fts5yy26 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy26, fts5yymsp[0].minor.fts5yy11);
+ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, fts5yymsp[-1].minor.fts5yy46, fts5yymsp[0].minor.fts5yy53);
}
+ fts5yymsp[-1].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
break;
- case 18: /* neardist_opt ::= */
-{ fts5yygotominor.fts5yy0.p = 0; fts5yygotominor.fts5yy0.n = 0; }
+ case 20: /* neardist_opt ::= */
+{ fts5yymsp[1].minor.fts5yy0.p = 0; fts5yymsp[1].minor.fts5yy0.n = 0; }
break;
- case 19: /* neardist_opt ::= COMMA STRING */
-{ fts5yygotominor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
+ case 21: /* neardist_opt ::= COMMA STRING */
+{ fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
break;
- case 20: /* phrase ::= phrase PLUS STRING star_opt */
+ case 22: /* phrase ::= phrase PLUS STRING star_opt */
{
- fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy11, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
+ fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy53, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
}
+ fts5yymsp[-3].minor.fts5yy53 = fts5yylhsminor.fts5yy53;
break;
- case 21: /* phrase ::= STRING star_opt */
+ case 23: /* phrase ::= STRING star_opt */
{
- fts5yygotominor.fts5yy11 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy20);
+ fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
}
+ fts5yymsp[-1].minor.fts5yy53 = fts5yylhsminor.fts5yy53;
break;
- case 22: /* star_opt ::= STAR */
-{ fts5yygotominor.fts5yy20 = 1; }
+ case 24: /* star_opt ::= STAR */
+{ fts5yymsp[0].minor.fts5yy4 = 1; }
break;
- case 23: /* star_opt ::= */
-{ fts5yygotominor.fts5yy20 = 0; }
+ case 25: /* star_opt ::= */
+{ fts5yymsp[1].minor.fts5yy4 = 0; }
break;
default:
break;
/********** End reduce actions ************************************************/
};
- assert( fts5yyruleno>=0 && fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) );
+ assert( fts5yyruleno<sizeof(fts5yyRuleInfo)/sizeof(fts5yyRuleInfo[0]) );
fts5yygoto = fts5yyRuleInfo[fts5yyruleno].lhs;
fts5yysize = fts5yyRuleInfo[fts5yyruleno].nrhs;
- fts5yypParser->fts5yyidx -= fts5yysize;
fts5yyact = fts5yy_find_reduce_action(fts5yymsp[-fts5yysize].stateno,(fts5YYCODETYPE)fts5yygoto);
if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
- if( fts5yyact>fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
- /* If the reduce action popped at least
- ** one element off the stack, then we can push the new element back
- ** onto the stack here, and skip the stack overflow test in fts5yy_shift().
- ** That gives a significant speed improvement. */
- if( fts5yysize ){
- fts5yypParser->fts5yyidx++;
- fts5yymsp -= fts5yysize-1;
- fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
- fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
- fts5yymsp->minor = fts5yygotominor;
- fts5yyTraceShift(fts5yypParser, fts5yyact);
- }else{
- fts5yy_shift(fts5yypParser,fts5yyact,fts5yygoto,&fts5yygotominor);
+ if( fts5yyact>fts5YY_MAX_SHIFT ){
+ fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
}
+ fts5yymsp -= fts5yysize-1;
+ fts5yypParser->fts5yytos = fts5yymsp;
+ fts5yymsp->stateno = (fts5YYACTIONTYPE)fts5yyact;
+ fts5yymsp->major = (fts5YYCODETYPE)fts5yygoto;
+ fts5yyTraceShift(fts5yypParser, fts5yyact);
}else{
assert( fts5yyact == fts5YY_ACCEPT_ACTION );
+ fts5yypParser->fts5yytos -= fts5yysize;
fts5yy_accept(fts5yypParser);
}
}
@@ -170237,7 +182185,7 @@ static void fts5yy_parse_failed(
fprintf(fts5yyTraceFILE,"%sFail!\n",fts5yyTracePrompt);
}
#endif
- while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
+ while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack ) fts5yy_pop_parser_stack(fts5yypParser);
/* Here code is inserted which will be executed whenever the
** parser fails */
/************ Begin %parse_failure code ***************************************/
@@ -170252,10 +182200,10 @@ static void fts5yy_parse_failed(
static void fts5yy_syntax_error(
fts5yyParser *fts5yypParser, /* The parser */
int fts5yymajor, /* The major type of the error token */
- fts5YYMINORTYPE fts5yyminor /* The minor type of the error token */
+ sqlite3Fts5ParserFTS5TOKENTYPE fts5yyminor /* The minor type of the error token */
){
sqlite3Fts5ParserARG_FETCH;
-#define FTS5TOKEN (fts5yyminor.fts5yy0)
+#define FTS5TOKEN fts5yyminor
/************ Begin %syntax_error code ****************************************/
UNUSED_PARAM(fts5yymajor); /* Silence a compiler warning */
@@ -170278,7 +182226,10 @@ static void fts5yy_accept(
fprintf(fts5yyTraceFILE,"%sAccept!\n",fts5yyTracePrompt);
}
#endif
- while( fts5yypParser->fts5yyidx>=0 ) fts5yy_pop_parser_stack(fts5yypParser);
+#ifndef fts5YYNOERRORRECOVERY
+ fts5yypParser->fts5yyerrcnt = -1;
+#endif
+ assert( fts5yypParser->fts5yytos==fts5yypParser->fts5yystack );
/* Here code is inserted which will be executed whenever the
** parser accepts */
/*********** Begin %parse_accept code *****************************************/
@@ -170312,7 +182263,7 @@ static void sqlite3Fts5Parser(
sqlite3Fts5ParserARG_PDECL /* Optional %extra_argument parameter */
){
fts5YYMINORTYPE fts5yyminorunion;
- int fts5yyact; /* The parser action. */
+ unsigned int fts5yyact; /* The parser action. */
#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
int fts5yyendofinput; /* True if we are at the end of input */
#endif
@@ -170321,29 +182272,8 @@ static void sqlite3Fts5Parser(
#endif
fts5yyParser *fts5yypParser; /* The parser */
- /* (re)initialize the parser, if necessary */
fts5yypParser = (fts5yyParser*)fts5yyp;
- if( fts5yypParser->fts5yyidx<0 ){
-#if fts5YYSTACKDEPTH<=0
- if( fts5yypParser->fts5yystksz <=0 ){
- /*memset(&fts5yyminorunion, 0, sizeof(fts5yyminorunion));*/
- fts5yyminorunion = fts5yyzerominor;
- fts5yyStackOverflow(fts5yypParser, &fts5yyminorunion);
- return;
- }
-#endif
- fts5yypParser->fts5yyidx = 0;
- fts5yypParser->fts5yyerrcnt = -1;
- fts5yypParser->fts5yystack[0].stateno = 0;
- fts5yypParser->fts5yystack[0].major = 0;
-#ifndef NDEBUG
- if( fts5yyTraceFILE ){
- fprintf(fts5yyTraceFILE,"%sInitialize. Empty stack. State 0\n",
- fts5yyTracePrompt);
- }
-#endif
- }
- fts5yyminorunion.fts5yy0 = fts5yyminor;
+ assert( fts5yypParser->fts5yytos!=0 );
#if !defined(fts5YYERRORSYMBOL) && !defined(fts5YYNOERRORRECOVERY)
fts5yyendofinput = (fts5yymajor==0);
#endif
@@ -170358,14 +182288,16 @@ static void sqlite3Fts5Parser(
do{
fts5yyact = fts5yy_find_shift_action(fts5yypParser,(fts5YYCODETYPE)fts5yymajor);
if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
- if( fts5yyact > fts5YY_MAX_SHIFT ) fts5yyact += fts5YY_MIN_REDUCE - fts5YY_MIN_SHIFTREDUCE;
- fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,&fts5yyminorunion);
+ fts5yy_shift(fts5yypParser,fts5yyact,fts5yymajor,fts5yyminor);
+#ifndef fts5YYNOERRORRECOVERY
fts5yypParser->fts5yyerrcnt--;
+#endif
fts5yymajor = fts5YYNOCODE;
}else if( fts5yyact <= fts5YY_MAX_REDUCE ){
fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE);
}else{
assert( fts5yyact == fts5YY_ERROR_ACTION );
+ fts5yyminorunion.fts5yy0 = fts5yyminor;
#ifdef fts5YYERRORSYMBOL
int fts5yymx;
#endif
@@ -170395,9 +182327,9 @@ static void sqlite3Fts5Parser(
**
*/
if( fts5yypParser->fts5yyerrcnt<0 ){
- fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
+ fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminor);
}
- fts5yymx = fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].major;
+ fts5yymx = fts5yypParser->fts5yytos->major;
if( fts5yymx==fts5YYERRORSYMBOL || fts5yyerrorhit ){
#ifndef NDEBUG
if( fts5yyTraceFILE ){
@@ -170405,26 +182337,26 @@ static void sqlite3Fts5Parser(
fts5yyTracePrompt,fts5yyTokenName[fts5yymajor]);
}
#endif
- fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
+ fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion);
fts5yymajor = fts5YYNOCODE;
}else{
- while(
- fts5yypParser->fts5yyidx >= 0 &&
- fts5yymx != fts5YYERRORSYMBOL &&
- (fts5yyact = fts5yy_find_reduce_action(
- fts5yypParser->fts5yystack[fts5yypParser->fts5yyidx].stateno,
+ while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack
+ && fts5yymx != fts5YYERRORSYMBOL
+ && (fts5yyact = fts5yy_find_reduce_action(
+ fts5yypParser->fts5yytos->stateno,
fts5YYERRORSYMBOL)) >= fts5YY_MIN_REDUCE
){
fts5yy_pop_parser_stack(fts5yypParser);
}
- if( fts5yypParser->fts5yyidx < 0 || fts5yymajor==0 ){
+ if( fts5yypParser->fts5yytos < fts5yypParser->fts5yystack || fts5yymajor==0 ){
fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
fts5yy_parse_failed(fts5yypParser);
+#ifndef fts5YYNOERRORRECOVERY
+ fts5yypParser->fts5yyerrcnt = -1;
+#endif
fts5yymajor = fts5YYNOCODE;
}else if( fts5yymx!=fts5YYERRORSYMBOL ){
- fts5YYMINORTYPE u2;
- u2.fts5YYERRSYMDT = 0;
- fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,&u2);
+ fts5yy_shift(fts5yypParser,fts5yyact,fts5YYERRORSYMBOL,fts5yyminor);
}
}
fts5yypParser->fts5yyerrcnt = 3;
@@ -170437,7 +182369,7 @@ static void sqlite3Fts5Parser(
** Applications can set this macro (for example inside %include) if
** they intend to abandon the parse upon the first syntax error seen.
*/
- fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
+ fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor);
fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
fts5yymajor = fts5YYNOCODE;
@@ -170452,24 +182384,29 @@ static void sqlite3Fts5Parser(
** three input tokens have been successfully shifted.
*/
if( fts5yypParser->fts5yyerrcnt<=0 ){
- fts5yy_syntax_error(fts5yypParser,fts5yymajor,fts5yyminorunion);
+ fts5yy_syntax_error(fts5yypParser,fts5yymajor, fts5yyminor);
}
fts5yypParser->fts5yyerrcnt = 3;
fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
if( fts5yyendofinput ){
fts5yy_parse_failed(fts5yypParser);
+#ifndef fts5YYNOERRORRECOVERY
+ fts5yypParser->fts5yyerrcnt = -1;
+#endif
}
fts5yymajor = fts5YYNOCODE;
#endif
}
- }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yyidx>=0 );
+ }while( fts5yymajor!=fts5YYNOCODE && fts5yypParser->fts5yytos>fts5yypParser->fts5yystack );
#ifndef NDEBUG
if( fts5yyTraceFILE ){
- int i;
+ fts5yyStackEntry *i;
+ char cDiv = '[';
fprintf(fts5yyTraceFILE,"%sReturn. Stack=",fts5yyTracePrompt);
- for(i=1; i<=fts5yypParser->fts5yyidx; i++)
- fprintf(fts5yyTraceFILE,"%c%s", i==1 ? '[' : ' ',
- fts5yyTokenName[fts5yypParser->fts5yystack[i].major]);
+ for(i=&fts5yypParser->fts5yystack[1]; i<=fts5yypParser->fts5yytos; i++){
+ fprintf(fts5yyTraceFILE,"%c%s", cDiv, fts5yyTokenName[i->major]);
+ cDiv = ' ';
+ }
fprintf(fts5yyTraceFILE,"]\n");
}
#endif
@@ -170667,7 +182604,7 @@ static int fts5HighlightCb(
if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
p->iOff = iEndOff;
- if( iPos<p->iter.iEnd ){
+ if( iPos>=p->iter.iStart && iPos<p->iter.iEnd ){
fts5HighlightAppend(&rc, p, p->zClose, -1);
}
}
@@ -170725,6 +182662,118 @@ static void fts5HighlightFunction(
**************************************************************************/
/*
+** Context object passed to the fts5SentenceFinderCb() function.
+*/
+typedef struct Fts5SFinder Fts5SFinder;
+struct Fts5SFinder {
+ int iPos; /* Current token position */
+ int nFirstAlloc; /* Allocated size of aFirst[] */
+ int nFirst; /* Number of entries in aFirst[] */
+ int *aFirst; /* Array of first token in each sentence */
+ const char *zDoc; /* Document being tokenized */
+};
+
+/*
+** Add an entry to the Fts5SFinder.aFirst[] array. Grow the array if
+** necessary. Return SQLITE_OK if successful, or SQLITE_NOMEM if an
+** error occurs.
+*/
+static int fts5SentenceFinderAdd(Fts5SFinder *p, int iAdd){
+ if( p->nFirstAlloc==p->nFirst ){
+ int nNew = p->nFirstAlloc ? p->nFirstAlloc*2 : 64;
+ int *aNew;
+
+ aNew = (int*)sqlite3_realloc(p->aFirst, nNew*sizeof(int));
+ if( aNew==0 ) return SQLITE_NOMEM;
+ p->aFirst = aNew;
+ p->nFirstAlloc = nNew;
+ }
+ p->aFirst[p->nFirst++] = iAdd;
+ return SQLITE_OK;
+}
+
+/*
+** This function is an xTokenize() callback used by the auxiliary snippet()
+** function. Its job is to identify tokens that are the first in a sentence.
+** For each such token, an entry is added to the SFinder.aFirst[] array.
+*/
+static int fts5SentenceFinderCb(
+ void *pContext, /* Pointer to HighlightContext object */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStartOff, /* Start offset of token */
+ int iEndOff /* End offset of token */
+){
+ int rc = SQLITE_OK;
+
+ UNUSED_PARAM2(pToken, nToken);
+ UNUSED_PARAM(iEndOff);
+
+ if( (tflags & FTS5_TOKEN_COLOCATED)==0 ){
+ Fts5SFinder *p = (Fts5SFinder*)pContext;
+ if( p->iPos>0 ){
+ int i;
+ char c = 0;
+ for(i=iStartOff-1; i>=0; i--){
+ c = p->zDoc[i];
+ if( c!=' ' && c!='\t' && c!='\n' && c!='\r' ) break;
+ }
+ if( i!=iStartOff-1 && (c=='.' || c==':') ){
+ rc = fts5SentenceFinderAdd(p, p->iPos);
+ }
+ }else{
+ rc = fts5SentenceFinderAdd(p, 0);
+ }
+ p->iPos++;
+ }
+ return rc;
+}
+
+static int fts5SnippetScore(
+ const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
+ Fts5Context *pFts, /* First arg to pass to pApi functions */
+ int nDocsize, /* Size of column in tokens */
+ unsigned char *aSeen, /* Array with one element per query phrase */
+ int iCol, /* Column to score */
+ int iPos, /* Starting offset to score */
+ int nToken, /* Max tokens per snippet */
+ int *pnScore, /* OUT: Score */
+ int *piPos /* OUT: Adjusted offset */
+){
+ int rc;
+ int i;
+ int ip = 0;
+ int ic = 0;
+ int iOff = 0;
+ int iFirst = -1;
+ int nInst;
+ int nScore = 0;
+ int iLast = 0;
+
+ rc = pApi->xInstCount(pFts, &nInst);
+ for(i=0; i<nInst && rc==SQLITE_OK; i++){
+ rc = pApi->xInst(pFts, i, &ip, &ic, &iOff);
+ if( rc==SQLITE_OK && ic==iCol && iOff>=iPos && iOff<(iPos+nToken) ){
+ nScore += (aSeen[ip] ? 1 : 1000);
+ aSeen[ip] = 1;
+ if( iFirst<0 ) iFirst = iOff;
+ iLast = iOff + pApi->xPhraseSize(pFts, ip);
+ }
+ }
+
+ *pnScore = nScore;
+ if( piPos ){
+ int iAdj = iFirst - (nToken - (iLast-iFirst)) / 2;
+ if( (iAdj+nToken)>nDocsize ) iAdj = nDocsize - nToken;
+ if( iAdj<0 ) iAdj = 0;
+ *piPos = iAdj;
+ }
+
+ return rc;
+}
+
+/*
** Implementation of snippet() function.
*/
static void fts5SnippetFunction(
@@ -170745,9 +182794,10 @@ static void fts5SnippetFunction(
unsigned char *aSeen; /* Array of "seen instance" flags */
int iBestCol; /* Column containing best snippet */
int iBestStart = 0; /* First token of best snippet */
- int iBestLast; /* Last token of best snippet */
int nBestScore = 0; /* Score of best snippet */
int nColSize = 0; /* Total size of iBestCol in tokens */
+ Fts5SFinder sFinder; /* Used to find the beginnings of sentences */
+ int nCol;
if( nVal!=5 ){
const char *zErr = "wrong number of arguments to function snippet()";
@@ -170755,13 +182805,13 @@ static void fts5SnippetFunction(
return;
}
+ nCol = pApi->xColumnCount(pFts);
memset(&ctx, 0, sizeof(HighlightContext));
iCol = sqlite3_value_int(apVal[0]);
ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
zEllips = (const char*)sqlite3_value_text(apVal[3]);
nToken = sqlite3_value_int(apVal[4]);
- iBestLast = nToken-1;
iBestCol = (iCol>=0 ? iCol : 0);
nPhrase = pApi->xPhraseCount(pFts);
@@ -170769,65 +182819,94 @@ static void fts5SnippetFunction(
if( aSeen==0 ){
rc = SQLITE_NOMEM;
}
-
if( rc==SQLITE_OK ){
rc = pApi->xInstCount(pFts, &nInst);
}
- for(i=0; rc==SQLITE_OK && i<nInst; i++){
- int ip, iSnippetCol, iStart;
- memset(aSeen, 0, nPhrase);
- rc = pApi->xInst(pFts, i, &ip, &iSnippetCol, &iStart);
- if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){
- int nScore = 1000;
- int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip);
- int j;
- aSeen[ip] = 1;
- for(j=i+1; rc==SQLITE_OK && j<nInst; j++){
- int ic; int io; int iFinal;
- rc = pApi->xInst(pFts, j, &ip, &ic, &io);
- iFinal = io + pApi->xPhraseSize(pFts, ip) - 1;
- if( rc==SQLITE_OK && ic==iSnippetCol && iLast<iStart+nToken ){
- nScore += aSeen[ip] ? 1000 : 1;
- aSeen[ip] = 1;
- if( iFinal>iLast ) iLast = iFinal;
+ memset(&sFinder, 0, sizeof(Fts5SFinder));
+ for(i=0; i<nCol; i++){
+ if( iCol<0 || iCol==i ){
+ int nDoc;
+ int nDocsize;
+ int ii;
+ sFinder.iPos = 0;
+ sFinder.nFirst = 0;
+ rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
+ if( rc!=SQLITE_OK ) break;
+ rc = pApi->xTokenize(pFts,
+ sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
+ );
+ if( rc!=SQLITE_OK ) break;
+ rc = pApi->xColumnSize(pFts, i, &nDocsize);
+ if( rc!=SQLITE_OK ) break;
+
+ for(ii=0; rc==SQLITE_OK && ii<nInst; ii++){
+ int ip, ic, io;
+ int iAdj;
+ int nScore;
+ int jj;
+
+ rc = pApi->xInst(pFts, ii, &ip, &ic, &io);
+ if( ic!=i || rc!=SQLITE_OK ) continue;
+ memset(aSeen, 0, nPhrase);
+ rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
+ io, nToken, &nScore, &iAdj
+ );
+ if( rc==SQLITE_OK && nScore>nBestScore ){
+ nBestScore = nScore;
+ iBestCol = i;
+ iBestStart = iAdj;
+ nColSize = nDocsize;
}
- }
- if( rc==SQLITE_OK && nScore>nBestScore ){
- iBestCol = iSnippetCol;
- iBestStart = iStart;
- iBestLast = iLast;
- nBestScore = nScore;
+ if( rc==SQLITE_OK && sFinder.nFirst && nDocsize>nToken ){
+ for(jj=0; jj<(sFinder.nFirst-1); jj++){
+ if( sFinder.aFirst[jj+1]>io ) break;
+ }
+
+ if( sFinder.aFirst[jj]<io ){
+ memset(aSeen, 0, nPhrase);
+ rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
+ sFinder.aFirst[jj], nToken, &nScore, 0
+ );
+
+ nScore += (sFinder.aFirst[jj]==0 ? 120 : 100);
+ if( rc==SQLITE_OK && nScore>nBestScore ){
+ nBestScore = nScore;
+ iBestCol = i;
+ iBestStart = sFinder.aFirst[jj];
+ nColSize = nDocsize;
+ }
+ }
+ }
}
}
}
if( rc==SQLITE_OK ){
- rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
- }
- if( rc==SQLITE_OK ){
rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn);
}
+ if( rc==SQLITE_OK && nColSize==0 ){
+ rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
+ }
if( ctx.zIn ){
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
}
- if( (iBestStart+nToken-1)>iBestLast ){
- iBestStart -= (iBestStart+nToken-1-iBestLast) / 2;
- }
- if( iBestStart+nToken>nColSize ){
- iBestStart = nColSize - nToken;
- }
- if( iBestStart<0 ) iBestStart = 0;
-
ctx.iRangeStart = iBestStart;
ctx.iRangeEnd = iBestStart + nToken - 1;
if( iBestStart>0 ){
fts5HighlightAppend(&rc, &ctx, zEllips, -1);
}
+
+ /* Advance iterator ctx.iter so that it points to the first coalesced
+ ** phrase instance at or following position iBestStart. */
+ while( ctx.iter.iStart>=0 && ctx.iter.iStart<iBestStart && rc==SQLITE_OK ){
+ rc = fts5CInstIterNext(&ctx.iter);
+ }
+
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
@@ -170836,15 +182915,15 @@ static void fts5SnippetFunction(
}else{
fts5HighlightAppend(&rc, &ctx, zEllips, -1);
}
-
- if( rc==SQLITE_OK ){
- sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
- }else{
- sqlite3_result_error_code(pCtx, rc);
- }
- sqlite3_free(ctx.zOut);
}
+ if( rc==SQLITE_OK ){
+ sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_error_code(pCtx, rc);
+ }
+ sqlite3_free(ctx.zOut);
sqlite3_free(aSeen);
+ sqlite3_free(sFinder.aFirst);
}
/************************************************************************/
@@ -171452,6 +183531,7 @@ static void sqlite3Fts5TermsetFree(Fts5Termset *p){
#define FTS5_DEFAULT_PAGE_SIZE 4050
#define FTS5_DEFAULT_AUTOMERGE 4
+#define FTS5_DEFAULT_USERMERGE 4
#define FTS5_DEFAULT_CRISISMERGE 16
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
@@ -171875,7 +183955,9 @@ static const char *fts5ConfigGobbleWord(
*pbQuoted = 1;
}else{
zRet = fts5ConfigSkipBareword(zIn);
- zOut[zRet-zIn] = '\0';
+ if( zRet ){
+ zOut[zRet-zIn] = '\0';
+ }
}
}
@@ -172291,6 +184373,18 @@ static int sqlite3Fts5ConfigSetValue(
}
}
+ else if( 0==sqlite3_stricmp(zKey, "usermerge") ){
+ int nUsermerge = -1;
+ if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+ nUsermerge = sqlite3_value_int(pVal);
+ }
+ if( nUsermerge<2 || nUsermerge>16 ){
+ *pbBadkey = 1;
+ }else{
+ pConfig->nUsermerge = nUsermerge;
+ }
+ }
+
else if( 0==sqlite3_stricmp(zKey, "crisismerge") ){
int nCrisisMerge = -1;
if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
@@ -172337,6 +184431,7 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
/* Set default values */
pConfig->pgsz = FTS5_DEFAULT_PAGE_SIZE;
pConfig->nAutomerge = FTS5_DEFAULT_AUTOMERGE;
+ pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
@@ -172547,6 +184642,7 @@ static int fts5ExprGetToken(
case ',': tok = FTS5_COMMA; break;
case '+': tok = FTS5_PLUS; break;
case '*': tok = FTS5_STAR; break;
+ case '-': tok = FTS5_MINUS; break;
case '\0': tok = FTS5_EOF; break;
case '"': {
@@ -172638,6 +184734,8 @@ static int sqlite3Fts5ExprNew(
pNew->nPhrase = sParse.nPhrase;
sParse.apPhrase = 0;
}
+ }else{
+ sqlite3Fts5ParseNodeFree(sParse.pExpr);
}
sqlite3_free(sParse.apPhrase);
@@ -173123,49 +185221,61 @@ static int fts5ExprNearTest(
** Initialize all term iterators in the pNear object. If any term is found
** to match no documents at all, return immediately without initializing any
** further iterators.
+**
+** If an error occurs, return an SQLite error code. Otherwise, return
+** SQLITE_OK. It is not considered an error if some term matches zero
+** documents.
*/
static int fts5ExprNearInitAll(
Fts5Expr *pExpr,
Fts5ExprNode *pNode
){
Fts5ExprNearset *pNear = pNode->pNear;
- int i, j;
- int rc = SQLITE_OK;
+ int i;
assert( pNode->bNomatch==0 );
- for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
+ for(i=0; i<pNear->nPhrase; i++){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- for(j=0; j<pPhrase->nTerm; j++){
- Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
- Fts5ExprTerm *p;
- int bEof = 1;
-
- for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){
- if( p->pIter ){
- sqlite3Fts5IterClose(p->pIter);
- p->pIter = 0;
- }
- rc = sqlite3Fts5IndexQuery(
- pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
- (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
- (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
- pNear->pColset,
- &p->pIter
- );
- assert( rc==SQLITE_OK || p->pIter==0 );
- if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){
- bEof = 0;
+ if( pPhrase->nTerm==0 ){
+ pNode->bEof = 1;
+ return SQLITE_OK;
+ }else{
+ int j;
+ for(j=0; j<pPhrase->nTerm; j++){
+ Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
+ Fts5ExprTerm *p;
+ int bHit = 0;
+
+ for(p=pTerm; p; p=p->pSynonym){
+ int rc;
+ if( p->pIter ){
+ sqlite3Fts5IterClose(p->pIter);
+ p->pIter = 0;
+ }
+ rc = sqlite3Fts5IndexQuery(
+ pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
+ (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
+ (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
+ pNear->pColset,
+ &p->pIter
+ );
+ assert( (rc==SQLITE_OK)==(p->pIter!=0) );
+ if( rc!=SQLITE_OK ) return rc;
+ if( 0==sqlite3Fts5IterEof(p->pIter) ){
+ bHit = 1;
+ }
}
- }
- if( bEof ){
- pNode->bEof = 1;
- return rc;
+ if( bHit==0 ){
+ pNode->bEof = 1;
+ return SQLITE_OK;
+ }
}
}
}
- return rc;
+ pNode->bEof = 0;
+ return SQLITE_OK;
}
/*
@@ -173298,7 +185408,7 @@ static int fts5ExprNodeTest_STRING(
}
}else{
Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
- if( pIter->iRowid==iLast ) continue;
+ if( pIter->iRowid==iLast || pIter->bEof ) continue;
bMatch = 0;
if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
return rc;
@@ -173648,6 +185758,8 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
if( Fts5NodeIsString(pNode) ){
/* Initialize all term iterators in the NEAR object. */
rc = fts5ExprNearInitAll(pExpr, pNode);
+ }else if( pNode->xNext==0 ){
+ pNode->bEof = 1;
}else{
int i;
int nEof = 0;
@@ -173699,23 +185811,25 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
*/
static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
Fts5ExprNode *pRoot = p->pRoot;
- int rc = SQLITE_OK;
- if( pRoot->xNext ){
- p->pIndex = pIdx;
- p->bDesc = bDesc;
- rc = fts5ExprNodeFirst(p, pRoot);
+ int rc; /* Return code */
- /* If not at EOF but the current rowid occurs earlier than iFirst in
- ** the iteration order, move to document iFirst or later. */
- if( pRoot->bEof==0 && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0 ){
- rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
- }
+ p->pIndex = pIdx;
+ p->bDesc = bDesc;
+ rc = fts5ExprNodeFirst(p, pRoot);
- /* If the iterator is not at a real match, skip forward until it is. */
- while( pRoot->bNomatch ){
- assert( pRoot->bEof==0 && rc==SQLITE_OK );
- rc = fts5ExprNodeNext(p, pRoot, 0, 0);
- }
+ /* If not at EOF but the current rowid occurs earlier than iFirst in
+ ** the iteration order, move to document iFirst or later. */
+ if( rc==SQLITE_OK
+ && 0==pRoot->bEof
+ && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0
+ ){
+ rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
+ }
+
+ /* If the iterator is not at a real match, skip forward until it is. */
+ while( pRoot->bNomatch ){
+ assert( pRoot->bEof==0 && rc==SQLITE_OK );
+ rc = fts5ExprNodeNext(p, pRoot, 0, 0);
}
return rc;
}
@@ -173824,6 +185938,21 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset(
sqlite3Fts5ParseNearsetFree(pNear);
sqlite3Fts5ParsePhraseFree(pPhrase);
}else{
+ if( pRet->nPhrase>0 ){
+ Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1];
+ assert( pLast==pParse->apPhrase[pParse->nPhrase-2] );
+ if( pPhrase->nTerm==0 ){
+ fts5ExprPhraseFree(pPhrase);
+ pRet->nPhrase--;
+ pParse->nPhrase--;
+ pPhrase = pLast;
+ }else if( pLast->nTerm==0 ){
+ fts5ExprPhraseFree(pLast);
+ pParse->apPhrase[pParse->nPhrase-2] = pPhrase;
+ pParse->nPhrase--;
+ pRet->nPhrase--;
+ }
+ }
pRet->apPhrase[pRet->nPhrase++] = pPhrase;
}
return pRet;
@@ -173855,9 +185984,9 @@ static int fts5ParseTokenize(
/* If an error has already occurred, this is a no-op */
if( pCtx->rc!=SQLITE_OK ) return pCtx->rc;
+ if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
- assert( pPhrase==0 || pPhrase->nTerm>0 );
- if( pPhrase && (tflags & FTS5_TOKEN_COLOCATED) ){
+ if( pPhrase && pPhrase->nTerm>0 && (tflags & FTS5_TOKEN_COLOCATED) ){
Fts5ExprTerm *pSyn;
int nByte = sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer) + nToken+1;
pSyn = (Fts5ExprTerm*)sqlite3_malloc(nByte);
@@ -173958,7 +186087,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
pParse->rc = rc;
fts5ExprPhraseFree(sCtx.pPhrase);
sCtx.pPhrase = 0;
- }else if( sCtx.pPhrase ){
+ }else{
if( pAppend==0 ){
if( (pParse->nPhrase % 8)==0 ){
@@ -173975,9 +186104,14 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
pParse->nPhrase++;
}
+ if( sCtx.pPhrase==0 ){
+ /* This happens when parsing a token or quoted phrase that contains
+ ** no token characters at all. (e.g ... MATCH '""'). */
+ sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, sizeof(Fts5ExprPhrase));
+ }else if( sCtx.pPhrase->nTerm ){
+ sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
+ }
pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
- assert( sCtx.pPhrase->nTerm>0 );
- sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = bPrefix;
}
return sCtx.pPhrase;
@@ -173994,7 +186128,6 @@ static int sqlite3Fts5ExprClonePhrase(
){
int rc = SQLITE_OK; /* Return code */
Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */
- int i; /* Used to iterate through phrase terms */
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */
@@ -174012,19 +186145,37 @@ static int sqlite3Fts5ExprClonePhrase(
pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
}
-
- for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
- int tflags = 0;
- Fts5ExprTerm *p;
- for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
- const char *zTerm = p->zTerm;
- rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
- 0, 0);
- tflags = FTS5_TOKEN_COLOCATED;
+ if( rc==SQLITE_OK ){
+ Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
+ if( pColsetOrig ){
+ int nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
+ Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
+ if( pColset ){
+ memcpy(pColset, pColsetOrig, nByte);
+ }
+ pNew->pRoot->pNear->pColset = pColset;
}
- if( rc==SQLITE_OK ){
- sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
+ }
+
+ if( pOrig->nTerm ){
+ int i; /* Used to iterate through phrase terms */
+ for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
+ int tflags = 0;
+ Fts5ExprTerm *p;
+ for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
+ const char *zTerm = p->zTerm;
+ rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
+ 0, 0);
+ tflags = FTS5_TOKEN_COLOCATED;
+ }
+ if( rc==SQLITE_OK ){
+ sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
+ }
}
+ }else{
+ /* This happens when parsing a token or quoted phrase that contains
+ ** no token characters at all. (e.g ... MATCH '""'). */
+ sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
}
if( rc==SQLITE_OK ){
@@ -174073,23 +186224,25 @@ static void sqlite3Fts5ParseSetDistance(
Fts5ExprNearset *pNear,
Fts5Token *p
){
- int nNear = 0;
- int i;
- if( p->n ){
- for(i=0; i<p->n; i++){
- char c = (char)p->p[i];
- if( c<'0' || c>'9' ){
- sqlite3Fts5ParseError(
- pParse, "expected integer, got \"%.*s\"", p->n, p->p
- );
- return;
+ if( pNear ){
+ int nNear = 0;
+ int i;
+ if( p->n ){
+ for(i=0; i<p->n; i++){
+ char c = (char)p->p[i];
+ if( c<'0' || c>'9' ){
+ sqlite3Fts5ParseError(
+ pParse, "expected integer, got \"%.*s\"", p->n, p->p
+ );
+ return;
+ }
+ nNear = nNear * 10 + (p->p[i] - '0');
}
- nNear = nNear * 10 + (p->p[i] - '0');
+ }else{
+ nNear = FTS5_DEFAULT_NEARDIST;
}
- }else{
- nNear = FTS5_DEFAULT_NEARDIST;
+ pNear->nNear = nNear;
}
- pNear->nNear = nNear;
}
/*
@@ -174137,6 +186290,34 @@ static Fts5Colset *fts5ParseColset(
return pNew;
}
+/*
+** Allocate and return an Fts5Colset object specifying the inverse of
+** the colset passed as the second argument. Free the colset passed
+** as the second argument before returning.
+*/
+static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){
+ Fts5Colset *pRet;
+ int nCol = pParse->pConfig->nCol;
+
+ pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
+ sizeof(Fts5Colset) + sizeof(int)*nCol
+ );
+ if( pRet ){
+ int i;
+ int iOld = 0;
+ for(i=0; i<nCol; i++){
+ if( iOld>=p->nCol || p->aiCol[iOld]!=i ){
+ pRet->aiCol[pRet->nCol++] = i;
+ }else{
+ iOld++;
+ }
+ }
+ }
+
+ sqlite3_free(p);
+ return pRet;
+}
+
static Fts5Colset *sqlite3Fts5ParseColset(
Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */
Fts5Colset *pColset, /* Existing colset object */
@@ -174276,10 +186457,14 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
int iPhrase;
for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
pNear->apPhrase[iPhrase]->pNode = pRet;
+ if( pNear->apPhrase[iPhrase]->nTerm==0 ){
+ pRet->xNext = 0;
+ pRet->eType = FTS5_EOF;
+ }
}
if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL
- && (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm!=1)
+ && (pNear->nPhrase!=1 || pNear->apPhrase[0]->nTerm>1)
){
assert( pParse->rc==SQLITE_OK );
pParse->rc = SQLITE_ERROR;
@@ -174308,6 +186493,70 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
return pRet;
}
+static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
+ Fts5Parse *pParse, /* Parse context */
+ Fts5ExprNode *pLeft, /* Left hand child expression */
+ Fts5ExprNode *pRight /* Right hand child expression */
+){
+ Fts5ExprNode *pRet = 0;
+ Fts5ExprNode *pPrev;
+
+ if( pParse->rc ){
+ sqlite3Fts5ParseNodeFree(pLeft);
+ sqlite3Fts5ParseNodeFree(pRight);
+ }else{
+
+ assert( pLeft->eType==FTS5_STRING
+ || pLeft->eType==FTS5_TERM
+ || pLeft->eType==FTS5_EOF
+ || pLeft->eType==FTS5_AND
+ );
+ assert( pRight->eType==FTS5_STRING
+ || pRight->eType==FTS5_TERM
+ || pRight->eType==FTS5_EOF
+ );
+
+ if( pLeft->eType==FTS5_AND ){
+ pPrev = pLeft->apChild[pLeft->nChild-1];
+ }else{
+ pPrev = pLeft;
+ }
+ assert( pPrev->eType==FTS5_STRING
+ || pPrev->eType==FTS5_TERM
+ || pPrev->eType==FTS5_EOF
+ );
+
+ if( pRight->eType==FTS5_EOF ){
+ assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] );
+ sqlite3Fts5ParseNodeFree(pRight);
+ pRet = pLeft;
+ pParse->nPhrase--;
+ }
+ else if( pPrev->eType==FTS5_EOF ){
+ Fts5ExprPhrase **ap;
+
+ if( pPrev==pLeft ){
+ pRet = pRight;
+ }else{
+ pLeft->apChild[pLeft->nChild-1] = pRight;
+ pRet = pLeft;
+ }
+
+ ap = &pParse->apPhrase[pParse->nPhrase-1-pRight->pNear->nPhrase];
+ assert( ap[0]==pPrev->pNear->apPhrase[0] );
+ memmove(ap, &ap[1], sizeof(Fts5ExprPhrase*)*pRight->pNear->nPhrase);
+ pParse->nPhrase--;
+
+ sqlite3Fts5ParseNodeFree(pPrev);
+ }
+ else{
+ pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0);
+ }
+ }
+
+ return pRet;
+}
+
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
int nByte = 0;
Fts5ExprTerm *p;
@@ -174442,6 +186691,9 @@ static char *fts5ExprPrintTcl(
static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
char *zRet = 0;
+ if( pExpr->eType==0 ){
+ return sqlite3_mprintf("\"\"");
+ }else
if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
Fts5ExprNearset *pNear = pExpr->pNear;
int i;
@@ -174502,7 +186754,7 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
zRet = 0;
}else{
int e = pExpr->apChild[i]->eType;
- int b = (e!=FTS5_STRING && e!=FTS5_TERM);
+ int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF);
zRet = fts5PrintfAppend(zRet, "%s%s%z%s",
(i==0 ? "" : zOp),
(b?"(":""), z, (b?")":"")
@@ -174780,12 +187032,13 @@ static int fts5ExprPopulatePoslistsCb(
UNUSED_PARAM2(iUnused1, iUnused2);
+ if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
for(i=0; i<pExpr->nPhrase; i++){
Fts5ExprTerm *pTerm;
if( p->aPopulator[i].bOk==0 ) continue;
for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
- int nTerm = strlen(pTerm->zTerm);
+ int nTerm = (int)strlen(pTerm->zTerm);
if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
&& memcmp(pTerm->zTerm, pToken, nTerm)==0
){
@@ -174889,17 +187142,6 @@ static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){
fts5ExprCheckPoslists(pExpr->pRoot, iRowid);
}
-static void fts5ExprClearEof(Fts5ExprNode *pNode){
- int i;
- for(i=0; i<pNode->nChild; i++){
- fts5ExprClearEof(pNode->apChild[i]);
- }
- pNode->bEof = 0;
-}
-static void sqlite3Fts5ExprClearEof(Fts5Expr *pExpr){
- fts5ExprClearEof(pExpr->pRoot);
-}
-
/*
** This function is only called for detail=columns tables.
*/
@@ -175286,11 +187528,11 @@ static int sqlite3Fts5HashWrite(
if( pHash->eDetail==FTS5_DETAIL_FULL ){
pPtr[p->nData++] = 0x01;
p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iCol);
- p->iCol = iCol;
+ p->iCol = (i16)iCol;
p->iPos = 0;
}else{
bNew = 1;
- p->iCol = iPos = iCol;
+ p->iCol = (i16)(iPos = iCol);
}
}
@@ -175773,6 +188015,10 @@ struct Fts5Index {
sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */
sqlite3_stmt *pIdxSelect;
int nRead; /* Total number of blocks read */
+
+ sqlite3_stmt *pDataVersion;
+ i64 iStructVersion; /* data_version when pStruct read */
+ Fts5Structure *pStruct; /* Current db structure (or NULL) */
};
struct Fts5DoclistIter {
@@ -176167,7 +188413,6 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
return pRet;
}
-
/*
** Release a reference to data record returned by an earlier call to
** fts5DataRead().
@@ -176176,6 +188421,18 @@ static void fts5DataRelease(Fts5Data *pData){
sqlite3_free(pData);
}
+static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){
+ Fts5Data *pRet = fts5DataRead(p, iRowid);
+ if( pRet ){
+ if( pRet->szLeaf>pRet->nn ){
+ p->rc = FTS5_CORRUPT;
+ fts5DataRelease(pRet);
+ pRet = 0;
+ }
+ }
+ return pRet;
+}
+
static int fts5IndexPrepareStmt(
Fts5Index *p,
sqlite3_stmt **ppStmt,
@@ -176335,7 +188592,7 @@ static int fts5StructureDecode(
for(iLvl=0; rc==SQLITE_OK && iLvl<nLevel; iLvl++){
Fts5StructureLevel *pLvl = &pRet->aLevel[iLvl];
- int nTotal;
+ int nTotal = 0;
int iSeg;
if( i>=nData ){
@@ -176428,6 +188685,50 @@ static void fts5StructureExtendLevel(
}
}
+static Fts5Structure *fts5StructureReadUncached(Fts5Index *p){
+ Fts5Structure *pRet = 0;
+ Fts5Config *pConfig = p->pConfig;
+ int iCookie; /* Configuration cookie */
+ Fts5Data *pData;
+
+ pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
+ if( p->rc==SQLITE_OK ){
+ /* TODO: Do we need this if the leaf-index is appended? Probably... */
+ memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
+ p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
+ if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
+ p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
+ }
+ fts5DataRelease(pData);
+ if( p->rc!=SQLITE_OK ){
+ fts5StructureRelease(pRet);
+ pRet = 0;
+ }
+ }
+
+ return pRet;
+}
+
+static i64 fts5IndexDataVersion(Fts5Index *p){
+ i64 iVersion = 0;
+
+ if( p->rc==SQLITE_OK ){
+ if( p->pDataVersion==0 ){
+ p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion,
+ sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb)
+ );
+ if( p->rc ) return 0;
+ }
+
+ if( SQLITE_ROW==sqlite3_step(p->pDataVersion) ){
+ iVersion = sqlite3_column_int64(p->pDataVersion, 0);
+ }
+ p->rc = sqlite3_reset(p->pDataVersion);
+ }
+
+ return iVersion;
+}
+
/*
** Read, deserialize and return the structure record.
**
@@ -176440,26 +188741,49 @@ static void fts5StructureExtendLevel(
** is called, it is a no-op.
*/
static Fts5Structure *fts5StructureRead(Fts5Index *p){
- Fts5Config *pConfig = p->pConfig;
- Fts5Structure *pRet = 0; /* Object to return */
- int iCookie; /* Configuration cookie */
- Fts5Data *pData;
- pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID);
- if( p->rc ) return 0;
- /* TODO: Do we need this if the leaf-index is appended? Probably... */
- memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING);
- p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet);
- if( p->rc==SQLITE_OK && pConfig->iCookie!=iCookie ){
- p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie);
+ if( p->pStruct==0 ){
+ p->iStructVersion = fts5IndexDataVersion(p);
+ if( p->rc==SQLITE_OK ){
+ p->pStruct = fts5StructureReadUncached(p);
+ }
}
- fts5DataRelease(pData);
- if( p->rc!=SQLITE_OK ){
- fts5StructureRelease(pRet);
- pRet = 0;
+#if 0
+ else{
+ Fts5Structure *pTest = fts5StructureReadUncached(p);
+ if( pTest ){
+ int i, j;
+ assert_nc( p->pStruct->nSegment==pTest->nSegment );
+ assert_nc( p->pStruct->nLevel==pTest->nLevel );
+ for(i=0; i<pTest->nLevel; i++){
+ assert_nc( p->pStruct->aLevel[i].nMerge==pTest->aLevel[i].nMerge );
+ assert_nc( p->pStruct->aLevel[i].nSeg==pTest->aLevel[i].nSeg );
+ for(j=0; j<pTest->aLevel[i].nSeg; j++){
+ Fts5StructureSegment *p1 = &pTest->aLevel[i].aSeg[j];
+ Fts5StructureSegment *p2 = &p->pStruct->aLevel[i].aSeg[j];
+ assert_nc( p1->iSegid==p2->iSegid );
+ assert_nc( p1->pgnoFirst==p2->pgnoFirst );
+ assert_nc( p1->pgnoLast==p2->pgnoLast );
+ }
+ }
+ fts5StructureRelease(pTest);
+ }
+ }
+#endif
+
+ if( p->rc!=SQLITE_OK ) return 0;
+ assert( p->iStructVersion!=0 );
+ assert( p->pStruct!=0 );
+ fts5StructureRef(p->pStruct);
+ return p->pStruct;
+}
+
+static void fts5StructureInvalidate(Fts5Index *p){
+ if( p->pStruct ){
+ fts5StructureRelease(p->pStruct);
+ p->pStruct = 0;
}
- return pRet;
}
/*
@@ -176917,7 +189241,7 @@ static void fts5SegIterNextPage(
pIter->pLeaf = pIter->pNextLeaf;
pIter->pNextLeaf = 0;
}else if( pIter->iLeafPgno<=pSeg->pgnoLast ){
- pIter->pLeaf = fts5DataRead(p,
+ pIter->pLeaf = fts5LeafRead(p,
FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno)
);
}else{
@@ -177420,9 +189744,8 @@ static void fts5SegIterNext(
if( pLeaf->nn>pLeaf->szLeaf ){
pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
&pLeaf->p[pLeaf->szLeaf], pIter->iEndofDoclist
- );
+ );
}
-
}
else if( pLeaf->nn>pLeaf->szLeaf ){
pIter->iPgidxOff = pLeaf->szLeaf + fts5GetVarint32(
@@ -177667,6 +189990,11 @@ static void fts5LeafSeek(
iTermOff += nKeep;
iOff = iTermOff;
+ if( iOff>=n ){
+ p->rc = FTS5_CORRUPT;
+ return;
+ }
+
/* Read the nKeep field of the next term. */
fts5FastGetVarint32(a, iOff, nKeep);
}
@@ -177719,6 +190047,18 @@ static void fts5LeafSeek(
fts5SegIterLoadNPos(p, pIter);
}
+static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){
+ if( p->pIdxSelect==0 ){
+ Fts5Config *pConfig = p->pConfig;
+ fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
+ "SELECT pgno FROM '%q'.'%q_idx' WHERE "
+ "segid=? AND term<=? ORDER BY term DESC LIMIT 1",
+ pConfig->zDb, pConfig->zName
+ ));
+ }
+ return p->pIdxSelect;
+}
+
/*
** Initialize the object pIter to point to term pTerm/nTerm within segment
** pSeg. If there is no such term in the index, the iterator is set to EOF.
@@ -177736,6 +190076,7 @@ static void fts5SegIterSeekInit(
int iPg = 1;
int bGe = (flags & FTS5INDEX_QUERY_SCAN);
int bDlidx = 0; /* True if there is a doclist-index */
+ sqlite3_stmt *pIdxSelect = 0;
assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 );
assert( pTerm && nTerm );
@@ -177744,23 +190085,16 @@ static void fts5SegIterSeekInit(
/* This block sets stack variable iPg to the leaf page number that may
** contain term (pTerm/nTerm), if it is present in the segment. */
- if( p->pIdxSelect==0 ){
- Fts5Config *pConfig = p->pConfig;
- fts5IndexPrepareStmt(p, &p->pIdxSelect, sqlite3_mprintf(
- "SELECT pgno FROM '%q'.'%q_idx' WHERE "
- "segid=? AND term<=? ORDER BY term DESC LIMIT 1",
- pConfig->zDb, pConfig->zName
- ));
- }
+ pIdxSelect = fts5IdxSelectStmt(p);
if( p->rc ) return;
- sqlite3_bind_int(p->pIdxSelect, 1, pSeg->iSegid);
- sqlite3_bind_blob(p->pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
- if( SQLITE_ROW==sqlite3_step(p->pIdxSelect) ){
- i64 val = sqlite3_column_int(p->pIdxSelect, 0);
+ sqlite3_bind_int(pIdxSelect, 1, pSeg->iSegid);
+ sqlite3_bind_blob(pIdxSelect, 2, pTerm, nTerm, SQLITE_STATIC);
+ if( SQLITE_ROW==sqlite3_step(pIdxSelect) ){
+ i64 val = sqlite3_column_int(pIdxSelect, 0);
iPg = (int)(val>>1);
bDlidx = (val & 0x0001);
}
- p->rc = sqlite3_reset(p->pIdxSelect);
+ p->rc = sqlite3_reset(pIdxSelect);
if( iPg<pSeg->pgnoFirst ){
iPg = pSeg->pgnoFirst;
@@ -178217,6 +190551,7 @@ static void fts5MultiIterNext(
i64 iFrom /* Advance at least as far as this */
){
int bUseFrom = bFrom;
+ assert( pIter->base.bEof==0 );
while( p->rc==SQLITE_OK ){
int iFirst = pIter->aFirst[1].iFirst;
int bNewTerm = 0;
@@ -178588,6 +190923,15 @@ static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){
}
/*
+** xSetOutputs callback used when the Fts5Colset object has nCol==0 (match
+** against no columns at all).
+*/
+static void fts5IterSetOutputs_ZeroColset(Fts5Iter *pIter, Fts5SegIter *pSeg){
+ UNUSED_PARAM(pSeg);
+ pIter->base.nData = 0;
+}
+
+/*
** xSetOutputs callback used by detail=col when there is a column filter
** and there are 100 or more columns. Also called as a fallback from
** fts5IterSetOutputs_Col100 if the column-list spans more than one page.
@@ -178636,7 +190980,7 @@ static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
if( aiCol==aiColEnd ) goto setoutputs_col_out;
}
if( *aiCol==iPrev ){
- *aOut++ = (iPrev - iPrevOut) + 2;
+ *aOut++ = (u8)((iPrev - iPrevOut) + 2);
iPrevOut = iPrev;
}
}
@@ -178692,6 +191036,10 @@ static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
pIter->xSetOutputs = fts5IterSetOutputs_Nocolset;
}
+ else if( pIter->pColset->nCol==0 ){
+ pIter->xSetOutputs = fts5IterSetOutputs_ZeroColset;
+ }
+
else if( pConfig->eDetail==FTS5_DETAIL_FULL ){
pIter->xSetOutputs = fts5IterSetOutputs_Full;
}
@@ -178922,18 +191270,46 @@ static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
if( pStruct->nSegment>=FTS5_MAX_SEGMENT ){
p->rc = SQLITE_FULL;
}else{
- while( iSegid==0 ){
- int iLvl, iSeg;
- sqlite3_randomness(sizeof(u32), (void*)&iSegid);
- iSegid = iSegid & ((1 << FTS5_DATA_ID_B)-1);
- for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
- for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
- if( iSegid==pStruct->aLevel[iLvl].aSeg[iSeg].iSegid ){
- iSegid = 0;
- }
+ /* FTS5_MAX_SEGMENT is currently defined as 2000. So the following
+ ** array is 63 elements, or 252 bytes, in size. */
+ u32 aUsed[(FTS5_MAX_SEGMENT+31) / 32];
+ int iLvl, iSeg;
+ int i;
+ u32 mask;
+ memset(aUsed, 0, sizeof(aUsed));
+ for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+ for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
+ int iId = pStruct->aLevel[iLvl].aSeg[iSeg].iSegid;
+ if( iId<=FTS5_MAX_SEGMENT ){
+ aUsed[(iId-1) / 32] |= 1 << ((iId-1) % 32);
}
}
}
+
+ for(i=0; aUsed[i]==0xFFFFFFFF; i++);
+ mask = aUsed[i];
+ for(iSegid=0; mask & (1 << iSegid); iSegid++);
+ iSegid += 1 + i*32;
+
+#ifdef SQLITE_DEBUG
+ for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+ for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
+ assert( iSegid!=pStruct->aLevel[iLvl].aSeg[iSeg].iSegid );
+ }
+ }
+ assert( iSegid>0 && iSegid<=FTS5_MAX_SEGMENT );
+
+ {
+ sqlite3_stmt *pIdxSelect = fts5IdxSelectStmt(p);
+ if( p->rc==SQLITE_OK ){
+ u8 aBlob[2] = {0xff, 0xff};
+ sqlite3_bind_int(pIdxSelect, 1, iSegid);
+ sqlite3_bind_blob(pIdxSelect, 2, aBlob, 2, SQLITE_STATIC);
+ assert( sqlite3_step(pIdxSelect)!=SQLITE_ROW );
+ p->rc = sqlite3_reset(pIdxSelect);
+ }
+ }
+#endif
}
}
@@ -179179,6 +191555,9 @@ static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
Fts5PageWriter *pPage = &pWriter->writer;
i64 iRowid;
+static int nCall = 0;
+nCall++;
+
assert( (pPage->pgidx.n==0)==(pWriter->bFirstTermInPage) );
/* Set the szLeaf header field. */
@@ -179378,7 +191757,9 @@ static void fts5WriteFinish(
fts5WriteFlushLeaf(p, pWriter);
}
*pnLeaf = pLeaf->pgno-1;
- fts5WriteFlushBtree(p, pWriter);
+ if( pLeaf->pgno>1 ){
+ fts5WriteFlushBtree(p, pWriter);
+ }
}
fts5BufferFree(&pLeaf->term);
fts5BufferFree(&pLeaf->buf);
@@ -179648,13 +192029,17 @@ static void fts5IndexMergeLevel(
/*
** Do up to nPg pages of automerge work on the index.
+**
+** Return true if any changes were actually made, or false otherwise.
*/
-static void fts5IndexMerge(
+static int fts5IndexMerge(
Fts5Index *p, /* FTS5 backend object */
Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */
- int nPg /* Pages of work to do */
+ int nPg, /* Pages of work to do */
+ int nMin /* Minimum number of segments to merge */
){
int nRem = nPg;
+ int bRet = 0;
Fts5Structure *pStruct = *ppStruct;
while( nRem>0 && p->rc==SQLITE_OK ){
int iLvl; /* To iterate through levels */
@@ -179685,17 +192070,17 @@ static void fts5IndexMerge(
}
#endif
- if( nBest<p->pConfig->nAutomerge
- && pStruct->aLevel[iBestLvl].nMerge==0
- ){
+ if( nBest<nMin && pStruct->aLevel[iBestLvl].nMerge==0 ){
break;
}
+ bRet = 1;
fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
fts5StructurePromote(p, iBestLvl+1, pStruct);
}
}
*ppStruct = pStruct;
+ return bRet;
}
/*
@@ -179723,7 +192108,7 @@ static void fts5IndexAutomerge(
pStruct->nWriteCounter += nLeaf;
nRem = (int)(p->nWorkUnit * nWork * pStruct->nLevel);
- fts5IndexMerge(p, ppStruct, nRem);
+ fts5IndexMerge(p, ppStruct, nRem, p->pConfig->nAutomerge);
}
}
@@ -179793,6 +192178,7 @@ static void fts5FlushOneHash(Fts5Index *p){
** for the new level-0 segment. */
pStruct = fts5StructureRead(p);
iSegid = fts5AllocateSegid(p, pStruct);
+ fts5StructureInvalidate(p);
if( iSegid ){
const int pgsz = p->pConfig->pgsz;
@@ -179943,28 +192329,41 @@ static void fts5IndexFlush(Fts5Index *p){
}
}
-
-static int sqlite3Fts5IndexOptimize(Fts5Index *p){
- Fts5Structure *pStruct;
+static Fts5Structure *fts5IndexOptimizeStruct(
+ Fts5Index *p,
+ Fts5Structure *pStruct
+){
Fts5Structure *pNew = 0;
- int nSeg = 0;
-
- assert( p->rc==SQLITE_OK );
- fts5IndexFlush(p);
- pStruct = fts5StructureRead(p);
+ int nByte = sizeof(Fts5Structure);
+ int nSeg = pStruct->nSegment;
+ int i;
- if( pStruct ){
- assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
- nSeg = pStruct->nSegment;
- if( nSeg>1 ){
- int nByte = sizeof(Fts5Structure);
- nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
- pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
+ /* Figure out if this structure requires optimization. A structure does
+ ** not require optimization if either:
+ **
+ ** + it consists of fewer than two segments, or
+ ** + all segments are on the same level, or
+ ** + all segments except one are currently inputs to a merge operation.
+ **
+ ** In the first case, return NULL. In the second, increment the ref-count
+ ** on *pStruct and return a copy of the pointer to it.
+ */
+ if( nSeg<2 ) return 0;
+ for(i=0; i<pStruct->nLevel; i++){
+ int nThis = pStruct->aLevel[i].nSeg;
+ if( nThis==nSeg || (nThis==nSeg-1 && pStruct->aLevel[i].nMerge==nThis) ){
+ fts5StructureRef(pStruct);
+ return pStruct;
}
+ assert( pStruct->aLevel[i].nMerge<=nThis );
}
+
+ nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel);
+ pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
+
if( pNew ){
Fts5StructureLevel *pLvl;
- int nByte = nSeg * sizeof(Fts5StructureSegment);
+ nByte = nSeg * sizeof(Fts5StructureSegment);
pNew->nLevel = pStruct->nLevel+1;
pNew->nRef = 1;
pNew->nWriteCounter = pStruct->nWriteCounter;
@@ -179989,8 +192388,27 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
}
}
+ return pNew;
+}
+
+static int sqlite3Fts5IndexOptimize(Fts5Index *p){
+ Fts5Structure *pStruct;
+ Fts5Structure *pNew = 0;
+
+ assert( p->rc==SQLITE_OK );
+ fts5IndexFlush(p);
+ pStruct = fts5StructureRead(p);
+ fts5StructureInvalidate(p);
+
+ if( pStruct ){
+ pNew = fts5IndexOptimizeStruct(p, pStruct);
+ }
+ fts5StructureRelease(pStruct);
+
+ assert( pNew==0 || pNew->nSegment>0 );
if( pNew ){
- int iLvl = pNew->nLevel-1;
+ int iLvl;
+ for(iLvl=0; pNew->aLevel[iLvl].nSeg==0; iLvl++){}
while( p->rc==SQLITE_OK && pNew->aLevel[iLvl].nSeg>0 ){
int nRem = FTS5_OPT_WORK_UNIT;
fts5IndexMergeLevel(p, &pNew, iLvl, &nRem);
@@ -180000,20 +192418,32 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
fts5StructureRelease(pNew);
}
- fts5StructureRelease(pStruct);
return fts5IndexReturn(p);
}
+/*
+** This is called to implement the special "VALUES('merge', $nMerge)"
+** INSERT command.
+*/
static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
- Fts5Structure *pStruct;
-
- pStruct = fts5StructureRead(p);
- if( pStruct && pStruct->nLevel ){
- fts5IndexMerge(p, &pStruct, nMerge);
- fts5StructureWrite(p, pStruct);
+ Fts5Structure *pStruct = fts5StructureRead(p);
+ if( pStruct ){
+ int nMin = p->pConfig->nUsermerge;
+ fts5StructureInvalidate(p);
+ if( nMerge<0 ){
+ Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
+ fts5StructureRelease(pStruct);
+ pStruct = pNew;
+ nMin = 2;
+ nMerge = nMerge*-1;
+ }
+ if( pStruct && pStruct->nLevel ){
+ if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
+ fts5StructureWrite(p, pStruct);
+ }
+ }
+ fts5StructureRelease(pStruct);
}
- fts5StructureRelease(pStruct);
-
return fts5IndexReturn(p);
}
@@ -180427,6 +192857,7 @@ static int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
static int sqlite3Fts5IndexRollback(Fts5Index *p){
fts5CloseReader(p);
fts5IndexDiscardData(p);
+ fts5StructureInvalidate(p);
/* assert( p->rc==SQLITE_OK ); */
return SQLITE_OK;
}
@@ -180438,6 +192869,7 @@ static int sqlite3Fts5IndexRollback(Fts5Index *p){
*/
static int sqlite3Fts5IndexReinit(Fts5Index *p){
Fts5Structure s;
+ fts5StructureInvalidate(p);
memset(&s, 0, sizeof(Fts5Structure));
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
fts5StructureWrite(p, &s);
@@ -180496,11 +192928,13 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
int rc = SQLITE_OK;
if( p ){
assert( p->pReader==0 );
+ fts5StructureInvalidate(p);
sqlite3_finalize(p->pWriter);
sqlite3_finalize(p->pDeleter);
sqlite3_finalize(p->pIdxWriter);
sqlite3_finalize(p->pIdxDeleter);
sqlite3_finalize(p->pIdxSelect);
+ sqlite3_finalize(p->pDataVersion);
sqlite3Fts5HashFree(p->pHash);
sqlite3_free(p->zDataTbl);
sqlite3_free(p);
@@ -181757,6 +194191,15 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
return rc;
}
+
+static int sqlite3Fts5IndexReset(Fts5Index *p){
+ assert( p->pStruct==0 || p->iStructVersion!=0 );
+ if( fts5IndexDataVersion(p)!=p->iStructVersion ){
+ fts5StructureInvalidate(p);
+ }
+ return fts5IndexReturn(p);
+}
+
/*
** 2014 Jun 09
**
@@ -182356,27 +194799,38 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
return SQLITE_OK;
}
+static int fts5NewTransaction(Fts5Table *pTab){
+ Fts5Cursor *pCsr;
+ for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
+ if( pCsr->base.pVtab==(sqlite3_vtab*)pTab ) return SQLITE_OK;
+ }
+ return sqlite3Fts5StorageReset(pTab->pStorage);
+}
+
/*
** Implementation of xOpen method.
*/
static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
Fts5Table *pTab = (Fts5Table*)pVTab;
Fts5Config *pConfig = pTab->pConfig;
- Fts5Cursor *pCsr; /* New cursor object */
+ Fts5Cursor *pCsr = 0; /* New cursor object */
int nByte; /* Bytes of space to allocate */
- int rc = SQLITE_OK; /* Return code */
+ int rc; /* Return code */
- nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
- pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
- if( pCsr ){
- Fts5Global *pGlobal = pTab->pGlobal;
- memset(pCsr, 0, nByte);
- pCsr->aColumnSize = (int*)&pCsr[1];
- pCsr->pNext = pGlobal->pCsr;
- pGlobal->pCsr = pCsr;
- pCsr->iCsrId = ++pGlobal->iNextId;
- }else{
- rc = SQLITE_NOMEM;
+ rc = fts5NewTransaction(pTab);
+ if( rc==SQLITE_OK ){
+ nByte = sizeof(Fts5Cursor) + pConfig->nCol * sizeof(int);
+ pCsr = (Fts5Cursor*)sqlite3_malloc(nByte);
+ if( pCsr ){
+ Fts5Global *pGlobal = pTab->pGlobal;
+ memset(pCsr, 0, nByte);
+ pCsr->aColumnSize = (int*)&pCsr[1];
+ pCsr->pNext = pGlobal->pCsr;
+ pGlobal->pCsr = pCsr;
+ pCsr->iCsrId = ++pGlobal->iNextId;
+ }else{
+ rc = SQLITE_NOMEM;
+ }
}
*ppCsr = (sqlite3_vtab_cursor*)pCsr;
return rc;
@@ -182934,7 +195388,6 @@ static int fts5FilterMethod(
pCsr->ePlan = FTS5_PLAN_SOURCE;
pCsr->pExpr = pTab->pSortCsr->pExpr;
rc = fts5CursorFirst(pTab, pCsr, bDesc);
- sqlite3Fts5ExprClearEof(pCsr->pExpr);
}else if( pMatch ){
const char *zExpr = (const char*)sqlite3_value_text(apVal[0]);
if( zExpr==0 ) zExpr = "";
@@ -183270,13 +195723,13 @@ static int fts5UpdateMethod(
rc = SQLITE_ERROR;
}
- /* Case 1: DELETE */
+ /* DELETE */
else if( nArg==1 ){
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
}
- /* Case 2: INSERT */
+ /* INSERT */
else if( eType0!=SQLITE_INTEGER ){
/* If this is a REPLACE, first remove the current entry (if any) */
if( eConflict==SQLITE_REPLACE
@@ -183288,7 +195741,7 @@ static int fts5UpdateMethod(
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
- /* Case 2: UPDATE */
+ /* UPDATE */
else{
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
@@ -183337,8 +195790,8 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
** Implementation of xBegin() method.
*/
static int fts5BeginMethod(sqlite3_vtab *pVtab){
- UNUSED_PARAM(pVtab); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
+ fts5NewTransaction((Fts5Table*)pVtab);
return SQLITE_OK;
}
@@ -184363,7 +196816,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2016-03-03 16:17:53 f047920ce16971e573bc6ec9a48b118c9de2b3a7", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2017-01-03 18:27:03 979f04392853b8053817a3eea2fc679947b437fd", -1, SQLITE_TRANSIENT);
}
static int fts5Init(sqlite3 *db){
@@ -184451,7 +196904,7 @@ static int fts5Init(sqlite3 *db){
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int SQLITE_STDCALL sqlite3_fts_init(
+SQLITE_API int sqlite3_fts_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -184464,7 +196917,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_fts_init(
#ifdef _WIN32
__declspec(dllexport)
#endif
-SQLITE_API int SQLITE_STDCALL sqlite3_fts5_init(
+SQLITE_API int sqlite3_fts5_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
@@ -184626,6 +197079,7 @@ static int fts5StorageGetStmt(
}
*ppStmt = p->aStmt[eStmt];
+ sqlite3_reset(*ppStmt);
return rc;
}
@@ -184727,7 +197181,11 @@ static int sqlite3Fts5CreateTable(
char *zErr = 0;
rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s",
- pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":""
+ pConfig->zDb, pConfig->zName, zPost, zDefn,
+#ifndef SQLITE_FTS5_NO_WITHOUT_ROWID
+ bWithout?" WITHOUT ROWID":
+#endif
+ ""
);
if( zErr ){
*pzErr = sqlite3_mprintf(
@@ -184849,6 +197307,7 @@ static int fts5StorageInsertCallback(
Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext;
Fts5Index *pIdx = pCtx->pStorage->pIndex;
UNUSED_PARAM2(iUnused1, iUnused2);
+ if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
pCtx->szCol++;
}
@@ -185120,6 +197579,10 @@ static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
return sqlite3Fts5IndexMerge(p->pIndex, nMerge);
}
+static int sqlite3Fts5StorageReset(Fts5Storage *p){
+ return sqlite3Fts5IndexReset(p->pIndex);
+}
+
/*
** Allocate a new rowid. This is used for "external content" tables when
** a NULL value is inserted into the rowid column. The new rowid is allocated
@@ -185291,6 +197754,7 @@ static int fts5StorageIntegrityCallback(
int iCol;
UNUSED_PARAM2(iUnused1, iUnused2);
+ if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
pCtx->szCol++;
@@ -185603,8 +198067,6 @@ static int sqlite3Fts5StorageConfigValue(
return rc;
}
-
-
/*
** 2014 May 31
**
@@ -187836,8 +200298,19 @@ static int fts5VocabBestIndexMethod(
}
}
- pInfo->idxNum = idxNum;
+ /* This virtual table always delivers results in ascending order of
+ ** the "term" column (column 0). So if the user has requested this
+ ** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the
+ ** sqlite3_index_info.orderByConsumed flag to tell the core the results
+ ** are already in sorted order. */
+ if( pInfo->nOrderBy==1
+ && pInfo->aOrderBy[0].iColumn==0
+ && pInfo->aOrderBy[0].desc==0
+ ){
+ pInfo->orderByConsumed = 1;
+ }
+ pInfo->idxNum = idxNum;
return SQLITE_OK;
}
diff --git a/src/3rdparty/sqlite/sqlite3.h b/src/3rdparty/sqlite/sqlite3.h
index 37d1024766..33910e0683 100644
--- a/src/3rdparty/sqlite/sqlite3.h
+++ b/src/3rdparty/sqlite/sqlite3.h
@@ -30,8 +30,8 @@
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
*/
-#ifndef _SQLITE3_H_
-#define _SQLITE3_H_
+#ifndef SQLITE3_H
+#define SQLITE3_H
#include <stdarg.h> /* Needed for the definition of va_list */
/*
@@ -54,8 +54,17 @@ extern "C" {
#ifndef SQLITE_CDECL
# define SQLITE_CDECL
#endif
+#ifndef SQLITE_APICALL
+# define SQLITE_APICALL
+#endif
#ifndef SQLITE_STDCALL
-# define SQLITE_STDCALL
+# define SQLITE_STDCALL SQLITE_APICALL
+#endif
+#ifndef SQLITE_CALLBACK
+# define SQLITE_CALLBACK
+#endif
+#ifndef SQLITE_SYSAPI
+# define SQLITE_SYSAPI
#endif
/*
@@ -99,7 +108,8 @@ extern "C" {
** be held constant and Z will be incremented or else Y will be incremented
** and Z will be reset to zero.
**
-** Since version 3.6.18, SQLite source code has been stored in the
+** Since [version 3.6.18] ([dateof:3.6.18]),
+** SQLite source code has been stored in the
** <a href="http://www.fossil-scm.org/">Fossil configuration management
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
** a string which identifies a particular check-in of SQLite
@@ -111,13 +121,13 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.11.1"
-#define SQLITE_VERSION_NUMBER 3011001
-#define SQLITE_SOURCE_ID "2016-03-03 16:17:53 f047920ce16971e573bc6ec9a48b118c9de2b3a7"
+#define SQLITE_VERSION "3.16.1"
+#define SQLITE_VERSION_NUMBER 3016001
+#define SQLITE_SOURCE_ID "2017-01-03 18:27:03 979f04392853b8053817a3eea2fc679947b437fd"
/*
** CAPI3REF: Run-Time Library Version Numbers
-** KEYWORDS: sqlite3_version, sqlite3_sourceid
+** KEYWORDS: sqlite3_version sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
@@ -146,9 +156,9 @@ extern "C" {
** See also: [sqlite_version()] and [sqlite_source_id()].
*/
SQLITE_API SQLITE_EXTERN const char sqlite3_version[];
-SQLITE_API const char *SQLITE_STDCALL sqlite3_libversion(void);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_sourceid(void);
-SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
+SQLITE_API const char *sqlite3_libversion(void);
+SQLITE_API const char *sqlite3_sourceid(void);
+SQLITE_API int sqlite3_libversion_number(void);
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
@@ -173,8 +183,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_libversion_number(void);
** [sqlite_compileoption_get()] and the [compile_options pragma].
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-SQLITE_API int SQLITE_STDCALL sqlite3_compileoption_used(const char *zOptName);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
+SQLITE_API int sqlite3_compileoption_used(const char *zOptName);
+SQLITE_API const char *sqlite3_compileoption_get(int N);
#endif
/*
@@ -213,7 +223,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_compileoption_get(int N);
**
** See the [threading mode] documentation for additional information.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_threadsafe(void);
+SQLITE_API int sqlite3_threadsafe(void);
/*
** CAPI3REF: Database Connection Handle
@@ -310,8 +320,8 @@ typedef sqlite_uint64 sqlite3_uint64;
** ^Calling sqlite3_close() or sqlite3_close_v2() with a NULL pointer
** argument is a harmless no-op.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_close(sqlite3*);
-SQLITE_API int SQLITE_STDCALL sqlite3_close_v2(sqlite3*);
+SQLITE_API int sqlite3_close(sqlite3*);
+SQLITE_API int sqlite3_close_v2(sqlite3*);
/*
** The type for a callback function.
@@ -382,7 +392,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
** </ul>
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_exec(
+SQLITE_API int sqlite3_exec(
sqlite3*, /* An open database */
const char *sql, /* SQL to be evaluated */
int (*callback)(void*,int,char**,char**), /* Callback function */
@@ -443,7 +453,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
** [result codes]. However, experience has shown that many of
** these result codes are too coarse-grained. They do not provide as
** much information about problems as programmers might like. In an effort to
-** address this, newer versions of SQLite (version 3.3.8 and later) include
+** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
+** and later) include
** support for additional result codes that provide more detailed information
** about errors. These [extended result codes] are enabled or disabled
** on a per database connection basis using the
@@ -506,6 +517,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_exec(
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
+#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
/*
** CAPI3REF: Flags For File Open Operations
@@ -966,6 +978,12 @@ struct sqlite3_io_methods {
** on whether or not the file has been renamed, moved, or deleted since it
** was first opened.
**
+** <li>[[SQLITE_FCNTL_WIN32_GET_HANDLE]]
+** The [SQLITE_FCNTL_WIN32_GET_HANDLE] opcode can be used to obtain the
+** underlying native file handle associated with a file handle. This file
+** control interprets its argument as a pointer to a native file handle and
+** writes the resulting value there.
+**
** <li>[[SQLITE_FCNTL_WIN32_SET_HANDLE]]
** The [SQLITE_FCNTL_WIN32_SET_HANDLE] opcode is used for debugging. This
** opcode causes the xFileControl method to swap the file handle with the one
@@ -1016,6 +1034,8 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_RBU 26
#define SQLITE_FCNTL_VFS_POINTER 27
#define SQLITE_FCNTL_JOURNAL_POINTER 28
+#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
+#define SQLITE_FCNTL_PDB 30
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -1036,6 +1056,16 @@ struct sqlite3_io_methods {
typedef struct sqlite3_mutex sqlite3_mutex;
/*
+** CAPI3REF: Loadable Extension Thunk
+**
+** A pointer to the opaque sqlite3_api_routines structure is passed as
+** the third parameter to entry points of [loadable extensions]. This
+** structure must be typedefed in order to work around compiler warnings
+** on some platforms.
+*/
+typedef struct sqlite3_api_routines sqlite3_api_routines;
+
+/*
** CAPI3REF: OS Interface Object
**
** An instance of the sqlite3_vfs object defines the interface between
@@ -1228,7 +1258,7 @@ struct sqlite3_vfs {
const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
/*
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
- ** New fields may be appended in figure versions. The iVersion
+ ** New fields may be appended in future versions. The iVersion
** value will increment whenever this happens.
*/
};
@@ -1370,10 +1400,10 @@ struct sqlite3_vfs {
** must return [SQLITE_OK] on success and some other [error code] upon
** failure.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_initialize(void);
-SQLITE_API int SQLITE_STDCALL sqlite3_shutdown(void);
-SQLITE_API int SQLITE_STDCALL sqlite3_os_init(void);
-SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
+SQLITE_API int sqlite3_initialize(void);
+SQLITE_API int sqlite3_shutdown(void);
+SQLITE_API int sqlite3_os_init(void);
+SQLITE_API int sqlite3_os_end(void);
/*
** CAPI3REF: Configuring The SQLite Library
@@ -1406,7 +1436,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_os_end(void);
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
-SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
+SQLITE_API int sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
@@ -1425,7 +1455,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_config(int, ...);
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
-SQLITE_API int SQLITE_CDECL sqlite3_db_config(sqlite3*, int op, ...);
+SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
@@ -1820,6 +1850,20 @@ struct sqlite3_mem_methods {
** is enabled (using the [PRAGMA threads] command) and the amount of content
** to be sorted exceeds the page size times the minimum of the
** [PRAGMA cache_size] setting and this value.
+**
+** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
+** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
+** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
+** becomes the [statement journal] spill-to-disk threshold.
+** [Statement journals] are held in memory until their size (in bytes)
+** exceeds this threshold, at which point they are written to disk.
+** Or if the threshold is -1, statement journals are always held
+** exclusively in memory.
+** Since many statement journals never become large, setting the spill
+** threshold to a value such as 64KiB can greatly reduce the amount of
+** I/O required to support statement rollback.
+** The default value for this setting is controlled by the
+** [SQLITE_STMTJRNL_SPILL] compile-time option.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1847,6 +1891,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
+#define SQLITE_CONFIG_STMTJRNL_SPILL 26 /* int nByte */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -1904,11 +1949,66 @@ struct sqlite3_mem_methods {
** following this call. The second parameter may be a NULL pointer, in
** which case the trigger setting is not reported back. </dd>
**
+** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
+** <dd> ^This option is used to enable or disable the two-argument
+** version of the [fts3_tokenizer()] function which is part of the
+** [FTS3] full-text search engine extension.
+** There should be two additional arguments.
+** The first argument is an integer which is 0 to disable fts3_tokenizer() or
+** positive to enable fts3_tokenizer() or negative to leave the setting
+** unchanged.
+** The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
+** following this call. The second parameter may be a NULL pointer, in
+** which case the new setting is not reported back. </dd>
+**
+** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
+** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
+** interface independently of the [load_extension()] SQL function.
+** The [sqlite3_enable_load_extension()] API enables or disables both the
+** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
+** There should be two additional arguments.
+** When the first argument to this interface is 1, then only the C-API is
+** enabled and the SQL function remains disabled. If the first argument to
+** this interface is 0, then both the C-API and the SQL function are disabled.
+** If the first argument is -1, then no changes are made to state of either the
+** C-API or the SQL function.
+** The second parameter is a pointer to an integer into which
+** is written 0 or 1 to indicate whether [sqlite3_load_extension()] interface
+** is disabled or enabled following this call. The second parameter may
+** be a NULL pointer, in which case the new setting is not reported back.
+** </dd>
+**
+** <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
+** <dd> ^This option is used to change the name of the "main" database
+** schema. ^The sole argument is a pointer to a constant UTF8 string
+** which will become the new schema name in place of "main". ^SQLite
+** does not make a copy of the new main schema name string, so the application
+** must ensure that the argument passed into this DBCONFIG option is unchanged
+** until after the database connection closes.
+** </dd>
+**
+** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
+** <dd> Usually, when a database in wal mode is closed or detached from a
+** database handle, SQLite checks if this will mean that there are now no
+** connections at all to the database. If so, it performs a checkpoint
+** operation before closing the connection. This option may be used to
+** override this behaviour. The first parameter passed to this operation
+** is an integer - non-zero to disable checkpoints-on-close, or zero (the
+** default) to enable them. The second parameter is a pointer to an integer
+** into which is written 0 or 1 to indicate whether checkpoints-on-close
+** have been disabled - 0 if they are not disabled, 1 if they are.
+** </dd>
+**
** </dl>
*/
-#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
-#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
-#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
+#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
+#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
+#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER 1004 /* int int* */
+#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
+#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
/*
@@ -1919,7 +2019,7 @@ struct sqlite3_mem_methods {
** [extended result codes] feature of SQLite. ^The extended result
** codes are disabled by default for historical compatibility.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff);
+SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
/*
** CAPI3REF: Last Insert Rowid
@@ -1971,7 +2071,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_extended_result_codes(sqlite3*, int onoff)
** unpredictable and might not equal either the old or the new
** last insert [rowid].
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
+SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
/*
** CAPI3REF: Count The Number Of Rows Modified
@@ -2024,7 +2124,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_last_insert_rowid(sqlite3*);
** while [sqlite3_changes()] is running then the value returned
** is unpredictable and not meaningful.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
+SQLITE_API int sqlite3_changes(sqlite3*);
/*
** CAPI3REF: Total Number Of Rows Modified
@@ -2048,7 +2148,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_changes(sqlite3*);
** while [sqlite3_total_changes()] is running then the value
** returned is unpredictable and not meaningful.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
+SQLITE_API int sqlite3_total_changes(sqlite3*);
/*
** CAPI3REF: Interrupt A Long-Running Query
@@ -2088,7 +2188,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_total_changes(sqlite3*);
** If the database connection closes while [sqlite3_interrupt()]
** is running then bad things will likely happen.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
+SQLITE_API void sqlite3_interrupt(sqlite3*);
/*
** CAPI3REF: Determine If An SQL Statement Is Complete
@@ -2123,8 +2223,8 @@ SQLITE_API void SQLITE_STDCALL sqlite3_interrupt(sqlite3*);
** The input to [sqlite3_complete16()] must be a zero-terminated
** UTF-16 string in native byte order.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_complete(const char *sql);
-SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
+SQLITE_API int sqlite3_complete(const char *sql);
+SQLITE_API int sqlite3_complete16(const void *sql);
/*
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
@@ -2185,7 +2285,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_complete16(const void *sql);
** A busy handler must not close the database connection
** or [prepared statement] that invoked the busy handler.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
+SQLITE_API int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
/*
** CAPI3REF: Set A Busy Timeout
@@ -2208,7 +2308,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_handler(sqlite3*, int(*)(void*,int),
**
** See also: [PRAGMA busy_timeout]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
+SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
/*
** CAPI3REF: Convenience Routines For Running Queries
@@ -2283,7 +2383,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_busy_timeout(sqlite3*, int ms);
** reflected in subsequent calls to [sqlite3_errcode()] or
** [sqlite3_errmsg()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
+SQLITE_API int sqlite3_get_table(
sqlite3 *db, /* An open database */
const char *zSql, /* SQL to be evaluated */
char ***pazResult, /* Results of the query */
@@ -2291,7 +2391,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_table(
int *pnColumn, /* Number of result columns written here */
char **pzErrmsg /* Error msg written here */
);
-SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
+SQLITE_API void sqlite3_free_table(char **result);
/*
** CAPI3REF: Formatted String Printing Functions
@@ -2397,10 +2497,10 @@ SQLITE_API void SQLITE_STDCALL sqlite3_free_table(char **result);
** addition that after the string has been read and copied into
** the result, [sqlite3_free()] is called on the input string.)^
*/
-SQLITE_API char *SQLITE_CDECL sqlite3_mprintf(const char*,...);
-SQLITE_API char *SQLITE_STDCALL sqlite3_vmprintf(const char*, va_list);
-SQLITE_API char *SQLITE_CDECL sqlite3_snprintf(int,char*,const char*, ...);
-SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list);
+SQLITE_API char *sqlite3_mprintf(const char*,...);
+SQLITE_API char *sqlite3_vmprintf(const char*, va_list);
+SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...);
+SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
/*
** CAPI3REF: Memory Allocation Subsystem
@@ -2490,12 +2590,12 @@ SQLITE_API char *SQLITE_STDCALL sqlite3_vsnprintf(int,char*,const char*, va_list
** a block of memory after it has been released using
** [sqlite3_free()] or [sqlite3_realloc()].
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc(int);
-SQLITE_API void *SQLITE_STDCALL sqlite3_malloc64(sqlite3_uint64);
-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc(void*, int);
-SQLITE_API void *SQLITE_STDCALL sqlite3_realloc64(void*, sqlite3_uint64);
-SQLITE_API void SQLITE_STDCALL sqlite3_free(void*);
-SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
+SQLITE_API void *sqlite3_malloc(int);
+SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
+SQLITE_API void *sqlite3_realloc(void*, int);
+SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
+SQLITE_API void sqlite3_free(void*);
+SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
/*
** CAPI3REF: Memory Allocator Statistics
@@ -2520,8 +2620,8 @@ SQLITE_API sqlite3_uint64 SQLITE_STDCALL sqlite3_msize(void*);
** by [sqlite3_memory_highwater(1)] is the high-water mark
** prior to the reset.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_used(void);
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
+SQLITE_API sqlite3_int64 sqlite3_memory_used(void);
+SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
/*
** CAPI3REF: Pseudo-Random Number Generator
@@ -2544,7 +2644,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_memory_highwater(int resetFlag);
** internally and without recourse to the [sqlite3_vfs] xRandomness
** method.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
+SQLITE_API void sqlite3_randomness(int N, void *P);
/*
** CAPI3REF: Compile-Time Authorization Callbacks
@@ -2627,7 +2727,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_randomness(int N, void *P);
** as stated in the previous paragraph, sqlite3_step() invokes
** sqlite3_prepare_v2() to reprepare a statement after a schema change.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
+SQLITE_API int sqlite3_set_authorizer(
sqlite3*,
int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
void *pUserData
@@ -2707,6 +2807,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
** CAPI3REF: Tracing And Profiling Functions
** METHOD: sqlite3
**
+** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
+** instead of the routines described here.
+**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
**
@@ -2732,11 +2835,105 @@ SQLITE_API int SQLITE_STDCALL sqlite3_set_authorizer(
** sqlite3_profile() function is considered experimental and is
** subject to change in future versions of SQLite.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
+SQLITE_API SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
+ void(*xTrace)(void*,const char*), void*);
+SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
+** CAPI3REF: SQL Trace Event Codes
+** KEYWORDS: SQLITE_TRACE
+**
+** These constants identify classes of events that can be monitored
+** using the [sqlite3_trace_v2()] tracing logic. The third argument
+** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of
+** the following constants. ^The first argument to the trace callback
+** is one of the following constants.
+**
+** New tracing constants may be added in future releases.
+**
+** ^A trace callback has four arguments: xCallback(T,C,P,X).
+** ^The T argument is one of the integer type codes above.
+** ^The C argument is a copy of the context pointer passed in as the
+** fourth argument to [sqlite3_trace_v2()].
+** The P and X arguments are pointers whose meanings depend on T.
+**
+** <dl>
+** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt>
+** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement
+** first begins running and possibly at other times during the
+** execution of the prepared statement, such as at the start of each
+** trigger subprogram. ^The P argument is a pointer to the
+** [prepared statement]. ^The X argument is a pointer to a string which
+** is the unexpanded SQL text of the prepared statement or an SQL comment
+** that indicates the invocation of a trigger. ^The callback can compute
+** the same text that would have been returned by the legacy [sqlite3_trace()]
+** interface by using the X argument when X begins with "--" and invoking
+** [sqlite3_expanded_sql(P)] otherwise.
+**
+** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt>
+** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
+** information as is provided by the [sqlite3_profile()] callback.
+** ^The P argument is a pointer to the [prepared statement] and the
+** X argument points to a 64-bit integer which is the estimated of
+** the number of nanosecond that the prepared statement took to run.
+** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
+**
+** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
+** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
+** statement generates a single row of result.
+** ^The P argument is a pointer to the [prepared statement] and the
+** X argument is unused.
+**
+** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt>
+** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database
+** connection closes.
+** ^The P argument is a pointer to the [database connection] object
+** and the X argument is unused.
+** </dl>
+*/
+#define SQLITE_TRACE_STMT 0x01
+#define SQLITE_TRACE_PROFILE 0x02
+#define SQLITE_TRACE_ROW 0x04
+#define SQLITE_TRACE_CLOSE 0x08
+
+/*
+** CAPI3REF: SQL Trace Hook
+** METHOD: sqlite3
+**
+** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback
+** function X against [database connection] D, using property mask M
+** and context pointer P. ^If the X callback is
+** NULL or if the M mask is zero, then tracing is disabled. The
+** M argument should be the bitwise OR-ed combination of
+** zero or more [SQLITE_TRACE] constants.
+**
+** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
+** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
+**
+** ^The X callback is invoked whenever any of the events identified by
+** mask M occur. ^The integer return value from the callback is currently
+** ignored, though this may change in future releases. Callback
+** implementations should return zero to ensure future compatibility.
+**
+** ^A trace callback is invoked with four arguments: callback(T,C,P,X).
+** ^The T argument is one of the [SQLITE_TRACE]
+** constants to indicate why the callback was invoked.
+** ^The C argument is a copy of the context pointer.
+** The P and X arguments are pointers whose meanings depend on T.
+**
+** The sqlite3_trace_v2() interface is intended to replace the legacy
+** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which
+** are deprecated.
+*/
+SQLITE_API int sqlite3_trace_v2(
+ sqlite3*,
+ unsigned uMask,
+ int(*xCallback)(unsigned,void*,void*,void*),
+ void *pCtx
+);
+
+/*
** CAPI3REF: Query Progress Callbacks
** METHOD: sqlite3
**
@@ -2768,7 +2965,7 @@ SQLITE_API SQLITE_EXPERIMENTAL void *SQLITE_STDCALL sqlite3_profile(sqlite3*,
** database connections for the meaning of "modify" in this paragraph.
**
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
+SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
/*
** CAPI3REF: Opening A New Database Connection
@@ -2997,15 +3194,15 @@ SQLITE_API void SQLITE_STDCALL sqlite3_progress_handler(sqlite3*, int, int(*)(vo
**
** See also: [sqlite3_temp_directory]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_open(
+SQLITE_API int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_open16(
+SQLITE_API int sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
+SQLITE_API int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
@@ -3051,9 +3248,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_open_v2(
** VFS method, then the behavior of this routine is undefined and probably
** undesirable.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_uri_parameter(const char *zFilename, const char *zParam);
-SQLITE_API int SQLITE_STDCALL sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
+SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
+SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
/*
@@ -3097,11 +3294,11 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_uri_int64(const char*, const cha
** was invoked incorrectly by the application. In that case, the
** error code and message may or may not be set.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_errcode(sqlite3 *db);
-SQLITE_API int SQLITE_STDCALL sqlite3_extended_errcode(sqlite3 *db);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_errmsg(sqlite3*);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_errmsg16(sqlite3*);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_errstr(int);
+SQLITE_API int sqlite3_errcode(sqlite3 *db);
+SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
+SQLITE_API const char *sqlite3_errmsg(sqlite3*);
+SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
+SQLITE_API const char *sqlite3_errstr(int);
/*
** CAPI3REF: Prepared Statement Object
@@ -3169,7 +3366,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
**
** New run-time limit categories may be added in future releases.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
+SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
/*
** CAPI3REF: Run-Time Limit Categories
@@ -3321,28 +3518,28 @@ SQLITE_API int SQLITE_STDCALL sqlite3_limit(sqlite3*, int id, int newVal);
** </li>
** </ol>
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare(
+SQLITE_API int sqlite3_prepare(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare_v2(
+SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16(
+SQLITE_API int sqlite3_prepare16(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const void **pzTail /* OUT: Pointer to unused portion of zSql */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
+SQLITE_API int sqlite3_prepare16_v2(
sqlite3 *db, /* Database handle */
const void *zSql, /* SQL statement, UTF-16 encoded */
int nByte, /* Maximum length of zSql in bytes. */
@@ -3354,11 +3551,35 @@ SQLITE_API int SQLITE_STDCALL sqlite3_prepare16_v2(
** CAPI3REF: Retrieving Statement SQL
** METHOD: sqlite3_stmt
**
-** ^This interface can be used to retrieve a saved copy of the original
-** SQL text used to create a [prepared statement] if that statement was
-** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
+** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
+** SQL text used to create [prepared statement] P if P was
+** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
+** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
+** string containing the SQL text of prepared statement P with
+** [bound parameters] expanded.
+**
+** ^(For example, if a prepared statement is created using the SQL
+** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
+** and parameter :xyz is unbound, then sqlite3_sql() will return
+** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql()
+** will return "SELECT 2345,NULL".)^
+**
+** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
+** is available to hold the result, or if the result would exceed the
+** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
+**
+** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
+** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time
+** option causes sqlite3_expanded_sql() to always return NULL.
+**
+** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
+** automatically freed when the prepared statement is finalized.
+** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
+** is obtained from [sqlite3_malloc()] and must be free by the application
+** by passing it to [sqlite3_free()].
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
+SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
+SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
@@ -3389,8 +3610,12 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_sql(sqlite3_stmt *pStmt);
** sqlite3_stmt_readonly() to return true since, while those statements
** change the configuration of a database connection, they do not make
** changes to the content of the database files on disk.
+** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
+** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
+** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
+** sqlite3_stmt_readonly() returns false for those commands.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
@@ -3411,7 +3636,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
** for example, in diagnostic routines to search for prepared
** statements that are holding a transaction open.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_busy(sqlite3_stmt*);
+SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
/*
** CAPI3REF: Dynamically Typed Value Object
@@ -3575,20 +3800,20 @@ typedef struct sqlite3_context sqlite3_context;
** See also: [sqlite3_bind_parameter_count()],
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
+SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
+SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
void(*)(void*));
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_double(sqlite3_stmt*, int, double);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int(sqlite3_stmt*, int, int);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_null(sqlite3_stmt*, int);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
+SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
+SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
+SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
+SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
+SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
+SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
+SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
void(*)(void*), unsigned char encoding);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
+SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
+SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
+SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64);
/*
** CAPI3REF: Number Of SQL Parameters
@@ -3609,7 +3834,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite
** [sqlite3_bind_parameter_name()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
+SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
/*
** CAPI3REF: Name Of A Host Parameter
@@ -3637,7 +3862,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_count(sqlite3_stmt*);
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_index()].
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*, int);
+SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
/*
** CAPI3REF: Index Of A Parameter With A Given Name
@@ -3654,7 +3879,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_bind_parameter_name(sqlite3_stmt*,
** [sqlite3_bind_parameter_count()], and
** [sqlite3_bind_parameter_name()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
+SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
/*
** CAPI3REF: Reset All Bindings On A Prepared Statement
@@ -3664,7 +3889,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_bind_parameter_index(sqlite3_stmt*, const
** the [sqlite3_bind_blob | bindings] on a [prepared statement].
** ^Use this routine to reset all host parameters to NULL.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
+SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
/*
** CAPI3REF: Number Of Columns In A Result Set
@@ -3676,7 +3901,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_clear_bindings(sqlite3_stmt*);
**
** See also: [sqlite3_data_count()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Column Names In A Result Set
@@ -3705,8 +3930,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_column_count(sqlite3_stmt *pStmt);
** then the name of the column is unspecified and may change from
** one release of SQLite to the next.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_name(sqlite3_stmt*, int N);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N);
+SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N);
+SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N);
/*
** CAPI3REF: Source Of Data In A Query Result
@@ -3754,12 +3979,12 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_name16(sqlite3_stmt*, int N
** for the same [prepared statement] and result column
** at the same time then the results are undefined.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_database_name(sqlite3_stmt*,int);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_database_name16(sqlite3_stmt*,int);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_table_name(sqlite3_stmt*,int);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_table_name16(sqlite3_stmt*,int);
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_origin_name(sqlite3_stmt*,int);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*,int);
+SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int);
+SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
+SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int);
+SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
+SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
+SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
/*
** CAPI3REF: Declared Datatype Of A Query Result
@@ -3791,8 +4016,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_origin_name16(sqlite3_stmt*
** is associated with individual values, not with the containers
** used to hold those values.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_column_decltype(sqlite3_stmt*,int);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,int);
+SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int);
+SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
/*
** CAPI3REF: Evaluate An SQL Statement
@@ -3853,7 +4078,8 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
** other than [SQLITE_ROW] before any subsequent invocation of
** sqlite3_step(). Failure to reset the prepared statement using
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
-** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began
+** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
+** sqlite3_step() began
** calling [sqlite3_reset()] automatically in this circumstance rather
** than returning [SQLITE_MISUSE]. This is not considered a compatibility
** break because any application that ever receives an SQLITE_MISUSE error
@@ -3872,7 +4098,7 @@ SQLITE_API const void *SQLITE_STDCALL sqlite3_column_decltype16(sqlite3_stmt*,in
** then the more specific [error codes] are returned directly
** by sqlite3_step(). The use of the "v2" interface is recommended.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
+SQLITE_API int sqlite3_step(sqlite3_stmt*);
/*
** CAPI3REF: Number of columns in a result set
@@ -3893,7 +4119,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_step(sqlite3_stmt*);
**
** See also: [sqlite3_column_count()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Fundamental Datatypes
@@ -4083,16 +4309,16 @@ SQLITE_API int SQLITE_STDCALL sqlite3_data_count(sqlite3_stmt *pStmt);
** pointer. Subsequent calls to [sqlite3_errcode()] will return
** [SQLITE_NOMEM].)^
*/
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_blob(sqlite3_stmt*, int iCol);
-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-SQLITE_API int SQLITE_STDCALL sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-SQLITE_API double SQLITE_STDCALL sqlite3_column_double(sqlite3_stmt*, int iCol);
-SQLITE_API int SQLITE_STDCALL sqlite3_column_int(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_column_int64(sqlite3_stmt*, int iCol);
-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_column_text(sqlite3_stmt*, int iCol);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_column_text16(sqlite3_stmt*, int iCol);
-SQLITE_API int SQLITE_STDCALL sqlite3_column_type(sqlite3_stmt*, int iCol);
-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int iCol);
+SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
+SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
+SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
+SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
+SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol);
+SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
/*
** CAPI3REF: Destroy A Prepared Statement Object
@@ -4120,7 +4346,7 @@ SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_column_value(sqlite3_stmt*, int
** statement after it has been finalized can result in undefined and
** undesirable behavior such as segfaults and heap corruption.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Reset A Prepared Statement Object
@@ -4147,7 +4373,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_finalize(sqlite3_stmt *pStmt);
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
+SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Create Or Redefine SQL Functions
@@ -4247,7 +4473,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_reset(sqlite3_stmt *pStmt);
** close the database connection nor finalize or reset the prepared
** statement in which the function is running.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
+SQLITE_API int sqlite3_create_function(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4257,7 +4483,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
+SQLITE_API int sqlite3_create_function16(
sqlite3 *db,
const void *zFunctionName,
int nArg,
@@ -4267,7 +4493,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function16(
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
+SQLITE_API int sqlite3_create_function_v2(
sqlite3 *db,
const char *zFunctionName,
int nArg,
@@ -4313,12 +4539,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_function_v2(
** these functions, we will not explain what they do.
*/
#ifndef SQLITE_OMIT_DEPRECATED
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_aggregate_count(sqlite3_context*);
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_expired(sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_global_recover(void);
-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_thread_cleanup(void);
-SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
+SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
+SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
+SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
void*,sqlite3_int64);
#endif
@@ -4368,18 +4594,18 @@ SQLITE_API SQLITE_DEPRECATED int SQLITE_STDCALL sqlite3_memory_alarm(void(*)(voi
** These routines must be called from the same thread as
** the SQL function that supplied the [sqlite3_value*] parameters.
*/
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_blob(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_bytes16(sqlite3_value*);
-SQLITE_API double SQLITE_STDCALL sqlite3_value_double(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_int(sqlite3_value*);
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_value_int64(sqlite3_value*);
-SQLITE_API const unsigned char *SQLITE_STDCALL sqlite3_value_text(sqlite3_value*);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16(sqlite3_value*);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16le(sqlite3_value*);
-SQLITE_API const void *SQLITE_STDCALL sqlite3_value_text16be(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_type(sqlite3_value*);
-SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
+SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
+SQLITE_API int sqlite3_value_bytes(sqlite3_value*);
+SQLITE_API int sqlite3_value_bytes16(sqlite3_value*);
+SQLITE_API double sqlite3_value_double(sqlite3_value*);
+SQLITE_API int sqlite3_value_int(sqlite3_value*);
+SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
+SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*);
+SQLITE_API const void *sqlite3_value_text16(sqlite3_value*);
+SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*);
+SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*);
+SQLITE_API int sqlite3_value_type(sqlite3_value*);
+SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
/*
** CAPI3REF: Finding The Subtype Of SQL Values
@@ -4395,7 +4621,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_value_numeric_type(sqlite3_value*);
** from the result of one [application-defined SQL function] into the
** input of another.
*/
-SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
+SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
/*
** CAPI3REF: Copy And Free SQL Values
@@ -4411,8 +4637,8 @@ SQLITE_API unsigned int SQLITE_STDCALL sqlite3_value_subtype(sqlite3_value*);
** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer
** then sqlite3_value_free(V) is a harmless no-op.
*/
-SQLITE_API sqlite3_value *SQLITE_STDCALL sqlite3_value_dup(const sqlite3_value*);
-SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
+SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value*);
+SQLITE_API void sqlite3_value_free(sqlite3_value*);
/*
** CAPI3REF: Obtain Aggregate Function Context
@@ -4457,7 +4683,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_value_free(sqlite3_value*);
** This routine must be called from the same thread in which
** the aggregate SQL function is running.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int nBytes);
+SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
/*
** CAPI3REF: User Data For Functions
@@ -4472,7 +4698,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_aggregate_context(sqlite3_context*, int
** This routine must be called from the same thread in which
** the application-defined function is running.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
+SQLITE_API void *sqlite3_user_data(sqlite3_context*);
/*
** CAPI3REF: Database Connection For Functions
@@ -4484,7 +4710,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_user_data(sqlite3_context*);
** and [sqlite3_create_function16()] routines that originally
** registered the application defined function.
*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
+SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
/*
** CAPI3REF: Function Auxiliary Data
@@ -4516,12 +4742,13 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
** SQLite will invoke the destructor function X with parameter P exactly
** once, when the metadata is discarded.
** SQLite is free to discard the metadata at any time, including: <ul>
-** <li> when the corresponding function parameter changes, or
-** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
-** SQL statement, or
-** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or
-** <li> during the original sqlite3_set_auxdata() call when a memory
-** allocation error occurs. </ul>)^
+** <li> ^(when the corresponding function parameter changes)^, or
+** <li> ^(when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
+** SQL statement)^, or
+** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
+** parameter)^, or
+** <li> ^(during the original sqlite3_set_auxdata() call when a memory
+** allocation error occurs.)^ </ul>
**
** Note the last bullet in particular. The destructor X in
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
@@ -4537,8 +4764,8 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_context_db_handle(sqlite3_context*);
** These routines must be called from the same thread in which
** the SQL function is running.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_get_auxdata(sqlite3_context*, int N);
-SQLITE_API void SQLITE_STDCALL sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
+SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
/*
@@ -4674,27 +4901,27 @@ typedef void (*sqlite3_destructor_type)(void*);
** than the one containing the application-defined function that received
** the [sqlite3_context] pointer, the results are undefined.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_blob64(sqlite3_context*,const void*,
+SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,
sqlite3_uint64,void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_double(sqlite3_context*, double);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error(sqlite3_context*, const char*, int);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error16(sqlite3_context*, const void*, int);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_toobig(sqlite3_context*);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_nomem(sqlite3_context*);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_error_code(sqlite3_context*, int);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_int(sqlite3_context*, int);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_null(sqlite3_context*);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
+SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
+SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
+SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
+SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*);
+SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*);
+SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int);
+SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
+SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
+SQLITE_API void sqlite3_result_null(sqlite3_context*);
+SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
+SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
void(*)(void*), unsigned char encoding);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-SQLITE_API void SQLITE_STDCALL sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-SQLITE_API void SQLITE_STDCALL sqlite3_result_zeroblob(sqlite3_context*, int n);
-SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
+SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
+SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
+SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
+SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n);
+SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
/*
@@ -4709,7 +4936,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_result_zeroblob64(sqlite3_context*, sqlite
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned int);
+SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
/*
** CAPI3REF: Define New Collating Sequences
@@ -4791,14 +5018,14 @@ SQLITE_API void SQLITE_STDCALL sqlite3_result_subtype(sqlite3_context*,unsigned
**
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation(
+SQLITE_API int sqlite3_create_collation(
sqlite3*,
const char *zName,
int eTextRep,
void *pArg,
int(*xCompare)(void*,int,const void*,int,const void*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
+SQLITE_API int sqlite3_create_collation_v2(
sqlite3*,
const char *zName,
int eTextRep,
@@ -4806,7 +5033,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation_v2(
int(*xCompare)(void*,int,const void*,int,const void*),
void(*xDestroy)(void*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
+SQLITE_API int sqlite3_create_collation16(
sqlite3*,
const void *zName,
int eTextRep,
@@ -4841,12 +5068,12 @@ SQLITE_API int SQLITE_STDCALL sqlite3_create_collation16(
** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
** [sqlite3_create_collation_v2()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed(
+SQLITE_API int sqlite3_collation_needed(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const char*)
);
-SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
+SQLITE_API int sqlite3_collation_needed16(
sqlite3*,
void*,
void(*)(void*,sqlite3*,int eTextRep,const void*)
@@ -4860,11 +5087,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_collation_needed16(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_key(
+SQLITE_API int sqlite3_key(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The key */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
+SQLITE_API int sqlite3_key_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The key */
@@ -4878,11 +5105,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_key_v2(
** The code to implement this API is not available in the public release
** of SQLite.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_rekey(
+SQLITE_API int sqlite3_rekey(
sqlite3 *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
+SQLITE_API int sqlite3_rekey_v2(
sqlite3 *db, /* Database to be rekeyed */
const char *zDbName, /* Name of the database */
const void *pKey, int nKey /* The new key */
@@ -4892,7 +5119,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_rekey_v2(
** Specify the activation key for a SEE database. Unless
** activated, none of the SEE routines will work.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
+SQLITE_API void sqlite3_activate_see(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4902,7 +5129,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_see(
** Specify the activation key for a CEROD database. Unless
** activated, none of the CEROD routines will work.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
+SQLITE_API void sqlite3_activate_cerod(
const char *zPassPhrase /* Activation phrase */
);
#endif
@@ -4924,7 +5151,7 @@ SQLITE_API void SQLITE_STDCALL sqlite3_activate_cerod(
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_sleep(int);
+SQLITE_API int sqlite3_sleep(int);
/*
** CAPI3REF: Name Of The Folder Holding Temporary Files
@@ -5043,7 +5270,7 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_data_directory;
** connection while this routine is running, then the return value
** is undefined.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
+SQLITE_API int sqlite3_get_autocommit(sqlite3*);
/*
** CAPI3REF: Find The Database Handle Of A Prepared Statement
@@ -5056,7 +5283,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_get_autocommit(sqlite3*);
** to the [sqlite3_prepare_v2()] call (or its variants) that was used to
** create the statement in the first place.
*/
-SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
+SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
/*
** CAPI3REF: Return The Filename For A Database Connection
@@ -5073,7 +5300,7 @@ SQLITE_API sqlite3 *SQLITE_STDCALL sqlite3_db_handle(sqlite3_stmt*);
** will be an absolute pathname, even if the filename used
** to open the database originally was a URI or relative pathname.
*/
-SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const char *zDbName);
+SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Determine if a database is read-only
@@ -5083,7 +5310,7 @@ SQLITE_API const char *SQLITE_STDCALL sqlite3_db_filename(sqlite3 *db, const cha
** of connection D is read-only, 0 if it is read/write, or -1 if N is not
** the name of a database on connection D.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
+SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
/*
** CAPI3REF: Find the next prepared statement
@@ -5099,7 +5326,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_readonly(sqlite3 *db, const char *zDbNa
** [sqlite3_next_stmt(D,S)] must refer to an open database
** connection and in particular must not be a NULL pointer.
*/
-SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
+SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
/*
** CAPI3REF: Commit And Rollback Notification Callbacks
@@ -5148,8 +5375,8 @@ SQLITE_API sqlite3_stmt *SQLITE_STDCALL sqlite3_next_stmt(sqlite3 *pDb, sqlite3_
**
** See also the [sqlite3_update_hook()] interface.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
+SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
+SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
/*
** CAPI3REF: Data Change Notification Callbacks
@@ -5158,7 +5385,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
** ^The sqlite3_update_hook() interface registers a callback function
** with the [database connection] identified by the first argument
** to be invoked whenever a row is updated, inserted or deleted in
-** a rowid table.
+** a [rowid table].
** ^Any callback set by a previous call to this function
** for the same database connection is overridden.
**
@@ -5197,10 +5424,10 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_rollback_hook(sqlite3*, void(*)(void *),
** on the same [database connection] D, or NULL for
** the first call on D.
**
-** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()]
-** interfaces.
+** See also the [sqlite3_commit_hook()], [sqlite3_rollback_hook()],
+** and [sqlite3_preupdate_hook()] interfaces.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
+SQLITE_API void *sqlite3_update_hook(
sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
@@ -5215,7 +5442,8 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
** and disabled if the argument is false.)^
**
** ^Cache sharing is enabled and disabled for an entire process.
-** This is a change as of SQLite version 3.5.0. In prior versions of SQLite,
+** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
+** In prior versions of SQLite,
** sharing was enabled or disabled for each thread separately.
**
** ^(The cache sharing mode set by this interface effects all subsequent
@@ -5240,7 +5468,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_update_hook(
**
** See Also: [SQLite Shared-Cache Mode]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
+SQLITE_API int sqlite3_enable_shared_cache(int);
/*
** CAPI3REF: Attempt To Free Heap Memory
@@ -5256,7 +5484,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_shared_cache(int);
**
** See also: [sqlite3_db_release_memory()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
+SQLITE_API int sqlite3_release_memory(int);
/*
** CAPI3REF: Free Memory Used By A Database Connection
@@ -5270,7 +5498,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_release_memory(int);
**
** See also: [sqlite3_release_memory()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
+SQLITE_API int sqlite3_db_release_memory(sqlite3*);
/*
** CAPI3REF: Impose A Limit On Heap Size
@@ -5309,7 +5537,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
** from the heap.
** </ul>)^
**
-** Beginning with SQLite version 3.7.3, the soft heap limit is enforced
+** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]),
+** the soft heap limit is enforced
** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT]
** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT],
** the soft heap limit is enforced on every memory allocation. Without
@@ -5322,7 +5551,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_release_memory(sqlite3*);
** The circumstances under which SQLite will enforce the soft heap limit may
** changes in future releases of SQLite.
*/
-SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64 N);
+SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N);
/*
** CAPI3REF: Deprecated Soft Heap Limit Interface
@@ -5333,7 +5562,7 @@ SQLITE_API sqlite3_int64 SQLITE_STDCALL sqlite3_soft_heap_limit64(sqlite3_int64
** only. All new applications should use the
** [sqlite3_soft_heap_limit64()] interface rather than this one.
*/
-SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
+SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
/*
@@ -5348,7 +5577,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
** column exists. ^The sqlite3_table_column_metadata() interface returns
** SQLITE_ERROR and if the specified column does not exist.
** ^If the column-name parameter to sqlite3_table_column_metadata() is a
-** NULL pointer, then this routine simply checks for the existance of the
+** NULL pointer, then this routine simply checks for the existence of the
** table and returns SQLITE_OK if the table exists and SQLITE_ERROR if it
** does not.
**
@@ -5403,7 +5632,7 @@ SQLITE_API SQLITE_DEPRECATED void SQLITE_STDCALL sqlite3_soft_heap_limit(int N);
** parsed, if that has not already been done, and returns an error if
** any errors are encountered while loading the schema.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
+SQLITE_API int sqlite3_table_column_metadata(
sqlite3 *db, /* Connection handle */
const char *zDbName, /* Database name or NULL */
const char *zTableName, /* Table name */
@@ -5445,12 +5674,21 @@ SQLITE_API int SQLITE_STDCALL sqlite3_table_column_metadata(
** should free this memory by calling [sqlite3_free()].
**
** ^Extension loading must be enabled using
-** [sqlite3_enable_load_extension()] prior to calling this API,
+** [sqlite3_enable_load_extension()] or
+** [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],1,NULL)
+** prior to calling this API,
** otherwise an error will be returned.
**
+** <b>Security warning:</b> It is recommended that the
+** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
+** interface. The use of the [sqlite3_enable_load_extension()] interface
+** should be avoided. This will keep the SQL function [load_extension()]
+** disabled and prevent SQL injections from giving attackers
+** access to extension loading capabilities.
+**
** See also the [load_extension() SQL function].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
+SQLITE_API int sqlite3_load_extension(
sqlite3 *db, /* Load the extension into this database connection */
const char *zFile, /* Name of the shared library containing extension */
const char *zProc, /* Entry point. Derived from zFile if 0 */
@@ -5470,8 +5708,19 @@ SQLITE_API int SQLITE_STDCALL sqlite3_load_extension(
** ^Call the sqlite3_enable_load_extension() routine with onoff==1
** to turn extension loading on and call it with onoff==0 to turn
** it back off again.
+**
+** ^This interface enables or disables both the C-API
+** [sqlite3_load_extension()] and the SQL function [load_extension()].
+** ^(Use [sqlite3_db_config](db,[SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION],..)
+** to enable or disable only the C-API.)^
+**
+** <b>Security warning:</b> It is recommended that extension loading
+** be disabled using the [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method
+** rather than this interface, so the [load_extension()] SQL function
+** remains disabled. This will prevent SQL injections from giving attackers
+** access to extension loading capabilities.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int onoff);
+SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
** CAPI3REF: Automatically Load Statically Linked Extensions
@@ -5483,7 +5732,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
**
** ^(Even though the function prototype shows that xEntryPoint() takes
** no arguments and returns void, SQLite invokes xEntryPoint() with three
-** arguments and expects and integer result as if the signature of the
+** arguments and expects an integer result as if the signature of the
** entry point where as follows:
**
** <blockquote><pre>
@@ -5509,7 +5758,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_enable_load_extension(sqlite3 *db, int ono
** See also: [sqlite3_reset_auto_extension()]
** and [sqlite3_cancel_auto_extension()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
/*
** CAPI3REF: Cancel Automatic Extension Loading
@@ -5521,7 +5770,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_auto_extension(void (*xEntryPoint)(void));
** unregistered and it returns 0 if X was not on the list of initialization
** routines.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
+SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
/*
** CAPI3REF: Reset Automatic Extension Loading
@@ -5529,7 +5778,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_cancel_auto_extension(void (*xEntryPoint)(
** ^This interface disables all automatic extensions previously
** registered using [sqlite3_auto_extension()].
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_reset_auto_extension(void);
+SQLITE_API void sqlite3_reset_auto_extension(void);
/*
** The interface to the virtual-table mechanism is currently considered
@@ -5683,13 +5932,15 @@ struct sqlite3_module {
** the xUpdate method are automatically rolled back by SQLite.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
-** structure for SQLite version 3.8.2. If a virtual table extension is
+** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
+** If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002. Similarly, the idxFlags field
-** was added for version 3.9.0. It may therefore only be used if
+** was added for [version 3.9.0] ([dateof:3.9.0]).
+** It may therefore only be used if
** sqlite3_libversion_number() returns a value greater than or equal to
** 3009000.
*/
@@ -5774,13 +6025,13 @@ struct sqlite3_index_info {
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_create_module(
+SQLITE_API int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_create_module_v2(
+SQLITE_API int sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -5843,7 +6094,7 @@ struct sqlite3_vtab_cursor {
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
+SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
@@ -5862,7 +6113,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_declare_vtab(sqlite3*, const char *zSQL);
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -5961,7 +6212,7 @@ typedef struct sqlite3_blob sqlite3_blob;
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
+SQLITE_API int sqlite3_blob_open(
sqlite3*,
const char *zDb,
const char *zTable,
@@ -5994,7 +6245,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_open(
**
** ^This function sets the database handle error code and message.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
+SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
/*
** CAPI3REF: Close A BLOB Handle
@@ -6017,7 +6268,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64)
** is passed a valid open blob handle, the values returned by the
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
+SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
/*
** CAPI3REF: Return The Size Of An Open BLOB
@@ -6033,7 +6284,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_close(sqlite3_blob *);
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
+SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *);
/*
** CAPI3REF: Read Data From A BLOB Incrementally
@@ -6062,7 +6313,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_bytes(sqlite3_blob *);
**
** See also: [sqlite3_blob_write()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
+SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
/*
** CAPI3REF: Write Data Into A BLOB Incrementally
@@ -6104,7 +6355,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_read(sqlite3_blob *, void *Z, int N,
**
** See also: [sqlite3_blob_read()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
+SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
/*
** CAPI3REF: Virtual File System Objects
@@ -6135,9 +6386,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_blob_write(sqlite3_blob *, const void *z,
** ^(If the default VFS is unregistered, another VFS is chosen as
** the default. The choice for the new VFS is arbitrary.)^
*/
-SQLITE_API sqlite3_vfs *SQLITE_STDCALL sqlite3_vfs_find(const char *zVfsName);
-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
-SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
+SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
+SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
+SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
/*
** CAPI3REF: Mutexes
@@ -6253,11 +6504,11 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vfs_unregister(sqlite3_vfs*);
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_mutex_alloc(int);
-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_free(sqlite3_mutex*);
-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_enter(sqlite3_mutex*);
-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_try(sqlite3_mutex*);
-SQLITE_API void SQLITE_STDCALL sqlite3_mutex_leave(sqlite3_mutex*);
+SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int);
+SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*);
+SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*);
+SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*);
+SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*);
/*
** CAPI3REF: Mutex Methods Object
@@ -6367,8 +6618,8 @@ struct sqlite3_mutex_methods {
** interface should also return 1 when given a NULL pointer.
*/
#ifndef NDEBUG
-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_held(sqlite3_mutex*);
-SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
+SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
+SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
#endif
/*
@@ -6387,7 +6638,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
-#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
+#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_randomness() */
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
@@ -6408,7 +6659,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_mutex_notheld(sqlite3_mutex*);
** ^If the [threading mode] is Single-thread or Multi-thread then this
** routine returns a NULL pointer.
*/
-SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
+SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
/*
** CAPI3REF: Low-Level Control Of Database Files
@@ -6443,7 +6694,7 @@ SQLITE_API sqlite3_mutex *SQLITE_STDCALL sqlite3_db_mutex(sqlite3*);
**
** See also: [SQLITE_FCNTL_LOCKSTATE]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
+SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
/*
** CAPI3REF: Testing Interface
@@ -6462,7 +6713,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_file_control(sqlite3*, const char *zDbName
** Unlike most of the SQLite API, this function is not guaranteed to
** operate consistently from one release to the next.
*/
-SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
+SQLITE_API int sqlite3_test_control(int op, ...);
/*
** CAPI3REF: Testing Interface Operation Codes
@@ -6491,6 +6742,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
+#define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
@@ -6525,8 +6777,8 @@ SQLITE_API int SQLITE_CDECL sqlite3_test_control(int op, ...);
**
** See also: [sqlite3_db_status()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
-SQLITE_API int SQLITE_STDCALL sqlite3_status64(
+SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
+SQLITE_API int sqlite3_status64(
int op,
sqlite3_int64 *pCurrent,
sqlite3_int64 *pHighwater,
@@ -6651,7 +6903,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_status64(
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
+SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
@@ -6697,6 +6949,18 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
**
+** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
+** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
+** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
+** pager cache is shared between two or more connections the bytes of heap
+** memory used by that pager cache is divided evenly between the attached
+** connections.)^ In other words, if none of the pager caches associated
+** with the database connection are shared, this request returns the same
+** value as DBSTATUS_CACHE_USED. Or, if one or more or the pager caches are
+** shared, the value returned by this call will be smaller than that returned
+** by DBSTATUS_CACHE_USED. ^The highwater mark associated with
+** SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0.
+**
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
** <dd>This parameter returns the approximate number of bytes of heap
** memory used to store the schema for all databases associated
@@ -6754,7 +7018,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
#define SQLITE_DBSTATUS_CACHE_MISS 8
#define SQLITE_DBSTATUS_CACHE_WRITE 9
#define SQLITE_DBSTATUS_DEFERRED_FKS 10
-#define SQLITE_DBSTATUS_MAX 10 /* Largest defined DBSTATUS */
+#define SQLITE_DBSTATUS_CACHE_USED_SHARED 11
+#define SQLITE_DBSTATUS_MAX 11 /* Largest defined DBSTATUS */
/*
@@ -6781,7 +7046,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_status(sqlite3*, int op, int *pCur, int
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
+SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
@@ -7108,7 +7373,7 @@ typedef struct sqlite3_backup sqlite3_backup;
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
** an error.
**
-** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
+** ^A call to sqlite3_backup_init() will fail, returning NULL, if
** there is already a read or read-write transaction open on the
** destination database.
**
@@ -7250,16 +7515,16 @@ typedef struct sqlite3_backup sqlite3_backup;
** same time as another thread is invoking sqlite3_backup_step() it is
** possible that they return invalid values.
*/
-SQLITE_API sqlite3_backup *SQLITE_STDCALL sqlite3_backup_init(
+SQLITE_API sqlite3_backup *sqlite3_backup_init(
sqlite3 *pDest, /* Destination database handle */
const char *zDestName, /* Destination database name */
sqlite3 *pSource, /* Source database handle */
const char *zSourceName /* Source database name */
);
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_step(sqlite3_backup *p, int nPage);
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_finish(sqlite3_backup *p);
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_remaining(sqlite3_backup *p);
-SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
+SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage);
+SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p);
+SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p);
+SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
/*
** CAPI3REF: Unlock Notification
@@ -7376,7 +7641,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_backup_pagecount(sqlite3_backup *p);
** the special "DROP TABLE/INDEX" case, the extended error code is just
** SQLITE_LOCKED.)^
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
+SQLITE_API int sqlite3_unlock_notify(
sqlite3 *pBlocked, /* Waiting connection */
void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */
void *pNotifyArg /* Argument to pass to xNotify */
@@ -7391,8 +7656,8 @@ SQLITE_API int SQLITE_STDCALL sqlite3_unlock_notify(
** strings in a case-independent fashion, using the same definition of "case
** independence" that SQLite uses internally when comparing identifiers.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stricmp(const char *, const char *);
-SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
+SQLITE_API int sqlite3_stricmp(const char *, const char *);
+SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
@@ -7409,7 +7674,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strnicmp(const char *, const char *, int);
**
** See also: [sqlite3_strlike()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zStr);
+SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
/*
** CAPI3REF: String LIKE Matching
@@ -7432,7 +7697,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strglob(const char *zGlob, const char *zSt
**
** See also: [sqlite3_strglob()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
+SQLITE_API int sqlite3_strlike(const char *zGlob, const char *zStr, unsigned int cEsc);
/*
** CAPI3REF: Error Logging Interface
@@ -7455,7 +7720,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_strlike(const char *zGlob, const char *zSt
** a few hundred characters, it will be truncated to the length of the
** buffer.
*/
-SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...);
+SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
** CAPI3REF: Write-Ahead Log Commit Hook
@@ -7489,9 +7754,9 @@ SQLITE_API void SQLITE_CDECL sqlite3_log(int iErrCode, const char *zFormat, ...)
** previously registered write-ahead log callback. ^Note that the
** [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
-** those overwrite any prior [sqlite3_wal_hook()] settings.
+** overwrite any prior [sqlite3_wal_hook()] settings.
*/
-SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
+SQLITE_API void *sqlite3_wal_hook(
sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
@@ -7526,7 +7791,7 @@ SQLITE_API void *SQLITE_STDCALL sqlite3_wal_hook(
** is only necessary if the default setting is found to be suboptimal
** for a particular application.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
+SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
/*
** CAPI3REF: Checkpoint a database
@@ -7548,7 +7813,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
** start a callback but which do not need the full power (and corresponding
** complication) of [sqlite3_wal_checkpoint_v2()].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
+SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
/*
** CAPI3REF: Checkpoint a database
@@ -7642,7 +7907,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint(sqlite3 *db, const char *zD
** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
** from SQL.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
+SQLITE_API int sqlite3_wal_checkpoint_v2(
sqlite3 *db, /* Database handle */
const char *zDb, /* Name of attached database (or NULL) */
int eMode, /* SQLITE_CHECKPOINT_* value */
@@ -7678,7 +7943,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_wal_checkpoint_v2(
** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options
** may be added in the future.
*/
-SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
+SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Virtual Table Configuration Options
@@ -7731,7 +7996,7 @@ SQLITE_API int SQLITE_CDECL sqlite3_vtab_config(sqlite3*, int op, ...);
** of the SQL statement that triggered the call to the [xUpdate] method of the
** [virtual table].
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
+SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Conflict resolution modes
@@ -7836,7 +8101,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_vtab_on_conflict(sqlite3 *);
**
** See also: [sqlite3_stmt_scanstatus_reset()]
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
+SQLITE_API int sqlite3_stmt_scanstatus(
sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
int idx, /* Index of loop to report on */
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
@@ -7852,7 +8117,7 @@ SQLITE_API int SQLITE_STDCALL sqlite3_stmt_scanstatus(
** This API is only available if the library is built with pre-processor
** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
*/
-SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
+SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
/*
** CAPI3REF: Flush caches to disk mid-transaction
@@ -7884,11 +8149,121 @@ SQLITE_API void SQLITE_STDCALL sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
** ^This function does not set the database handle error code or message
** returned by the [sqlite3_errcode()] and [sqlite3_errmsg()] functions.
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*);
+SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
+
+/*
+** CAPI3REF: The pre-update hook.
+**
+** ^These interfaces are only available if SQLite is compiled using the
+** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
+**
+** ^The [sqlite3_preupdate_hook()] interface registers a callback function
+** that is invoked prior to each [INSERT], [UPDATE], and [DELETE] operation
+** on a [rowid table].
+** ^At most one preupdate hook may be registered at a time on a single
+** [database connection]; each call to [sqlite3_preupdate_hook()] overrides
+** the previous setting.
+** ^The preupdate hook is disabled by invoking [sqlite3_preupdate_hook()]
+** with a NULL pointer as the second parameter.
+** ^The third parameter to [sqlite3_preupdate_hook()] is passed through as
+** the first parameter to callbacks.
+**
+** ^The preupdate hook only fires for changes to [rowid tables]; the preupdate
+** hook is not invoked for changes to [virtual tables] or [WITHOUT ROWID]
+** tables.
+**
+** ^The second parameter to the preupdate callback is a pointer to
+** the [database connection] that registered the preupdate hook.
+** ^The third parameter to the preupdate callback is one of the constants
+** [SQLITE_INSERT], [SQLITE_DELETE], or [SQLITE_UPDATE] to identify the
+** kind of update operation that is about to occur.
+** ^(The fourth parameter to the preupdate callback is the name of the
+** database within the database connection that is being modified. This
+** will be "main" for the main database or "temp" for TEMP tables or
+** the name given after the AS keyword in the [ATTACH] statement for attached
+** databases.)^
+** ^The fifth parameter to the preupdate callback is the name of the
+** table that is being modified.
+** ^The sixth parameter to the preupdate callback is the initial [rowid] of the
+** row being changes for SQLITE_UPDATE and SQLITE_DELETE changes and is
+** undefined for SQLITE_INSERT changes.
+** ^The seventh parameter to the preupdate callback is the final [rowid] of
+** the row being changed for SQLITE_UPDATE and SQLITE_INSERT changes and is
+** undefined for SQLITE_DELETE changes.
+**
+** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
+** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
+** provide additional information about a preupdate event. These routines
+** may only be called from within a preupdate callback. Invoking any of
+** these routines from outside of a preupdate callback or with a
+** [database connection] pointer that is different from the one supplied
+** to the preupdate callback results in undefined and probably undesirable
+** behavior.
+**
+** ^The [sqlite3_preupdate_count(D)] interface returns the number of columns
+** in the row that is being inserted, updated, or deleted.
+**
+** ^The [sqlite3_preupdate_old(D,N,P)] interface writes into P a pointer to
+** a [protected sqlite3_value] that contains the value of the Nth column of
+** the table row before it is updated. The N parameter must be between 0
+** and one less than the number of columns or the behavior will be
+** undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE
+** preupdate callbacks; if it is used by an SQLITE_INSERT callback then the
+** behavior is undefined. The [sqlite3_value] that P points to
+** will be destroyed when the preupdate callback returns.
+**
+** ^The [sqlite3_preupdate_new(D,N,P)] interface writes into P a pointer to
+** a [protected sqlite3_value] that contains the value of the Nth column of
+** the table row after it is updated. The N parameter must be between 0
+** and one less than the number of columns or the behavior will be
+** undefined. This must only be used within SQLITE_INSERT and SQLITE_UPDATE
+** preupdate callbacks; if it is used by an SQLITE_DELETE callback then the
+** behavior is undefined. The [sqlite3_value] that P points to
+** will be destroyed when the preupdate callback returns.
+**
+** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
+** callback was invoked as a result of a direct insert, update, or delete
+** operation; or 1 for inserts, updates, or deletes invoked by top-level
+** triggers; or 2 for changes resulting from triggers called by top-level
+** triggers; and so forth.
+**
+** See also: [sqlite3_update_hook()]
+*/
+#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
+SQLITE_API void *sqlite3_preupdate_hook(
+ sqlite3 *db,
+ void(*xPreUpdate)(
+ void *pCtx, /* Copy of third arg to preupdate_hook() */
+ sqlite3 *db, /* Database handle */
+ int op, /* SQLITE_UPDATE, DELETE or INSERT */
+ char const *zDb, /* Database name */
+ char const *zName, /* Table name */
+ sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */
+ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */
+ ),
+ void*
+);
+SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
+SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
+SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
+SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
+#endif
+
+/*
+** CAPI3REF: Low-level system error code
+**
+** ^Attempt to return the underlying operating system error code or error
+** number that caused the most recent I/O error or failure to open a file.
+** The return value is OS-dependent. For example, on unix systems, after
+** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
+** called to get back the underlying "errno" that caused the problem, such
+** as ENOSPC, EAUTH, EISDIR, and so forth.
+*/
+SQLITE_API int sqlite3_system_errno(sqlite3*);
/*
** CAPI3REF: Database Snapshot
-** KEYWORDS: {snapshot}
+** KEYWORDS: {snapshot} {sqlite3_snapshot}
** EXPERIMENTAL
**
** An instance of the snapshot object records the state of a [WAL mode]
@@ -7912,7 +8287,9 @@ SQLITE_API int SQLITE_STDCALL sqlite3_db_cacheflush(sqlite3*);
** to an historical snapshot (if possible). The destructor for
** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
*/
-typedef struct sqlite3_snapshot sqlite3_snapshot;
+typedef struct sqlite3_snapshot {
+ unsigned char hidden[48];
+} sqlite3_snapshot;
/*
** CAPI3REF: Record A Database Snapshot
@@ -7923,9 +8300,32 @@ typedef struct sqlite3_snapshot sqlite3_snapshot;
** schema S in database connection D. ^On success, the
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
-** ^If schema S of [database connection] D is not a [WAL mode] database
-** that is in a read transaction, then [sqlite3_snapshot_get(D,S,P)]
-** leaves the *P value unchanged and returns an appropriate [error code].
+** If there is not already a read-transaction open on schema S when
+** this function is called, one is opened automatically.
+**
+** The following must be true for this function to succeed. If any of
+** the following statements are false when sqlite3_snapshot_get() is
+** called, SQLITE_ERROR is returned. The final value of *P is undefined
+** in this case.
+**
+** <ul>
+** <li> The database handle must be in [autocommit mode].
+**
+** <li> Schema S of [database connection] D must be a [WAL mode] database.
+**
+** <li> There must not be a write transaction open on schema S of database
+** connection D.
+**
+** <li> One or more transactions must have been written to the current wal
+** file since it was created on disk (by any connection). This means
+** that a snapshot cannot be taken on a wal mode database with no wal
+** file immediately after it is first opened. At least one transaction
+** must be written to it first.
+** </ul>
+**
+** This function may also return SQLITE_NOMEM. If it is called with the
+** database handle in autocommit mode but fails for some other reason,
+** whether or not a read transaction is opened on schema S is undefined.
**
** The [sqlite3_snapshot] object returned from a successful call to
** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()]
@@ -7934,7 +8334,7 @@ typedef struct sqlite3_snapshot sqlite3_snapshot;
** The [sqlite3_snapshot_get()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get(
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
sqlite3 *db,
const char *zSchema,
sqlite3_snapshot **ppSnapshot
@@ -7944,22 +8344,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_get(
** CAPI3REF: Start a read transaction on an historical snapshot
** EXPERIMENTAL
**
-** ^The [sqlite3_snapshot_open(D,S,P)] interface attempts to move the
-** read transaction that is currently open on schema S of
-** [database connection] D so that it refers to historical [snapshot] P.
+** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
+** read transaction for schema S of
+** [database connection] D such that the read transaction
+** refers to historical [snapshot] P, rather than the most
+** recent change to the database.
** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
** or an appropriate [error code] if it fails.
**
** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
-** the first operation, apart from other sqlite3_snapshot_open() calls,
-** following the [BEGIN] that starts a new read transaction.
-** ^A [snapshot] will fail to open if it has been overwritten by a
-** [checkpoint].
+** the first operation following the [BEGIN] that takes the schema S
+** out of [autocommit mode].
+** ^In other words, schema S must not currently be in
+** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
+** database connection D must be out of [autocommit mode].
+** ^A [snapshot] will fail to open if it has been overwritten by a
+** [checkpoint].
+** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
+** database connection D does not know that the database file for
+** schema S is in [WAL mode]. A database connection might not know
+** that the database file is in [WAL mode] if there has been no prior
+** I/O on that database connection, or if the database entered [WAL mode]
+** after the most recent I/O on the database connection.)^
+** (Hint: Run "[PRAGMA application_id]" against a newly opened
+** database connection in order to make it ready to use snapshots.)
**
** The [sqlite3_snapshot_open()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
-SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open(
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
sqlite3 *db,
const char *zSchema,
sqlite3_snapshot *pSnapshot
@@ -7976,7 +8389,56 @@ SQLITE_API SQLITE_EXPERIMENTAL int SQLITE_STDCALL sqlite3_snapshot_open(
** The [sqlite3_snapshot_free()] interface is only available when the
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
*/
-SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3_snapshot*);
+SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
+
+/*
+** CAPI3REF: Compare the ages of two snapshot handles.
+** EXPERIMENTAL
+**
+** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
+** of two valid snapshot handles.
+**
+** If the two snapshot handles are not associated with the same database
+** file, the result of the comparison is undefined.
+**
+** Additionally, the result of the comparison is only valid if both of the
+** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
+** last time the wal file was deleted. The wal file is deleted when the
+** database is changed back to rollback mode or when the number of database
+** clients drops to zero. If either snapshot handle was obtained before the
+** wal file was last deleted, the value returned by this function
+** is undefined.
+**
+** Otherwise, this API returns a negative value if P1 refers to an older
+** snapshot than P2, zero if the two handles refer to the same database
+** snapshot, and a positive value if P1 is a newer snapshot than P2.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
+ sqlite3_snapshot *p1,
+ sqlite3_snapshot *p2
+);
+
+/*
+** CAPI3REF: Recover snapshots from a wal file
+** EXPERIMENTAL
+**
+** If all connections disconnect from a database file but do not perform
+** a checkpoint, the existing wal file is opened along with the database
+** file the next time the database is opened. At this point it is only
+** possible to successfully call sqlite3_snapshot_open() to open the most
+** recent snapshot of the database (the one at the head of the wal file),
+** even though the wal file may contain other valid snapshots for which
+** clients have sqlite3_snapshot handles.
+**
+** This function attempts to scan the wal file associated with database zDb
+** of database handle db and make all valid snapshots available to
+** sqlite3_snapshot_open(). It is an error if there is already a read
+** transaction open on the database, or if the database is not a wal mode
+** database.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+*/
+SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
/*
** Undo the hack that converts floating point types to integer for
@@ -7989,8 +8451,9 @@ SQLITE_API SQLITE_EXPERIMENTAL void SQLITE_STDCALL sqlite3_snapshot_free(sqlite3
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif
-#endif /* _SQLITE3_H_ */
+#endif /* SQLITE3_H */
+/******** Begin file sqlite3rtree.h *********/
/*
** 2010 August 30
**
@@ -8030,7 +8493,7 @@ typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_geometry_callback(
+SQLITE_API int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
@@ -8056,7 +8519,7 @@ struct sqlite3_rtree_geometry {
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
*/
-SQLITE_API int SQLITE_STDCALL sqlite3_rtree_query_callback(
+SQLITE_API int sqlite3_rtree_query_callback(
sqlite3 *db,
const char *zQueryFunc,
int (*xQueryFunc)(sqlite3_rtree_query_info*),
@@ -8108,6 +8571,1291 @@ struct sqlite3_rtree_query_info {
#endif /* ifndef _SQLITE3RTREE_H_ */
+/******** End of sqlite3rtree.h *********/
+/******** Begin file sqlite3session.h *********/
+
+#if !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION)
+#define __SQLITESESSION_H_ 1
+
+/*
+** Make sure we can call this stuff from C++.
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+** CAPI3REF: Session Object Handle
+*/
+typedef struct sqlite3_session sqlite3_session;
+
+/*
+** CAPI3REF: Changeset Iterator Handle
+*/
+typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
+
+/*
+** CAPI3REF: Create A New Session Object
+**
+** Create a new session object attached to database handle db. If successful,
+** a pointer to the new object is written to *ppSession and SQLITE_OK is
+** returned. If an error occurs, *ppSession is set to NULL and an SQLite
+** error code (e.g. SQLITE_NOMEM) is returned.
+**
+** It is possible to create multiple session objects attached to a single
+** database handle.
+**
+** Session objects created using this function should be deleted using the
+** [sqlite3session_delete()] function before the database handle that they
+** are attached to is itself closed. If the database handle is closed before
+** the session object is deleted, then the results of calling any session
+** module function, including [sqlite3session_delete()] on the session object
+** are undefined.
+**
+** Because the session module uses the [sqlite3_preupdate_hook()] API, it
+** is not possible for an application to register a pre-update hook on a
+** database handle that has one or more session objects attached. Nor is
+** it possible to create a session object attached to a database handle for
+** which a pre-update hook is already defined. The results of attempting
+** either of these things are undefined.
+**
+** The session object will be used to create changesets for tables in
+** database zDb, where zDb is either "main", or "temp", or the name of an
+** attached database. It is not an error if database zDb is not attached
+** to the database when the session object is created.
+*/
+int sqlite3session_create(
+ sqlite3 *db, /* Database handle */
+ const char *zDb, /* Name of db (e.g. "main") */
+ sqlite3_session **ppSession /* OUT: New session object */
+);
+
+/*
+** CAPI3REF: Delete A Session Object
+**
+** Delete a session object previously allocated using
+** [sqlite3session_create()]. Once a session object has been deleted, the
+** results of attempting to use pSession with any other session module
+** function are undefined.
+**
+** Session objects must be deleted before the database handle to which they
+** are attached is closed. Refer to the documentation for
+** [sqlite3session_create()] for details.
+*/
+void sqlite3session_delete(sqlite3_session *pSession);
+
+
+/*
+** CAPI3REF: Enable Or Disable A Session Object
+**
+** Enable or disable the recording of changes by a session object. When
+** enabled, a session object records changes made to the database. When
+** disabled - it does not. A newly created session object is enabled.
+** Refer to the documentation for [sqlite3session_changeset()] for further
+** details regarding how enabling and disabling a session object affects
+** the eventual changesets.
+**
+** Passing zero to this function disables the session. Passing a value
+** greater than zero enables it. Passing a value less than zero is a
+** no-op, and may be used to query the current state of the session.
+**
+** The return value indicates the final state of the session object: 0 if
+** the session is disabled, or 1 if it is enabled.
+*/
+int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
+
+/*
+** CAPI3REF: Set Or Clear the Indirect Change Flag
+**
+** Each change recorded by a session object is marked as either direct or
+** indirect. A change is marked as indirect if either:
+**
+** <ul>
+** <li> The session object "indirect" flag is set when the change is
+** made, or
+** <li> The change is made by an SQL trigger or foreign key action
+** instead of directly as a result of a users SQL statement.
+** </ul>
+**
+** If a single row is affected by more than one operation within a session,
+** then the change is considered indirect if all operations meet the criteria
+** for an indirect change above, or direct otherwise.
+**
+** This function is used to set, clear or query the session object indirect
+** flag. If the second argument passed to this function is zero, then the
+** indirect flag is cleared. If it is greater than zero, the indirect flag
+** is set. Passing a value less than zero does not modify the current value
+** of the indirect flag, and may be used to query the current state of the
+** indirect flag for the specified session object.
+**
+** The return value indicates the final state of the indirect flag: 0 if
+** it is clear, or 1 if it is set.
+*/
+int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
+
+/*
+** CAPI3REF: Attach A Table To A Session Object
+**
+** If argument zTab is not NULL, then it is the name of a table to attach
+** to the session object passed as the first argument. All subsequent changes
+** made to the table while the session object is enabled will be recorded. See
+** documentation for [sqlite3session_changeset()] for further details.
+**
+** Or, if argument zTab is NULL, then changes are recorded for all tables
+** in the database. If additional tables are added to the database (by
+** executing "CREATE TABLE" statements) after this call is made, changes for
+** the new tables are also recorded.
+**
+** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
+** defined as part of their CREATE TABLE statement. It does not matter if the
+** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
+** KEY may consist of a single column, or may be a composite key.
+**
+** It is not an error if the named table does not exist in the database. Nor
+** is it an error if the named table does not have a PRIMARY KEY. However,
+** no changes will be recorded in either of these scenarios.
+**
+** Changes are not recorded for individual rows that have NULL values stored
+** in one or more of their PRIMARY KEY columns.
+**
+** SQLITE_OK is returned if the call completes without error. Or, if an error
+** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
+*/
+int sqlite3session_attach(
+ sqlite3_session *pSession, /* Session object */
+ const char *zTab /* Table name */
+);
+
+/*
+** CAPI3REF: Set a table filter on a Session Object.
+**
+** The second argument (xFilter) is the "filter callback". For changes to rows
+** in tables that are not attached to the Session object, the filter is called
+** to determine whether changes to the table's rows should be tracked or not.
+** If xFilter returns 0, changes is not tracked. Note that once a table is
+** attached, xFilter will not be called again.
+*/
+void sqlite3session_table_filter(
+ sqlite3_session *pSession, /* Session object */
+ int(*xFilter)(
+ void *pCtx, /* Copy of third arg to _filter_table() */
+ const char *zTab /* Table name */
+ ),
+ void *pCtx /* First argument passed to xFilter */
+);
+
+/*
+** CAPI3REF: Generate A Changeset From A Session Object
+**
+** Obtain a changeset containing changes to the tables attached to the
+** session object passed as the first argument. If successful,
+** set *ppChangeset to point to a buffer containing the changeset
+** and *pnChangeset to the size of the changeset in bytes before returning
+** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
+** zero and return an SQLite error code.
+**
+** A changeset consists of zero or more INSERT, UPDATE and/or DELETE changes,
+** each representing a change to a single row of an attached table. An INSERT
+** change contains the values of each field of a new database row. A DELETE
+** contains the original values of each field of a deleted database row. An
+** UPDATE change contains the original values of each field of an updated
+** database row along with the updated values for each updated non-primary-key
+** column. It is not possible for an UPDATE change to represent a change that
+** modifies the values of primary key columns. If such a change is made, it
+** is represented in a changeset as a DELETE followed by an INSERT.
+**
+** Changes are not recorded for rows that have NULL values stored in one or
+** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
+** no corresponding change is present in the changesets returned by this
+** function. If an existing row with one or more NULL values stored in
+** PRIMARY KEY columns is updated so that all PRIMARY KEY columns are non-NULL,
+** only an INSERT is appears in the changeset. Similarly, if an existing row
+** with non-NULL PRIMARY KEY values is updated so that one or more of its
+** PRIMARY KEY columns are set to NULL, the resulting changeset contains a
+** DELETE change only.
+**
+** The contents of a changeset may be traversed using an iterator created
+** using the [sqlite3changeset_start()] API. A changeset may be applied to
+** a database with a compatible schema using the [sqlite3changeset_apply()]
+** API.
+**
+** Within a changeset generated by this function, all changes related to a
+** single table are grouped together. In other words, when iterating through
+** a changeset or when applying a changeset to a database, all changes related
+** to a single table are processed before moving on to the next table. Tables
+** are sorted in the same order in which they were attached (or auto-attached)
+** to the sqlite3_session object. The order in which the changes related to
+** a single table are stored is undefined.
+**
+** Following a successful call to this function, it is the responsibility of
+** the caller to eventually free the buffer that *ppChangeset points to using
+** [sqlite3_free()].
+**
+** <h3>Changeset Generation</h3>
+**
+** Once a table has been attached to a session object, the session object
+** records the primary key values of all new rows inserted into the table.
+** It also records the original primary key and other column values of any
+** deleted or updated rows. For each unique primary key value, data is only
+** recorded once - the first time a row with said primary key is inserted,
+** updated or deleted in the lifetime of the session.
+**
+** There is one exception to the previous paragraph: when a row is inserted,
+** updated or deleted, if one or more of its primary key columns contain a
+** NULL value, no record of the change is made.
+**
+** The session object therefore accumulates two types of records - those
+** that consist of primary key values only (created when the user inserts
+** a new record) and those that consist of the primary key values and the
+** original values of other table columns (created when the users deletes
+** or updates a record).
+**
+** When this function is called, the requested changeset is created using
+** both the accumulated records and the current contents of the database
+** file. Specifically:
+**
+** <ul>
+** <li> For each record generated by an insert, the database is queried
+** for a row with a matching primary key. If one is found, an INSERT
+** change is added to the changeset. If no such row is found, no change
+** is added to the changeset.
+**
+** <li> For each record generated by an update or delete, the database is
+** queried for a row with a matching primary key. If such a row is
+** found and one or more of the non-primary key fields have been
+** modified from their original values, an UPDATE change is added to
+** the changeset. Or, if no such row is found in the table, a DELETE
+** change is added to the changeset. If there is a row with a matching
+** primary key in the database, but all fields contain their original
+** values, no change is added to the changeset.
+** </ul>
+**
+** This means, amongst other things, that if a row is inserted and then later
+** deleted while a session object is active, neither the insert nor the delete
+** will be present in the changeset. Or if a row is deleted and then later a
+** row with the same primary key values inserted while a session object is
+** active, the resulting changeset will contain an UPDATE change instead of
+** a DELETE and an INSERT.
+**
+** When a session object is disabled (see the [sqlite3session_enable()] API),
+** it does not accumulate records when rows are inserted, updated or deleted.
+** This may appear to have some counter-intuitive effects if a single row
+** is written to more than once during a session. For example, if a row
+** is inserted while a session object is enabled, then later deleted while
+** the same session object is disabled, no INSERT record will appear in the
+** changeset, even though the delete took place while the session was disabled.
+** Or, if one field of a row is updated while a session is disabled, and
+** another field of the same row is updated while the session is enabled, the
+** resulting changeset will contain an UPDATE change that updates both fields.
+*/
+int sqlite3session_changeset(
+ sqlite3_session *pSession, /* Session object */
+ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
+ void **ppChangeset /* OUT: Buffer containing changeset */
+);
+
+/*
+** CAPI3REF: Load The Difference Between Tables Into A Session
+**
+** If it is not already attached to the session object passed as the first
+** argument, this function attaches table zTbl in the same manner as the
+** [sqlite3session_attach()] function. If zTbl does not exist, or if it
+** does not have a primary key, this function is a no-op (but does not return
+** an error).
+**
+** Argument zFromDb must be the name of a database ("main", "temp" etc.)
+** attached to the same database handle as the session object that contains
+** a table compatible with the table attached to the session by this function.
+** A table is considered compatible if it:
+**
+** <ul>
+** <li> Has the same name,
+** <li> Has the same set of columns declared in the same order, and
+** <li> Has the same PRIMARY KEY definition.
+** </ul>
+**
+** If the tables are not compatible, SQLITE_SCHEMA is returned. If the tables
+** are compatible but do not have any PRIMARY KEY columns, it is not an error
+** but no changes are added to the session object. As with other session
+** APIs, tables without PRIMARY KEYs are simply ignored.
+**
+** This function adds a set of changes to the session object that could be
+** used to update the table in database zFrom (call this the "from-table")
+** so that its content is the same as the table attached to the session
+** object (call this the "to-table"). Specifically:
+**
+** <ul>
+** <li> For each row (primary key) that exists in the to-table but not in
+** the from-table, an INSERT record is added to the session object.
+**
+** <li> For each row (primary key) that exists in the to-table but not in
+** the from-table, a DELETE record is added to the session object.
+**
+** <li> For each row (primary key) that exists in both tables, but features
+** different in each, an UPDATE record is added to the session.
+** </ul>
+**
+** To clarify, if this function is called and then a changeset constructed
+** using [sqlite3session_changeset()], then after applying that changeset to
+** database zFrom the contents of the two compatible tables would be
+** identical.
+**
+** It an error if database zFrom does not exist or does not contain the
+** required compatible table.
+**
+** If the operation successful, SQLITE_OK is returned. Otherwise, an SQLite
+** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
+** may be set to point to a buffer containing an English language error
+** message. It is the responsibility of the caller to free this buffer using
+** sqlite3_free().
+*/
+int sqlite3session_diff(
+ sqlite3_session *pSession,
+ const char *zFromDb,
+ const char *zTbl,
+ char **pzErrMsg
+);
+
+
+/*
+** CAPI3REF: Generate A Patchset From A Session Object
+**
+** The differences between a patchset and a changeset are that:
+**
+** <ul>
+** <li> DELETE records consist of the primary key fields only. The
+** original values of other fields are omitted.
+** <li> The original values of any modified fields are omitted from
+** UPDATE records.
+** </ul>
+**
+** A patchset blob may be used with up to date versions of all
+** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
+** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
+** attempting to use a patchset blob with old versions of the
+** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
+**
+** Because the non-primary key "old.*" fields are omitted, no
+** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
+** is passed to the sqlite3changeset_apply() API. Other conflict types work
+** in the same way as for changesets.
+**
+** Changes within a patchset are ordered in the same way as for changesets
+** generated by the sqlite3session_changeset() function (i.e. all changes for
+** a single table are grouped together, tables appear in the order in which
+** they were attached to the session object).
+*/
+int sqlite3session_patchset(
+ sqlite3_session *pSession, /* Session object */
+ int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
+ void **ppPatchset /* OUT: Buffer containing changeset */
+);
+
+/*
+** CAPI3REF: Test if a changeset has recorded any changes.
+**
+** Return non-zero if no changes to attached tables have been recorded by
+** the session object passed as the first argument. Otherwise, if one or
+** more changes have been recorded, return zero.
+**
+** Even if this function returns zero, it is possible that calling
+** [sqlite3session_changeset()] on the session handle may still return a
+** changeset that contains no changes. This can happen when a row in
+** an attached table is modified and then later on the original values
+** are restored. However, if this function returns non-zero, then it is
+** guaranteed that a call to sqlite3session_changeset() will return a
+** changeset containing zero changes.
+*/
+int sqlite3session_isempty(sqlite3_session *pSession);
+
+/*
+** CAPI3REF: Create An Iterator To Traverse A Changeset
+**
+** Create an iterator used to iterate through the contents of a changeset.
+** If successful, *pp is set to point to the iterator handle and SQLITE_OK
+** is returned. Otherwise, if an error occurs, *pp is set to zero and an
+** SQLite error code is returned.
+**
+** The following functions can be used to advance and query a changeset
+** iterator created by this function:
+**
+** <ul>
+** <li> [sqlite3changeset_next()]
+** <li> [sqlite3changeset_op()]
+** <li> [sqlite3changeset_new()]
+** <li> [sqlite3changeset_old()]
+** </ul>
+**
+** It is the responsibility of the caller to eventually destroy the iterator
+** by passing it to [sqlite3changeset_finalize()]. The buffer containing the
+** changeset (pChangeset) must remain valid until after the iterator is
+** destroyed.
+**
+** Assuming the changeset blob was created by one of the
+** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
+** [sqlite3changeset_invert()] functions, all changes within the changeset
+** that apply to a single table are grouped together. This means that when
+** an application iterates through a changeset using an iterator created by
+** this function, all changes that relate to a single table are visited
+** consecutively. There is no chance that the iterator will visit a change
+** the applies to table X, then one for table Y, and then later on visit
+** another change for table X.
+*/
+int sqlite3changeset_start(
+ sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */
+ int nChangeset, /* Size of changeset blob in bytes */
+ void *pChangeset /* Pointer to blob containing changeset */
+);
+
+
+/*
+** CAPI3REF: Advance A Changeset Iterator
+**
+** This function may only be used with iterators created by function
+** [sqlite3changeset_start()]. If it is called on an iterator passed to
+** a conflict-handler callback by [sqlite3changeset_apply()], SQLITE_MISUSE
+** is returned and the call has no effect.
+**
+** Immediately after an iterator is created by sqlite3changeset_start(), it
+** does not point to any change in the changeset. Assuming the changeset
+** is not empty, the first call to this function advances the iterator to
+** point to the first change in the changeset. Each subsequent call advances
+** the iterator to point to the next change in the changeset (if any). If
+** no error occurs and the iterator points to a valid change after a call
+** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
+** Otherwise, if all changes in the changeset have already been visited,
+** SQLITE_DONE is returned.
+**
+** If an error occurs, an SQLite error code is returned. Possible error
+** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
+** SQLITE_NOMEM.
+*/
+int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
+
+/*
+** CAPI3REF: Obtain The Current Operation From A Changeset Iterator
+**
+** The pIter argument passed to this function may either be an iterator
+** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
+** created by [sqlite3changeset_start()]. In the latter case, the most recent
+** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
+** is not the case, this function returns [SQLITE_MISUSE].
+**
+** If argument pzTab is not NULL, then *pzTab is set to point to a
+** nul-terminated utf-8 encoded string containing the name of the table
+** affected by the current change. The buffer remains valid until either
+** sqlite3changeset_next() is called on the iterator or until the
+** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
+** set to the number of columns in the table affected by the change. If
+** pbIncorrect is not NULL, then *pbIndirect is set to true (1) if the change
+** is an indirect change, or false (0) otherwise. See the documentation for
+** [sqlite3session_indirect()] for a description of direct and indirect
+** changes. Finally, if pOp is not NULL, then *pOp is set to one of
+** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
+** type of change that the iterator currently points to.
+**
+** If no error occurs, SQLITE_OK is returned. If an error does occur, an
+** SQLite error code is returned. The values of the output variables may not
+** be trusted in this case.
+*/
+int sqlite3changeset_op(
+ sqlite3_changeset_iter *pIter, /* Iterator object */
+ const char **pzTab, /* OUT: Pointer to table name */
+ int *pnCol, /* OUT: Number of columns in table */
+ int *pOp, /* OUT: SQLITE_INSERT, DELETE or UPDATE */
+ int *pbIndirect /* OUT: True for an 'indirect' change */
+);
+
+/*
+** CAPI3REF: Obtain The Primary Key Definition Of A Table
+**
+** For each modified table, a changeset includes the following:
+**
+** <ul>
+** <li> The number of columns in the table, and
+** <li> Which of those columns make up the tables PRIMARY KEY.
+** </ul>
+**
+** This function is used to find which columns comprise the PRIMARY KEY of
+** the table modified by the change that iterator pIter currently points to.
+** If successful, *pabPK is set to point to an array of nCol entries, where
+** nCol is the number of columns in the table. Elements of *pabPK are set to
+** 0x01 if the corresponding column is part of the tables primary key, or
+** 0x00 if it is not.
+**
+** If argument pnCol is not NULL, then *pnCol is set to the number of columns
+** in the table.
+**
+** If this function is called when the iterator does not point to a valid
+** entry, SQLITE_MISUSE is returned and the output variables zeroed. Otherwise,
+** SQLITE_OK is returned and the output variables populated as described
+** above.
+*/
+int sqlite3changeset_pk(
+ sqlite3_changeset_iter *pIter, /* Iterator object */
+ unsigned char **pabPK, /* OUT: Array of boolean - true for PK cols */
+ int *pnCol /* OUT: Number of entries in output array */
+);
+
+/*
+** CAPI3REF: Obtain old.* Values From A Changeset Iterator
+**
+** The pIter argument passed to this function may either be an iterator
+** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
+** created by [sqlite3changeset_start()]. In the latter case, the most recent
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
+** Furthermore, it may only be called if the type of change that the iterator
+** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
+** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
+**
+** Argument iVal must be greater than or equal to 0, and less than the number
+** of columns in the table affected by the current change. Otherwise,
+** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
+**
+** If successful, this function sets *ppValue to point to a protected
+** sqlite3_value object containing the iVal'th value from the vector of
+** original row values stored as part of the UPDATE or DELETE change and
+** returns SQLITE_OK. The name of the function comes from the fact that this
+** is similar to the "old.*" columns available to update or delete triggers.
+**
+** If some other error occurs (e.g. an OOM condition), an SQLite error code
+** is returned and *ppValue is set to NULL.
+*/
+int sqlite3changeset_old(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int iVal, /* Column number */
+ sqlite3_value **ppValue /* OUT: Old value (or NULL pointer) */
+);
+
+/*
+** CAPI3REF: Obtain new.* Values From A Changeset Iterator
+**
+** The pIter argument passed to this function may either be an iterator
+** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
+** created by [sqlite3changeset_start()]. In the latter case, the most recent
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
+** Furthermore, it may only be called if the type of change that the iterator
+** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
+** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
+**
+** Argument iVal must be greater than or equal to 0, and less than the number
+** of columns in the table affected by the current change. Otherwise,
+** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
+**
+** If successful, this function sets *ppValue to point to a protected
+** sqlite3_value object containing the iVal'th value from the vector of
+** new row values stored as part of the UPDATE or INSERT change and
+** returns SQLITE_OK. If the change is an UPDATE and does not include
+** a new value for the requested column, *ppValue is set to NULL and
+** SQLITE_OK returned. The name of the function comes from the fact that
+** this is similar to the "new.*" columns available to update or delete
+** triggers.
+**
+** If some other error occurs (e.g. an OOM condition), an SQLite error code
+** is returned and *ppValue is set to NULL.
+*/
+int sqlite3changeset_new(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int iVal, /* Column number */
+ sqlite3_value **ppValue /* OUT: New value (or NULL pointer) */
+);
+
+/*
+** CAPI3REF: Obtain Conflicting Row Values From A Changeset Iterator
+**
+** This function should only be used with iterator objects passed to a
+** conflict-handler callback by [sqlite3changeset_apply()] with either
+** [SQLITE_CHANGESET_DATA] or [SQLITE_CHANGESET_CONFLICT]. If this function
+** is called on any other iterator, [SQLITE_MISUSE] is returned and *ppValue
+** is set to NULL.
+**
+** Argument iVal must be greater than or equal to 0, and less than the number
+** of columns in the table affected by the current change. Otherwise,
+** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
+**
+** If successful, this function sets *ppValue to point to a protected
+** sqlite3_value object containing the iVal'th value from the
+** "conflicting row" associated with the current conflict-handler callback
+** and returns SQLITE_OK.
+**
+** If some other error occurs (e.g. an OOM condition), an SQLite error code
+** is returned and *ppValue is set to NULL.
+*/
+int sqlite3changeset_conflict(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int iVal, /* Column number */
+ sqlite3_value **ppValue /* OUT: Value from conflicting row */
+);
+
+/*
+** CAPI3REF: Determine The Number Of Foreign Key Constraint Violations
+**
+** This function may only be called with an iterator passed to an
+** SQLITE_CHANGESET_FOREIGN_KEY conflict handler callback. In this case
+** it sets the output variable to the total number of known foreign key
+** violations in the destination database and returns SQLITE_OK.
+**
+** In all other cases this function returns SQLITE_MISUSE.
+*/
+int sqlite3changeset_fk_conflicts(
+ sqlite3_changeset_iter *pIter, /* Changeset iterator */
+ int *pnOut /* OUT: Number of FK violations */
+);
+
+
+/*
+** CAPI3REF: Finalize A Changeset Iterator
+**
+** This function is used to finalize an iterator allocated with
+** [sqlite3changeset_start()].
+**
+** This function should only be called on iterators created using the
+** [sqlite3changeset_start()] function. If an application calls this
+** function with an iterator passed to a conflict-handler by
+** [sqlite3changeset_apply()], [SQLITE_MISUSE] is immediately returned and the
+** call has no effect.
+**
+** If an error was encountered within a call to an sqlite3changeset_xxx()
+** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
+** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
+** to that error is returned by this function. Otherwise, SQLITE_OK is
+** returned. This is to allow the following pattern (pseudo-code):
+**
+** sqlite3changeset_start();
+** while( SQLITE_ROW==sqlite3changeset_next() ){
+** // Do something with change.
+** }
+** rc = sqlite3changeset_finalize();
+** if( rc!=SQLITE_OK ){
+** // An error has occurred
+** }
+*/
+int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
+
+/*
+** CAPI3REF: Invert A Changeset
+**
+** This function is used to "invert" a changeset object. Applying an inverted
+** changeset to a database reverses the effects of applying the uninverted
+** changeset. Specifically:
+**
+** <ul>
+** <li> Each DELETE change is changed to an INSERT, and
+** <li> Each INSERT change is changed to a DELETE, and
+** <li> For each UPDATE change, the old.* and new.* values are exchanged.
+** </ul>
+**
+** This function does not change the order in which changes appear within
+** the changeset. It merely reverses the sense of each individual change.
+**
+** If successful, a pointer to a buffer containing the inverted changeset
+** is stored in *ppOut, the size of the same buffer is stored in *pnOut, and
+** SQLITE_OK is returned. If an error occurs, both *pnOut and *ppOut are
+** zeroed and an SQLite error code returned.
+**
+** It is the responsibility of the caller to eventually call sqlite3_free()
+** on the *ppOut pointer to free the buffer allocation following a successful
+** call to this function.
+**
+** WARNING/TODO: This function currently assumes that the input is a valid
+** changeset. If it is not, the results are undefined.
+*/
+int sqlite3changeset_invert(
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+/*
+** CAPI3REF: Concatenate Two Changeset Objects
+**
+** This function is used to concatenate two changesets, A and B, into a
+** single changeset. The result is a changeset equivalent to applying
+** changeset A followed by changeset B.
+**
+** This function combines the two input changesets using an
+** sqlite3_changegroup object. Calling it produces similar results as the
+** following code fragment:
+**
+** sqlite3_changegroup *pGrp;
+** rc = sqlite3_changegroup_new(&pGrp);
+** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nA, pA);
+** if( rc==SQLITE_OK ) rc = sqlite3changegroup_add(pGrp, nB, pB);
+** if( rc==SQLITE_OK ){
+** rc = sqlite3changegroup_output(pGrp, pnOut, ppOut);
+** }else{
+** *ppOut = 0;
+** *pnOut = 0;
+** }
+**
+** Refer to the sqlite3_changegroup documentation below for details.
+*/
+int sqlite3changeset_concat(
+ int nA, /* Number of bytes in buffer pA */
+ void *pA, /* Pointer to buffer containing changeset A */
+ int nB, /* Number of bytes in buffer pB */
+ void *pB, /* Pointer to buffer containing changeset B */
+ int *pnOut, /* OUT: Number of bytes in output changeset */
+ void **ppOut /* OUT: Buffer containing output changeset */
+);
+
+
+/*
+** CAPI3REF: Changegroup Handle
+*/
+typedef struct sqlite3_changegroup sqlite3_changegroup;
+
+/*
+** CAPI3REF: Create A New Changegroup Object
+**
+** An sqlite3_changegroup object is used to combine two or more changesets
+** (or patchsets) into a single changeset (or patchset). A single changegroup
+** object may combine changesets or patchsets, but not both. The output is
+** always in the same format as the input.
+**
+** If successful, this function returns SQLITE_OK and populates (*pp) with
+** a pointer to a new sqlite3_changegroup object before returning. The caller
+** should eventually free the returned object using a call to
+** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
+** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
+**
+** The usual usage pattern for an sqlite3_changegroup object is as follows:
+**
+** <ul>
+** <li> It is created using a call to sqlite3changegroup_new().
+**
+** <li> Zero or more changesets (or patchsets) are added to the object
+** by calling sqlite3changegroup_add().
+**
+** <li> The result of combining all input changesets together is obtained
+** by the application via a call to sqlite3changegroup_output().
+**
+** <li> The object is deleted using a call to sqlite3changegroup_delete().
+** </ul>
+**
+** Any number of calls to add() and output() may be made between the calls to
+** new() and delete(), and in any order.
+**
+** As well as the regular sqlite3changegroup_add() and
+** sqlite3changegroup_output() functions, also available are the streaming
+** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
+*/
+int sqlite3changegroup_new(sqlite3_changegroup **pp);
+
+/*
+** CAPI3REF: Add A Changeset To A Changegroup
+**
+** Add all changes within the changeset (or patchset) in buffer pData (size
+** nData bytes) to the changegroup.
+**
+** If the buffer contains a patchset, then all prior calls to this function
+** on the same changegroup object must also have specified patchsets. Or, if
+** the buffer contains a changeset, so must have the earlier calls to this
+** function. Otherwise, SQLITE_ERROR is returned and no changes are added
+** to the changegroup.
+**
+** Rows within the changeset and changegroup are identified by the values in
+** their PRIMARY KEY columns. A change in the changeset is considered to
+** apply to the same row as a change already present in the changegroup if
+** the two rows have the same primary key.
+**
+** Changes to rows that do not already appear in the changegroup are
+** simply copied into it. Or, if both the new changeset and the changegroup
+** contain changes that apply to a single row, the final contents of the
+** changegroup depends on the type of each change, as follows:
+**
+** <table border=1 style="margin-left:8ex;margin-right:8ex">
+** <tr><th style="white-space:pre">Existing Change </th>
+** <th style="white-space:pre">New Change </th>
+** <th>Output Change
+** <tr><td>INSERT <td>INSERT <td>
+** The new change is ignored. This case does not occur if the new
+** changeset was recorded immediately after the changesets already
+** added to the changegroup.
+** <tr><td>INSERT <td>UPDATE <td>
+** The INSERT change remains in the changegroup. The values in the
+** INSERT change are modified as if the row was inserted by the
+** existing change and then updated according to the new change.
+** <tr><td>INSERT <td>DELETE <td>
+** The existing INSERT is removed from the changegroup. The DELETE is
+** not added.
+** <tr><td>UPDATE <td>INSERT <td>
+** The new change is ignored. This case does not occur if the new
+** changeset was recorded immediately after the changesets already
+** added to the changegroup.
+** <tr><td>UPDATE <td>UPDATE <td>
+** The existing UPDATE remains within the changegroup. It is amended
+** so that the accompanying values are as if the row was updated once
+** by the existing change and then again by the new change.
+** <tr><td>UPDATE <td>DELETE <td>
+** The existing UPDATE is replaced by the new DELETE within the
+** changegroup.
+** <tr><td>DELETE <td>INSERT <td>
+** If one or more of the column values in the row inserted by the
+** new change differ from those in the row deleted by the existing
+** change, the existing DELETE is replaced by an UPDATE within the
+** changegroup. Otherwise, if the inserted row is exactly the same
+** as the deleted row, the existing DELETE is simply discarded.
+** <tr><td>DELETE <td>UPDATE <td>
+** The new change is ignored. This case does not occur if the new
+** changeset was recorded immediately after the changesets already
+** added to the changegroup.
+** <tr><td>DELETE <td>DELETE <td>
+** The new change is ignored. This case does not occur if the new
+** changeset was recorded immediately after the changesets already
+** added to the changegroup.
+** </table>
+**
+** If the new changeset contains changes to a table that is already present
+** in the changegroup, then the number of columns and the position of the
+** primary key columns for the table must be consistent. If this is not the
+** case, this function fails with SQLITE_SCHEMA. If the input changeset
+** appears to be corrupt and the corruption is detected, SQLITE_CORRUPT is
+** returned. Or, if an out-of-memory condition occurs during processing, this
+** function returns SQLITE_NOMEM. In all cases, if an error occurs the
+** final contents of the changegroup is undefined.
+**
+** If no error occurs, SQLITE_OK is returned.
+*/
+int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
+
+/*
+** CAPI3REF: Obtain A Composite Changeset From A Changegroup
+**
+** Obtain a buffer containing a changeset (or patchset) representing the
+** current contents of the changegroup. If the inputs to the changegroup
+** were themselves changesets, the output is a changeset. Or, if the
+** inputs were patchsets, the output is also a patchset.
+**
+** As with the output of the sqlite3session_changeset() and
+** sqlite3session_patchset() functions, all changes related to a single
+** table are grouped together in the output of this function. Tables appear
+** in the same order as for the very first changeset added to the changegroup.
+** If the second or subsequent changesets added to the changegroup contain
+** changes for tables that do not appear in the first changeset, they are
+** appended onto the end of the output changeset, again in the order in
+** which they are first encountered.
+**
+** If an error occurs, an SQLite error code is returned and the output
+** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
+** is returned and the output variables are set to the size of and a
+** pointer to the output buffer, respectively. In this case it is the
+** responsibility of the caller to eventually free the buffer using a
+** call to sqlite3_free().
+*/
+int sqlite3changegroup_output(
+ sqlite3_changegroup*,
+ int *pnData, /* OUT: Size of output buffer in bytes */
+ void **ppData /* OUT: Pointer to output buffer */
+);
+
+/*
+** CAPI3REF: Delete A Changegroup Object
+*/
+void sqlite3changegroup_delete(sqlite3_changegroup*);
+
+/*
+** CAPI3REF: Apply A Changeset To A Database
+**
+** Apply a changeset to a database. This function attempts to update the
+** "main" database attached to handle db with the changes found in the
+** changeset passed via the second and third arguments.
+**
+** The fourth argument (xFilter) passed to this function is the "filter
+** callback". If it is not NULL, then for each table affected by at least one
+** change in the changeset, the filter callback is invoked with
+** the table name as the second argument, and a copy of the context pointer
+** passed as the sixth argument to this function as the first. If the "filter
+** callback" returns zero, then no attempt is made to apply any changes to
+** the table. Otherwise, if the return value is non-zero or the xFilter
+** argument to this function is NULL, all changes related to the table are
+** attempted.
+**
+** For each table that is not excluded by the filter callback, this function
+** tests that the target database contains a compatible table. A table is
+** considered compatible if all of the following are true:
+**
+** <ul>
+** <li> The table has the same name as the name recorded in the
+** changeset, and
+** <li> The table has the same number of columns as recorded in the
+** changeset, and
+** <li> The table has primary key columns in the same position as
+** recorded in the changeset.
+** </ul>
+**
+** If there is no compatible table, it is not an error, but none of the
+** changes associated with the table are applied. A warning message is issued
+** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
+** one such warning is issued for each table in the changeset.
+**
+** For each change for which there is a compatible table, an attempt is made
+** to modify the table contents according to the UPDATE, INSERT or DELETE
+** change. If a change cannot be applied cleanly, the conflict handler
+** function passed as the fifth argument to sqlite3changeset_apply() may be
+** invoked. A description of exactly when the conflict handler is invoked for
+** each type of change is below.
+**
+** Unlike the xFilter argument, xConflict may not be passed NULL. The results
+** of passing anything other than a valid function pointer as the xConflict
+** argument are undefined.
+**
+** Each time the conflict handler function is invoked, it must return one
+** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
+** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
+** if the second argument passed to the conflict handler is either
+** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
+** returns an illegal value, any changes already made are rolled back and
+** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
+** actions are taken by sqlite3changeset_apply() depending on the value
+** returned by each invocation of the conflict-handler function. Refer to
+** the documentation for the three
+** [SQLITE_CHANGESET_OMIT|available return values] for details.
+**
+** <dl>
+** <dt>DELETE Changes<dd>
+** For each DELETE change, this function checks if the target database
+** contains a row with the same primary key value (or values) as the
+** original row values stored in the changeset. If it does, and the values
+** stored in all non-primary key columns also match the values stored in
+** the changeset the row is deleted from the target database.
+**
+** If a row with matching primary key values is found, but one or more of
+** the non-primary key fields contains a value different from the original
+** row value stored in the changeset, the conflict-handler function is
+** invoked with [SQLITE_CHANGESET_DATA] as the second argument.
+**
+** If no row with matching primary key values is found in the database,
+** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
+** passed as the second argument.
+**
+** If the DELETE operation is attempted, but SQLite returns SQLITE_CONSTRAINT
+** (which can only happen if a foreign key constraint is violated), the
+** conflict-handler function is invoked with [SQLITE_CHANGESET_CONSTRAINT]
+** passed as the second argument. This includes the case where the DELETE
+** operation is attempted because an earlier call to the conflict handler
+** function returned [SQLITE_CHANGESET_REPLACE].
+**
+** <dt>INSERT Changes<dd>
+** For each INSERT change, an attempt is made to insert the new row into
+** the database.
+**
+** If the attempt to insert the row fails because the database already
+** contains a row with the same primary key values, the conflict handler
+** function is invoked with the second argument set to
+** [SQLITE_CHANGESET_CONFLICT].
+**
+** If the attempt to insert the row fails because of some other constraint
+** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
+** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
+** This includes the case where the INSERT operation is re-attempted because
+** an earlier call to the conflict handler function returned
+** [SQLITE_CHANGESET_REPLACE].
+**
+** <dt>UPDATE Changes<dd>
+** For each UPDATE change, this function checks if the target database
+** contains a row with the same primary key value (or values) as the
+** original row values stored in the changeset. If it does, and the values
+** stored in all non-primary key columns also match the values stored in
+** the changeset the row is updated within the target database.
+**
+** If a row with matching primary key values is found, but one or more of
+** the non-primary key fields contains a value different from an original
+** row value stored in the changeset, the conflict-handler function is
+** invoked with [SQLITE_CHANGESET_DATA] as the second argument. Since
+** UPDATE changes only contain values for non-primary key fields that are
+** to be modified, only those fields need to match the original values to
+** avoid the SQLITE_CHANGESET_DATA conflict-handler callback.
+**
+** If no row with matching primary key values is found in the database,
+** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
+** passed as the second argument.
+**
+** If the UPDATE operation is attempted, but SQLite returns
+** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
+** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
+** This includes the case where the UPDATE operation is attempted after
+** an earlier call to the conflict handler function returned
+** [SQLITE_CHANGESET_REPLACE].
+** </dl>
+**
+** It is safe to execute SQL statements, including those that write to the
+** table that the callback related to, from within the xConflict callback.
+** This can be used to further customize the applications conflict
+** resolution strategy.
+**
+** All changes made by this function are enclosed in a savepoint transaction.
+** If any other error (aside from a constraint failure when attempting to
+** write to the target database) occurs, then the savepoint transaction is
+** rolled back, restoring the target database to its original state, and an
+** SQLite error code returned.
+*/
+int sqlite3changeset_apply(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int nChangeset, /* Size of changeset in bytes */
+ void *pChangeset, /* Changeset blob */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx /* First argument passed to xConflict */
+);
+
+/*
+** CAPI3REF: Constants Passed To The Conflict Handler
+**
+** Values that may be passed as the second argument to a conflict-handler.
+**
+** <dl>
+** <dt>SQLITE_CHANGESET_DATA<dd>
+** The conflict handler is invoked with CHANGESET_DATA as the second argument
+** when processing a DELETE or UPDATE change if a row with the required
+** PRIMARY KEY fields is present in the database, but one or more other
+** (non primary-key) fields modified by the update do not contain the
+** expected "before" values.
+**
+** The conflicting row, in this case, is the database row with the matching
+** primary key.
+**
+** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
+** The conflict handler is invoked with CHANGESET_NOTFOUND as the second
+** argument when processing a DELETE or UPDATE change if a row with the
+** required PRIMARY KEY fields is not present in the database.
+**
+** There is no conflicting row in this case. The results of invoking the
+** sqlite3changeset_conflict() API are undefined.
+**
+** <dt>SQLITE_CHANGESET_CONFLICT<dd>
+** CHANGESET_CONFLICT is passed as the second argument to the conflict
+** handler while processing an INSERT change if the operation would result
+** in duplicate primary key values.
+**
+** The conflicting row in this case is the database row with the matching
+** primary key.
+**
+** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
+** If foreign key handling is enabled, and applying a changeset leaves the
+** database in a state containing foreign key violations, the conflict
+** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
+** exactly once before the changeset is committed. If the conflict handler
+** returns CHANGESET_OMIT, the changes, including those that caused the
+** foreign key constraint violation, are committed. Or, if it returns
+** CHANGESET_ABORT, the changeset is rolled back.
+**
+** No current or conflicting row information is provided. The only function
+** it is possible to call on the supplied sqlite3_changeset_iter handle
+** is sqlite3changeset_fk_conflicts().
+**
+** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
+** If any other constraint violation occurs while applying a change (i.e.
+** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
+** invoked with CHANGESET_CONSTRAINT as the second argument.
+**
+** There is no conflicting row in this case. The results of invoking the
+** sqlite3changeset_conflict() API are undefined.
+**
+** </dl>
+*/
+#define SQLITE_CHANGESET_DATA 1
+#define SQLITE_CHANGESET_NOTFOUND 2
+#define SQLITE_CHANGESET_CONFLICT 3
+#define SQLITE_CHANGESET_CONSTRAINT 4
+#define SQLITE_CHANGESET_FOREIGN_KEY 5
+
+/*
+** CAPI3REF: Constants Returned By The Conflict Handler
+**
+** A conflict handler callback must return one of the following three values.
+**
+** <dl>
+** <dt>SQLITE_CHANGESET_OMIT<dd>
+** If a conflict handler returns this value no special action is taken. The
+** change that caused the conflict is not applied. The session module
+** continues to the next change in the changeset.
+**
+** <dt>SQLITE_CHANGESET_REPLACE<dd>
+** This value may only be returned if the second argument to the conflict
+** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
+** is not the case, any changes applied so far are rolled back and the
+** call to sqlite3changeset_apply() returns SQLITE_MISUSE.
+**
+** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
+** handler, then the conflicting row is either updated or deleted, depending
+** on the type of change.
+**
+** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_CONFLICT conflict
+** handler, then the conflicting row is removed from the database and a
+** second attempt to apply the change is made. If this second attempt fails,
+** the original row is restored to the database before continuing.
+**
+** <dt>SQLITE_CHANGESET_ABORT<dd>
+** If this value is returned, any changes applied so far are rolled back
+** and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
+** </dl>
+*/
+#define SQLITE_CHANGESET_OMIT 0
+#define SQLITE_CHANGESET_REPLACE 1
+#define SQLITE_CHANGESET_ABORT 2
+
+/*
+** CAPI3REF: Streaming Versions of API functions.
+**
+** The six streaming API xxx_strm() functions serve similar purposes to the
+** corresponding non-streaming API functions:
+**
+** <table border=1 style="margin-left:8ex;margin-right:8ex">
+** <tr><th>Streaming function<th>Non-streaming equivalent</th>
+** <tr><td>sqlite3changeset_apply_str<td>[sqlite3changeset_apply]
+** <tr><td>sqlite3changeset_concat_str<td>[sqlite3changeset_concat]
+** <tr><td>sqlite3changeset_invert_str<td>[sqlite3changeset_invert]
+** <tr><td>sqlite3changeset_start_str<td>[sqlite3changeset_start]
+** <tr><td>sqlite3session_changeset_str<td>[sqlite3session_changeset]
+** <tr><td>sqlite3session_patchset_str<td>[sqlite3session_patchset]
+** </table>
+**
+** Non-streaming functions that accept changesets (or patchsets) as input
+** require that the entire changeset be stored in a single buffer in memory.
+** Similarly, those that return a changeset or patchset do so by returning
+** a pointer to a single large buffer allocated using sqlite3_malloc().
+** Normally this is convenient. However, if an application running in a
+** low-memory environment is required to handle very large changesets, the
+** large contiguous memory allocations required can become onerous.
+**
+** In order to avoid this problem, instead of a single large buffer, input
+** is passed to a streaming API functions by way of a callback function that
+** the sessions module invokes to incrementally request input data as it is
+** required. In all cases, a pair of API function parameters such as
+**
+** <pre>
+** &nbsp; int nChangeset,
+** &nbsp; void *pChangeset,
+** </pre>
+**
+** Is replaced by:
+**
+** <pre>
+** &nbsp; int (*xInput)(void *pIn, void *pData, int *pnData),
+** &nbsp; void *pIn,
+** </pre>
+**
+** Each time the xInput callback is invoked by the sessions module, the first
+** argument passed is a copy of the supplied pIn context pointer. The second
+** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
+** error occurs the xInput method should copy up to (*pnData) bytes of data
+** into the buffer and set (*pnData) to the actual number of bytes copied
+** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
+** should be set to zero to indicate this. Or, if an error occurs, an SQLite
+** error code should be returned. In all cases, if an xInput callback returns
+** an error, all processing is abandoned and the streaming API function
+** returns a copy of the error code to the caller.
+**
+** In the case of sqlite3changeset_start_strm(), the xInput callback may be
+** invoked by the sessions module at any point during the lifetime of the
+** iterator. If such an xInput callback returns an error, the iterator enters
+** an error state, whereby all subsequent calls to iterator functions
+** immediately fail with the same error code as returned by xInput.
+**
+** Similarly, streaming API functions that return changesets (or patchsets)
+** return them in chunks by way of a callback function instead of via a
+** pointer to a single large buffer. In this case, a pair of parameters such
+** as:
+**
+** <pre>
+** &nbsp; int *pnChangeset,
+** &nbsp; void **ppChangeset,
+** </pre>
+**
+** Is replaced by:
+**
+** <pre>
+** &nbsp; int (*xOutput)(void *pOut, const void *pData, int nData),
+** &nbsp; void *pOut
+** </pre>
+**
+** The xOutput callback is invoked zero or more times to return data to
+** the application. The first parameter passed to each call is a copy of the
+** pOut pointer supplied by the application. The second parameter, pData,
+** points to a buffer nData bytes in size containing the chunk of output
+** data being returned. If the xOutput callback successfully processes the
+** supplied data, it should return SQLITE_OK to indicate success. Otherwise,
+** it should return some other SQLite error code. In this case processing
+** is immediately abandoned and the streaming API function returns a copy
+** of the xOutput error code to the application.
+**
+** The sessions module never invokes an xOutput callback with the third
+** parameter set to a value less than or equal to zero. Other than this,
+** no guarantees are made as to the size of the chunks of data returned.
+*/
+int sqlite3changeset_apply_strm(
+ sqlite3 *db, /* Apply change to "main" db of this handle */
+ int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
+ void *pIn, /* First arg for xInput */
+ int(*xFilter)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ const char *zTab /* Table name */
+ ),
+ int(*xConflict)(
+ void *pCtx, /* Copy of sixth arg to _apply() */
+ int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
+ sqlite3_changeset_iter *p /* Handle describing change and conflict */
+ ),
+ void *pCtx /* First argument passed to xConflict */
+);
+int sqlite3changeset_concat_strm(
+ int (*xInputA)(void *pIn, void *pData, int *pnData),
+ void *pInA,
+ int (*xInputB)(void *pIn, void *pData, int *pnData),
+ void *pInB,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+int sqlite3changeset_invert_strm(
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+int sqlite3changeset_start_strm(
+ sqlite3_changeset_iter **pp,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn
+);
+int sqlite3session_changeset_strm(
+ sqlite3_session *pSession,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+int sqlite3session_patchset_strm(
+ sqlite3_session *pSession,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+int sqlite3changegroup_add_strm(sqlite3_changegroup*,
+ int (*xInput)(void *pIn, void *pData, int *pnData),
+ void *pIn
+);
+int sqlite3changegroup_output_strm(sqlite3_changegroup*,
+ int (*xOutput)(void *pOut, const void *pData, int nData),
+ void *pOut
+);
+
+
+/*
+** Make sure we can call this stuff from C++.
+*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(__SQLITESESSION_H_) && defined(SQLITE_ENABLE_SESSION) */
+
+/******** End of sqlite3session.h *********/
+/******** Begin file fts5.h *********/
/*
** 2014 May 31
**
@@ -8252,11 +10000,13 @@ struct Fts5PhraseIter {
** ... FROM ftstable WHERE ftstable MATCH $p ORDER BY rowid
**
** with $p set to a phrase equivalent to the phrase iPhrase of the
-** current query is executed. For each row visited, the callback function
-** passed as the fourth argument is invoked. The context and API objects
-** passed to the callback function may be used to access the properties of
-** each matched row. Invoking Api.xUserData() returns a copy of the pointer
-** passed as the third argument to pUserData.
+** current query is executed. Any column filter that applies to
+** phrase iPhrase of the current query is included in $p. For each
+** row visited, the callback function passed as the fourth argument
+** is invoked. The context and API objects passed to the callback
+** function may be used to access the properties of each matched row.
+** Invoking Api.xUserData() returns a copy of the pointer passed as
+** the third argument to pUserData.
**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
@@ -8425,7 +10175,7 @@ struct Fts5ExtensionApi {
** behaviour. The structure methods are expected to function as follows:
**
** xCreate:
-** This function is used to allocate and inititalize a tokenizer instance.
+** This function is used to allocate and initialize a tokenizer instance.
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
@@ -8685,4 +10435,4 @@ struct fts5_api {
#endif /* _FTS5_H */
-
+/******** End of fts5.h *********/
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
index 710648e25a..c74e38d997 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
@@ -423,7 +423,9 @@ public class QtNative
i == 0,
(int)event.getX(i),
(int)event.getY(i),
- event.getSize(i),
+ event.getTouchMajor(i),
+ event.getTouchMinor(i),
+ event.getOrientation(i),
event.getPressure(i));
}
@@ -791,7 +793,7 @@ public class QtNative
public static native void mouseUp(int winId, int x, int y);
public static native void mouseMove(int winId, int x, int y);
public static native void touchBegin(int winId);
- public static native void touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float size, float pressure);
+ public static native void touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float major, float minor, float rotation, float pressure);
public static native void touchEnd(int winId, int action);
public static native void longPress(int winId, int x, int y);
// pointer methods
diff --git a/src/android/templates/res/values/libs.xml b/src/android/templates/res/values/libs.xml
index 77f422cfb2..4009a7785a 100644
--- a/src/android/templates/res/values/libs.xml
+++ b/src/android/templates/res/values/libs.xml
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<array name="qt_sources">
- <item>https://download.qt.io/ministro/android/qt5/qt-5.8</item>
+ <item>https://download.qt.io/ministro/android/qt5/qt-5.9</item>
</array>
<!-- The following is handled automatically by the deployment tool. It should
diff --git a/src/angle/src/libGLESv2/libGLESv2.pro b/src/angle/src/QtANGLE/QtANGLE.pro
index b699ae159a..ee3111b6ee 100644
--- a/src/angle/src/libGLESv2/libGLESv2.pro
+++ b/src/angle/src/QtANGLE/QtANGLE.pro
@@ -1,10 +1,59 @@
CONFIG += simd no_batch
include(../common/common.pri)
+TARGET=$$qtLibraryTarget($${LIBQTANGLE_NAME})
DEF_FILE_TARGET=$${TARGET}
-TARGET=$$qtLibraryTarget($${LIBGLESV2_NAME})
INCLUDEPATH += $$OUT_PWD/.. $$ANGLE_DIR/src/libANGLE
+!build_pass {
+ # Merge libGLESv2 and libEGL .def files located under $$ANGLE_DIR into QtANGLE$${SUFFIX}.def
+ DEF_FILES = \
+ libGLESv2/libGLESv2 \
+ libEGL/libEGL
+
+ SUFFIX =
+ for (DEBUG_RELEASE, $$list(0 1)) {
+ DEF_MERGED = \
+ "LIBRARY $${LIBQTANGLE_NAME}$$SUFFIX" \
+ EXPORTS
+ mingw: SUFFIX = $${SUFFIX}_mingw32
+ PASS = 0
+ MAX_ORDINAL = 0
+
+ for (DEF_FILE, DEF_FILES) {
+ DEF_FILE_PATH = $$ANGLE_DIR/src/$$DEF_FILE$${SUFFIX}.def
+ DEF_SRC = $$cat($$DEF_FILE_PATH, lines)
+ DEF_MERGED += \
+ ";" \
+ "; Generated from:" \
+ "; $$DEF_FILE_PATH"
+
+ for (line, DEF_SRC) {
+ !contains(line, "(LIBRARY.*|EXPORTS)") {
+ LINESPLIT = $$split(line, @)
+ !count(LINESPLIT, 1) {
+ equals(PASS, 1) {
+ # In the second .def file we must allocate new ordinals in order
+ # to not clash with the ordinals from the first file. We then start off
+ # from MAX_ORDINAL + 1 and increase sequentially
+ MAX_ORDINAL = $$num_add($$MAX_ORDINAL, 1)
+ line = $$section(line, @, 0, -2)@$$MAX_ORDINAL
+ } else {
+ ORDINAL = $$last(LINESPLIT)
+ greaterThan(ORDINAL, $$MAX_ORDINAL): \
+ MAX_ORDINAL = $$ORDINAL
+ }
+ }
+ DEF_MERGED += $$line
+ }
+ }
+ PASS = 1
+ }
+ write_file($${LIBQTANGLE_NAME}$${SUFFIX}.def, DEF_MERGED)|error()
+ SUFFIX = "d"
+ }
+}
+
# Remember to adapt tools/configure/configureapp.cpp if the Direct X version changes.
!winrt: \
LIBS_PRIVATE += -ld3d9
@@ -234,7 +283,8 @@ SOURCES += \
$$ANGLE_DIR/src/libGLESv2/entry_points_gles_3_0.cpp \
$$ANGLE_DIR/src/libGLESv2/entry_points_gles_3_0_ext.cpp \
$$ANGLE_DIR/src/libGLESv2/global_state.cpp \
- $$ANGLE_DIR/src/libGLESv2/libGLESv2.cpp
+ $$ANGLE_DIR/src/libGLESv2/libGLESv2.cpp \
+ $$ANGLE_DIR/src/libEGL/libEGL.cpp
SSE2_SOURCES += $$ANGLE_DIR/src/libANGLE/renderer/d3d/loadimageSSE2.cpp
@@ -361,8 +411,8 @@ angle_d3d11 {
}
!static {
- DEF_FILE = $$ANGLE_DIR/src/libGLESv2/$${DEF_FILE_TARGET}.def
- mingw:equals(QT_ARCH, i386): DEF_FILE = $$ANGLE_DIR/src/libGLESv2/$${DEF_FILE_TARGET}_mingw32.def
+ DEF_FILE = $$PWD/$${DEF_FILE_TARGET}.def
+ mingw: equals(QT_ARCH, i386): DEF_FILE = $$PWD/$${DEF_FILE_TARGET}_mingw32.def
} else {
DEFINES += DllMain=DllMain_ANGLE # prevent symbol from conflicting with the user's DllMain
}
@@ -610,5 +660,10 @@ gles3_headers.files = \
$$ANGLE_DIR/include/GLES3/gl3ext.h \
$$ANGLE_DIR/include/GLES3/gl3platform.h
gles3_headers.path = $$[QT_INSTALL_HEADERS]/QtANGLE/GLES3
-INSTALLS += khr_headers gles2_headers
+egl_headers.files = \
+ $$ANGLE_DIR/include/EGL/egl.h \
+ $$ANGLE_DIR/include/EGL/eglext.h \
+ $$ANGLE_DIR/include/EGL/eglplatform.h
+egl_headers.path = $$[QT_INSTALL_HEADERS]/QtANGLE/EGL
+INSTALLS += khr_headers gles2_headers egl_headers
angle_d3d11: INSTALLS += gles3_headers
diff --git a/src/angle/src/common/common.pri b/src/angle/src/common/common.pri
index 3da59c61e2..7305362d86 100644
--- a/src/angle/src/common/common.pri
+++ b/src/angle/src/common/common.pri
@@ -30,29 +30,11 @@ winrt|msvc {
error("Cannot determine DirectX SDK location. Please set DXSDK_DIR environment variable.")
}
- DXINC_DIR = $${DX_DIR}Include
- contains(QT_ARCH, x86_64) {
- DXLIB_DIR = $${DX_DIR}Lib\\x64
- } else {
- DXLIB_DIR = $${DX_DIR}Lib\\x86
- }
-
equals(QMAKE_TARGET.arch, x86_64) {
FXC = \"$${DX_DIR}Utilities\\bin\\x64\\fxc.exe\"
} else {
FXC = \"$${DX_DIR}Utilities\\bin\\x86\\fxc.exe\"
}
-
- msvc {
- # Unfortunately MinGW cannot use the DirectX headers from the DX SDK because d3d11shader.h uses
- # buffer annotation macros (eg: __out, __in) which are not defined in the MinGW copy of
- # specstrings_strict.h
- INCLUDEPATH += $$DXINC_DIR
-
- # Similarly we want the MinGW linker to use the import libraries shipped with the compiler
- # instead of those from the SDK which cause a crash on startup.
- LIBS_PRIVATE += -L$$DXLIB_DIR
- }
}
static: DEFINES *= LIBGLESV2_EXPORT_H_ ANGLE_EXPORT=
diff --git a/src/angle/src/libEGL/libEGL.pro b/src/angle/src/libEGL/libEGL.pro
deleted file mode 100644
index 3b2d516ecb..0000000000
--- a/src/angle/src/libEGL/libEGL.pro
+++ /dev/null
@@ -1,27 +0,0 @@
-include(../common/common.pri)
-DEF_FILE_TARGET=$${TARGET}
-TARGET=$$qtLibraryTarget($${LIBEGL_NAME})
-winrt: LIBS_PRIVATE += -ld3d11
-
-LIBS_PRIVATE += -ldxguid
-QMAKE_USE_PRIVATE += $${LIBGLESV2_NAME}
-
-DEFINES += GL_APICALL= GL_GLEXT_PROTOTYPES= EGLAPI= LIBEGL_IMPLEMENTATION
-
-HEADERS += \
- $$ANGLE_DIR/src/libEGL/resource.h
-
-SOURCES += \
- $$ANGLE_DIR/src/libEGL/libEGL.cpp
-
-!static {
- DEF_FILE = $$ANGLE_DIR/src/libEGL/$${DEF_FILE_TARGET}.def
- mingw:equals(QT_ARCH, i386): DEF_FILE = $$ANGLE_DIR/src/libEGL/$${DEF_FILE_TARGET}_mingw32.def
-}
-
-egl_headers.files = \
- $$ANGLE_DIR/include/EGL/egl.h \
- $$ANGLE_DIR/include/EGL/eglext.h \
- $$ANGLE_DIR/include/EGL/eglplatform.h
-egl_headers.path = $$[QT_INSTALL_HEADERS]/QtANGLE/EGL
-INSTALLS += egl_headers
diff --git a/src/angle/src/src.pro b/src/angle/src/src.pro
index d1f5f57591..77c3ee7198 100644
--- a/src/angle/src/src.pro
+++ b/src/angle/src/src.pro
@@ -1,3 +1,3 @@
TEMPLATE = subdirs
-SUBDIRS += compiler libGLESv2 libEGL
+SUBDIRS += compiler QtANGLE
CONFIG += ordered
diff --git a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentfilter.cpp b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentfilter.cpp
index d0deed4cc8..9b15eeaa99 100644
--- a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentfilter.cpp
+++ b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentfilter.cpp
@@ -145,19 +145,11 @@ bool QString::contains(const QRegularExpression &regexp) const;
//! [9]
-//! [10]
-std::bind(&QString::contains, QRegularExpression("^\\S+$")); // matches strings without whitespace
-//! [10]
-
-
-//! [11]
-bool contains(const QString &string)
-//! [11]
-
-
//! [12]
QStringList strings = ...;
-std::bind(static_cast<bool(QString::*)(const QRegularExpression&)>( &QString::contains ), QRegularExpression("..."));
+QFuture<QString> future = QtConcurrent::filtered(list, [](const QString &str) {
+ return str.contains(QRegularExpression("^\\S+$")); // matches strings without whitespace
+});
//! [12]
//! [13]
diff --git a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentmap.cpp b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentmap.cpp
index 91e76be0db..183b82bb9a 100644
--- a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentmap.cpp
+++ b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentmap.cpp
@@ -158,19 +158,11 @@ QImage QImage::scaledToWidth(int width, Qt::TransformationMode) const;
//! [10]
-//! [11]
-std::bind(&QImage::scaledToWidth, 100, Qt::SmoothTransformation)
-//! [11]
-
-
-//! [12]
-QImage scaledToWith(const QImage &image)
-//! [12]
-
-
//! [13]
QList<QImage> images = ...;
-QFuture<QImage> thumbnails = QtConcurrent::mapped(images, std::bind(&QImage::scaledToWidth, 100, Qt::SmoothTransformation));
+QFuture<QImage> thumbnails = QtConcurrent::mapped(images, [](const QImage &img) {
+ return img.scaledToWidth(100, Qt::SmoothTransformation);
+});
//! [13]
//! [14]
diff --git a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp
index 78e4591b0a..5437822842 100644
--- a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp
+++ b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrentrun.cpp
@@ -109,7 +109,8 @@ future.waitForFinished();
//! [6]
-void someFunction(int arg1, double arg2);
-QFuture<void> future = QtConcurrent::run(std::bind(someFunction, 1, 2.0));
+QFuture<void> future = QtConcurrent::run([=]() {
+ // Code in this block will run in another thread
+});
...
//! [6]
diff --git a/src/concurrent/qtconcurrentfilter.cpp b/src/concurrent/qtconcurrentfilter.cpp
index a660815daf..3e3ed7cf68 100644
--- a/src/concurrent/qtconcurrentfilter.cpp
+++ b/src/concurrent/qtconcurrentfilter.cpp
@@ -148,13 +148,11 @@
\snippet code/src_concurrent_qtconcurrentfilter.cpp 13
- \section2 Using Bound Function Arguments
+ \section2 Wrapping Functions that Take Multiple Arguments
If you want to use a filter function takes more than one argument, you can
- use std::bind() to transform it onto a function that takes one argument. If
- C++11 support is not available, \l{http://www.boost.org/libs/bind/bind.html}
- {boost::bind()} or \l{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf}
- {std::tr1::bind()} are suitable replacements.
+ use a lambda function or \c std::bind() to transform it onto a function that
+ takes one argument.
As an example, we use QString::contains():
@@ -166,16 +164,6 @@
use QString::contains() with QtConcurrent::filtered() we have to provide a
value for the \e regexp argument:
- \snippet code/src_concurrent_qtconcurrentfilter.cpp 10
-
- The return value from std::bind() is a function object (functor) with
- the following signature:
-
- \snippet code/src_concurrent_qtconcurrentfilter.cpp 11
-
- This matches what QtConcurrent::filtered() expects, and the complete
- example becomes:
-
\snippet code/src_concurrent_qtconcurrentfilter.cpp 12
*/
diff --git a/src/concurrent/qtconcurrentmap.cpp b/src/concurrent/qtconcurrentmap.cpp
index e6c347b511..884bf4b4f9 100644
--- a/src/concurrent/qtconcurrentmap.cpp
+++ b/src/concurrent/qtconcurrentmap.cpp
@@ -198,13 +198,11 @@
\snippet code/src_concurrent_qtconcurrentmap.cpp 14
- \section2 Using Bound Function Arguments
+ \section2 Wrapping Functions that Take Multiple Arguments
If you want to use a map function that takes more than one argument you can
- use std::bind() to transform it onto a function that takes one argument. If
- C++11 support is not available, \l{http://www.boost.org/libs/bind/bind.html}
- {boost::bind()} or \l{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf}
- {std::tr1::bind()} are suitable replacements.
+ use a lambda function or \c std::bind() to transform it onto a function that
+ takes one argument.
As an example, we'll use QImage::scaledToWidth():
@@ -216,16 +214,6 @@
QImage::scaledToWidth() with QtConcurrent::mapped() we have to provide a
value for the \e{width} and the \e{transformation mode}:
- \snippet code/src_concurrent_qtconcurrentmap.cpp 11
-
- The return value from std::bind() is a function object (functor) with
- the following signature:
-
- \snippet code/src_concurrent_qtconcurrentmap.cpp 12
-
- This matches what QtConcurrent::mapped() expects, and the complete example
- becomes:
-
\snippet code/src_concurrent_qtconcurrentmap.cpp 13
*/
diff --git a/src/concurrent/qtconcurrentrun.cpp b/src/concurrent/qtconcurrentrun.cpp
index d1208e0ffb..1d8f7afe85 100644
--- a/src/concurrent/qtconcurrentrun.cpp
+++ b/src/concurrent/qtconcurrentrun.cpp
@@ -107,25 +107,9 @@
\snippet code/src_concurrent_qtconcurrentrun.cpp 5
- \section2 Using Bound Function Arguments
+ \section2 Using Lambda Functions
- You can use std::bind() to \e bind a number of arguments to a function when
- called. If C++11 support is not available, \l{http://www.boost.org/libs/bind/bind.html}
- {boost::bind()} or \l{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf}
- {std::tr1::bind()} are suitable replacements.
-
- There are number of reasons for binding:
-
- \list
- \li To call a function that takes more than 5 arguments.
- \li To simplify calling a function with constant arguments.
- \li Changing the order of arguments.
- \endlist
-
- See the documentation for the relevant functions for details on how to use
- the bind API.
-
- Calling a bound function is done like this:
+ Calling a lambda function is done like this:
\snippet code/src_concurrent_qtconcurrentrun.cpp 6
*/
diff --git a/src/concurrent/qtconcurrentrun.h b/src/concurrent/qtconcurrentrun.h
index 4b45a02b50..8e7c495a0f 100644
--- a/src/concurrent/qtconcurrentrun.h
+++ b/src/concurrent/qtconcurrentrun.h
@@ -101,7 +101,7 @@ QFuture<T> run(T (*functionPointer)(Param1, Param2, Param3, Param4, Param5), con
#if defined(Q_COMPILER_DECLTYPE) && defined(Q_COMPILER_AUTO_FUNCTION)
template <typename Functor>
-auto run(Functor functor) -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor())> >::Type
+auto run(Functor functor) -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor())>>::type
{
typedef decltype(functor()) result_type;
return (new StoredFunctorCall0<result_type, Functor>(functor))->start();
@@ -109,7 +109,7 @@ auto run(Functor functor) -> typename QtPrivate::QEnableIf<!QtPrivate::HasResult
template <typename Functor, typename Arg1>
auto run(Functor functor, const Arg1 &arg1)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1))>>::type
{
typedef decltype(functor(arg1)) result_type;
return (new StoredFunctorCall1<result_type, Functor, Arg1>(functor, arg1))->start();
@@ -117,7 +117,7 @@ auto run(Functor functor, const Arg1 &arg1)
template <typename Functor, typename Arg1, typename Arg2>
auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2))>>::type
{
typedef decltype(functor(arg1, arg2)) result_type;
return (new StoredFunctorCall2<result_type, Functor, Arg1, Arg2>(functor, arg1, arg2))->start();
@@ -125,7 +125,7 @@ auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2)
template <typename Functor, typename Arg1, typename Arg2, typename Arg3>
auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3))>>::type
{
typedef decltype(functor(arg1, arg2, arg3)) result_type;
return (new StoredFunctorCall3<result_type, Functor, Arg1, Arg2, Arg3>(functor, arg1, arg2, arg3))->start();
@@ -133,7 +133,7 @@ auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
template <typename Functor, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3, arg4))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3, arg4))>>::type
{
typedef decltype(functor(arg1, arg2, arg3, arg4)) result_type;
return (new StoredFunctorCall4<result_type, Functor, Arg1, Arg2, Arg3, Arg4>(functor, arg1, arg2, arg3, arg4))->start();
@@ -141,7 +141,7 @@ auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3,
template <typename Functor, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3, arg4, arg5))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3, arg4, arg5))>>::type
{
typedef decltype(functor(arg1, arg2, arg3, arg4, arg5)) result_type;
return (new StoredFunctorCall5<result_type, Functor, Arg1, Arg2, Arg3, Arg4, Arg5>(functor, arg1, arg2, arg3, arg4, arg5))->start();
@@ -372,7 +372,7 @@ QFuture<T> run(QThreadPool *pool, T (*functionPointer)(Param1, Param2, Param3, P
#if defined(Q_COMPILER_DECLTYPE) && defined(Q_COMPILER_AUTO_FUNCTION)
template <typename Functor>
-auto run(QThreadPool *pool, Functor functor) -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor())> >::Type
+auto run(QThreadPool *pool, Functor functor) -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor())>>::type
{
typedef decltype(functor()) result_type;
return (new StoredFunctorCall0<result_type, Functor>(functor))->start(pool);
@@ -380,7 +380,7 @@ auto run(QThreadPool *pool, Functor functor) -> typename QtPrivate::QEnableIf<!Q
template <typename Functor, typename Arg1>
auto run(QThreadPool *pool, Functor functor, const Arg1 &arg1)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1))>>::type
{
typedef decltype(functor(arg1)) result_type;
return (new StoredFunctorCall1<result_type, Functor, Arg1>(functor, arg1))->start(pool);
@@ -388,7 +388,7 @@ auto run(QThreadPool *pool, Functor functor, const Arg1 &arg1)
template <typename Functor, typename Arg1, typename Arg2>
auto run(QThreadPool *pool, Functor functor, const Arg1 &arg1, const Arg2 &arg2)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2))>>::type
{
typedef decltype(functor(arg1, arg2)) result_type;
return (new StoredFunctorCall2<result_type, Functor, Arg1, Arg2>(functor, arg1, arg2))->start(pool);
@@ -396,7 +396,7 @@ auto run(QThreadPool *pool, Functor functor, const Arg1 &arg1, const Arg2 &arg2)
template <typename Functor, typename Arg1, typename Arg2, typename Arg3>
auto run(QThreadPool *pool, Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3))>>::type
{
typedef decltype(functor(arg1, arg2, arg3)) result_type;
return (new StoredFunctorCall3<result_type, Functor, Arg1, Arg2, Arg3>(functor, arg1, arg2, arg3))->start(pool);
@@ -404,7 +404,7 @@ auto run(QThreadPool *pool, Functor functor, const Arg1 &arg1, const Arg2 &arg2,
template <typename Functor, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
auto run(QThreadPool *pool, Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3, arg4))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3, arg4))>>::type
{
typedef decltype(functor(arg1, arg2, arg3, arg4)) result_type;
return (new StoredFunctorCall4<result_type, Functor, Arg1, Arg2, Arg3, Arg4>(functor, arg1, arg2, arg3, arg4))->start(pool);
@@ -412,7 +412,7 @@ auto run(QThreadPool *pool, Functor functor, const Arg1 &arg1, const Arg2 &arg2,
template <typename Functor, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
auto run(QThreadPool *pool, Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5)
- -> typename QtPrivate::QEnableIf<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3, arg4, arg5))> >::Type
+ -> typename std::enable_if<!QtPrivate::HasResultType<Functor>::Value, QFuture<decltype(functor(arg1, arg2, arg3, arg4, arg5))>>::type
{
typedef decltype(functor(arg1, arg2, arg3, arg4, arg5)) result_type;
return (new StoredFunctorCall5<result_type, Functor, Arg1, Arg2, Arg3, Arg4, Arg5>(functor, arg1, arg2, arg3, arg4, arg5))->start(pool);
diff --git a/src/corelib/configure.json b/src/corelib/configure.json
index 6da3b61a2d..c6c5c93ddb 100644
--- a/src/corelib/configure.json
+++ b/src/corelib/configure.json
@@ -84,11 +84,11 @@
"-ldl"
]
},
- "pcre": {
- "label": "PCRE",
- "test": "unix/pcre",
+ "pcre2": {
+ "label": "PCRE2",
+ "test": "unix/pcre2",
"sources": [
- "-lpcre16"
+ "-lpcre2-16"
]
},
"pps": {
@@ -301,14 +301,14 @@
"condition": "features.textcodec",
"output": [ "publicFeature", "feature" ]
},
- "system-pcre": {
- "label": "Using system PCRE",
+ "system-pcre2": {
+ "label": "Using system PCRE2",
"disable": "input.pcre == 'qt'",
"enable": "input.pcre == 'system'",
- "condition": "libs.pcre",
+ "condition": "libs.pcre2",
"output": [
"privateFeature",
- { "type": "privateConfig", "negative": true, "name": "pcre" }
+ { "type": "privateConfig", "negative": true, "name": "pcre2" }
]
},
"poll_ppoll": {
@@ -436,9 +436,16 @@
"label": "QProcess",
"purpose": "Supports external process invocation.",
"section": "File I/O",
- "condition": "!config.winrt && !config.uikit && !config.integrity && !config.vxworks",
+ "condition": "features.processenvironment && !config.winrt && !config.uikit && !config.integrity && !config.vxworks",
"output": [ "publicFeature", "feature" ]
},
+ "processenvironment": {
+ "label": "QProcessEnvironment",
+ "purpose": "Provides a higher-level abstraction of environment variables.",
+ "section": "File I/O",
+ "condition": "!config.winrt && !config.integrity",
+ "output": [ "publicFeature" ]
+ },
"temporaryfile": {
"label": "QTemporaryFile",
"purpose": "Provides an I/O device that operates on temporary files.",
@@ -624,7 +631,7 @@ Please apply the patch corresponding to your Standard Library vendor, found in
"args": "qqnx_pps",
"condition": "config.qnx"
},
- "system-pcre"
+ "system-pcre2"
]
}
]
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h
index 9734f99d50..bb44782ac5 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.h
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2016 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm
index 8abd576259..7c40330de0 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractnativeeventfilter.mm
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2016 Samuel Gaist <samuel.gaist@edeltech.ch>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
index 9fd52517c2..c12ed147db 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
@@ -48,14 +48,6 @@
**
****************************************************************************/
-//! [0]
-QLineEdit *lineEdit = static_cast<QLineEdit *>(
- qt_find_obj_child(myWidget, "QLineEdit", "my line edit"));
-if (lineEdit)
- lineEdit->setText("Default");
-//! [0]
-
-
//! [1]
QObject *obj = new QPushButton;
obj->metaObject()->className(); // returns "QPushButton"
@@ -164,6 +156,17 @@ MyObject::MyObject(QObject *parent)
startTimer(50); // 50-millisecond timer
startTimer(1000); // 1-second timer
startTimer(60000); // 1-minute timer
+
+ using namespace std::chrono;
+ startTimer(milliseconds(50));
+ startTimer(seconds(1));
+ startTimer(minutes(1));
+
+ // since C++14 we can use std::chrono::duration literals, e.g.:
+ startTimer(100ms);
+ startTimer(5s);
+ startTimer(2min);
+ startTimer(1h);
}
void MyObject::timerEvent(QTimerEvent *event)
diff --git a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
index 6366350cde..ed61511c62 100644
--- a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
+++ b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
@@ -364,9 +364,6 @@
connect(sender, &QObject::destroyed, [=](){ this->m_objects.remove(sender); });
\endcode
- Note that if your compiler does not support C++11 variadic templates,
- this syntax only works if the signal and slot have 6 arguments or less.
-
The other way to connect a signal to a slot is to use QObject::connect()
and the \c{SIGNAL} and \c{SLOT} macros.
The rule about whether to
diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri
index 36655ca1dd..f162dd95dd 100644
--- a/src/corelib/global/global.pri
+++ b/src/corelib/global/global.pri
@@ -2,6 +2,8 @@
HEADERS += \
global/qglobal.h \
+ global/qoperatingsystemversion.h \
+ global/qoperatingsystemversion_p.h \
global/qsystemdetection.h \
global/qcompilerdetection.h \
global/qprocessordetection.h \
@@ -9,6 +11,8 @@ HEADERS += \
global/qendian.h \
global/qnumeric_p.h \
global/qnumeric.h \
+ global/qfloat16_p.h \
+ global/qfloat16.h \
global/qglobalstatic.h \
global/qlibraryinfo.h \
global/qlogging.h \
@@ -27,11 +31,16 @@ SOURCES += \
global/qlibraryinfo.cpp \
global/qmalloc.cpp \
global/qnumeric.cpp \
+ global/qfloat16.cpp \
+ global/qoperatingsystemversion.cpp \
global/qlogging.cpp \
global/qhooks.cpp
VERSIONTAGGING_SOURCES = global/qversiontagging.cpp
+darwin: SOURCES += global/qoperatingsystemversion_darwin.mm
+win32: SOURCES += global/qoperatingsystemversion_win.cpp
+
# qlibraryinfo.cpp includes qconfig.cpp
INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global
@@ -70,3 +79,17 @@ gcc:ltcg {
} else {
SOURCES += $$VERSIONTAGGING_SOURCES
}
+
+# On AARCH64 the fp16 extension is mandatory, so we don't need the conversion tables.
+!contains(QT_ARCH, "arm64") {
+ QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h
+
+ qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables)
+
+ qfloat16_tables.commands = $$QMAKE_QFLOAT16_TABLES ${QMAKE_FILE_OUT}
+ qfloat16_tables.output = global/qfloat16tables.cpp
+ qfloat16_tables.depends = $$QMAKE_QFLOAT16_TABLES
+ qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE
+ qfloat16_tables.variable_out = SOURCES
+ QMAKE_EXTRA_COMPILERS += qfloat16_tables
+}
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index eacb7a04d7..fcfe020509 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -354,6 +354,7 @@
# elif defined(__ghs)
# define Q_CC_GHS
# define Q_DECL_DEPRECATED __attribute__ ((__deprecated__))
+# define Q_PACKED __attribute__ ((__packed__))
# define Q_FUNC_INFO __PRETTY_FUNCTION__
# define Q_TYPEOF(expr) __typeof__(expr)
# define Q_ALIGNOF(type) __alignof__(type)
diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h
index b871c90c9d..feeb488acd 100644
--- a/src/corelib/global/qflags.h
+++ b/src/corelib/global/qflags.h
@@ -42,15 +42,14 @@
#ifndef QFLAGS_H
#define QFLAGS_H
-#include <QtCore/qtypeinfo.h>
-#include <QtCore/qtypetraits.h>
-
#ifdef Q_COMPILER_INITIALIZER_LISTS
#include <initializer_list>
#endif
QT_BEGIN_NAMESPACE
+class QDataStream;
+
class QFlag
{
int i;
@@ -94,8 +93,12 @@ class QFlags
Q_STATIC_ASSERT_X((sizeof(Enum) <= sizeof(int)),
"QFlags uses an int as storage, so an enum with underlying "
"long long will overflow.");
+ Q_STATIC_ASSERT_X((std::is_enum<Enum>::value), "QFlags is only usable on enumeration types.");
+
struct Private;
typedef int (Private::*Zero);
+ template <typename E> friend QDataStream &operator>>(QDataStream &, QFlags<E> &);
+ template <typename E> friend QDataStream &operator<<(QDataStream &, QFlags<E>);
public:
#if defined(Q_CC_MSVC) || defined(Q_QDOC)
// see above for MSVC
@@ -103,7 +106,7 @@ public:
typedef int Int;
#else
typedef typename std::conditional<
- QtPrivate::QIsUnsignedEnum<Enum>::value,
+ std::is_unsigned<typename std::underlying_type<Enum>::type>::value,
unsigned int,
signed int
>::type Int;
diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp
new file mode 100644
index 0000000000..1de1ae65fb
--- /dev/null
+++ b/src/corelib/global/qfloat16.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 by Southwest Research Institute (R)
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfloat16_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*! \headerfile <QFloat16>
+
+ This header file provides support for half-precision (16-bit) floating
+ point data with the class \c qfloat16. It is fully compliant with IEEE
+ 754 as a storage type. This implies that any arithmetic operation on a
+ \c qfloat16 instance results in the value first being converted to a
+ \c float. This conversion to and from \c float is performed by hardware
+ when possible, but on processors that do not natively support half-precision,
+ the conversion is performed through a sequence of lookup table operations.
+
+ \c qfloat16 should be treated as if it were a POD (plain old data) type.
+ Consequently, none of the supported operations need any elaboration beyond
+ stating that it supports all arithmetic operators incident to floating point
+ types.
+
+ \since 5.9
+*/
+
+Q_STATIC_ASSERT_X(sizeof(float) == sizeof(quint32),
+ "qfloat16 assumes that floats are 32 bits wide");
+
+// There are a few corner cases regarding denormals where GHS compiler is relying
+// hardware behavior that is not IEC 559 compliant. Therefore the compiler
+// reports std::numeric_limits<float>::is_iec559 as false. This is all right
+// according to our needs.
+
+#if !defined(Q_CC_GHS)
+Q_STATIC_ASSERT_X(std::numeric_limits<float>::is_iec559,
+ "Only works with IEEE 754 floating point");
+#endif
+
+Q_STATIC_ASSERT_X(std::numeric_limits<float>::has_infinity &&
+ std::numeric_limits<float>::has_quiet_NaN &&
+ std::numeric_limits<float>::has_signaling_NaN,
+ "Only works with IEEE 754 floating point");
+
+/*!
+ Returns true if the \c qfloat16 \a {f} is equivalent to infinity.
+ \relates <QFloat16>
+
+ \sa qIsInf
+*/
+Q_REQUIRED_RESULT bool qIsInf(qfloat16 f) Q_DECL_NOTHROW { return qt_is_inf(f); }
+
+/*!
+ Returns true if the \c qfloat16 \a {f} is not a number (NaN).
+ \relates <QFloat16>
+
+ \sa qIsNaN
+*/
+Q_REQUIRED_RESULT bool qIsNaN(qfloat16 f) Q_DECL_NOTHROW { return qt_is_nan(f); }
+
+/*!
+ Returns true if the \c qfloat16 \a {f} is a finite number.
+ \relates <QFloat16>
+
+ \sa qIsFinite
+*/
+Q_REQUIRED_RESULT bool qIsFinite(qfloat16 f) Q_DECL_NOTHROW { return qt_is_finite(f); }
+
+/*! \fn int qRound(qfloat16 value)
+ \relates <QFloat16>
+
+ Rounds \a value to the nearest integer.
+
+ \sa qRound
+*/
+
+/*! \fn qint64 qRound64(qfloat16 value)
+ \relates <QFloat16>
+
+ Rounds \a value to the nearest 64-bit integer.
+
+ \sa qRound64
+*/
+
+/*! \fn bool qFuzzyCompare(qfloat16 p1, qfloat16 p2)
+ \relates <QFloat16>
+
+ Compares the floating point value \a p1 and \a p2 and
+ returns \c true if they are considered equal, otherwise \c false.
+
+ The two numbers are compared in a relative way, where the
+ exactness is stronger the smaller the numbers are.
+ */
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h
new file mode 100644
index 0000000000..05b88e0e92
--- /dev/null
+++ b/src/corelib/global/qfloat16.h
@@ -0,0 +1,258 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 by Southwest Research Institute (R)
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFLOAT16_H
+#define QFLOAT16_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+#include <string.h>
+
+#if defined __F16C__
+#include <immintrin.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if 0
+#pragma qt_class(QFloat16)
+#pragma qt_no_master_include
+#endif
+
+class qfloat16
+{
+public:
+#ifndef Q_QDOC
+ Q_DECL_CONSTEXPR inline qfloat16() Q_DECL_NOTHROW : b16(0) { }
+ inline qfloat16(float f) Q_DECL_NOTHROW;
+ inline operator float() const Q_DECL_NOTHROW;
+ inline operator double() const Q_DECL_NOTHROW;
+ inline operator long double() const Q_DECL_NOTHROW;
+#endif
+
+private:
+ quint16 b16;
+
+ Q_CORE_EXPORT static const quint32 mantissatable[];
+ Q_CORE_EXPORT static const quint32 exponenttable[];
+ Q_CORE_EXPORT static const quint32 offsettable[];
+ Q_CORE_EXPORT static const quint32 basetable[];
+ Q_CORE_EXPORT static const quint32 shifttable[];
+
+ friend bool qIsNull(qfloat16 f) Q_DECL_NOTHROW;
+ friend qfloat16 operator-(qfloat16 a) Q_DECL_NOTHROW;
+};
+
+Q_DECLARE_TYPEINFO(qfloat16, Q_PRIMITIVE_TYPE);
+
+Q_CORE_EXPORT Q_REQUIRED_RESULT bool qIsInf(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
+Q_CORE_EXPORT Q_REQUIRED_RESULT bool qIsNaN(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
+Q_CORE_EXPORT Q_REQUIRED_RESULT bool qIsFinite(qfloat16 f) Q_DECL_NOTHROW; // complements qnumeric.h
+
+// The remainder of these utility functions complement qglobal.h
+inline Q_REQUIRED_RESULT int qRound(qfloat16 d) Q_DECL_NOTHROW
+{ return qRound(static_cast<float>(d)); }
+
+inline Q_REQUIRED_RESULT qint64 qRound64(qfloat16 d) Q_DECL_NOTHROW
+{ return qRound64(static_cast<float>(d)); }
+
+inline Q_REQUIRED_RESULT bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) Q_DECL_NOTHROW
+{
+ float f1 = static_cast<float>(p1);
+ float f2 = static_cast<float>(p2);
+ // The significand precision for IEEE754 half precision is
+ // 11 bits (10 explicitly stored), or approximately 3 decimal
+ // digits. In selecting the fuzzy comparison factor of 102.5f
+ // (that is, (2^10+1)/10) below, we effectively select a
+ // window of about 1 (least significant) decimal digit about
+ // which the two operands can vary and still return true.
+ return (qAbs(f1 - f2) * 102.5f <= qMin(qAbs(f1), qAbs(f2)));
+}
+
+inline Q_REQUIRED_RESULT bool qIsNull(qfloat16 f) Q_DECL_NOTHROW
+{
+ return (f.b16 & static_cast<quint16>(0x7fff)) == 0;
+}
+
+inline int qIntCast(qfloat16 f) Q_DECL_NOTHROW
+{ return int(static_cast<float>(f)); }
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wc99-extensions")
+inline qfloat16::qfloat16(float f) Q_DECL_NOTHROW
+{
+#if defined(QT_COMPILER_SUPPORTS_F16C) && (defined(__F16C__) || defined(__AVX2__))
+ __m128 packsingle = _mm_set_ss(f);
+ __m128i packhalf = _mm_cvtps_ph(packsingle, 0);
+ b16 = _mm_extract_epi16(packhalf, 0);
+#elif defined (__ARM_FP16_FORMAT_IEEE)
+ __fp16 f16 = f;
+ memcpy(&b16, &f16, sizeof(quint16));
+#else
+ quint32 u;
+ memcpy(&u, &f, sizeof(quint32));
+ b16 = basetable[(u >> 23) & 0x1ff]
+ + ((u & 0x007fffff) >> shifttable[(u >> 23) & 0x1ff]);
+#endif
+}
+QT_WARNING_POP
+
+inline qfloat16::operator float() const Q_DECL_NOTHROW
+{
+#if defined(QT_COMPILER_SUPPORTS_F16C) && (defined(__F16C__) || defined(__AVX2__))
+ __m128i packhalf = _mm_cvtsi32_si128(b16);
+ __m128 packsingle = _mm_cvtph_ps(packhalf);
+ return _mm_cvtss_f32(packsingle);
+#elif defined (__ARM_FP16_FORMAT_IEEE)
+ __fp16 f16;
+ memcpy(&f16, &b16, sizeof(quint16));
+ return f16;
+#else
+ quint32 u = mantissatable[offsettable[b16 >> 10] + (b16 & 0x3ff)]
+ + exponenttable[b16 >> 10];
+ float f;
+ memcpy(&f, &u, sizeof(quint32));
+ return f;
+#endif
+}
+
+inline qfloat16::operator double() const Q_DECL_NOTHROW
+{
+ return static_cast<double>(float(*this));
+}
+
+inline qfloat16::operator long double() const Q_DECL_NOTHROW
+{
+ return static_cast<long double>(float(*this));
+}
+
+inline qfloat16 operator-(qfloat16 a) Q_DECL_NOTHROW
+{
+ qfloat16 f;
+ f.b16 = a.b16 ^ quint16(0x8000);
+ return f;
+}
+
+inline qfloat16 operator+(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) + static_cast<float>(b)); }
+inline qfloat16 operator-(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) - static_cast<float>(b)); }
+inline qfloat16 operator*(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) * static_cast<float>(b)); }
+inline qfloat16 operator/(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return qfloat16(static_cast<float>(a) / static_cast<float>(b)); }
+
+#define QF16_MAKE_ARITH_OP_FP(FP, OP) \
+ inline FP operator OP(qfloat16 lhs, FP rhs) Q_DECL_NOTHROW { return static_cast<FP>(lhs) OP rhs; } \
+ inline FP operator OP(FP lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<FP>(rhs); }
+#define QF16_MAKE_ARITH_OP_EQ_FP(FP, OP_EQ, OP) \
+ inline qfloat16& operator OP_EQ(qfloat16& lhs, FP rhs) Q_DECL_NOTHROW { lhs = qfloat16(static_cast<FP>(lhs) OP rhs); return lhs; }
+#define QF16_MAKE_ARITH_OP(FP) \
+ QF16_MAKE_ARITH_OP_FP(FP, +) \
+ QF16_MAKE_ARITH_OP_FP(FP, -) \
+ QF16_MAKE_ARITH_OP_FP(FP, *) \
+ QF16_MAKE_ARITH_OP_FP(FP, /) \
+ QF16_MAKE_ARITH_OP_EQ_FP(FP, +=, +) \
+ QF16_MAKE_ARITH_OP_EQ_FP(FP, -=, -) \
+ QF16_MAKE_ARITH_OP_EQ_FP(FP, *=, *) \
+ QF16_MAKE_ARITH_OP_EQ_FP(FP, /=, /)
+QF16_MAKE_ARITH_OP(long double)
+QF16_MAKE_ARITH_OP(double)
+QF16_MAKE_ARITH_OP(float)
+#undef QF16_MAKE_ARITH_OP
+#undef QF16_MAKE_ARITH_OP_FP
+
+#define QF16_MAKE_ARITH_OP_INT(OP) \
+ inline double operator OP(qfloat16 lhs, int rhs) Q_DECL_NOTHROW { return static_cast<double>(lhs) OP rhs; } \
+ inline double operator OP(int lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<double>(rhs); }
+QF16_MAKE_ARITH_OP_INT(+)
+QF16_MAKE_ARITH_OP_INT(-)
+QF16_MAKE_ARITH_OP_INT(*)
+QF16_MAKE_ARITH_OP_INT(/)
+#undef QF16_MAKE_ARITH_OP_INT
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
+QT_WARNING_DISABLE_GCC("-Wfloat-equal")
+
+inline bool operator>(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) > static_cast<float>(b); }
+inline bool operator<(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) < static_cast<float>(b); }
+inline bool operator>=(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) >= static_cast<float>(b); }
+inline bool operator<=(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) <= static_cast<float>(b); }
+inline bool operator==(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) == static_cast<float>(b); }
+inline bool operator!=(qfloat16 a, qfloat16 b) Q_DECL_NOTHROW { return static_cast<float>(a) != static_cast<float>(b); }
+
+#define QF16_MAKE_BOOL_OP_FP(FP, OP) \
+ inline bool operator OP(qfloat16 lhs, FP rhs) Q_DECL_NOTHROW { return static_cast<FP>(lhs) OP rhs; } \
+ inline bool operator OP(FP lhs, qfloat16 rhs) Q_DECL_NOTHROW { return lhs OP static_cast<FP>(rhs); }
+#define QF16_MAKE_BOOL_OP(FP) \
+ QF16_MAKE_BOOL_OP_FP(FP, <) \
+ QF16_MAKE_BOOL_OP_FP(FP, >) \
+ QF16_MAKE_BOOL_OP_FP(FP, >=) \
+ QF16_MAKE_BOOL_OP_FP(FP, <=) \
+ QF16_MAKE_BOOL_OP_FP(FP, ==) \
+ QF16_MAKE_BOOL_OP_FP(FP, !=)
+QF16_MAKE_BOOL_OP(long double)
+QF16_MAKE_BOOL_OP(double)
+QF16_MAKE_BOOL_OP(float)
+#undef QF16_MAKE_BOOL_OP
+#undef QF16_MAKE_BOOL_OP_FP
+
+#define QF16_MAKE_BOOL_OP_INT(OP) \
+ inline bool operator OP(qfloat16 a, int b) Q_DECL_NOTHROW { return static_cast<float>(a) OP b; } \
+ inline bool operator OP(int a, qfloat16 b) Q_DECL_NOTHROW { return a OP static_cast<float>(b); }
+QF16_MAKE_BOOL_OP_INT(>)
+QF16_MAKE_BOOL_OP_INT(<)
+QF16_MAKE_BOOL_OP_INT(>=)
+QF16_MAKE_BOOL_OP_INT(<=)
+QF16_MAKE_BOOL_OP_INT(==)
+QF16_MAKE_BOOL_OP_INT(!=)
+#undef QF16_MAKE_BOOL_OP_INT
+
+QT_WARNING_POP
+
+/*!
+ \internal
+*/
+inline Q_REQUIRED_RESULT bool qFuzzyIsNull(qfloat16 f) Q_DECL_NOTHROW
+{
+ return qAbs(static_cast<float>(f)) <= 0.001f;
+}
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(qfloat16)
+
+#endif // QFLOAT16_H
diff --git a/src/corelib/global/qfloat16_p.h b/src/corelib/global/qfloat16_p.h
new file mode 100644
index 0000000000..ae52e64435
--- /dev/null
+++ b/src/corelib/global/qfloat16_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 by Southwest Research Institute (R)
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFLOAT16_P_H
+#define QFLOAT16_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qfloat16.h>
+#include <QtCore/qsysinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+static inline bool qt_is_inf(qfloat16 d) Q_DECL_NOTHROW
+{
+ bool is_inf;
+ uchar *ch = (uchar *)&d;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ is_inf = (ch[0] & 0x7c) == 0x7c;
+ else
+ is_inf = (ch[1] & 0x7c) == 0x7c;
+ return is_inf;
+}
+
+static inline bool qt_is_nan(qfloat16 d) Q_DECL_NOTHROW
+{
+ bool is_nan;
+ uchar *ch = (uchar *)&d;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ is_nan = (ch[0] & 0x7c) == 0x7c && (ch[0] & 0x02) != 0;
+ else
+ is_nan = (ch[1] & 0x7c) == 0x7c && (ch[1] & 0x02) != 0;
+ return is_nan;
+}
+
+static inline bool qt_is_finite(qfloat16 d) Q_DECL_NOTHROW
+{
+ bool is_finite;
+ uchar *ch = (uchar *)&d;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ is_finite = (ch[0] & 0x7c) != 0x7c;
+ else
+ is_finite = (ch[1] & 0x7c) != 0x7c;
+ return is_finite;
+}
+
+
+QT_END_NAMESPACE
+
+#endif // QFLOAT16_P_H
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 6b3cb502e5..1f93d3cbec 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -45,6 +45,8 @@
#include "qthreadstorage.h"
#include "qdir.h"
#include "qdatetime.h"
+#include "qoperatingsystemversion.h"
+#include "qoperatingsystemversion_p.h"
#include <private/qlocale_tools_p.h>
#include <qmutex.h>
@@ -956,7 +958,8 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
\snippet code/src_corelib_global_qglobal.cpp 53
- \sa qConstOverload(), qNonConstOverload()
+ \sa qConstOverload(), qNonConstOverload(), {Differences between String-Based
+ and Functor-Based Connections}
*/
/*! \fn auto qConstOverload(T memberFunctionPointer)
@@ -967,7 +970,8 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
\snippet code/src_corelib_global_qglobal.cpp 54
- \sa qOverload, qNonConstOverload
+ \sa qOverload, qNonConstOverload, {Differences between String-Based
+ and Functor-Based Connections}
*/
/*! \fn auto qNonConstOverload(T memberFunctionPointer)
@@ -978,7 +982,8 @@ Q_STATIC_ASSERT_X(QT_POINTER_SIZE == sizeof(void *), "QT_POINTER_SIZE defined in
\snippet code/src_corelib_global_qglobal.cpp 54
- \sa qOverload, qNonConstOverload
+ \sa qOverload, qNonConstOverload, {Differences between String-Based
+ and Functor-Based Connections}
*/
/*!
@@ -1064,10 +1069,6 @@ bool qSharedBuild() Q_DECL_NOTHROW
on which the application is compiled.
\li \l ByteOrder specifies whether the platform is big-endian or
little-endian.
- \li \l WindowsVersion specifies the version of the Windows operating
- system on which the application is run.
- \li \l MacintoshVersion specifies the version of the Macintosh
- operating system on which the application is run.
\endlist
Some constants are defined only on certain platforms. You can use
@@ -1088,12 +1089,14 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\variable QSysInfo::WindowsVersion
\brief the version of the Windows operating system on which the
application is run.
*/
/*!
+ \deprecated
\fn QSysInfo::WindowsVersion QSysInfo::windowsVersion()
\since 4.4
@@ -1103,12 +1106,14 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\variable QSysInfo::MacintoshVersion
\brief the version of the Macintosh operating system on which
the application is run.
*/
/*!
+ \deprecated
\fn QSysInfo::MacVersion QSysInfo::macVersion()
Returns the version of Darwin (\macos or iOS) on which the
@@ -1126,6 +1131,7 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\enum QSysInfo::WinVersion
This enum provides symbolic names for the various versions of the
@@ -1182,6 +1188,7 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
+ \deprecated
\enum QSysInfo::MacVersion
This enum provides symbolic names for the various versions of the
@@ -1335,13 +1342,6 @@ bool qSharedBuild() Q_DECL_NOTHROW
*/
/*!
- \macro Q_OS_WINPHONE
- \relates <QtGlobal>
-
- Defined on Windows Phone 8.
-*/
-
-/*!
\macro Q_OS_CYGWIN
\relates <QtGlobal>
@@ -1941,6 +1941,19 @@ bool qSharedBuild() Q_DECL_NOTHROW
disable functions deprecated in Qt 5.1 and earlier. In any release, set
QT_DISABLE_DEPRECATED_BEFORE=0x000000 to enable any functions, including the ones
deprecated in Qt 5.0
+
+ \sa QT_DEPRECATED_WARNINGS
+ */
+
+
+/*!
+ \macro QT_DEPRECATED_WARNINGS
+ \relates <QtGlobal>
+
+ If this macro is defined, the compiler will generate warnings if API declared as
+ deprecated by Qt is used.
+
+ \sa QT_DISABLE_DEPRECATED_BEFORE
*/
#if defined(QT_BUILD_QMAKE)
@@ -1956,28 +1969,34 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include "qnamespace.h"
QT_END_INCLUDE_NAMESPACE
+#if QT_DEPRECATED_SINCE(5, 9)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QSysInfo::MacVersion QSysInfo::macVersion()
{
- const QAppleOperatingSystemVersion version = qt_apple_os_version(); // qtcore_mac_objc.mm
+ const auto version = QOperatingSystemVersion::current();
#if defined(Q_OS_OSX)
- return QSysInfo::MacVersion(Q_MV_OSX(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_OSX(version.majorVersion(), version.minorVersion()));
#elif defined(Q_OS_IOS)
- return QSysInfo::MacVersion(Q_MV_IOS(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_IOS(version.majorVersion(), version.minorVersion()));
#elif defined(Q_OS_TVOS)
- return QSysInfo::MacVersion(Q_MV_TVOS(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_TVOS(version.majorVersion(), version.minorVersion()));
#elif defined(Q_OS_WATCHOS)
- return QSysInfo::MacVersion(Q_MV_WATCHOS(version.major, version.minor));
+ return QSysInfo::MacVersion(Q_MV_WATCHOS(version.majorVersion(), version.minorVersion()));
#else
return QSysInfo::MV_Unknown;
#endif
}
const QSysInfo::MacVersion QSysInfo::MacintoshVersion = QSysInfo::macVersion();
+QT_WARNING_POP
+#endif
-#ifdef Q_OS_OSX
-static const char *osxVer_helper(QAppleOperatingSystemVersion version = qt_apple_os_version())
+#ifdef Q_OS_DARWIN
+static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
{
- if (version.major == 10) {
- switch (version.minor) {
+#ifdef Q_OS_MACOS
+ if (version.majorVersion() == 10) {
+ switch (version.minorVersion()) {
case 9:
return "Mavericks";
case 10:
@@ -1989,6 +2008,9 @@ static const char *osxVer_helper(QAppleOperatingSystemVersion version = qt_apple
}
}
// unknown, future version
+#else
+ Q_UNUSED(version);
+#endif
return 0;
}
#endif
@@ -2029,140 +2051,33 @@ QWindowsSockInit::~QWindowsSockInit()
Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit)
# endif // QT_BOOTSTRAPPED
-#ifdef Q_OS_WINRT
-static inline HMODULE moduleHandleForFunction(LPCVOID address)
-{
- // This is a widely used, decades-old technique for retrieving the handle
- // of a module and is effectively equivalent to GetModuleHandleEx
- // (which is unavailable on WinRT)
- MEMORY_BASIC_INFORMATION mbi = { 0, 0, 0, 0, 0, 0, 0 };
- if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0)
- return 0;
- return reinterpret_cast<HMODULE>(mbi.AllocationBase);
-}
-#endif
-
-static inline OSVERSIONINFOEX determineWinOsVersion()
-{
- OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0};
-
-#define GetProcAddressA GetProcAddress
-
- // GetModuleHandle is not supported in WinRT and linking to it at load time
- // will not pass the Windows App Certification Kit... but it exists and is functional,
- // so use some unusual but widely used techniques to get a pointer to it
-#ifdef Q_OS_WINRT
- // 1. Get HMODULE of kernel32.dll, using the address of some function exported by that DLL
- HMODULE kernelModule = moduleHandleForFunction(reinterpret_cast<LPCVOID>(VirtualQuery));
- if (Q_UNLIKELY(!kernelModule))
- return result;
-
- // 2. Get pointer to GetModuleHandle so we can then load other arbitrary modules (DLLs)
- typedef HMODULE(WINAPI *GetModuleHandleFunction)(LPCWSTR);
- GetModuleHandleFunction pGetModuleHandle = reinterpret_cast<GetModuleHandleFunction>(
- GetProcAddressA(kernelModule, "GetModuleHandleW"));
- if (Q_UNLIKELY(!pGetModuleHandle))
- return result;
-#else
-#define pGetModuleHandle GetModuleHandleW
-#endif
-
-#ifndef Q_OS_WINCE
- HMODULE ntdll = pGetModuleHandle(L"ntdll.dll");
- if (Q_UNLIKELY(!ntdll))
- return result;
-
- // NTSTATUS is not defined on WinRT
- typedef LONG NTSTATUS;
- typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO);
-
- // RtlGetVersion is documented public API but we must load it dynamically
- // because linking to it at load time will not pass the Windows App Certification Kit
- // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx
- RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
- GetProcAddressA(ntdll, "RtlGetVersion"));
- if (Q_UNLIKELY(!pRtlGetVersion))
- return result;
-
- // GetVersionEx() has been deprecated in Windows 8.1 and will return
- // only Windows 8 from that version on, so use the kernel API function.
- pRtlGetVersion((LPOSVERSIONINFO) &result); // always returns STATUS_SUCCESS
-#else // !Q_OS_WINCE
- GetVersionEx(&result);
-#endif
- return result;
-}
-
-static OSVERSIONINFOEX winOsVersion()
-{
- OSVERSIONINFOEX realResult = determineWinOsVersion();
-#ifdef QT_DEBUG
- {
- if (Q_UNLIKELY(qEnvironmentVariableIsSet("QT_WINVER_OVERRIDE"))) {
- OSVERSIONINFOEX result = realResult;
- result.dwMajorVersion = 0;
- result.dwMinorVersion = 0;
-
- // Erase any build number and service pack information
- result.dwBuildNumber = 0;
- result.szCSDVersion[0] = L'\0';
- result.wServicePackMajor = 0;
- result.wServicePackMinor = 0;
-
- const QByteArray winVerOverride = qgetenv("QT_WINVER_OVERRIDE");
- if (winVerOverride == "WINDOWS7" || winVerOverride == "2008_R2") {
- result.dwMajorVersion = 6;
- result.dwMinorVersion = 1;
- } else if (winVerOverride == "WINDOWS8" || winVerOverride == "2012") {
- result.dwMajorVersion = 6;
- result.dwMinorVersion = 2;
- } else if (winVerOverride == "WINDOWS8_1" || winVerOverride == "2012_R2") {
- result.dwMajorVersion = 6;
- result.dwMinorVersion = 3;
- } else if (winVerOverride == "WINDOWS10" || winVerOverride == "2016") {
- result.dwMajorVersion = 10;
- } else {
- return realResult;
- }
-
- if (winVerOverride == "2008_R2"
- || winVerOverride == "2012"
- || winVerOverride == "2012_R2"
- || winVerOverride == "2016") {
- // If the current host OS is a domain controller and the override OS
- // is also a server type OS, preserve that information
- if (result.wProductType == VER_NT_WORKSTATION)
- result.wProductType = VER_NT_SERVER;
- } else {
- // Any other OS must be a workstation OS type
- result.wProductType = VER_NT_WORKSTATION;
- }
- }
- }
-#endif
- return realResult;
-}
-
+#if QT_DEPRECATED_SINCE(5, 9)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QSysInfo::WinVersion QSysInfo::windowsVersion()
{
- const OSVERSIONINFOEX osver = winOsVersion();
- if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1)
+ const auto version = QOperatingSystemVersion::current();
+ if (version.majorVersion() == 6 && version.minorVersion() == 1)
return QSysInfo::WV_WINDOWS7;
- if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 2)
+ if (version.majorVersion() == 6 && version.minorVersion() == 2)
return QSysInfo::WV_WINDOWS8;
- if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 3)
+ if (version.majorVersion() == 6 && version.minorVersion() == 3)
return QSysInfo::WV_WINDOWS8_1;
- if (osver.dwMajorVersion == 10 && osver.dwMinorVersion == 0)
+ if (version.majorVersion() == 10 && version.minorVersion() == 0)
return QSysInfo::WV_WINDOWS10;
return QSysInfo::WV_NT_based;
}
+const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion();
+QT_WARNING_POP
+#endif
static QString winSp_helper()
{
- const qint16 major = winOsVersion().wServicePackMajor;
+ const auto osv = qWindowsVersionInfo();
+ const qint16 major = osv.wServicePackMajor;
if (major) {
QString sp = QStringLiteral(" SP ") + QString::number(major);
- const qint16 minor = winOsVersion().wServicePackMinor;
+ const qint16 minor = osv.wServicePackMinor;
if (minor)
sp += QLatin1Char('.') + QString::number(minor);
@@ -2171,9 +2086,10 @@ static QString winSp_helper()
return QString();
}
-static const char *winVer_helper()
+static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
{
- const OSVERSIONINFOEX osver = winOsVersion();
+ Q_UNUSED(version);
+ const OSVERSIONINFOEX osver = qWindowsVersionInfo();
const bool workstation = osver.wProductType == VER_NT_WORKSTATION;
#define Q_WINVER(major, minor) (major << 8 | minor)
@@ -2192,8 +2108,6 @@ static const char *winVer_helper()
return 0;
}
-const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion();
-
#endif
#if defined(Q_OS_UNIX)
# if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
@@ -2374,6 +2288,68 @@ static bool findUnixOsVersion(QUnixOSVersion &v)
# endif // USE_ETC_OS_RELEASE
#endif // Q_OS_UNIX
+#ifdef Q_OS_ANDROID
+static const char *osVer_helper(QOperatingSystemVersion)
+{
+/* Data:
+
+
+
+Cupcake
+Donut
+Eclair
+Eclair
+Eclair
+Froyo
+Gingerbread
+Gingerbread
+Honeycomb
+Honeycomb
+Honeycomb
+Ice Cream Sandwich
+Ice Cream Sandwich
+Jelly Bean
+Jelly Bean
+Jelly Bean
+KitKat
+KitKat
+Lollipop
+Lollipop
+Marshmallow
+Nougat
+Nougat
+ */
+ static const char versions_string[] =
+ "\0"
+ "Cupcake\0"
+ "Donut\0"
+ "Eclair\0"
+ "Froyo\0"
+ "Gingerbread\0"
+ "Honeycomb\0"
+ "Ice Cream Sandwich\0"
+ "Jelly Bean\0"
+ "KitKat\0"
+ "Lollipop\0"
+ "Marshmallow\0"
+ "Nougat\0"
+ "\0";
+
+ static const int versions_indices[] = {
+ 0, 0, 0, 1, 9, 15, 15, 15,
+ 22, 28, 28, 40, 40, 40, 50, 50,
+ 69, 69, 69, 80, 80, 87, 87, 96,
+ 108, 108, -1
+ };
+
+ static const int versions_count = (sizeof versions_indices) / (sizeof versions_indices[0]);
+
+ // https://source.android.com/source/build-numbers.html
+ // https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels
+ const int sdk_int = QJNIObjectPrivate::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT");
+ return &versions_string[versions_indices[qBound(0, sdk_int, versions_count - 1)]];
+}
+#endif
/*!
\since 5.4
@@ -2622,9 +2598,9 @@ QString QSysInfo::kernelType()
QString QSysInfo::kernelVersion()
{
#ifdef Q_OS_WIN
- const OSVERSIONINFOEX osver = winOsVersion();
- return QString::number(int(osver.dwMajorVersion)) + QLatin1Char('.') + QString::number(int(osver.dwMinorVersion))
- + QLatin1Char('.') + QString::number(int(osver.dwBuildNumber));
+ const auto osver = QOperatingSystemVersion::current();
+ return QString::number(osver.majorVersion()) + QLatin1Char('.') + QString::number(osver.minorVersion())
+ + QLatin1Char('.') + QString::number(osver.microVersion());
#else
struct utsname u;
if (uname(&u) == 0)
@@ -2662,8 +2638,8 @@ QString QSysInfo::kernelVersion()
\b{FreeBSD note}: this function returns "debian" for Debian/kFreeBSD and
"unknown" otherwise.
- \b{Windows note}: this function returns "winphone" for builds for Windows
- Phone, "winrt" for WinRT builds, and "windows" for normal desktop builds.
+ \b{Windows note}: this function "winrt" for WinRT builds, and "windows"
+ for normal desktop builds.
For other Unix-type systems, this function usually returns "unknown".
@@ -2672,9 +2648,7 @@ QString QSysInfo::kernelVersion()
QString QSysInfo::productType()
{
// similar, but not identical to QFileSelectorPrivate::platformSelectors
-#if defined(Q_OS_WINPHONE)
- return QStringLiteral("winphone");
-#elif defined(Q_OS_WINRT)
+#if defined(Q_OS_WINRT)
return QStringLiteral("winrt");
#elif defined(Q_OS_WIN)
return QStringLiteral("windows");
@@ -2692,8 +2666,8 @@ QString QSysInfo::productType()
#elif defined(Q_OS_WATCHOS)
return QStringLiteral("watchos");
#elif defined(Q_OS_MACOS)
- const QAppleOperatingSystemVersion version = qt_apple_os_version();
- if (version.major == 10 && version.minor < 12)
+ const auto version = QOperatingSystemVersion::current();
+ if (version.majorVersion() == 10 && version.minorVersion() < 12)
return QStringLiteral("osx");
return QStringLiteral("macos");
#elif defined(Q_OS_DARWIN)
@@ -2715,8 +2689,23 @@ QString QSysInfo::productType()
version could not be determined, this function returns "unknown".
It will return the Android, iOS, \macos, Windows full-product
- versions on those systems. In particular, on OS X, iOS and Windows, the
- returned string is similar to the macVersion() or windowsVersion() enums.
+ versions on those systems.
+
+ Typical returned values are (note: list not exhaustive):
+ \list
+ \li "2016.09" (Amazon Linux AMI 2016.09)
+ \li "7.1" (Android Nougat)
+ \li "25" (Fedora 25)
+ \li "10.1" (iOS 10.1)
+ \li "10.12" (macOS Sierra)
+ \li "10.0" (tvOS 10)
+ \li "16.10" (Ubuntu 16.10)
+ \li "3.1" (watchOS 3.1)
+ \li "7 SP 1" (Windows 7 Service Pack 1)
+ \li "8.1" (Windows 8.1)
+ \li "10" (Windows 10)
+ \li "Server 2016" (Windows Server 2016)
+ \endlist
On Linux systems, it will try to determine the distribution version and will
return that. This is also done on Debian/kFreeBSD, so this function will
@@ -2733,20 +2722,17 @@ QString QSysInfo::productType()
*/
QString QSysInfo::productVersion()
{
-#if defined(Q_OS_MAC)
- const QAppleOperatingSystemVersion version = qt_apple_os_version();
- return QString::number(version.major) + QLatin1Char('.') + QString::number(version.minor);
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)
+ const auto version = QOperatingSystemVersion::current();
+ return QString::number(version.majorVersion()) + QLatin1Char('.') + QString::number(version.minorVersion());
#elif defined(Q_OS_WIN)
- const char *version = winVer_helper();
+ const char *version = osVer_helper();
if (version) {
const QLatin1Char spaceChar(' ');
return QString::fromLatin1(version).remove(spaceChar).toLower() + winSp_helper().remove(spaceChar).toLower();
}
// fall through
-// Android should not fall through to the Unix code
-#elif defined(Q_OS_ANDROID)
- return QJNIObjectPrivate::getStaticObjectField("android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString();
#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
QUnixOSVersion unixOsVersion;
findUnixOsVersion(unixOsVersion);
@@ -2774,44 +2760,21 @@ QString QSysInfo::productVersion()
*/
QString QSysInfo::prettyProductName()
{
-#if defined(Q_OS_IOS)
- return QLatin1String("iOS ") + productVersion();
-#elif defined(Q_OS_TVOS)
- return QLatin1String("tvOS ") + productVersion();
-#elif defined(Q_OS_WATCHOS)
- return QLatin1String("watchOS ") + productVersion();
-#elif defined(Q_OS_MACOS)
- const QAppleOperatingSystemVersion version = qt_apple_os_version();
- const char *name = osxVer_helper(version);
- if (name) {
- return (version.major == 10 && version.minor < 12
- ? QLatin1String("OS X ")
- : QLatin1String("macOS "))
- + QLatin1String(name)
- + QLatin1String(" (") + QString::number(version.major)
- + QLatin1Char('.') + QString::number(version.minor)
- + QLatin1Char(')');
- } else {
- return QLatin1String("macOS ")
- + QString::number(version.major) + QLatin1Char('.')
- + QString::number(version.minor);
- }
-#elif defined(Q_OS_WINPHONE)
- return QLatin1String("Windows Phone ") + QLatin1String(winVer_helper());
-#elif defined(Q_OS_WIN)
- const char *name = winVer_helper();
- const OSVERSIONINFOEX osver = winOsVersion();
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
+ const auto version = QOperatingSystemVersion::current();
+ const char *name = osVer_helper(version);
if (name)
- return QLatin1String("Windows ") + QLatin1String(name) + winSp_helper()
- + QLatin1String(" (") + QString::number(osver.dwMajorVersion)
- + QLatin1Char('.') + QString::number(osver.dwMinorVersion)
+ return version.name() + QLatin1Char(' ') + QLatin1String(name)
+# if defined(Q_OS_WIN)
+ + winSp_helper()
+# endif
+ + QLatin1String(" (") + QString::number(version.majorVersion())
+ + QLatin1Char('.') + QString::number(version.minorVersion())
+ QLatin1Char(')');
- else
- return QLatin1String("Windows ")
- + QString::number(osver.dwMajorVersion) + QLatin1Char('.')
- + QString::number(osver.dwMinorVersion);
-#elif defined(Q_OS_ANDROID)
- return QLatin1String("Android ") + productVersion();
+ else
+ return version.name() + QLatin1Char(' ')
+ + QString::number(version.majorVersion()) + QLatin1Char('.')
+ + QString::number(version.minorVersion());
#elif defined(Q_OS_HAIKU)
return QLatin1String("Haiku ") + productVersion();
#elif defined(Q_OS_UNIX)
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index b4245ac8f6..9ac29acd16 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -44,6 +44,7 @@
#ifdef __cplusplus
# include <type_traits>
# include <cstddef>
+# include <utility>
#endif
#include <stddef.h>
@@ -915,19 +916,57 @@ QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantic
# endif
#endif
+namespace QtPrivate {
+template <typename T> struct QAddConst { typedef const T Type; };
+}
+
+// this adds const to non-const objects (like std::as_const)
+template <typename T>
+Q_DECL_CONSTEXPR typename QtPrivate::QAddConst<T>::Type &qAsConst(T &t) Q_DECL_NOTHROW { return t; }
+// prevent rvalue arguments:
+template <typename T>
+void qAsConst(const T &&) Q_DECL_EQ_DELETE;
+
#ifndef QT_NO_FOREACH
+namespace QtPrivate {
+
template <typename T>
class QForeachContainer {
- QForeachContainer &operator=(const QForeachContainer &) Q_DECL_EQ_DELETE;
+ Q_DISABLE_COPY(QForeachContainer)
public:
- QForeachContainer(const T &t) : c(t), i(c.begin()), e(c.end()) {}
- QForeachContainer(T &&t) : c(std::move(t)), i(c.begin()), e(c.end()) {}
- const T c;
+ QForeachContainer(const T &t) : c(t), i(qAsConst(c).begin()), e(qAsConst(c).end()) {}
+ QForeachContainer(T &&t) : c(std::move(t)), i(qAsConst(c).begin()), e(qAsConst(c).end()) {}
+
+ QForeachContainer(QForeachContainer &&other)
+ : c(std::move(other.c)),
+ i(qAsConst(c).begin()),
+ e(qAsConst(c).end()),
+ control(std::move(other.control))
+ {
+ }
+
+ QForeachContainer &operator=(QForeachContainer &&other)
+ {
+ c = std::move(other.c);
+ i = qAsConst(c).begin();
+ e = qAsConst(c).end();
+ control = std::move(other.control);
+ return *this;
+ }
+
+ T c;
typename T::const_iterator i, e;
int control = 1;
};
+template<typename T>
+QForeachContainer<typename std::decay<T>::type> qMakeForeachContainer(T &&t)
+{
+ return QForeachContainer<typename std::decay<T>::type>(std::forward<T>(t));
+}
+
+}
// Explanation of the control word:
// - it's initialized to 1
// - that means both the inner and outer loops start
@@ -938,7 +977,7 @@ public:
// - if there was a break inside the inner loop, it will exit with control still
// set to 1; in that case, the outer loop will invert it to 0 and will exit too
#define Q_FOREACH(variable, container) \
-for (QForeachContainer<typename std::remove_reference<decltype(container)>::type> _container_((container)); \
+for (auto _container_ = QtPrivate::qMakeForeachContainer(container); \
_container_.control && _container_.i != _container_.e; \
++_container_.i, _container_.control ^= 1) \
for (variable = *_container_.i; _container_.control; _container_.control = 0)
@@ -966,8 +1005,8 @@ template <typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelpe
friend class Class##Private;
#define Q_DECLARE_PRIVATE_D(Dptr, Class) \
- inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(Dptr); } \
- inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(Dptr); } \
+ inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr)); } \
+ inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(Dptr)); } \
friend class Class##Private;
#define Q_DECLARE_PUBLIC(Class) \
@@ -1105,17 +1144,8 @@ template <typename T> struct QEnableIf<true, T> { typedef T Type; };
template <bool B, typename T, typename F> struct QConditional { typedef T Type; };
template <typename T, typename F> struct QConditional<false, T, F> { typedef F Type; };
-
-template <typename T> struct QAddConst { typedef const T Type; };
}
-// this adds const to non-const objects (like std::as_const)
-template <typename T>
-Q_DECL_CONSTEXPR typename QtPrivate::QAddConst<T>::Type &qAsConst(T &t) Q_DECL_NOTHROW { return t; }
-// prevent rvalue arguments:
-template <typename T>
-void qAsConst(const T &&) Q_DECL_EQ_DELETE;
-
QT_END_NAMESPACE
// We need to keep QTypeInfo, QSysInfo, QFlags, qDebug & family in qglobal.h for compatibility with Qt 4.
diff --git a/src/corelib/global/qglobal_p.h b/src/corelib/global/qglobal_p.h
index b8f9e5fbf7..b1d2836783 100644
--- a/src/corelib/global/qglobal_p.h
+++ b/src/corelib/global/qglobal_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2015 Intel Corporation.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/corelib/global/qhooks.cpp b/src/corelib/global/qhooks.cpp
index 7b9a3db30d..bbddb1cbf1 100644
--- a/src/corelib/global/qhooks.cpp
+++ b/src/corelib/global/qhooks.cpp
@@ -67,7 +67,7 @@ quintptr Q_CORE_EXPORT qtHookData[] = {
// The required sizes and offsets are tested in tests/auto/other/toolsupport.
// When this fails and the change was intentional, adjust the test and
// adjust this value here.
- 15
+ 16
};
Q_STATIC_ASSERT(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]));
diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp
index 03ee0730db..b4ba0b5b2e 100644
--- a/src/corelib/global/qlibraryinfo.cpp
+++ b/src/corelib/global/qlibraryinfo.cpp
@@ -663,6 +663,8 @@ QStringList QLibraryInfo::platformPluginArguments(const QString &platformName)
+ QLatin1String("Arguments");
return settings->value(key).toStringList();
}
+#else
+ Q_UNUSED(platformName);
#endif // !QT_BUILD_QMAKE && !QT_NO_SETTINGS
return QStringList();
}
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index 6b90a47388..e525869733 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -197,7 +197,7 @@ static bool willLogToConsole()
# elif defined(Q_OS_UNIX)
// if /dev/tty exists, we can only open it if we have a controlling TTY
int devtty = qt_safe_open("/dev/tty", O_RDONLY);
- if (devtty == -1 && (errno == ENOENT || errno == EPERM)) {
+ if (devtty == -1 && (errno == ENOENT || errno == EPERM || errno == ENXIO)) {
// no /dev/tty, fall back to isatty on stderr
return isatty(STDERR_FILENO);
} else if (devtty != -1) {
@@ -1445,12 +1445,14 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
now.start();
uint ms = now.msecsSinceReference();
message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
+#if QT_CONFIG(datestring)
} else if (timeFormat.isEmpty()) {
message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
} else {
message.append(QDateTime::currentDateTime().toString(timeFormat));
+#endif // QT_CONFIG(datestring)
}
-#endif
+#endif // !QT_BOOTSTRAPPED
} else if (token == ifCategoryTokenC) {
if (!context.category || (strcmp(context.category, "default") == 0))
skip = true;
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index a30344995e..da44c01594 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -472,6 +472,8 @@ public:
WA_AlwaysStackOnTop = 128,
+ WA_TabletTracking = 129,
+
// Add new attributes before this line
WA_AttributeCount
};
@@ -505,6 +507,7 @@ public:
AA_SynthesizeMouseForUnhandledTabletEvents = 24,
AA_CompressHighFrequencyEvents = 25,
AA_DontCheckOpenGLContextThreadAffinity = 26,
+ AA_DisableShaderDiskCache = 27,
// Add new attributes before this line
AA_AttributeCount
@@ -1655,6 +1658,11 @@ public:
};
Q_DECLARE_FLAGS(MouseEventFlags, MouseEventFlag)
+ enum ChecksumType {
+ ChecksumIso3309,
+ ChecksumItuV41
+ };
+
#ifndef Q_QDOC
// NOTE: Generally, do not add QT_Q_ENUM if a corresponding Q_Q_FLAG exists.
QT_Q_ENUM(ScrollBarPolicy)
@@ -1739,6 +1747,7 @@ public:
QT_Q_ENUM(ScrollPhase)
QT_Q_ENUM(MouseEventSource)
QT_Q_FLAG(MouseEventFlag)
+ QT_Q_ENUM(ChecksumType)
QT_Q_ENUM(TabFocusBehavior)
#endif // Q_DOC
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 59fa0b519c..404bbfe65a 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -254,6 +254,15 @@
\l{QOpenGLContext::makeCurrent}{makeCurrent()}. This value has been
added in Qt 5.8.
+ \value AA_DisableShaderDiskCache Disables caching of shader program binaries
+ on disk. By default Qt Quick, QPainter's OpenGL backend, and any
+ application using QOpenGLShaderProgram with one of its
+ \e addCacheableShaderFromSource overloads will employ a disk-based
+ \l{Caching Program Binaries}{program binary cache} in either the shared
+ or per-process cache storage location, on systems that support
+ \e glProgramBinary(). In the unlikely event of this being problematic,
+ set this attribute to disable all disk-based caching of shaders.
+
The following values are obsolete:
\value AA_ImmediateWidgetCreation This attribute is no longer fully
@@ -1130,6 +1139,9 @@
\value WA_StyleSheet Indicates that the widget is styled using a
\l{Qt Style Sheets}{style sheet}.
+ \value WA_TabletTracking Indicates that the widget has tablet
+ tracking enabled. See QWidget::tabletTracking.
+
\value WA_TranslucentBackground Indicates that the widget should have a
translucent background, i.e., any non-opaque regions of the widgets will be
translucent because the widget will have an alpha channel. Setting this
@@ -3146,3 +3158,14 @@
\omitvalue MouseEventFlagMask
*/
+
+/*!
+ \enum Qt::ChecksumType
+ \since 5.9
+
+ This enum describes the possible standards used by qChecksum().
+
+ \value ChecksumIso3309 Checksum calculation based on ISO 3309.
+
+ \value ChecksumItuV41 Checksum calculation based on ITU-V.41.
+*/
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index 06658b422d..2291675501 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -167,7 +167,7 @@ static inline bool qt_is_finite(float f)
// Unsigned overflow math
//
namespace {
-template <typename T> inline typename QtPrivate::QEnableIf<std::is_unsigned<T>::value, bool>::Type
+template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
add_overflow(T v1, T v2, T *r)
{
// unsigned additions are well-defined
@@ -175,7 +175,7 @@ add_overflow(T v1, T v2, T *r)
return v1 > T(v1 + v2);
}
-template <typename T> inline typename QtPrivate::QEnableIf<std::is_unsigned<T>::value, bool>::Type
+template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
mul_overflow(T v1, T v2, T *r)
{
// use the next biggest type
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
new file mode 100644
index 0000000000..bed08f0000
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -0,0 +1,491 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoperatingsystemversion.h"
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
+#include "qoperatingsystemversion_p.h"
+#endif
+
+#include <qversionnumber.h>
+
+#if defined(Q_OS_ANDROID)
+#include <private/qjni_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QOperatingSystemVersion
+ \inmodule QtCore
+ \since 5.9
+ \brief The QOperatingSystemVersion class provides information about the
+ operating system version.
+
+ Unlike other version functions in QSysInfo, QOperatingSystemVersion provides
+ access to the full version number that \a developers typically use to vary
+ behavior or determine whether to enable APIs or features based on the
+ operating system version (as opposed to the kernel version number or
+ marketing version).
+
+ This class is also a complete replacement for QSysInfo::macVersion and
+ QSysInfo::windowsVersion, additionally providing access to the third (micro)
+ version number component.
+
+ Presently, Android, Apple Platforms (iOS, macOS, tvOS, and watchOS),
+ and Windows are supported.
+
+ The \a majorVersion(), \a minorVersion(), and \a microVersion() functions
+ return the parts of the operating system version number based on:
+
+ \table
+ \header
+ \li Platforms
+ \li Value
+ \row
+ \li Android
+ \li result of parsing
+ \l{https://developer.android.com/reference/android/os/Build.VERSION.html#RELEASE}{android.os.Build.VERSION.RELEASE}
+ using QVersionNumber, with a fallback to
+ \l{https://developer.android.com/reference/android/os/Build.VERSION.html#SDK_INT}{android.os.Build.VERSION.SDK_INT}
+ to determine the major and minor version component if the former
+ fails
+ \row
+ \li Apple Platforms
+ \li majorVersion, minorVersion, and patchVersion from
+ \l{https://developer.apple.com/reference/foundation/nsprocessinfo/1410906-operatingsystemversion?language=objc}{NSProcessInfo.operatingSystemVersion}
+ \row
+ \li Windows
+ \li dwMajorVersion, dwMinorVersion, and dwBuildNumber from
+ \l{https://msdn.microsoft.com/en-us/library/mt723418.aspx}{RtlGetVersion} -
+ note that this function ALWAYS return the version number of the
+ underlying operating system, as opposed to the shim underneath
+ GetVersionEx that hides the real version number if the
+ application is not manifested for that version of the OS
+ \endtable
+
+ Because QOperatingSystemVersion stores both a version number and an OS type, the OS type
+ can be taken into account when performing comparisons. For example, on a macOS system running
+ macOS Sierra (v10.12), the following expression will return \c false even though the
+ major version number component of the object on the left hand side of the expression (10) is
+ greater than that of the object on the right (9):
+
+ \code
+ QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)
+ \endcode
+
+ This allows expressions for multiple operating systems to be joined with a logical OR operator
+ and still work as expected. For example:
+
+ \code
+ auto current = QOperatingSystemVersion::current();
+ if (current >= QOperatingSystemVersion::OSXYosemite ||
+ current >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) {
+ // returns true on macOS >= 10.10 and iOS >= 8.0, but false on macOS < 10.10 and iOS < 8.0
+ }
+ \endcode
+
+ A more naive comparison algorithm might incorrectly return true on all versions of macOS,
+ including Mac OS 9. This behavior is achieved by overloading the comparison operators to return
+ \c false whenever the OS types of the QOperatingSystemVersion instances being compared do not
+ match. Be aware that due to this it can be the case \c x >= y and \c x < y are BOTH \c false
+ for the same instances of \c x and \c y.
+*/
+
+/*!
+ \enum QOperatingSystemVersion::OSType
+
+ This enum provides symbolic names for the various operating
+ system families supported by QOperatingSystemVersion.
+
+ \value Android The Google Android operating system.
+ \value IOS The Apple iOS operating system.
+ \value MacOS The Apple macOS operating system.
+ \value TvOS The Apple tvOS operating system.
+ \value WatchOS The Apple watchOS operating system.
+ \value Windows The Microsoft Windows operating system.
+
+ \value Unknown An unknown or unsupported operating system.
+*/
+
+/*!
+ \fn QOperatingSystemVersion::QOperatingSystemVersion(OSType osType, int vmajor, int vminor = -1, int vmicro = -1)
+
+ Constructs a QOperatingSystemVersion consisting of the OS type \a osType, and
+ major, minor, and micro version numbers \a vmajor, \a vminor and \a vmicro, respectively.
+*/
+
+/*!
+ \fn QOperatingSystemVersion QOperatingSystemVersion::current()
+
+ Returns a QOperatingSystemVersion indicating the current OS and its version number.
+*/
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_WIN)
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ QOperatingSystemVersion version;
+ version.m_os = currentType();
+#if defined(Q_OS_ANDROID)
+#ifndef QT_BOOTSTRAPPED
+ const QVersionNumber v = QVersionNumber::fromString(QJNIObjectPrivate::getStaticObjectField(
+ "android/os/Build$VERSION", "RELEASE", "Ljava/lang/String;").toString());
+ if (!v.isNull()) {
+ version.m_major = v.majorVersion();
+ version.m_minor = v.minorVersion();
+ version.m_micro = v.microVersion();
+ return version;
+ }
+#endif
+
+ version.m_major = -1;
+ version.m_minor = -1;
+
+ static const int versions[][2] = {
+ { 1, 0 }, // API level 1
+ { 1, 1 }, // API level 2
+ { 1, 5 }, // API level 3
+ { 1, 6 }, // API level 4
+ { 2, 0 }, // API level 5
+ { 2, 0 }, // API level 6
+ { 2, 1 }, // API level 7
+ { 2, 2 }, // API level 8
+ { 2, 3 }, // API level 9
+ { 2, 3 }, // API level 10
+ { 3, 0 }, // API level 11
+ { 3, 1 }, // API level 12
+ { 3, 2 }, // API level 13
+ { 4, 0 }, // API level 14
+ { 4, 0 }, // API level 15
+ { 4, 1 }, // API level 16
+ { 4, 2 }, // API level 17
+ { 4, 3 }, // API level 18
+ { 4, 4 }, // API level 19
+ { 4, 4 }, // API level 20
+ { 5, 0 }, // API level 21
+ { 5, 1 }, // API level 22
+ { 6, 0 }, // API level 23
+ { 7, 0 }, // API level 24
+ { 7, 1 }, // API level 25
+ };
+
+ // This will give us at least the first 2 version components
+ const size_t versionIdx = size_t(QJNIObjectPrivate::getStaticField<jint>(
+ "android/os/Build$VERSION", "SDK_INT")) - 1;
+ if (versionIdx < sizeof(versions) / sizeof(versions[0])) {
+ version.m_major = versions[versionIdx][0];
+ version.m_minor = versions[versionIdx][1];
+ }
+
+ // API level 6 was exactly version 2.0.1
+ version.m_micro = versionIdx == 5 ? 1 : -1;
+#else
+ version.m_major = -1;
+ version.m_minor = -1;
+ version.m_micro = -1;
+#endif
+ return version;
+}
+#endif
+
+static inline int compareVersionComponents(int lhs, int rhs)
+{
+ return lhs >= 0 && rhs >= 0 ? lhs - rhs : 0;
+}
+
+int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1,
+ const QOperatingSystemVersion &v2)
+{
+ if (v1.m_major == v2.m_major) {
+ if (v1.m_minor == v2.m_minor) {
+ return compareVersionComponents(v1.m_micro, v2.m_micro);
+ }
+ return compareVersionComponents(v1.m_minor, v2.m_minor);
+ }
+ return compareVersionComponents(v1.m_major, v2.m_major);
+}
+
+/*!
+ \fn int QOperatingSystemVersion::majorVersion() const
+
+ Returns the major version number, that is, the first segment of the
+ operating system's version number.
+
+ See the main class documentation for what the major version number is on a given
+ operating system.
+
+ -1 indicates an unknown or absent version number component.
+
+ \sa minorVersion(), microVersion()
+*/
+
+/*!
+ \fn int QOperatingSystemVersion::minorVersion() const
+
+ Returns the minor version number, that is, the second segment of the
+ operating system's version number.
+
+ See the main class documentation for what the minor version number is on a given
+ operating system.
+
+ -1 indicates an unknown or absent version number component.
+
+ \sa majorVersion(), microVersion()
+*/
+
+/*!
+ \fn int QOperatingSystemVersion::microVersion() const
+
+ Returns the micro version number, that is, the third segment of the
+ operating system's version number.
+
+ See the main class documentation for what the micro version number is on a given
+ operating system.
+
+ -1 indicates an unknown or absent version number component.
+
+ \sa majorVersion(), minorVersion()
+*/
+
+/*!
+ \fn int QOperatingSystemVersion::segmentCount() const
+
+ Returns the number of integers stored in the version number.
+*/
+
+/*!
+ \fn QOperatingSystemVersion::OSType QOperatingSystemVersion::type() const
+
+ Returns the OS type identified by the QOperatingSystemVersion.
+
+ \sa name()
+*/
+
+/*!
+ \fn QString QOperatingSystemVersion::name() const
+
+ Returns a string representation of the OS type identified by the QOperatingSystemVersion.
+
+ \sa type()
+*/
+QString QOperatingSystemVersion::name() const
+{
+ switch (type()) {
+ case QOperatingSystemVersion::Windows:
+ return QStringLiteral("Windows");
+ case QOperatingSystemVersion::MacOS: {
+ if (majorVersion() < 10)
+ return QStringLiteral("Mac OS");
+ if (majorVersion() == 10 && minorVersion() < 8)
+ return QStringLiteral("Mac OS X");
+ if (majorVersion() == 10 && minorVersion() < 12)
+ return QStringLiteral("OS X");
+ return QStringLiteral("macOS");
+ }
+ case QOperatingSystemVersion::IOS: {
+ if (majorVersion() < 4)
+ return QStringLiteral("iPhone OS");
+ return QStringLiteral("iOS");
+ }
+ case QOperatingSystemVersion::TvOS:
+ return QStringLiteral("tvOS");
+ case QOperatingSystemVersion::WatchOS:
+ return QStringLiteral("watchOS");
+ case QOperatingSystemVersion::Android:
+ return QStringLiteral("Android");
+ case QOperatingSystemVersion::Unknown:
+ default:
+ return QString();
+ }
+}
+
+/*!
+ \fn bool QOperatingSystemVersion::isAnyOfType(std::initializer_list<OSType> types) const
+
+ Returns whether the OS type identified by the QOperatingSystemVersion
+ matches any of the OS types in \a types.
+*/
+bool QOperatingSystemVersion::isAnyOfType(std::initializer_list<OSType> types) const
+{
+ for (const auto &t : qAsConst(types)) {
+ if (type() == t)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \variable QOperatingSystemVersion::Windows7
+ \brief a version corresponding to Windows 7 (version 6.1).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows7 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 1);
+
+/*!
+ \variable QOperatingSystemVersion::Windows8
+ \brief a version corresponding to Windows 8 (version 6.2).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows8 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 2);
+
+/*!
+ \variable QOperatingSystemVersion::Windows8_1
+ \brief a version corresponding to Windows 8.1 (version 6.3).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows8_1 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 6, 3);
+
+/*!
+ \variable QOperatingSystemVersion::Windows10
+ \brief a version corresponding to Windows 10 (version 10.0).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10);
+
+/*!
+ \variable QOperatingSystemVersion::OSXMavericks
+ \brief a version corresponding to OS X Mavericks (version 10.9).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::OSXMavericks =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 9);
+
+/*!
+ \variable QOperatingSystemVersion::OSXYosemite
+ \brief a version corresponding to OS X Yosemite (version 10.10).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::OSXYosemite =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 10);
+
+/*!
+ \variable QOperatingSystemVersion::OSXElCapitan
+ \brief a version corresponding to OS X El Capitan (version 10.11).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::OSXElCapitan =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 11);
+
+/*!
+ \variable QOperatingSystemVersion::MacOSSierra
+ \brief a version corresponding to macOS Sierra (version 10.12).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::MacOSSierra =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 12);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidJellyBean
+ \brief a version corresponding to Android Jelly Bean (version 4.1, API level 16).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 1);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidJellyBean_MR1
+ \brief a version corresponding to Android Jelly Bean, maintenance release 1
+ (version 4.2, API level 17).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR1 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 2);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidJellyBean_MR2
+ \brief a version corresponding to Android Jelly Bean, maintenance release 2
+ (version 4.3, API level 18).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidJellyBean_MR2 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 3);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidKitKat
+ \brief a version corresponding to Android KitKat (versions 4.4 & 4.4W, API levels 19 & 20).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidKitKat =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 4, 4);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidLollipop
+ \brief a version corresponding to Android Lollipop (version 5.0, API level 21).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 0);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidLollipop_MR1
+ \brief a version corresponding to Android Lollipop, maintenance release 1
+ (version 5.1, API level 22).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidLollipop_MR1 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 5, 1);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidMarshmallow
+ \brief a version corresponding to Android Marshmallow (version 6.0, API level 23).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidMarshmallow =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 6, 0);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidNougat
+ \brief a version corresponding to Android Nougat (version 7.0, API level 24).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 0);
+
+/*!
+ \variable QOperatingSystemVersion::AndroidNougat_MR1
+ \brief a version corresponding to Android Nougat, maintenance release 1
+ (version 7.0, API level 25).
+ \since 5.9
+ */
+const QOperatingSystemVersion QOperatingSystemVersion::AndroidNougat_MR1 =
+ QOperatingSystemVersion(QOperatingSystemVersion::Android, 7, 1);
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
new file mode 100644
index 0000000000..cc14d701e1
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+
+#ifndef QOPERATINGSYSTEMVERSION_H
+#define QOPERATINGSYSTEMVERSION_H
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+class QVersionNumber;
+
+class Q_CORE_EXPORT QOperatingSystemVersion
+{
+public:
+ enum OSType {
+ Unknown = 0,
+ Windows,
+ MacOS,
+ IOS,
+ TvOS,
+ WatchOS,
+ Android
+ };
+
+ static const QOperatingSystemVersion Windows7;
+ static const QOperatingSystemVersion Windows8;
+ static const QOperatingSystemVersion Windows8_1;
+ static const QOperatingSystemVersion Windows10;
+
+ static const QOperatingSystemVersion OSXMavericks;
+ static const QOperatingSystemVersion OSXYosemite;
+ static const QOperatingSystemVersion OSXElCapitan;
+ static const QOperatingSystemVersion MacOSSierra;
+
+ static const QOperatingSystemVersion AndroidJellyBean;
+ static const QOperatingSystemVersion AndroidJellyBean_MR1;
+ static const QOperatingSystemVersion AndroidJellyBean_MR2;
+ static const QOperatingSystemVersion AndroidKitKat;
+ static const QOperatingSystemVersion AndroidLollipop;
+ static const QOperatingSystemVersion AndroidLollipop_MR1;
+ static const QOperatingSystemVersion AndroidMarshmallow;
+ static const QOperatingSystemVersion AndroidNougat;
+ static const QOperatingSystemVersion AndroidNougat_MR1;
+
+ QOperatingSystemVersion(const QOperatingSystemVersion &other) = default;
+ Q_DECL_CONSTEXPR QOperatingSystemVersion(OSType osType,
+ int vmajor, int vminor = -1, int vmicro = -1)
+ : m_os(osType),
+ m_major(qMax(-1, vmajor)),
+ m_minor(vmajor < 0 ? -1 : qMax(-1, vminor)),
+ m_micro(vmajor < 0 || vminor < 0 ? -1 : qMax(-1, vmicro))
+ { }
+
+ static QOperatingSystemVersion current();
+
+ Q_DECL_CONSTEXPR int majorVersion() const { return m_major; }
+ Q_DECL_CONSTEXPR int minorVersion() const { return m_minor; }
+ Q_DECL_CONSTEXPR int microVersion() const { return m_micro; }
+
+ Q_DECL_CONSTEXPR int segmentCount() const
+ { return m_micro >= 0 ? 3 : m_minor >= 0 ? 2 : m_major >= 0 ? 1 : 0; }
+
+ bool isAnyOfType(std::initializer_list<OSType> types) const;
+ Q_DECL_CONSTEXPR OSType type() const { return m_os; }
+ QString name() const;
+
+ friend bool operator>(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+ { return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) > 0; }
+
+ friend bool operator>=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+ { return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) >= 0; }
+
+ friend bool operator<(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+ { return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) < 0; }
+
+ friend bool operator<=(const QOperatingSystemVersion &lhs, const QOperatingSystemVersion &rhs)
+ { return lhs.type() == rhs.type() && QOperatingSystemVersion::compare(lhs, rhs) <= 0; }
+
+private:
+ QOperatingSystemVersion() = default;
+ OSType m_os;
+ int m_major;
+ int m_minor;
+ int m_micro;
+
+ static int compare(const QOperatingSystemVersion &v1, const QOperatingSystemVersion &v2);
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPERATINGSYSTEMVERSION_H
diff --git a/src/corelib/global/qoperatingsystemversion_darwin.mm b/src/corelib/global/qoperatingsystemversion_darwin.mm
new file mode 100644
index 0000000000..d8b927ff5d
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_darwin.mm
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoperatingsystemversion_p.h"
+#import <Foundation/Foundation.h>
+
+QT_BEGIN_NAMESPACE
+
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion;
+ QOperatingSystemVersion v;
+ v.m_os = currentType();
+ v.m_major = osv.majorVersion;
+ v.m_minor = osv.minorVersion;
+ v.m_micro = osv.patchVersion;
+ return v;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qoperatingsystemversion_p.h b/src/corelib/global/qoperatingsystemversion_p.h
new file mode 100644
index 0000000000..78d0daf0c6
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPERATINGSYSTEMVERSION_P_H
+#define QOPERATINGSYSTEMVERSION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qoperatingsystemversion.h"
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN
+OSVERSIONINFOEX qWindowsVersionInfo();
+#endif
+
+static inline QOperatingSystemVersion::OSType currentType()
+{
+#if defined(Q_OS_WIN)
+ return QOperatingSystemVersion::Windows;
+#elif defined(Q_OS_MACOS)
+ return QOperatingSystemVersion::MacOS;
+#elif defined(Q_OS_IOS)
+ return QOperatingSystemVersion::IOS;
+#elif defined(Q_OS_TVOS)
+ return QOperatingSystemVersion::TvOS;
+#elif defined(Q_OS_WATCHOS)
+ return QOperatingSystemVersion::WatchOS;
+#elif defined(Q_OS_ANDROID)
+ return QOperatingSystemVersion::Android;
+#else
+ return QOperatingSystemVersion::Unknown;
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif // QOPERATINGSYSTEMVERSION_P_H
diff --git a/src/corelib/global/qoperatingsystemversion_win.cpp b/src/corelib/global/qoperatingsystemversion_win.cpp
new file mode 100644
index 0000000000..060ca2f7da
--- /dev/null
+++ b/src/corelib/global/qoperatingsystemversion_win.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoperatingsystemversion_p.h"
+#include <qt_windows.h>
+#include <qbytearray.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WINRT
+static inline HMODULE moduleHandleForFunction(LPCVOID address)
+{
+ // This is a widely used, decades-old technique for retrieving the handle
+ // of a module and is effectively equivalent to GetModuleHandleEx
+ // (which is unavailable on WinRT)
+ MEMORY_BASIC_INFORMATION mbi = { 0, 0, 0, 0, 0, 0, 0 };
+ if (VirtualQuery(address, &mbi, sizeof(mbi)) == 0)
+ return 0;
+ return reinterpret_cast<HMODULE>(mbi.AllocationBase);
+}
+#endif
+
+static inline OSVERSIONINFOEX determineWinOsVersion()
+{
+ OSVERSIONINFOEX result = { sizeof(OSVERSIONINFOEX), 0, 0, 0, 0, {'\0'}, 0, 0, 0, 0, 0};
+
+#define GetProcAddressA GetProcAddress
+
+ // GetModuleHandle is not supported in WinRT and linking to it at load time
+ // will not pass the Windows App Certification Kit... but it exists and is functional,
+ // so use some unusual but widely used techniques to get a pointer to it
+#ifdef Q_OS_WINRT
+ // 1. Get HMODULE of kernel32.dll, using the address of some function exported by that DLL
+ HMODULE kernelModule = moduleHandleForFunction(reinterpret_cast<LPCVOID>(VirtualQuery));
+ if (Q_UNLIKELY(!kernelModule))
+ return result;
+
+ // 2. Get pointer to GetModuleHandle so we can then load other arbitrary modules (DLLs)
+ typedef HMODULE(WINAPI *GetModuleHandleFunction)(LPCWSTR);
+ GetModuleHandleFunction pGetModuleHandle = reinterpret_cast<GetModuleHandleFunction>(
+ GetProcAddressA(kernelModule, "GetModuleHandleW"));
+ if (Q_UNLIKELY(!pGetModuleHandle))
+ return result;
+#else
+#define pGetModuleHandle GetModuleHandleW
+#endif
+
+#ifndef Q_OS_WINCE
+ HMODULE ntdll = pGetModuleHandle(L"ntdll.dll");
+ if (Q_UNLIKELY(!ntdll))
+ return result;
+
+ // NTSTATUS is not defined on WinRT
+ typedef LONG NTSTATUS;
+ typedef NTSTATUS (NTAPI *RtlGetVersionFunction)(LPOSVERSIONINFO);
+
+ // RtlGetVersion is documented public API but we must load it dynamically
+ // because linking to it at load time will not pass the Windows App Certification Kit
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx
+ RtlGetVersionFunction pRtlGetVersion = reinterpret_cast<RtlGetVersionFunction>(
+ GetProcAddressA(ntdll, "RtlGetVersion"));
+ if (Q_UNLIKELY(!pRtlGetVersion))
+ return result;
+
+ // GetVersionEx() has been deprecated in Windows 8.1 and will return
+ // only Windows 8 from that version on, so use the kernel API function.
+ pRtlGetVersion((LPOSVERSIONINFO) &result); // always returns STATUS_SUCCESS
+#else // !Q_OS_WINCE
+ GetVersionEx(&result);
+#endif
+ return result;
+}
+
+OSVERSIONINFOEX qWindowsVersionInfo()
+{
+ OSVERSIONINFOEX realResult = determineWinOsVersion();
+#ifdef QT_DEBUG
+ {
+ if (Q_UNLIKELY(qEnvironmentVariableIsSet("QT_WINVER_OVERRIDE"))) {
+ OSVERSIONINFOEX result = realResult;
+ result.dwMajorVersion = 0;
+ result.dwMinorVersion = 0;
+
+ // Erase any build number and service pack information
+ result.dwBuildNumber = 0;
+ result.szCSDVersion[0] = L'\0';
+ result.wServicePackMajor = 0;
+ result.wServicePackMinor = 0;
+
+ const QByteArray winVerOverride = qgetenv("QT_WINVER_OVERRIDE");
+ if (winVerOverride == "WINDOWS7" || winVerOverride == "2008_R2") {
+ result.dwMajorVersion = 6;
+ result.dwMinorVersion = 1;
+ } else if (winVerOverride == "WINDOWS8" || winVerOverride == "2012") {
+ result.dwMajorVersion = 6;
+ result.dwMinorVersion = 2;
+ } else if (winVerOverride == "WINDOWS8_1" || winVerOverride == "2012_R2") {
+ result.dwMajorVersion = 6;
+ result.dwMinorVersion = 3;
+ } else if (winVerOverride == "WINDOWS10" || winVerOverride == "2016") {
+ result.dwMajorVersion = 10;
+ } else {
+ return realResult;
+ }
+
+ if (winVerOverride == "2008_R2"
+ || winVerOverride == "2012"
+ || winVerOverride == "2012_R2"
+ || winVerOverride == "2016") {
+ // If the current host OS is a domain controller and the override OS
+ // is also a server type OS, preserve that information
+ if (result.wProductType == VER_NT_WORKSTATION)
+ result.wProductType = VER_NT_SERVER;
+ } else {
+ // Any other OS must be a workstation OS type
+ result.wProductType = VER_NT_WORKSTATION;
+ }
+ }
+ }
+#endif
+ return realResult;
+}
+
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ QOperatingSystemVersion v;
+ v.m_os = currentType();
+ const OSVERSIONINFOEX osv = qWindowsVersionInfo();
+ v.m_major = osv.dwMajorVersion;
+ v.m_minor = osv.dwMinorVersion;
+ v.m_micro = osv.dwBuildNumber;
+ return v;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qprocessordetection.h b/src/corelib/global/qprocessordetection.h
index 55fcb37093..ed11e013f2 100644
--- a/src/corelib/global/qprocessordetection.h
+++ b/src/corelib/global/qprocessordetection.h
@@ -107,14 +107,17 @@
# define Q_PROCESSOR_ARM __TARGET_ARCH_ARM
# elif defined(_M_ARM) && _M_ARM > 1
# define Q_PROCESSOR_ARM _M_ARM
-# elif defined(__ARM64_ARCH_8__) || defined(__aarch64__)
+# elif defined(__ARM64_ARCH_8__) \
+ || defined(__aarch64__) \
+ || defined(__CORE_CORTEXAV8__) // GHS-specific for INTEGRITY
# define Q_PROCESSOR_ARM 8
# elif defined(__ARM_ARCH_7__) \
|| defined(__ARM_ARCH_7A__) \
|| defined(__ARM_ARCH_7R__) \
|| defined(__ARM_ARCH_7M__) \
|| defined(__ARM_ARCH_7S__) \
- || defined(_ARM_ARCH_7)
+ || defined(_ARM_ARCH_7) \
+ || defined(__CORE_CORTEXA__) // GHS-specific for INTEGRITY
# define Q_PROCESSOR_ARM 7
# elif defined(__ARM_ARCH_6__) \
|| defined(__ARM_ARCH_6J__) \
diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h
index 23f412aa6a..f443ab4b93 100644
--- a/src/corelib/global/qsysinfo.h
+++ b/src/corelib/global/qsysinfo.h
@@ -49,6 +49,23 @@ QT_BEGIN_NAMESPACE
System information
*/
+/*
+ * GCC (5-7) has a regression that causes it to emit wrong deprecated warnings:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77849
+ *
+ * Try to work around it by defining our own macro.
+ */
+
+#ifdef QT_SYSINFO_DEPRECATED_X
+#error "QT_SYSINFO_DEPRECATED_X already defined"
+#endif
+
+#ifdef Q_CC_GNU
+#define QT_SYSINFO_DEPRECATED_X(x)
+#else
+#define QT_SYSINFO_DEPRECATED_X(x) QT_DEPRECATED_X(x)
+#endif
+
class QString;
class Q_CORE_EXPORT QSysInfo {
public:
@@ -79,7 +96,8 @@ public:
# endif
};
#endif
- enum WinVersion {
+#if QT_DEPRECATED_SINCE(5, 9)
+ enum QT_DEPRECATED_X("Use QOperatingSystemVersion") WinVersion {
WV_None = 0x0000,
WV_32s = 0x0001,
@@ -117,19 +135,12 @@ public:
WV_CE_6 = 0x0400,
WV_CE_based = 0x0f00
};
-#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
- static const WinVersion WindowsVersion;
- static WinVersion windowsVersion();
-#else
- static const WinVersion WindowsVersion = WV_None;
- static WinVersion windowsVersion() { return WV_None; }
-#endif
#define Q_MV_OSX(major, minor) (major == 10 ? minor + 2 : (major == 9 ? 1 : 0))
#define Q_MV_IOS(major, minor) (QSysInfo::MV_IOS | major << 4 | minor)
#define Q_MV_TVOS(major, minor) (QSysInfo::MV_TVOS | major << 4 | minor)
#define Q_MV_WATCHOS(major, minor) (QSysInfo::MV_WATCHOS | major << 4 | minor)
- enum MacVersion {
+ enum QT_DEPRECATED_X("Use QOperatingSystemVersion") MacVersion {
MV_None = 0xffff,
MV_Unknown = 0x0000,
@@ -198,13 +209,29 @@ public:
MV_WATCHOS_2_2 = Q_MV_WATCHOS(2, 2),
MV_WATCHOS_3_0 = Q_MV_WATCHOS(3, 0)
};
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
+QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
+QT_WARNING_DISABLE_INTEL(1478)
+QT_WARNING_DISABLE_INTEL(1786)
+QT_WARNING_DISABLE_MSVC(4996)
+#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const WinVersion WindowsVersion;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static WinVersion windowsVersion();
+#else
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const WinVersion WindowsVersion = WV_None;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static WinVersion windowsVersion() { return WV_None; }
+#endif
#if defined(Q_OS_MAC)
- static const MacVersion MacintoshVersion;
- static MacVersion macVersion();
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const MacVersion MacintoshVersion;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static MacVersion macVersion();
#else
- static const MacVersion MacintoshVersion = MV_None;
- static MacVersion macVersion() { return MV_None; }
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static const MacVersion MacintoshVersion = MV_None;
+ QT_SYSINFO_DEPRECATED_X("Use QOperatingSystemVersion::current()") static MacVersion macVersion() { return MV_None; }
#endif
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(5, 9)
static QString buildCpuArchitecture();
static QString currentCpuArchitecture();
@@ -219,5 +246,7 @@ public:
static QString machineHostName();
};
+#undef QT_SYSINFO_DEPRECATED_X
+
QT_END_NAMESPACE
#endif // QSYSINFO_H
diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h
index 3b486b8f6f..3133b4a719 100644
--- a/src/corelib/global/qsystemdetection.h
+++ b/src/corelib/global/qsystemdetection.h
@@ -134,7 +134,6 @@
# define WINAPI_FAMILY_PC_APP WINAPI_FAMILY_APP
# endif
# if defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP
-# define Q_OS_WINPHONE
# define Q_OS_WINRT
# elif WINAPI_FAMILY==WINAPI_FAMILY_PC_APP
# define Q_OS_WINRT
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h
index 8aa5cb4fb4..7031021e16 100644
--- a/src/corelib/global/qtypeinfo.h
+++ b/src/corelib/global/qtypeinfo.h
@@ -58,9 +58,10 @@ class QTypeInfo
{
public:
enum {
+ isSpecialized = std::is_enum<T>::value, // don't require every enum to be marked manually
isPointer = false,
isIntegral = std::is_integral<T>::value,
- isComplex = true,
+ isComplex = !isIntegral && !std::is_enum<T>::value,
isStatic = true,
isRelocatable = std::is_enum<T>::value,
isLarge = (sizeof(T)>sizeof(void*)),
@@ -74,6 +75,7 @@ class QTypeInfo<void>
{
public:
enum {
+ isSpecialized = true,
isPointer = false,
isIntegral = false,
isComplex = false,
@@ -90,6 +92,7 @@ class QTypeInfo<T*>
{
public:
enum {
+ isSpecialized = true,
isPointer = true,
isIntegral = false,
isComplex = false,
@@ -124,7 +127,7 @@ struct QTypeInfoQuery : public QTypeInfo<T>
// if QTypeInfo<T>::isRelocatable exists, use it
template <typename T>
-struct QTypeInfoQuery<T, typename QtPrivate::QEnableIf<QTypeInfo<T>::isRelocatable || true>::Type> : public QTypeInfo<T>
+struct QTypeInfoQuery<T, typename std::enable_if<QTypeInfo<T>::isRelocatable || true>::type> : public QTypeInfo<T>
{};
/*!
@@ -152,6 +155,7 @@ class QTypeInfoMerger
{
public:
enum {
+ isSpecialized = true,
isComplex = QTypeInfoQuery<T1>::isComplex || QTypeInfoQuery<T2>::isComplex
|| QTypeInfoQuery<T3>::isComplex || QTypeInfoQuery<T4>::isComplex,
isStatic = QTypeInfoQuery<T1>::isStatic || QTypeInfoQuery<T2>::isStatic
@@ -173,6 +177,7 @@ class QTypeInfo< CONTAINER<T> > \
{ \
public: \
enum { \
+ isSpecialized = true, \
isPointer = false, \
isIntegral = false, \
isComplex = true, \
@@ -201,6 +206,7 @@ class QTypeInfo< CONTAINER<K, V> > \
{ \
public: \
enum { \
+ isSpecialized = true, \
isPointer = false, \
isIntegral = false, \
isComplex = true, \
@@ -241,6 +247,7 @@ class QTypeInfo<TYPE > \
{ \
public: \
enum { \
+ isSpecialized = true, \
isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0), \
isStatic = (((FLAGS) & (Q_MOVABLE_TYPE | Q_PRIMITIVE_TYPE)) == 0), \
isRelocatable = !isStatic || ((FLAGS) & Q_RELOCATABLE_TYPE), \
diff --git a/src/corelib/global/qtypetraits.h b/src/corelib/global/qtypetraits.h
index 9773db919b..35e407e2de 100644
--- a/src/corelib/global/qtypetraits.h
+++ b/src/corelib/global/qtypetraits.h
@@ -37,6 +37,12 @@
**
****************************************************************************/
+// ### Qt 6: remove this header
+//
+// This header is deliberately empty. Although it did not contain any public API,
+// it was accidentally made public in Qt 5. So: do not remove it for the moment
+// being, to prevent #include breaks in downstreams.
+
#include "QtCore/qglobal.h"
#ifndef QTYPETRAITS_H
@@ -44,53 +50,6 @@
QT_BEGIN_NAMESPACE
-namespace QtPrivate {
-
-//
-// Define QIsUnsignedEnum, QIsSignedEnum -
-// std::is_signed, std::is_unsigned does not work for enum's
-//
-
-// a metafunction to invert an integral_constant:
-template <typename T>
-struct not_
- : std::integral_constant<bool, !T::value> {};
-
-// Checks whether a type is unsigned (T must be convertible to unsigned int):
-template <typename T>
-struct QIsUnsignedEnum
- : std::integral_constant<bool, (T(0) < T(-1))> {};
-
-// Checks whether a type is signed (T must be convertible to int):
-template <typename T>
-struct QIsSignedEnum
- : not_< QIsUnsignedEnum<T> > {};
-
-Q_STATIC_ASSERT(( QIsUnsignedEnum<quint8>::value));
-Q_STATIC_ASSERT((!QIsUnsignedEnum<qint8>::value));
-
-Q_STATIC_ASSERT((!QIsSignedEnum<quint8>::value));
-Q_STATIC_ASSERT(( QIsSignedEnum<qint8>::value));
-
-Q_STATIC_ASSERT(( QIsUnsignedEnum<quint16>::value));
-Q_STATIC_ASSERT((!QIsUnsignedEnum<qint16>::value));
-
-Q_STATIC_ASSERT((!QIsSignedEnum<quint16>::value));
-Q_STATIC_ASSERT(( QIsSignedEnum<qint16>::value));
-
-Q_STATIC_ASSERT(( QIsUnsignedEnum<quint32>::value));
-Q_STATIC_ASSERT((!QIsUnsignedEnum<qint32>::value));
-
-Q_STATIC_ASSERT((!QIsSignedEnum<quint32>::value));
-Q_STATIC_ASSERT(( QIsSignedEnum<qint32>::value));
-
-Q_STATIC_ASSERT(( QIsUnsignedEnum<quint64>::value));
-Q_STATIC_ASSERT((!QIsUnsignedEnum<qint64>::value));
-
-Q_STATIC_ASSERT((!QIsSignedEnum<quint64>::value));
-Q_STATIC_ASSERT(( QIsSignedEnum<qint64>::value));
-
-} // namespace QtPrivate
-
QT_END_NAMESPACE
+
#endif // QTYPETRAITS_H
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index b5bfec8857..b0cac59f42 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -93,7 +93,7 @@ SOURCES += \
io/qloggingcategory.cpp \
io/qloggingregistry.cpp
-qtConfig(process) {
+qtConfig(processenvironment) {
SOURCES += \
io/qprocess.cpp
HEADERS += \
@@ -154,6 +154,8 @@ win32 {
}
mac {
SOURCES += io/qstorageinfo_mac.cpp
+ qtConfig(processenvironment): \
+ OBJECTIVE_SOURCES += io/qprocess_darwin.mm
OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm
osx {
OBJECTIVE_SOURCES += io/qfilesystemwatcher_fsevents.mm
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp
index b4eb98e062..9a42fb4a37 100644
--- a/src/corelib/io/qdatastream.cpp
+++ b/src/corelib/io/qdatastream.cpp
@@ -42,6 +42,7 @@
#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
#include "qbuffer.h"
+#include "qfloat16.h"
#include "qstring.h"
#include <stdio.h>
#include <ctype.h>
@@ -448,6 +449,9 @@ QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
The default is DoublePrecision.
+ Note that this property does not affect the serialization or deserialization of \c qfloat16
+ instances.
+
\warning This property must be set to the same value on the object that writes and the object
that reads the data stream.
@@ -557,6 +561,7 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_5_6 Version 17 (Qt 5.6)
\value Qt_5_7 Same as Qt_5_6
\value Qt_5_8 Same as Qt_5_6
+ \value Qt_5_9 Same as Qt_5_6
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
@@ -766,6 +771,17 @@ int QDataStream::readBlock(char *data, int len)
}
/*!
+ \fn QDataStream &QDataStream::operator>>(std::nullptr &ptr)
+ \since 5.9
+ \overload
+
+ Simulates reading a \c{std::nullptr_t} from the stream into \a ptr and
+ returns a reference to the stream. This function does not actually read
+ anything from the stream, as \c{std::nullptr_t} values are stored as 0
+ bytes.
+*/
+
+/*!
\fn QDataStream &QDataStream::operator>>(quint8 &i)
\overload
@@ -972,6 +988,20 @@ QDataStream &QDataStream::operator>>(double &f)
/*!
\overload
+ \since 5.9
+
+ Reads a floating point number from the stream into \a f,
+ using the standard IEEE 754 format. Returns a reference to the
+ stream.
+*/
+QDataStream &QDataStream::operator>>(qfloat16 &f)
+{
+ return *this >> reinterpret_cast<qint16&>(f);
+}
+
+
+/*!
+ \overload
Reads the '\\0'-terminated string \a s from the stream and returns
a reference to the stream.
@@ -1065,6 +1095,15 @@ int QDataStream::readRawData(char *s, int len)
QDataStream write functions
*****************************************************************************/
+/*!
+ \fn QDataStream &QDataStream::operator<<(std::nullptr ptr)
+ \since 5.9
+ \overload
+
+ Simulates writing a \c{std::nullptr_t}, \a ptr, to the stream and returns a
+ reference to the stream. This function does not actually write anything to
+ the stream, as \c{std::nullptr_t} values are stored as 0 bytes.
+*/
/*!
\fn QDataStream &QDataStream::operator<<(quint8 i)
@@ -1259,6 +1298,19 @@ QDataStream &QDataStream::operator<<(double f)
/*!
+ \fn QDataStream &QDataStream::operator<<(qfloat16 f)
+ \overload
+ \since 5.9
+
+ Writes a floating point number, \a f, to the stream using
+ the standard IEEE 754 format. Returns a reference to the stream.
+*/
+QDataStream &QDataStream::operator<<(qfloat16 f)
+{
+ return *this << reinterpret_cast<qint16&>(f);
+}
+
+/*!
\overload
Writes the '\\0'-terminated string \a s to the stream and returns a
@@ -1281,7 +1333,6 @@ QDataStream &QDataStream::operator<<(const char *s)
return *this;
}
-
/*!
Writes the length specifier \a len and the buffer \a s to the
stream and returns a reference to the stream.
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
index ac58677b77..575607e147 100644
--- a/src/corelib/io/qdatastream.h
+++ b/src/corelib/io/qdatastream.h
@@ -50,7 +50,7 @@
QT_BEGIN_NAMESPACE
-
+class qfloat16;
class QByteArray;
class QIODevice;
@@ -95,10 +95,11 @@ public:
Qt_5_6 = 17,
Qt_5_7 = Qt_5_6,
Qt_5_8 = Qt_5_7,
-#if QT_VERSION >= 0x050900
+ Qt_5_9 = Qt_5_8,
+#if QT_VERSION >= 0x050a00
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
- Qt_DefaultCompiledVersion = Qt_5_8
+ Qt_DefaultCompiledVersion = Qt_5_9
};
enum ByteOrder {
@@ -151,8 +152,10 @@ public:
QDataStream &operator>>(quint32 &i);
QDataStream &operator>>(qint64 &i);
QDataStream &operator>>(quint64 &i);
+ QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; }
QDataStream &operator>>(bool &i);
+ QDataStream &operator>>(qfloat16 &f);
QDataStream &operator>>(float &f);
QDataStream &operator>>(double &f);
QDataStream &operator>>(char *&str);
@@ -165,7 +168,9 @@ public:
QDataStream &operator<<(quint32 i);
QDataStream &operator<<(qint64 i);
QDataStream &operator<<(quint64 i);
+ QDataStream &operator<<(std::nullptr_t) { return *this; }
QDataStream &operator<<(bool i);
+ QDataStream &operator<<(qfloat16 f);
QDataStream &operator<<(float f);
QDataStream &operator<<(double f);
QDataStream &operator<<(const char *str);
@@ -222,6 +227,98 @@ private:
QDataStream::Status oldStatus;
};
+template <typename Container>
+QDataStream &readArrayBasedContainer(QDataStream &s, Container &c)
+{
+ StreamStateSaver stateSaver(&s);
+
+ c.clear();
+ quint32 n;
+ s >> n;
+ c.reserve(n);
+ for (quint32 i = 0; i < n; ++i) {
+ typename Container::value_type t;
+ s >> t;
+ if (s.status() != QDataStream::Ok) {
+ c.clear();
+ break;
+ }
+ c.append(t);
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &readListBasedContainer(QDataStream &s, Container &c)
+{
+ StreamStateSaver stateSaver(&s);
+
+ c.clear();
+ quint32 n;
+ s >> n;
+ for (quint32 i = 0; i < n; ++i) {
+ typename Container::value_type t;
+ s >> t;
+ if (s.status() != QDataStream::Ok) {
+ c.clear();
+ break;
+ }
+ c << t;
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
+{
+ StreamStateSaver stateSaver(&s);
+
+ c.clear();
+ quint32 n;
+ s >> n;
+ for (quint32 i = 0; i < n; ++i) {
+ typename Container::key_type k;
+ typename Container::mapped_type t;
+ s >> k >> t;
+ if (s.status() != QDataStream::Ok) {
+ c.clear();
+ break;
+ }
+ c.insertMulti(k, t);
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
+{
+ s << quint32(c.size());
+ for (const typename Container::value_type &t : c)
+ s << t;
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
+{
+ s << quint32(c.size());
+ // Deserialization should occur in the reverse order.
+ // Otherwise, value() will return the least recently inserted
+ // value instead of the most recently inserted one.
+ auto it = c.constEnd();
+ auto begin = c.constBegin();
+ while (it != begin) {
+ --it;
+ s << it.key() << it.value();
+ }
+
+ return s;
+}
+
} // QtPrivate namespace
/*****************************************************************************
@@ -264,210 +361,84 @@ inline QDataStream &QDataStream::operator<<(quint32 i)
inline QDataStream &QDataStream::operator<<(quint64 i)
{ return *this << qint64(i); }
-template <typename T>
-QDataStream& operator>>(QDataStream& s, QList<T>& l)
-{
- QtPrivate::StreamStateSaver stateSaver(&s);
+template <typename Enum>
+inline QDataStream &operator<<(QDataStream &s, QFlags<Enum> e)
+{ return s << e.i; }
- l.clear();
- quint32 c;
- s >> c;
- l.reserve(c);
- for(quint32 i = 0; i < c; ++i)
- {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- l.clear();
- break;
- }
- l.append(t);
- }
+template <typename Enum>
+inline QDataStream &operator>>(QDataStream &s, QFlags<Enum> &e)
+{ return s >> e.i; }
- return s;
+template <typename T>
+inline QDataStream &operator>>(QDataStream &s, QList<T> &l)
+{
+ return QtPrivate::readArrayBasedContainer(s, l);
}
template <typename T>
-QDataStream& operator<<(QDataStream& s, const QList<T>& l)
+inline QDataStream &operator<<(QDataStream &s, const QList<T> &l)
{
- s << quint32(l.size());
- for (int i = 0; i < l.size(); ++i)
- s << l.at(i);
- return s;
+ return QtPrivate::writeSequentialContainer(s, l);
}
template <typename T>
-QDataStream& operator>>(QDataStream& s, QLinkedList<T>& l)
+inline QDataStream &operator>>(QDataStream &s, QLinkedList<T> &l)
{
- QtPrivate::StreamStateSaver stateSaver(&s);
-
- l.clear();
- quint32 c;
- s >> c;
- for(quint32 i = 0; i < c; ++i)
- {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- l.clear();
- break;
- }
- l.append(t);
- }
-
- return s;
+ return QtPrivate::readListBasedContainer(s, l);
}
template <typename T>
-QDataStream& operator<<(QDataStream& s, const QLinkedList<T>& l)
+inline QDataStream &operator<<(QDataStream &s, const QLinkedList<T> &l)
{
- s << quint32(l.size());
- typename QLinkedList<T>::ConstIterator it = l.constBegin();
- for(; it != l.constEnd(); ++it)
- s << *it;
- return s;
+ return QtPrivate::writeSequentialContainer(s, l);
}
template<typename T>
-QDataStream& operator>>(QDataStream& s, QVector<T>& v)
+inline QDataStream &operator>>(QDataStream &s, QVector<T> &v)
{
- QtPrivate::StreamStateSaver stateSaver(&s);
-
- v.clear();
- quint32 c;
- s >> c;
- v.resize(c);
- for(quint32 i = 0; i < c; ++i) {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- v.clear();
- break;
- }
- v[i] = t;
- }
-
- return s;
+ return QtPrivate::readArrayBasedContainer(s, v);
}
template<typename T>
-QDataStream& operator<<(QDataStream& s, const QVector<T>& v)
+inline QDataStream &operator<<(QDataStream &s, const QVector<T> &v)
{
- s << quint32(v.size());
- for (typename QVector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
- s << *it;
- return s;
+ return QtPrivate::writeSequentialContainer(s, v);
}
template <typename T>
-QDataStream &operator>>(QDataStream &in, QSet<T> &set)
+inline QDataStream &operator>>(QDataStream &s, QSet<T> &set)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- set.clear();
- quint32 c;
- in >> c;
- for (quint32 i = 0; i < c; ++i) {
- T t;
- in >> t;
- if (in.status() != QDataStream::Ok) {
- set.clear();
- break;
- }
- set << t;
- }
-
- return in;
+ return QtPrivate::readListBasedContainer(s, set);
}
template <typename T>
-QDataStream& operator<<(QDataStream &out, const QSet<T> &set)
+inline QDataStream &operator<<(QDataStream &s, const QSet<T> &set)
{
- out << quint32(set.size());
- typename QSet<T>::const_iterator i = set.constBegin();
- while (i != set.constEnd()) {
- out << *i;
- ++i;
- }
- return out;
+ return QtPrivate::writeSequentialContainer(s, set);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash<Key, T> &hash)
+inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- hash.clear();
- quint32 n;
- in >> n;
-
- for (quint32 i = 0; i < n; ++i) {
- if (in.status() != QDataStream::Ok)
- break;
-
- Key k;
- T t;
- in >> k >> t;
- hash.insertMulti(k, t);
- }
-
- if (in.status() != QDataStream::Ok)
- hash.clear();
- return in;
+ return QtPrivate::readAssociativeContainer(s, hash);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash)
+inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash)
{
- out << quint32(hash.size());
- typename QHash<Key, T>::ConstIterator it = hash.end();
- typename QHash<Key, T>::ConstIterator begin = hash.begin();
- while (it != begin) {
- --it;
- out << it.key() << it.value();
- }
- return out;
+ return QtPrivate::writeAssociativeContainer(s, hash);
}
-#ifdef Q_QDOC
+
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<Key, T> &map)
-#else
-template <class aKey, class aT>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<aKey, aT> &map)
-#endif
+inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- map.clear();
- quint32 n;
- in >> n;
-
- map.detach();
- for (quint32 i = 0; i < n; ++i) {
- if (in.status() != QDataStream::Ok)
- break;
-
- aKey key;
- aT value;
- in >> key >> value;
- map.insertMulti(key, value);
- }
- if (in.status() != QDataStream::Ok)
- map.clear();
- return in;
+ return QtPrivate::readAssociativeContainer(s, map);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map)
+inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map)
{
- out << quint32(map.size());
- typename QMap<Key, T>::ConstIterator it = map.end();
- typename QMap<Key, T>::ConstIterator begin = map.begin();
- while (it != begin) {
- --it;
- out << it.key() << it.value();
- }
- return out;
+ return QtPrivate::writeAssociativeContainer(s, map);
}
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index abc2abeaec..61059dd694 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -365,7 +365,7 @@ Q_CORE_EXPORT QDebug qt_QMetaEnum_debugOperator(QDebug&, int value, const QMetaO
Q_CORE_EXPORT QDebug qt_QMetaEnum_flagDebugOperator(QDebug &dbg, quint64 value, const QMetaObject *meta, const char *name);
template<typename T>
-typename QtPrivate::QEnableIf<QtPrivate::IsQEnumHelper<T>::Value, QDebug>::Type
+typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, QDebug>::type
operator<<(QDebug dbg, T value)
{
const QMetaObject *obj = qt_getEnumMetaObject(value);
@@ -374,9 +374,9 @@ operator<<(QDebug dbg, T value)
}
template <class T>
-inline typename QtPrivate::QEnableIf<
+inline typename std::enable_if<
QtPrivate::IsQEnumHelper<T>::Value || QtPrivate::IsQEnumHelper<QFlags<T> >::Value,
- QDebug>::Type
+ QDebug>::type
qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
{
const QMetaObject *obj = qt_getEnumMetaObject(T());
@@ -385,9 +385,9 @@ qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
}
template <class T>
-inline typename QtPrivate::QEnableIf<
+inline typename std::enable_if<
!QtPrivate::IsQEnumHelper<T>::Value && !QtPrivate::IsQEnumHelper<QFlags<T> >::Value,
- QDebug>::Type
+ QDebug>::type
qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
#else // !QT_NO_QOBJECT && !Q_QDOC
template <class T>
@@ -402,7 +402,7 @@ template<typename T>
inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
{
// We have to use an indirection otherwise specialisation of some other overload of the
- // operator<< the compiler would try to instantiate QFlags<T> for the QEnableIf
+ // operator<< the compiler would try to instantiate QFlags<T> for the std::enable_if
return qt_QMetaEnum_flagDebugOperator_helper(debug, flags);
}
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 437f774547..6d144cb65d 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -1843,6 +1843,26 @@ bool QDir::exists(const QString &name) const
}
/*!
+ Returns whether the directory is empty.
+
+ Equivalent to \c{count() == 0} with filters
+ \c{QDir::AllEntries | QDir::NoDotAndDotDot}, but faster as it just checks
+ whether the directory contains at least one entry.
+
+ \note Unless you set the \a filters flags to include \c{QDir::NoDotAndDotDot}
+ (as the default value does), no directory is empty.
+
+ \sa count(), entryList(), setFilter()
+ \since 5.9
+*/
+bool QDir::isEmpty(Filters filters) const
+{
+ const auto d = d_ptr.constData();
+ QDirIterator it(d->dirEntry.filePath(), d->nameFilters, filters);
+ return !it.hasNext();
+}
+
+/*!
Returns a list of the root directories on this system.
On Windows this returns a list of QFileInfo objects containing "C:/",
@@ -2085,11 +2105,11 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
return name;
int i = len - 1;
- QVarLengthArray<QChar> outVector(len);
+ QVarLengthArray<ushort> outVector(len);
int used = len;
- QChar *out = outVector.data();
- const QChar *p = name.unicode();
- const QChar *prefix = p;
+ ushort *out = outVector.data();
+ const ushort *p = name.utf16();
+ const ushort *prefix = p;
int up = 0;
const int prefixLength = rootLength(name, allowUncPaths);
@@ -2097,39 +2117,39 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
i -= prefixLength;
// replicate trailing slash (i > 0 checks for emptiness of input string p)
- if (i > 0 && p[i].unicode() == '/') {
- out[--used].unicode() = '/';
+ if (i > 0 && p[i] == '/') {
+ out[--used] = '/';
--i;
}
while (i >= 0) {
// remove trailing slashes
- if (p[i].unicode() == '/') {
+ if (p[i] == '/') {
--i;
continue;
}
// remove current directory
- if (p[i].unicode() == '.' && (i == 0 || p[i-1].unicode() == '/')) {
+ if (p[i] == '.' && (i == 0 || p[i-1] == '/')) {
--i;
continue;
}
// detect up dir
- if (i >= 1 && p[i].unicode() == '.' && p[i-1].unicode() == '.'
- && (i == 1 || (i >= 2 && p[i-2].unicode() == '/'))) {
+ if (i >= 1 && p[i] == '.' && p[i-1] == '.'
+ && (i == 1 || (i >= 2 && p[i-2] == '/'))) {
++up;
i -= 2;
continue;
}
// prepend a slash before copying when not empty
- if (!up && used != len && out[used].unicode() != '/')
- out[--used] = QLatin1Char('/');
+ if (!up && used != len && out[used] != '/')
+ out[--used] = '/';
// skip or copy
while (i >= 0) {
- if (p[i].unicode() == '/') { // do not copy slashes
+ if (p[i] == '/') { // do not copy slashes
--i;
break;
}
@@ -2151,17 +2171,17 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
// add remaining '..'
while (up) {
- if (used != len && out[used].unicode() != '/') // is not empty and there isn't already a '/'
- out[--used] = QLatin1Char('/');
- out[--used] = QLatin1Char('.');
- out[--used] = QLatin1Char('.');
+ if (used != len && out[used] != '/') // is not empty and there isn't already a '/'
+ out[--used] = '/';
+ out[--used] = '.';
+ out[--used] = '.';
--up;
}
bool isEmpty = used == len;
if (prefixLength) {
- if (!isEmpty && out[used].unicode() == '/') {
+ if (!isEmpty && out[used] == '/') {
// Eventhough there is a prefix the out string is a slash. This happens, if the input
// string only consists of a prefix followed by one or more slashes. Just skip the slash.
++used;
@@ -2172,18 +2192,19 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
if (isEmpty) {
// After resolving the input path, the resulting string is empty (e.g. "foo/.."). Return
// a dot in that case.
- out[--used] = QLatin1Char('.');
- } else if (out[used].unicode() == '/') {
+ out[--used] = '.';
+ } else if (out[used] == '/') {
// After parsing the input string, out only contains a slash. That happens whenever all
// parts are resolved and there is a trailing slash ("./" or "foo/../" for example).
// Prepend a dot to have the correct return value.
- out[--used] = QLatin1Char('.');
+ out[--used] = '.';
}
}
// If path was not modified return the original value
- QString ret = (used == 0 ? name : QString(out + used, len - used));
- return ret;
+ if (used == 0)
+ return name;
+ return QString::fromUtf16(out + used, len - used);
}
static QString qt_cleanPath(const QString &path, bool *ok)
diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h
index ef7ec2c701..950a26f327 100644
--- a/src/corelib/io/qdir.h
+++ b/src/corelib/io/qdir.h
@@ -144,6 +144,8 @@ public:
void setSorting(SortFlags sort);
uint count() const;
+ bool isEmpty(Filters filters = Filters(AllEntries | NoDotAndDotDot)) const;
+
QString operator[](int) const;
static QStringList nameFiltersFromString(const QString &nameFilter);
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 5acee25d02..12fd7d3048 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -1295,7 +1295,7 @@ qint64 QFileInfo::size() const
}
/*!
- Returns the date and time when the file was created.
+ Returns the date and local time when the file was created.
On most Unix systems, this function returns the time of the last
status change. A status change occurs when the file is created,
@@ -1316,13 +1316,13 @@ QDateTime QFileInfo::created() const
if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::CreationTime))
if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::CreationTime))
return QDateTime();
- return d->metaData.creationTime();
+ return d->metaData.creationTime().toLocalTime();
}
- return d->getFileTime(QAbstractFileEngine::CreationTime);
+ return d->getFileTime(QAbstractFileEngine::CreationTime).toLocalTime();
}
/*!
- Returns the date and time when the file was last modified.
+ Returns the date and local time when the file was last modified.
\sa created(), lastRead()
*/
@@ -1335,13 +1335,13 @@ QDateTime QFileInfo::lastModified() const
if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ModificationTime))
if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ModificationTime))
return QDateTime();
- return d->metaData.modificationTime();
+ return d->metaData.modificationTime().toLocalTime();
}
- return d->getFileTime(QAbstractFileEngine::ModificationTime);
+ return d->getFileTime(QAbstractFileEngine::ModificationTime).toLocalTime();
}
/*!
- Returns the date and time when the file was last read (accessed).
+ Returns the date and local time when the file was last read (accessed).
On platforms where this information is not available, returns the
same as lastModified().
@@ -1357,9 +1357,9 @@ QDateTime QFileInfo::lastRead() const
if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::AccessTime))
if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::AccessTime))
return QDateTime();
- return d->metaData.accessTime();
+ return d->metaData.accessTime().toLocalTime();
}
- return d->getFileTime(QAbstractFileEngine::AccessTime);
+ return d->getFileTime(QAbstractFileEngine::AccessTime).toLocalTime();
}
/*!
diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp
index 920281cef7..cb4f5c4b07 100644
--- a/src/corelib/io/qfileselector.cpp
+++ b/src/corelib/io/qfileselector.cpp
@@ -133,9 +133,9 @@ QFileSelectorPrivate::QFileSelectorPrivate()
With those files available, you would select a different file on the android platform,
but only if the locale was en_GB.
- QFileSelector will not attempt to select if the base file does not exist. For error handling in
- the case no valid selectors are present, it is recommended to have a default or error-handling
- file in the base file location even if you expect selectors to be present for all deployments.
+ For error handling in the case no valid selectors are present, it is recommended to have a default or
+ error-handling file in the base file location even if you expect selectors to be present for all
+ deployments.
In a future version, some may be marked as deploy-time static and be moved during the
deployment step as an optimization. As selectors come with a performance cost, it is
@@ -298,9 +298,6 @@ QString QFileSelectorPrivate::select(const QString &filePath) const
{
Q_Q(const QFileSelector);
QFileInfo fi(filePath);
- // If file doesn't exist, don't select
- if (!fi.exists())
- return filePath;
QString ret = selectionHelper(fi.path().isEmpty() ? QString() : fi.path() + QLatin1Char('/'),
fi.fileName(), q->allSelectors());
@@ -368,14 +365,10 @@ QStringList QFileSelectorPrivate::platformSelectors()
// similar, but not identical to QSysInfo::osType
QStringList ret;
#if defined(Q_OS_WIN)
- // can't fall back to QSysInfo because we need both "winphone" and "winrt" for the Windows Phone case
ret << QStringLiteral("windows");
ret << QSysInfo::kernelType(); // "winnt"
# if defined(Q_OS_WINRT)
ret << QStringLiteral("winrt");
-# if defined(Q_OS_WINPHONE)
- ret << QStringLiteral("winphone");
-# endif
# endif
#elif defined(Q_OS_UNIX)
ret << QStringLiteral("unix");
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 96829b3b03..e195afdae9 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2017 Intel Corporation.
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2013 Samuel Gaist <samuel.gaist@edeltech.ch>
** Contact: https://www.qt.io/licensing/
@@ -122,13 +123,10 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
if (CFBundleGetPackageInfoInDirectory(url, &type, &creator))
return true;
-#ifdef Q_OS_OSX
+#ifdef Q_OS_MACOS
// Find if an application other than Finder claims to know how to handle the package
- QCFType<CFURLRef> application;
- LSGetApplicationForURL(url,
- kLSRolesEditor|kLSRolesViewer,
- NULL,
- &application);
+ QCFType<CFURLRef> application = LSCopyDefaultApplicationURLForURL(url,
+ kLSRolesEditor | kLSRolesViewer, nullptr);
if (application) {
QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, application);
@@ -606,25 +604,7 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
if (!createParents)
return false;
- // we need the cleaned path in order to create the parents
- // and we save errno just in case encodeName needs to load codecs
- int savedErrno = errno;
- bool pathChanged;
- {
- QString cleanName = QDir::cleanPath(dirName);
-
- // Check if the cleaned name is the same or not. If we were given a
- // path with resolvable "../" sections, cleanPath will remove them, but
- // this may change the target dir if one of those segments was a
- // symlink. This operation depends on cleanPath's optimization of
- // returning the original string if it didn't modify anything.
- pathChanged = !dirName.isSharedWith(cleanName);
- if (pathChanged)
- nativeName = QFile::encodeName(cleanName);
- }
-
- errno = savedErrno;
- return createDirectoryWithParents(nativeName, pathChanged);
+ return createDirectoryWithParents(nativeName, false);
}
//static
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 0d4ef94622..b1e218de9c 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qfilesystemengine_p.h"
-
+#include "qoperatingsystemversion.h"
#include "qplatformdefs.h"
#include "qsysinfo.h"
#include "private/qabstractfileengine_p.h"
@@ -81,11 +81,6 @@ using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::ApplicationModel;
-
-#if _MSC_VER < 1900
-#define Q_OS_WINRT_WIN81
-#endif
-
#endif // Q_OS_WINRT
#ifndef SPI_GETPLATFORMTYPE
@@ -157,7 +152,6 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
#if defined(Q_OS_WINRT)
-static QString qfsPrivateCurrentDir = QLatin1String("");
// As none of the functions we try to resolve do exist on WinRT we
// avoid library loading on WinRT in general to shorten everything
// up a little bit.
@@ -504,7 +498,6 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
{
// can be //server or //server/share
QString absPath;
-#if !defined(Q_OS_WINRT_WIN81)
QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1));
wchar_t *fileName = 0;
DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
@@ -524,12 +517,7 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
if (absPath.size() < rootPath.size() && rootPath.startsWith(absPath))
absPath = rootPath;
# endif // Q_OS_WINRT
-#else // !Q_OS_WINRT_WIN81
- if (QDir::isRelativePath(path))
- absPath = QDir::toNativeSeparators(QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + path));
- else
- absPath = QDir::toNativeSeparators(QDir::cleanPath(path));
-#endif // Q_OS_WINRT_WIN81
+
// This is really ugly, but GetFullPathName strips off whitespace at the end.
// If you for instance write ". " in the lineedit of QFileDialog,
// (which is an invalid filename) this function will strip the space off and viola,
@@ -551,14 +539,7 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
else
ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(entry.filePath()));
} else {
-#ifndef Q_OS_WINRT_WIN81
ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + entry.filePath());
-#else
- // Some WinRT APIs do not support absolute paths (due to sandboxing).
- // Thus the port uses the executable's directory as its root directory
- // and treats paths relative to that as absolute paths.
- ret = QDir::cleanPath(QDir::current().relativeFilePath(entry.filePath()));
-#endif
}
#ifndef Q_OS_WINRT
@@ -638,7 +619,7 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
FILE_SHARE_READ, OPEN_EXISTING, NULL);
#endif // Q_OS_WINRT
if (handle) {
- result = QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8 ?
+ result = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ?
fileIdWin8(handle) : fileId(handle);
CloseHandle(handle);
}
@@ -1219,9 +1200,6 @@ QString QFileSystemEngine::tempPath()
ret = QDir::fromNativeSeparators(ret);
}
#else // !Q_OS_WINRT
- // According to http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.applicationdata.temporaryfolder.aspx
- // the API is not available on winphone which should cause one of the functions
- // below to fail
ComPtr<IApplicationDataStatics> applicationDataStatics;
if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
return ret;
@@ -1253,20 +1231,14 @@ bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry)
if(!(meta.exists() && meta.isDirectory()))
return false;
-#if !defined(Q_OS_WINRT_WIN81)
//TODO: this should really be using nativeFilePath(), but that returns a path in long format \\?\c:\foo
//which causes many problems later on when it's returned through currentPath()
return ::SetCurrentDirectory(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(entry.filePath()).utf16())) != 0;
-#else
- qfsPrivateCurrentDir = entry.filePath();
- return true;
-#endif
}
QFileSystemEntry QFileSystemEngine::currentPath()
{
QString ret;
-#if !defined(Q_OS_WINRT_WIN81)
DWORD size = 0;
wchar_t currentName[PATH_MAX];
size = ::GetCurrentDirectory(PATH_MAX, currentName);
@@ -1282,13 +1254,6 @@ QFileSystemEntry QFileSystemEngine::currentPath()
}
if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
-#else // !Q_OS_WINRT_WIN81
- //TODO - a race condition exists when using currentPath / setCurrentPath from multiple threads
- if (qfsPrivateCurrentDir.isEmpty())
- qfsPrivateCurrentDir = QDir::rootPath();
-
- ret = qfsPrivateCurrentDir;
-#endif // Q_OS_WINRT_WIN81
return QFileSystemEntry(ret, QFileSystemEntry::FromNativePath());
}
@@ -1369,15 +1334,11 @@ bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Per
static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
{
- QDateTime ret;
-
- SYSTEMTIME sTime, lTime;
+ SYSTEMTIME sTime;
FileTimeToSystemTime(time, &sTime);
- SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime);
- ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay));
- ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds));
-
- return ret;
+ return QDateTime(QDate(sTime.wYear, sTime.wMonth, sTime.wDay),
+ QTime(sTime.wHour, sTime.wMinute, sTime.wSecond, sTime.wMilliseconds),
+ Qt::UTC);
}
QDateTime QFileSystemMetaData::creationTime() const
diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp
index 2e92f8fbba..de4c852068 100644
--- a/src/corelib/io/qfilesystementry.cpp
+++ b/src/corelib/io/qfilesystementry.cpp
@@ -175,10 +175,8 @@ void QFileSystemEntry::resolveNativeFilePath() const
// WinRT/MSVC2015 allows a maximum of 256 characters for a filepath
// unless //?/ is prepended which extends the rule to have a maximum
// of 256 characters in the filename plus the preprending path
-#if _MSC_VER >= 1900
m_nativeFilePath.prepend("\\\\?\\");
#endif
-#endif
}
}
diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp
index 2ce7bd7a4b..2905a8e54e 100644
--- a/src/corelib/io/qfilesystemiterator_win.cpp
+++ b/src/corelib/io/qfilesystemiterator_win.cpp
@@ -39,6 +39,7 @@
#include "qfilesystemiterator_p.h"
#include "qfilesystemengine_p.h"
+#include "qoperatingsystemversion.h"
#include "qplatformdefs.h"
#include "qvector.h"
@@ -68,10 +69,6 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi
nativePath.append(QLatin1Char('\\'));
nativePath.append(QLatin1Char('*'));
// In MSVC2015+ case we prepend //?/ for longer file-name support
-#if defined(Q_OS_WINRT) && _MSC_VER < 1900
- if (nativePath.startsWith(QLatin1Char('\\')))
- nativePath.remove(0, 1);
-#endif
if (!dirPath.endsWith(QLatin1Char('/')))
dirPath.append(QLatin1Char('/'));
if ((filters & (QDir::Dirs|QDir::Drives)) && (!(filters & (QDir::Files))))
@@ -93,7 +90,7 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
haveData = true;
int infoLevel = 0 ; // FindExInfoStandard;
DWORD dwAdditionalFlags = 0;
- if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows7) {
dwAdditionalFlags = 2; // FIND_FIRST_EX_LARGE_FETCH
infoLevel = 1 ; // FindExInfoBasic;
}
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index 091552f86e..b09223d656 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE
class QFileSystemEngine;
-class QFileSystemMetaData
+class Q_AUTOTEST_EXPORT QFileSystemMetaData
{
public:
QFileSystemMetaData()
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index a1d90c76f4..612b3fa57c 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -64,6 +64,9 @@
# include "qfilesystemwatcher_fsevents_p.h"
#endif
+#include <algorithm>
+#include <iterator>
+
QT_BEGIN_NAMESPACE
QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject *parent)
@@ -102,6 +105,17 @@ void QFileSystemWatcherPrivate::init()
SIGNAL(directoryChanged(QString,bool)),
q,
SLOT(_q_directoryChanged(QString,bool)));
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveLockForRemoval,
+ q, [this] (const QString &p) { _q_winDriveLockForRemoval(p); });
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed,
+ q, [this] (const QString &p) { _q_winDriveLockForRemovalFailed(p); });
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveRemoved,
+ q, [this] (const QString &p) { _q_winDriveRemoved(p); });
+#endif // !Q_OS_WINRT
}
}
@@ -146,7 +160,46 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re
emit q->directoryChanged(path, QFileSystemWatcher::QPrivateSignal());
}
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+
+void QFileSystemWatcherPrivate::_q_winDriveLockForRemoval(const QString &path)
+{
+ // Windows: Request to lock a (removable/USB) drive for removal, release
+ // its paths under watch, temporarily storing them should the lock fail.
+ Q_Q(QFileSystemWatcher);
+ QStringList pathsToBeRemoved;
+ auto pred = [&path] (const QString &f) { return !f.startsWith(path, Qt::CaseInsensitive); };
+ std::remove_copy_if(files.cbegin(), files.cend(),
+ std::back_inserter(pathsToBeRemoved), pred);
+ std::remove_copy_if(directories.cbegin(), directories.cend(),
+ std::back_inserter(pathsToBeRemoved), pred);
+ if (!pathsToBeRemoved.isEmpty()) {
+ q->removePaths(pathsToBeRemoved);
+ temporarilyRemovedPaths.insert(path.at(0), pathsToBeRemoved);
+ }
+}
+
+void QFileSystemWatcherPrivate::_q_winDriveLockForRemovalFailed(const QString &path)
+{
+ // Windows: Request to lock a (removable/USB) drive failed (blocked by other
+ // application), restore the watched paths.
+ Q_Q(QFileSystemWatcher);
+ if (!path.isEmpty()) {
+ const auto it = temporarilyRemovedPaths.find(path.at(0));
+ if (it != temporarilyRemovedPaths.end()) {
+ q->addPaths(it.value());
+ temporarilyRemovedPaths.erase(it);
+ }
+ }
+}
+void QFileSystemWatcherPrivate::_q_winDriveRemoved(const QString &path)
+{
+ // Windows: Drive finally removed, clear out paths stored in lock request.
+ if (!path.isEmpty())
+ temporarilyRemovedPaths.remove(path.at(0));
+}
+#endif // Q_OS_WIN && !Q_OS_WINRT
/*!
\class QFileSystemWatcher
diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h
index 6c64411f92..4220c1db28 100644
--- a/src/corelib/io/qfilesystemwatcher_p.h
+++ b/src/corelib/io/qfilesystemwatcher_p.h
@@ -58,6 +58,7 @@
#include <private/qobject_p.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qhash.h>
QT_BEGIN_NAMESPACE
@@ -106,6 +107,15 @@ public:
// private slots
void _q_fileChanged(const QString &path, bool removed);
void _q_directoryChanged(const QString &path, bool removed);
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ void _q_winDriveLockForRemoval(const QString &);
+ void _q_winDriveLockForRemovalFailed(const QString &);
+ void _q_winDriveRemoved(const QString &);
+
+private:
+ QHash<QChar, QStringList> temporarilyRemovedPaths;
+#endif // Q_OS_WIN && !Q_OS_WINRT
};
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index be56d8dd1d..c385a82fc5 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -52,6 +52,16 @@
#include <qt_windows.h>
+#ifndef Q_OS_WINRT
+# include <qabstractnativeeventfilter.h>
+# include <qcoreapplication.h>
+# include <qdir.h>
+# include <private/qeventdispatcher_win_p.h>
+# include <dbt.h>
+# include <algorithm>
+# include <vector>
+#endif // !Q_OS_WINRT
+
QT_BEGIN_NAMESPACE
// #define WINQFSW_DEBUG
@@ -61,11 +71,275 @@ QT_BEGIN_NAMESPACE
# define DEBUG if (false) qDebug
#endif
+#ifndef Q_OS_WINRT
+///////////
+// QWindowsRemovableDriveListener
+// Listen for the various WM_DEVICECHANGE message indicating drive addition/removal
+// requests and removals.
+///////////
+class QWindowsRemovableDriveListener : public QObject, public QAbstractNativeEventFilter
+{
+ Q_OBJECT
+public:
+ // Device UUids as declared in ioevent.h (GUID_IO_VOLUME_LOCK, ...)
+ enum VolumeUuid { UnknownUuid, UuidIoVolumeLock, UuidIoVolumeLockFailed,
+ UuidIoVolumeUnlock, UuidIoMediaRemoval };
+
+ struct RemovableDriveEntry {
+ HDEVNOTIFY devNotify;
+ wchar_t drive;
+ };
+
+ explicit QWindowsRemovableDriveListener(QObject *parent = nullptr);
+ ~QWindowsRemovableDriveListener();
+
+ // Call from QFileSystemWatcher::addPaths() to set up notifications on drives
+ void addPath(const QString &path);
+
+ bool nativeEventFilter(const QByteArray &, void *messageIn, long *) override;
+
+signals:
+ void driveAdded();
+ void driveRemoved(const QString &);
+ void driveLockForRemoval(const QString &);
+ void driveLockForRemovalFailed(const QString &);
+
+private:
+ static VolumeUuid volumeUuid(const UUID &needle);
+ void handleDbtCustomEvent(const MSG *msg);
+ void handleDbtDriveArrivalRemoval(const MSG *msg);
+
+ std::vector<RemovableDriveEntry> m_removableDrives;
+ quintptr m_lastMessageHash;
+};
+
+static inline QEventDispatcherWin32 *winEventDispatcher()
+{
+ return static_cast<QEventDispatcherWin32 *>(QCoreApplication::instance()->eventDispatcher());
+}
+
+QWindowsRemovableDriveListener::QWindowsRemovableDriveListener(QObject *parent)
+ : QObject(parent)
+ , m_lastMessageHash(0)
+{
+ winEventDispatcher()->installNativeEventFilter(this);
+}
+
+static void stopDeviceNotification(QWindowsRemovableDriveListener::RemovableDriveEntry &e)
+{
+ UnregisterDeviceNotification(e.devNotify);
+ e.devNotify = 0;
+}
+
+template <class Iterator> // Search sequence of RemovableDriveEntry for HDEVNOTIFY.
+static inline Iterator findByHDevNotify(Iterator i1, Iterator i2, HDEVNOTIFY hdevnotify)
+{
+ return std::find_if(i1, i2,
+ [hdevnotify] (const QWindowsRemovableDriveListener::RemovableDriveEntry &e) { return e.devNotify == hdevnotify; });
+}
+
+QWindowsRemovableDriveListener::~QWindowsRemovableDriveListener()
+{
+ std::for_each(m_removableDrives.begin(), m_removableDrives.end(), stopDeviceNotification);
+}
+
+static QString pathFromEntry(const QWindowsRemovableDriveListener::RemovableDriveEntry &re)
+{
+ QString path = QStringLiteral("A:/");
+ path[0] = QChar::fromLatin1(re.drive);
+ return path;
+}
+
+// Handle WM_DEVICECHANGE+DBT_CUSTOMEVENT, which is sent based on the registration
+// on the volume handle with QEventDispatcherWin32's message window in the class.
+// Capture the GUID_IO_VOLUME_LOCK indicating the drive is to be removed.
+QWindowsRemovableDriveListener::VolumeUuid QWindowsRemovableDriveListener::volumeUuid(const UUID &needle)
+{
+ static const struct VolumeUuidMapping // UUIDs from IoEvent.h (missing in MinGW)
+ {
+ VolumeUuid v;
+ UUID uuid;
+ } mapping[] = {
+ { UuidIoVolumeLock, // GUID_IO_VOLUME_LOCK
+ {0x50708874, 0xc9af, 0x11d1, {0x8f, 0xef, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoVolumeLockFailed, // GUID_IO_VOLUME_LOCK_FAILED
+ {0xae2eed10, 0x0ba8, 0x11d2, {0x8f, 0xfb, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoVolumeUnlock, // GUID_IO_VOLUME_UNLOCK
+ {0x9a8c3d68, 0xd0cb, 0x11d1, {0x8f, 0xef, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoMediaRemoval, // GUID_IO_MEDIA_REMOVAL
+ {0xd07433c1, 0xa98e, 0x11d2, {0x91, 0x7a, 0x0, 0xa0, 0xc9, 0x06, 0x8f, 0xf3}} }
+ };
+
+ static const VolumeUuidMapping *end = mapping + sizeof(mapping) / sizeof(mapping[0]);
+ const VolumeUuidMapping *m =
+ std::find_if(mapping, end, [&needle] (const VolumeUuidMapping &m) { return IsEqualGUID(m.uuid, needle); });
+ return m != end ? m->v : UnknownUuid;
+}
+
+inline void QWindowsRemovableDriveListener::handleDbtCustomEvent(const MSG *msg)
+{
+ const DEV_BROADCAST_HDR *broadcastHeader = reinterpret_cast<const DEV_BROADCAST_HDR *>(msg->lParam);
+ if (broadcastHeader->dbch_devicetype != DBT_DEVTYP_HANDLE)
+ return;
+ const DEV_BROADCAST_HANDLE *broadcastHandle = reinterpret_cast<const DEV_BROADCAST_HANDLE *>(broadcastHeader);
+ const auto it = findByHDevNotify(m_removableDrives.cbegin(), m_removableDrives.cend(),
+ broadcastHandle->dbch_hdevnotify);
+ if (it == m_removableDrives.cend())
+ return;
+ switch (volumeUuid(broadcastHandle->dbch_eventguid)) {
+ case UuidIoVolumeLock: // Received for removable USB media
+ emit driveLockForRemoval(pathFromEntry(*it));
+ break;
+ case UuidIoVolumeLockFailed:
+ emit driveLockForRemovalFailed(pathFromEntry(*it));
+ break;
+ case UuidIoVolumeUnlock:
+ break;
+ case UuidIoMediaRemoval: // Received for optical drives
+ break;
+ default:
+ break;
+ }
+}
+
+// Handle WM_DEVICECHANGE+DBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETE which are
+// sent to all top level windows and cannot be registered for (that is, their
+// triggering depends on top level windows being present)
+inline void QWindowsRemovableDriveListener::handleDbtDriveArrivalRemoval(const MSG *msg)
+{
+ const DEV_BROADCAST_HDR *broadcastHeader = reinterpret_cast<const DEV_BROADCAST_HDR *>(msg->lParam);
+ switch (broadcastHeader->dbch_devicetype) {
+ case DBT_DEVTYP_HANDLE: // WM_DEVICECHANGE/DBT_DEVTYP_HANDLE is sent for our registered drives.
+ if (msg->wParam == DBT_DEVICEREMOVECOMPLETE) {
+ const DEV_BROADCAST_HANDLE *broadcastHandle = reinterpret_cast<const DEV_BROADCAST_HANDLE *>(broadcastHeader);
+ const auto it = findByHDevNotify(m_removableDrives.begin(), m_removableDrives.end(),
+ broadcastHandle->dbch_hdevnotify);
+ // Emit for removable USB drives we were registered for.
+ if (it != m_removableDrives.end()) {
+ emit driveRemoved(pathFromEntry(*it));
+ stopDeviceNotification(*it);
+ m_removableDrives.erase(it);
+ }
+ }
+ break;
+ case DBT_DEVTYP_VOLUME: {
+ const DEV_BROADCAST_VOLUME *broadcastVolume = reinterpret_cast<const DEV_BROADCAST_VOLUME *>(broadcastHeader);
+ // WM_DEVICECHANGE/DBT_DEVTYP_VOLUME messages are sent to all toplevel windows. Compare a hash value to ensure
+ // it is handled only once.
+ const quintptr newHash = reinterpret_cast<quintptr>(broadcastVolume) + msg->wParam
+ + quintptr(broadcastVolume->dbcv_flags) + quintptr(broadcastVolume->dbcv_unitmask);
+ if (newHash == m_lastMessageHash)
+ return;
+ m_lastMessageHash = newHash;
+ // Check for DBTF_MEDIA (inserted/Removed Optical drives). Ignore for now.
+ if (broadcastVolume->dbcv_flags & DBTF_MEDIA)
+ return;
+ // Continue with plugged in USB media where dbcv_flags=0.
+ switch (msg->wParam) {
+ case DBT_DEVICEARRIVAL:
+ emit driveAdded();
+ break;
+ case DBT_DEVICEREMOVECOMPLETE: // handled by DBT_DEVTYP_HANDLE above
+ break;
+ }
+ }
+ break;
+ }
+}
+
+bool QWindowsRemovableDriveListener::nativeEventFilter(const QByteArray &, void *messageIn, long *)
+{
+ const MSG *msg = reinterpret_cast<const MSG *>(messageIn);
+ if (msg->message == WM_DEVICECHANGE) {
+ switch (msg->wParam) {
+ case DBT_CUSTOMEVENT:
+ handleDbtCustomEvent(msg);
+ break;
+ case DBT_DEVICEARRIVAL:
+ case DBT_DEVICEREMOVECOMPLETE:
+ handleDbtDriveArrivalRemoval(msg);
+ break;
+ }
+ }
+ return false;
+}
+
+// Set up listening for WM_DEVICECHANGE+DBT_CUSTOMEVENT for a removable drive path,
+void QWindowsRemovableDriveListener::addPath(const QString &p)
+{
+ const wchar_t drive = p.size() >= 2 && p.at(0).isLetter() && p.at(1) == QLatin1Char(':')
+ ? wchar_t(p.at(0).toUpper().unicode()) : L'\0';
+ if (!drive)
+ return;
+ // Already listening?
+ if (std::any_of(m_removableDrives.cbegin(), m_removableDrives.cend(),
+ [drive](const RemovableDriveEntry &e) { return e.drive == drive; })) {
+ return;
+ }
+
+ wchar_t devicePath[8] = L"\\\\.\\A:\\";
+ devicePath[4] = drive;
+ RemovableDriveEntry re;
+ re.drive = drive;
+ if (GetDriveTypeW(devicePath + 4) != DRIVE_REMOVABLE)
+ return;
+ const HANDLE volumeHandle =
+ CreateFile(devicePath, FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, // Volume requires BACKUP_SEMANTICS
+ 0);
+ if (volumeHandle == INVALID_HANDLE_VALUE) {
+ qErrnoWarning("CreateFile %s failed.",
+ qPrintable(QString::fromWCharArray(devicePath)));
+ return;
+ }
+
+ DEV_BROADCAST_HANDLE notify;
+ ZeroMemory(&notify, sizeof(notify));
+ notify.dbch_size = sizeof(notify);
+ notify.dbch_devicetype = DBT_DEVTYP_HANDLE;
+ notify.dbch_handle = volumeHandle;
+ re.devNotify = RegisterDeviceNotification(winEventDispatcher()->internalHwnd(),
+ &notify, DEVICE_NOTIFY_WINDOW_HANDLE);
+ // Empirically found: The notifications also work when the handle is immediately
+ // closed. Do it here to avoid having to close/reopen in lock message handling.
+ CloseHandle(volumeHandle);
+ if (!re.devNotify) {
+ qErrnoWarning("RegisterDeviceNotification %s failed.",
+ qPrintable(QString::fromWCharArray(devicePath)));
+ return;
+ }
+
+ m_removableDrives.push_back(re);
+}
+#endif // !Q_OS_WINRT
+
+///////////
+// QWindowsFileSystemWatcherEngine
+///////////
QWindowsFileSystemWatcherEngine::Handle::Handle()
: handle(INVALID_HANDLE_VALUE), flags(0u)
{
}
+QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine(QObject *parent)
+ : QFileSystemWatcherEngine(parent)
+#ifndef Q_OS_WINRT
+ , m_driveListener(new QWindowsRemovableDriveListener(this))
+#endif
+{
+#ifndef Q_OS_WINRT
+ parent->setProperty("_q_driveListener",
+ QVariant::fromValue(static_cast<QObject *>(m_driveListener)));
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveLockForRemoval,
+ this, &QWindowsFileSystemWatcherEngine::driveLockForRemoval);
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveLockForRemovalFailed,
+ this, &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed);
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveRemoved,
+ this, &QWindowsFileSystemWatcherEngine::driveRemoved);
+#endif // !Q_OS_WINRT
+}
+
QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine()
{
for (auto *thread : qAsConst(threads))
@@ -210,6 +484,13 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
}
}
}
+
+#ifndef Q_OS_WINRT
+ for (const QString &path : paths) {
+ if (!p.contains(path))
+ m_driveListener->addPath(path);
+ }
+#endif // !Q_OS_WINRT
return p;
}
@@ -439,4 +720,9 @@ void QWindowsFileSystemWatcherEngineThread::wakeup()
}
QT_END_NAMESPACE
+
+#ifndef Q_OS_WINRT
+# include "qfilesystemwatcher_win.moc"
+#endif
+
#endif // QT_NO_FILESYSTEMWATCHER
diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h
index e8f5c49dec..51c7082483 100644
--- a/src/corelib/io/qfilesystemwatcher_win_p.h
+++ b/src/corelib/io/qfilesystemwatcher_win_p.h
@@ -66,6 +66,7 @@
QT_BEGIN_NAMESPACE
class QWindowsFileSystemWatcherEngineThread;
+class QWindowsRemovableDriveListener;
// Even though QWindowsFileSystemWatcherEngine is derived of QThread
// via QFileSystemWatcher, it does not start a thread.
@@ -75,9 +76,7 @@ class QWindowsFileSystemWatcherEngine : public QFileSystemWatcherEngine
{
Q_OBJECT
public:
- inline QWindowsFileSystemWatcherEngine(QObject *parent)
- : QFileSystemWatcherEngine(parent)
- { }
+ explicit QWindowsFileSystemWatcherEngine(QObject *parent);
~QWindowsFileSystemWatcherEngine();
QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
@@ -121,9 +120,17 @@ public:
|| lastModified != fileInfo.lastModified());
}
};
+
+signals:
+ void driveLockForRemoval(const QString &);
+ void driveLockForRemovalFailed(const QString &);
+ void driveRemoved(const QString &);
+
private:
QList<QWindowsFileSystemWatcherEngineThread *> threads;
-
+#ifndef Q_OS_WINRT
+ QWindowsRemovableDriveListener *m_driveListener;
+#endif
};
class QFileSystemWatcherPathKey : public QString
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index f8e31ed92b..e152b035e2 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -144,7 +144,7 @@ static inline bool setCloseOnExec(int fd)
static inline QString msgOpenDirectory()
{
const char message[] = QT_TRANSLATE_NOOP("QIODevice", "file to open is a directory");
-#ifndef QT_BOOTSTRAPPED
+#if QT_CONFIG(translation)
return QIODevice::tr(message);
#else
return QLatin1String(message);
@@ -629,7 +629,7 @@ QString QFSFileEngine::fileName(FileName file) const
bool QFSFileEngine::isRelativePath() const
{
Q_D(const QFSFileEngine);
- return d->fileEntry.filePath().length() ? d->fileEntry.filePath()[0] != QLatin1Char('/') : true;
+ return d->fileEntry.filePath().length() ? d->fileEntry.filePath().at(0) != QLatin1Char('/') : true;
}
uint QFSFileEngine::ownerId(FileOwner own) const
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index e427b62136..7d16e59195 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -108,6 +108,20 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
{
Q_Q(QFSFileEngine);
+ // Check if the file name is valid:
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions
+ const QString fileName = fileEntry.fileName();
+ for (QString::const_iterator it = fileName.constBegin(), end = fileName.constEnd();
+ it != end; ++it) {
+ const QChar c = *it;
+ if (c == QLatin1Char('<') || c == QLatin1Char('>') || c == QLatin1Char(':') ||
+ c == QLatin1Char('\"') || c == QLatin1Char('/') || c == QLatin1Char('\\') ||
+ c == QLatin1Char('|') || c == QLatin1Char('?') || c == QLatin1Char('*')) {
+ q->setError(QFile::OpenError, QStringLiteral("Invalid file name"));
+ return false;
+ }
+ }
+
// All files are opened in share mode (both read and write).
DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
@@ -850,7 +864,6 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
QFile::MemoryMapFlags flags)
{
-#ifndef Q_OS_WINPHONE
Q_Q(QFSFileEngine);
Q_UNUSED(flags);
if (openMode == QFile::NotOpen) {
@@ -960,18 +973,11 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
::CloseHandle(mapHandle);
mapHandle = NULL;
-#else // !Q_OS_WINPHONE
- Q_UNUSED(offset);
- Q_UNUSED(size);
- Q_UNUSED(flags);
- Q_UNIMPLEMENTED();
-#endif // Q_OS_WINPHONE
return 0;
}
bool QFSFileEnginePrivate::unmap(uchar *ptr)
{
-#ifndef Q_OS_WINPHONE
Q_Q(QFSFileEngine);
if (!maps.contains(ptr)) {
q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
@@ -990,11 +996,6 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
}
return true;
-#else // !Q_OS_WINPHONE
- Q_UNUSED(ptr);
- Q_UNIMPLEMENTED();
- return false;
-#endif // Q_OS_WINPHONE
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index 5a02741727..ccc607afd5 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -115,6 +115,7 @@ int QLockFilePrivate::checkFcntlWorksAfterFlock(const QString &fn)
return 0;
return 1;
#else
+ Q_UNUSED(fn);
return 0;
#endif
}
diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index 77a8c891b4..47fb1fb6b8 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -186,9 +186,10 @@ void QLoggingRule::parse(const QStringRef &pattern)
*/
void QLoggingSettingsParser::setContent(const QString &content)
{
- QString content_ = content;
- QTextStream stream(&content_, QIODevice::ReadOnly);
- setContent(stream);
+ _rules.clear();
+ const auto lines = content.splitRef(QLatin1Char('\n'));
+ for (const auto &line : lines)
+ parseNextLine(line);
}
/*!
@@ -198,42 +199,50 @@ void QLoggingSettingsParser::setContent(const QString &content)
void QLoggingSettingsParser::setContent(QTextStream &stream)
{
_rules.clear();
- while (!stream.atEnd()) {
- QString line = stream.readLine();
-
- // Remove all whitespace from line
- line = line.simplified();
- line.remove(QLatin1Char(' '));
+ QString line;
+ while (stream.readLineInto(&line))
+ parseNextLine(QStringRef(&line));
+}
- // comment
- if (line.startsWith(QLatin1Char(';')))
- continue;
+/*!
+ \internal
+ Parses one line of the configuation file
+*/
- if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
- // new section
- _section = line.mid(1, line.size() - 2);
- continue;
- }
+void QLoggingSettingsParser::parseNextLine(QStringRef line)
+{
+ // Remove whitespace at start and end of line:
+ line = line.trimmed();
+
+ // comment
+ if (line.startsWith(QLatin1Char(';')))
+ return;
+
+ if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
+ // new section
+ auto sectionName = line.mid(1, line.size() - 2).trimmed();
+ m_inRulesSection = sectionName.compare(QLatin1String("rules"), Qt::CaseInsensitive) == 0;
+ return;
+ }
- if (_section.toLower() == QLatin1String("rules")) {
- int equalPos = line.indexOf(QLatin1Char('='));
- if (equalPos != -1) {
- if (line.lastIndexOf(QLatin1Char('=')) == equalPos) {
- const QStringRef pattern = line.leftRef(equalPos);
- const QStringRef valueStr = line.midRef(equalPos + 1);
- int value = -1;
- if (valueStr == QLatin1String("true"))
- value = 1;
- else if (valueStr == QLatin1String("false"))
- value = 0;
- QLoggingRule rule(pattern, (value == 1));
- if (rule.flags != 0 && (value != -1))
- _rules.append(rule);
- else
- warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
- } else {
+ if (m_inRulesSection) {
+ int equalPos = line.indexOf(QLatin1Char('='));
+ if (equalPos != -1) {
+ if (line.lastIndexOf(QLatin1Char('=')) == equalPos) {
+ const auto pattern = line.left(equalPos).trimmed();
+ const auto valueStr = line.mid(equalPos + 1).trimmed();
+ int value = -1;
+ if (valueStr == QLatin1String("true"))
+ value = 1;
+ else if (valueStr == QLatin1String("false"))
+ value = 0;
+ QLoggingRule rule(pattern, (value == 1));
+ if (rule.flags != 0 && (value != -1))
+ _rules.append(rule);
+ else
warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
- }
+ } else {
+ warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
}
}
}
@@ -286,7 +295,7 @@ void QLoggingRegistry::init()
if (!rulesSrc.isEmpty()) {
QTextStream stream(rulesSrc);
QLoggingSettingsParser parser;
- parser.setSection(QStringLiteral("Rules"));
+ parser.setImplicitRulesSection(true);
parser.setContent(stream);
er += parser.rules();
}
@@ -350,7 +359,7 @@ void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat)
void QLoggingRegistry::setApiRules(const QString &content)
{
QLoggingSettingsParser parser;
- parser.setSection(QStringLiteral("Rules"));
+ parser.setImplicitRulesSection(true);
parser.setContent(content);
if (qtLoggingDebug())
@@ -371,7 +380,12 @@ void QLoggingRegistry::setApiRules(const QString &content)
*/
void QLoggingRegistry::updateRules()
{
- rules = qtConfigRules + configRules + apiRules + envRules;
+ rules.clear();
+ rules.reserve(qtConfigRules.size() + configRules.size() + apiRules.size() + envRules.size()),
+ rules += qtConfigRules;
+ rules += configRules;
+ rules += apiRules;
+ rules += envRules;
for (auto it = categories.keyBegin(), end = categories.keyEnd(); it != end; ++it)
(*categoryFilter)(*it);
diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h
index 23740c4955..69fc6ea4ec 100644
--- a/src/corelib/io/qloggingregistry_p.h
+++ b/src/corelib/io/qloggingregistry_p.h
@@ -93,7 +93,7 @@ Q_DECLARE_TYPEINFO(QLoggingRule, Q_MOVABLE_TYPE);
class Q_AUTOTEST_EXPORT QLoggingSettingsParser
{
public:
- void setSection(const QString &section) { _section = section; }
+ void setImplicitRulesSection(bool inRulesSection) { m_inRulesSection = inRulesSection; }
void setContent(const QString &content);
void setContent(QTextStream &stream);
@@ -101,7 +101,10 @@ public:
QVector<QLoggingRule> rules() const { return _rules; }
private:
- QString _section;
+ void parseNextLine(QStringRef line);
+
+private:
+ bool m_inRulesSection = false;
QVector<QLoggingRule> _rules;
};
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index fd340ca607..c0ec35ff32 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -428,6 +428,8 @@ void QProcessEnvironment::insert(const QProcessEnvironment &e)
d->insert(*e.d);
}
+#if QT_CONFIG(process)
+
void QProcessPrivate::Channel::clear()
{
switch (type) {
@@ -1527,7 +1529,7 @@ void QProcess::setStandardOutputProcess(QProcess *destination)
dto->stdinChannel.pipeFrom(dfrom);
}
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
/*!
\since 4.7
@@ -2599,6 +2601,8 @@ QString QProcess::nullDevice()
\sa QProcess::pid()
*/
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
#include "moc_qprocess.cpp"
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 67c163c012..19157bdd02 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -46,11 +46,13 @@
#include <functional>
-QT_REQUIRE_CONFIG(process);
+QT_REQUIRE_CONFIG(processenvironment);
QT_BEGIN_NAMESPACE
-#if !defined(Q_OS_WIN) || defined(Q_QDOC)
+class QProcessPrivate;
+
+#if !defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
typedef qint64 Q_PID;
#else
QT_END_NAMESPACE
@@ -60,7 +62,6 @@ typedef struct _STARTUPINFOW Q_STARTUPINFO;
QT_BEGIN_NAMESPACE
#endif
-class QProcessPrivate;
class QProcessEnvironmentPrivate;
class Q_CORE_EXPORT QProcessEnvironment
@@ -104,6 +105,8 @@ private:
Q_DECLARE_SHARED(QProcessEnvironment)
+#if QT_CONFIG(process)
+
class Q_CORE_EXPORT QProcess : public QIODevice
{
Q_OBJECT
@@ -186,7 +189,7 @@ public:
void setStandardErrorFile(const QString &fileName, OpenMode mode = Truncate);
void setStandardOutputProcess(QProcess *destination);
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
QString nativeArguments() const;
void setNativeArguments(const QString &arguments);
struct CreateProcessArguments
@@ -205,7 +208,7 @@ public:
typedef std::function<void(CreateProcessArguments *)> CreateProcessArgumentModifier;
CreateProcessArgumentModifier createProcessArgumentsModifier() const;
void setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier);
-#endif // Q_OS_WIN
+#endif // Q_OS_WIN || Q_CLANG_QDOC
QString workingDirectory() const;
void setWorkingDirectory(const QString &dir);
@@ -297,6 +300,8 @@ private:
friend class QProcessManager;
};
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
#endif // QPROCESS_H
diff --git a/src/gui/painting/qgammatables.cpp b/src/corelib/io/qprocess_darwin.mm
index 1d76f7ee3c..dd7a8275b9 100644
--- a/src/gui/painting/qgammatables.cpp
+++ b/src/corelib/io/qprocess_darwin.mm
@@ -3,7 +3,7 @@
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -37,28 +37,22 @@
**
****************************************************************************/
-#include <private/qdrawhelper_p.h>
+#include <private/qprocess_p.h>
-QT_BEGIN_NAMESPACE
-
-
-QDrawHelperGammaTables::QDrawHelperGammaTables(qreal smoothing)
-{
- const qreal gray_gamma = 2.31;
- for (int i=0; i<256; ++i)
- qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
- for (int i=0; i<2048; ++i)
- qt_pow_invgamma[i] = uchar(qRound(qPow(i / qreal(2047.0), 1 / gray_gamma) * 255));
+#import <Foundation/Foundation.h>
- refresh(smoothing);
-}
+QT_BEGIN_NAMESPACE
-void QDrawHelperGammaTables::refresh(qreal smoothing)
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
{
- for (int i=0; i<256; ++i) {
- qt_pow_rgb_gamma[i] = uchar(qRound(qPow(i / qreal(255.0), smoothing) * 255));
- qt_pow_rgb_invgamma[i] = uchar(qRound(qPow(i / qreal(255.), 1 / smoothing) * 255));
- }
+ __block QProcessEnvironment env;
+ [[[NSProcessInfo processInfo] environment]
+ enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *__unused stop) {
+ env.d->hash.insert(
+ QProcessEnvironmentPrivate::Key(QString::fromNSString(name).toLocal8Bit()),
+ QProcessEnvironmentPrivate::Value(QString::fromNSString(value).toLocal8Bit()));
+ }];
+ return env;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index 250eeb5de6..6e0630eb66 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -58,7 +58,7 @@
#include "QtCore/qshareddata.h"
#include "private/qiodevice_p.h"
-QT_REQUIRE_CONFIG(process);
+QT_REQUIRE_CONFIG(processenvironment);
#ifdef Q_OS_UNIX
#include <QtCore/private/qorderedmutexlocker_p.h>
@@ -234,6 +234,8 @@ template<> Q_INLINE_TEMPLATE void QSharedDataPointer<QProcessEnvironmentPrivate>
d = x;
}
+#if QT_CONFIG(process)
+
class QProcessPrivate : public QIODevicePrivate
{
public:
@@ -387,6 +389,8 @@ public:
void setErrorAndEmit(QProcess::ProcessError error, const QString &description = QString());
};
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
#endif // QPROCESS_P_H
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 03e2c0c4ce..b822417ddf 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -41,7 +41,7 @@
//#define QPROCESS_DEBUG
#include "qdebug.h"
-#if defined QPROCESS_DEBUG
+#if QT_CONFIG(process) && defined(QPROCESS_DEBUG)
#include "private/qtools_p.h"
#include <ctype.h>
@@ -112,10 +112,40 @@ QT_END_NAMESPACE
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+
+#if QT_CONFIG(process)
#include <forkfd.h>
+#endif
QT_BEGIN_NAMESPACE
+#if !defined(Q_OS_DARWIN)
+
+QT_BEGIN_INCLUDE_NAMESPACE
+extern char **environ;
+QT_END_INCLUDE_NAMESPACE
+
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
+{
+ QProcessEnvironment env;
+ const char *entry;
+ for (int count = 0; (entry = environ[count]); ++count) {
+ const char *equal = strchr(entry, '=');
+ if (!equal)
+ continue;
+
+ QByteArray name(entry, equal - entry);
+ QByteArray value(equal + 1);
+ env.d->hash.insert(QProcessEnvironmentPrivate::Key(name),
+ QProcessEnvironmentPrivate::Value(value));
+ }
+ return env;
+}
+
+#endif // !defined(Q_OS_DARWIN)
+
+#if QT_CONFIG(process)
+
// POSIX requires PIPE_BUF to be 512 or larger
// so we will use 512
static const int errorBufferMax = 512;
@@ -308,34 +338,6 @@ bool QProcessPrivate::openChannel(Channel &channel)
}
}
-QT_BEGIN_INCLUDE_NAMESPACE
-#if defined(Q_OS_MACX)
-# include <crt_externs.h>
-# define environ (*_NSGetEnviron())
-#else
- extern char **environ;
-#endif
-QT_END_INCLUDE_NAMESPACE
-
-QProcessEnvironment QProcessEnvironment::systemEnvironment()
-{
- QProcessEnvironment env;
-#if !defined(QT_PLATFORM_UIKIT)
- const char *entry;
- for (int count = 0; (entry = environ[count]); ++count) {
- const char *equal = strchr(entry, '=');
- if (!equal)
- continue;
-
- QByteArray name(entry, equal - entry);
- QByteArray value(equal + 1);
- env.d->hash.insert(QProcessEnvironmentPrivate::Key(name),
- QProcessEnvironmentPrivate::Value(value));
- }
-#endif
- return env;
-}
-
static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Hash &environment, int *envc)
{
*envc = 0;
@@ -1042,4 +1044,6 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
return success;
}
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 6dd431eb47..329d1842f0 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -38,6 +38,7 @@
**
****************************************************************************/
+//#define QPROCESS_DEBUG
#include "qprocess.h"
#include "qprocess_p.h"
#include "qwindowspipereader_p.h"
@@ -61,7 +62,29 @@
QT_BEGIN_NAMESPACE
-//#define QPROCESS_DEBUG
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
+{
+ QProcessEnvironment env;
+ // Calls to setenv() affect the low-level environment as well.
+ // This is not the case the other way round.
+ if (wchar_t *envStrings = GetEnvironmentStringsW()) {
+ for (const wchar_t *entry = envStrings; *entry; ) {
+ const int entryLen = int(wcslen(entry));
+ // + 1 to permit magic cmd variable names starting with =
+ if (const wchar_t *equal = wcschr(entry + 1, L'=')) {
+ int nameLen = equal - entry;
+ QString name = QString::fromWCharArray(entry, nameLen);
+ QString value = QString::fromWCharArray(equal + 1, entryLen - nameLen - 1);
+ env.d->hash.insert(QProcessEnvironmentPrivate::Key(name), value);
+ }
+ entry += entryLen + 1;
+ }
+ FreeEnvironmentStringsW(envStrings);
+ }
+ return env;
+}
+
+#if QT_CONFIG(process)
static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
{
@@ -367,28 +390,6 @@ static QString qt_create_commandline(const QString &program, const QStringList &
return args;
}
-QProcessEnvironment QProcessEnvironment::systemEnvironment()
-{
- QProcessEnvironment env;
- // Calls to setenv() affect the low-level environment as well.
- // This is not the case the other way round.
- if (wchar_t *envStrings = GetEnvironmentStringsW()) {
- for (const wchar_t *entry = envStrings; *entry; ) {
- const int entryLen = int(wcslen(entry));
- // + 1 to permit magic cmd variable names starting with =
- if (const wchar_t *equal = wcschr(entry + 1, L'=')) {
- int nameLen = equal - entry;
- QString name = QString::fromWCharArray(entry, nameLen);
- QString value = QString::fromWCharArray(equal + 1, entryLen - nameLen - 1);
- env.d->hash.insert(QProcessEnvironmentPrivate::Key(name), value);
- }
- entry += entryLen + 1;
- }
- FreeEnvironmentStringsW(envStrings);
- }
- return env;
-}
-
static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Hash &environment)
{
QByteArray envlist;
@@ -890,4 +891,6 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
return success;
}
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp
index 0254eb984f..d8166014db 100644
--- a/src/corelib/io/qsavefile.cpp
+++ b/src/corelib/io/qsavefile.cpp
@@ -104,13 +104,14 @@ QSaveFilePrivate::~QSaveFilePrivate()
\sa QTextStream, QDataStream, QFileInfo, QDir, QFile, QTemporaryFile
*/
-/*!
- Constructs a new file object with the given \a parent.
-*/
-QSaveFile::QSaveFile(QObject *parent)
- : QFileDevice(*new QSaveFilePrivate, parent)
+#ifdef QT_NO_QOBJECT
+QSaveFile::QSaveFile(const QString &name)
+ : QFileDevice(*new QSaveFilePrivate)
{
+ Q_D(QSaveFile);
+ d->fileName = name;
}
+#else
/*!
Constructs a new file object to represent the file with the given \a name.
*/
@@ -120,6 +121,14 @@ QSaveFile::QSaveFile(const QString &name)
Q_D(QSaveFile);
d->fileName = name;
}
+
+/*!
+ Constructs a new file object with the given \a parent.
+*/
+QSaveFile::QSaveFile(QObject *parent)
+ : QFileDevice(*new QSaveFilePrivate, parent)
+{
+}
/*!
Constructs a new file object with the given \a parent to represent the
file with the specified \a name.
@@ -130,6 +139,7 @@ QSaveFile::QSaveFile(const QString &name, QObject *parent)
Q_D(QSaveFile);
d->fileName = name;
}
+#endif
/*!
Destroys the file object, discarding the saved contents unless commit() was called.
diff --git a/src/corelib/io/qsavefile.h b/src/corelib/io/qsavefile.h
index 10857c27d1..09d6e29272 100644
--- a/src/corelib/io/qsavefile.h
+++ b/src/corelib/io/qsavefile.h
@@ -58,14 +58,18 @@ class QSaveFilePrivate;
class Q_CORE_EXPORT QSaveFile : public QFileDevice
{
+#ifndef QT_NO_QOBJECT
Q_OBJECT
+#endif
Q_DECLARE_PRIVATE(QSaveFile)
public:
explicit QSaveFile(const QString &name);
+#ifndef QT_NO_QOBJECT
explicit QSaveFile(QObject *parent = Q_NULLPTR);
explicit QSaveFile(const QString &name, QObject *parent);
+#endif
~QSaveFile();
QString fileName() const Q_DECL_OVERRIDE;
@@ -84,6 +88,9 @@ protected:
private:
void close() Q_DECL_OVERRIDE;
+#if !QT_CONFIG(translation)
+ static QString tr(const char *string) { return QString::fromLatin1(string); }
+#endif
private:
Q_DISABLE_COPY(QSaveFile)
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index e12da68671..16dab38a60 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -128,7 +128,18 @@ Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_MOVABLE_TYPE);
typedef QHash<QString, QConfFile *> ConfFileHash;
typedef QCache<QString, QConfFile> ConfFileCache;
-typedef QHash<int, QString> PathHash;
+namespace {
+ struct Path
+ {
+ // Note: Defining constructors explicitly because of buggy C++11
+ // implementation in MSVC (uniform initialization).
+ Path() {}
+ Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
+ QString path;
+ bool userDefined; //!< true - user defined, overridden by setPath
+ };
+}
+typedef QHash<int, Path> PathHash;
typedef QVector<QConfFileCustomFormat> CustomFormatVector;
Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
@@ -220,7 +231,7 @@ void QConfFile::clearCache()
// QSettingsPrivate
QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
- : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), spec(0), fallbacks(true),
+ : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), fallbacks(true),
pendingChanges(false), status(QSettings::NoError)
{
}
@@ -228,7 +239,7 @@ QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
: format(format), scope(scope), organizationName(organization), applicationName(application),
- iniCodec(0), spec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
+ iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
{
}
@@ -940,7 +951,7 @@ void QConfFileSettingsPrivate::initFormat()
void QConfFileSettingsPrivate::initAccess()
{
- if (confFiles[spec]) {
+ if (!confFiles.isEmpty()) {
if (format > QSettings::IniFormat) {
if (!readFunc)
setStatus(QSettings::AccessError);
@@ -1070,22 +1081,22 @@ static void initDefaultPaths(QMutexLocker *locker)
const QString programDataFolder = windowsConfigPath(FOLDERID_ProgramData);
# endif
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope),
- roamingAppDataFolder + QDir::separator());
+ Path(roamingAppDataFolder + QDir::separator(), false));
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
- programDataFolder + QDir::separator());
+ Path(programDataFolder + QDir::separator(), false));
#else
const QString userPath = make_user_path();
- pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), userPath);
- pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), systemPath);
+ pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
+ pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
#ifndef Q_OS_MAC
- pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), userPath);
- pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), systemPath);
+ pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
+ pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
#endif
#endif // Q_OS_WIN
}
}
-static QString getPath(QSettings::Format format, QSettings::Scope scope)
+static Path getPath(QSettings::Format format, QSettings::Scope scope)
{
Q_ASSERT((int)QSettings::NativeFormat == 0);
Q_ASSERT((int)QSettings::IniFormat == 1);
@@ -1095,14 +1106,23 @@ static QString getPath(QSettings::Format format, QSettings::Scope scope)
if (pathHash->isEmpty())
initDefaultPaths(&locker);
- QString result = pathHash->value(pathHashKey(format, scope));
- if (!result.isEmpty())
+ Path result = pathHash->value(pathHashKey(format, scope));
+ if (!result.path.isEmpty())
return result;
// fall back on INI path
return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
}
+#if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
+// Note: Suitable only for autotests.
+void Q_AUTOTEST_EXPORT clearDefaultPaths()
+{
+ QMutexLocker locker(&settingsGlobalMutex);
+ pathHashFunc()->clear();
+}
+#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
+
QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QSettings::Scope scope,
const QString &organization,
@@ -1110,7 +1130,6 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
: QSettingsPrivate(format, scope, organization, application),
nextPosition(0x40000000) // big positive number
{
- int i;
initFormat();
QString org = organization;
@@ -1123,22 +1142,43 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QString orgFile = org + extension;
if (scope == QSettings::UserScope) {
- QString userPath = getPath(format, QSettings::UserScope);
+ Path userPath = getPath(format, QSettings::UserScope);
if (!application.isEmpty())
- confFiles[F_User | F_Application].reset(QConfFile::fromName(userPath + appFile, true));
- confFiles[F_User | F_Organization].reset(QConfFile::fromName(userPath + orgFile, true));
+ confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
+ confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
}
- QString systemPath = getPath(format, QSettings::SystemScope);
- if (!application.isEmpty())
- confFiles[F_System | F_Application].reset(QConfFile::fromName(systemPath + appFile, false));
- confFiles[F_System | F_Organization].reset(QConfFile::fromName(systemPath + orgFile, false));
-
- for (i = 0; i < NumConfFiles; ++i) {
- if (confFiles[i]) {
- spec = i;
- break;
+ Path systemPath = getPath(format, QSettings::SystemScope);
+#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
+ // check if the systemPath wasn't overridden by QSettings::setPath()
+ if (!systemPath.userDefined) {
+ // Note: We can't use QStandardPaths::locateAll() as we need all the
+ // possible files (not just the existing ones) and there is no way
+ // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
+ QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
+ // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
+ if (!dirs.isEmpty())
+ dirs.takeFirst();
+ QStringList paths;
+ if (!application.isEmpty()) {
+ paths.reserve(dirs.size() * 2);
+ for (const auto &dir : qAsConst(dirs))
+ paths.append(dir + QLatin1Char('/') + appFile);
+ } else {
+ paths.reserve(dirs.size());
}
+ for (const auto &dir : qAsConst(dirs))
+ paths.append(dir + QLatin1Char('/') + orgFile);
+
+ // Note: No check for existence of files is done intentionaly.
+ for (const auto &path : qAsConst(paths))
+ confFiles.append(QConfFile::fromName(path, false));
+ } else
+#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
+ {
+ if (!application.isEmpty())
+ confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
+ confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
}
initAccess();
@@ -1151,7 +1191,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
{
initFormat();
- confFiles[0].reset(QConfFile::fromName(fileName, true));
+ confFiles.append(QConfFile::fromName(fileName, true));
initAccess();
}
@@ -1162,40 +1202,39 @@ QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
ConfFileHash *usedHash = usedHashFunc();
ConfFileCache *unusedCache = unusedCacheFunc();
- for (int i = 0; i < NumConfFiles; ++i) {
- if (confFiles[i] && !confFiles[i]->ref.deref()) {
- if (confFiles[i]->size == 0) {
- delete confFiles[i].take();
+ for (auto conf_file : qAsConst(confFiles)) {
+ if (!conf_file->ref.deref()) {
+ if (conf_file->size == 0) {
+ delete conf_file;
} else {
if (usedHash)
- usedHash->remove(confFiles[i]->name);
+ usedHash->remove(conf_file->name);
if (unusedCache) {
QT_TRY {
// compute a better size?
- unusedCache->insert(confFiles[i]->name, confFiles[i].data(),
- 10 + (confFiles[i]->originalKeys.size() / 4));
- confFiles[i].take();
+ unusedCache->insert(conf_file->name, conf_file,
+ 10 + (conf_file->originalKeys.size() / 4));
} QT_CATCH(...) {
// out of memory. Do not cache the file.
- delete confFiles[i].take();
+ delete conf_file;
}
} else {
// unusedCache is gone - delete the entry to prevent a memory leak
- delete confFiles[i].take();
+ delete conf_file;
}
}
}
- // prevent the ScopedPointer to deref it again.
- confFiles[i].take();
}
}
void QConfFileSettingsPrivate::remove(const QString &key)
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QSettingsKey theKey(key, caseSensitivity);
QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
QMutexLocker locker(&confFile->mutex);
@@ -1219,10 +1258,12 @@ void QConfFileSettingsPrivate::remove(const QString &key)
void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QSettingsKey theKey(key, caseSensitivity, nextPosition++);
QMutexLocker locker(&confFile->mutex);
confFile->removedKeys.remove(theKey);
@@ -1235,29 +1276,27 @@ bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
ParsedSettingsMap::const_iterator j;
bool found = false;
- for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i].data()) {
- QMutexLocker locker(&confFile->mutex);
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
- if (!confFile->addedKeys.isEmpty()) {
- j = confFile->addedKeys.constFind(theKey);
- found = (j != confFile->addedKeys.constEnd());
- }
- if (!found) {
- ensureSectionParsed(confFile, theKey);
- j = confFile->originalKeys.constFind(theKey);
- found = (j != confFile->originalKeys.constEnd()
- && !confFile->removedKeys.contains(theKey));
- }
+ if (!confFile->addedKeys.isEmpty()) {
+ j = confFile->addedKeys.constFind(theKey);
+ found = (j != confFile->addedKeys.constEnd());
+ }
+ if (!found) {
+ ensureSectionParsed(confFile, theKey);
+ j = confFile->originalKeys.constFind(theKey);
+ found = (j != confFile->originalKeys.constEnd()
+ && !confFile->removedKeys.contains(theKey));
+ }
- if (found && value)
- *value = *j;
+ if (found && value)
+ *value = *j;
- if (found)
- return true;
- if (!fallbacks)
- break;
- }
+ if (found)
+ return true;
+ if (!fallbacks)
+ break;
}
return false;
}
@@ -1270,34 +1309,31 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
QSettingsKey thePrefix(prefix, caseSensitivity);
int startPos = prefix.size();
- for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i].data()) {
- QMutexLocker locker(&confFile->mutex);
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
- if (thePrefix.isEmpty()) {
- ensureAllSectionsParsed(confFile);
- } else {
- ensureSectionParsed(confFile, thePrefix);
- }
-
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->originalKeys)->lowerBound( thePrefix);
- while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
- if (!confFile->removedKeys.contains(j.key()))
- processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
- ++j;
- }
+ if (thePrefix.isEmpty())
+ ensureAllSectionsParsed(confFile);
+ else
+ ensureSectionParsed(confFile, thePrefix);
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->addedKeys)->lowerBound(thePrefix);
- while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ j = const_cast<const ParsedSettingsMap *>(
+ &confFile->originalKeys)->lowerBound( thePrefix);
+ while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ if (!confFile->removedKeys.contains(j.key()))
processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
- ++j;
- }
+ ++j;
+ }
- if (!fallbacks)
- break;
+ j = const_cast<const ParsedSettingsMap *>(
+ &confFile->addedKeys)->lowerBound(thePrefix);
+ while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
+ ++j;
}
+
+ if (!fallbacks)
+ break;
}
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()),
@@ -1307,10 +1343,12 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
void QConfFileSettingsPrivate::clear()
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QMutexLocker locker(&confFile->mutex);
ensureAllSectionsParsed(confFile);
confFile->addedKeys.clear();
@@ -1322,12 +1360,9 @@ void QConfFileSettingsPrivate::sync()
// people probably won't be checking the status a whole lot, so in case of
// error we just try to go on and make the best of it
- for (int i = 0; i < NumConfFiles; ++i) {
- QConfFile *confFile = confFiles[i].data();
- if (confFile) {
- QMutexLocker locker(&confFile->mutex);
- syncConfFile(i);
- }
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
+ syncConfFile(confFile);
}
}
@@ -1338,10 +1373,11 @@ void QConfFileSettingsPrivate::flush()
QString QConfFileSettingsPrivate::fileName() const
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return QString();
- return confFile->name;
+
+ // Note: First config file is always the most specific.
+ return confFiles.at(0)->name;
}
bool QConfFileSettingsPrivate::isWritable() const
@@ -1349,16 +1385,14 @@ bool QConfFileSettingsPrivate::isWritable() const
if (format > QSettings::IniFormat && !writeFunc)
return false;
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return false;
- return confFile->isWritable();
+ return confFiles.at(0)->isWritable();
}
-void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
+void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
{
- QConfFile *confFile = confFiles[confFileNo].data();
bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
/*
@@ -2188,9 +2222,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\list 1
\li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf})
\li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf})
- \li \c{/etc/xdg/MySoft/Star Runner.conf}
- \li \c{/etc/xdg/MySoft.conf}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
\endlist
+ \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
On \macos versions 10.2 and 10.3, these files are used by
default:
@@ -2225,9 +2260,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\list 1
\li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini})
\li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini})
- \li \c{/etc/xdg/MySoft/Star Runner.ini}
- \li \c{/etc/xdg/MySoft.ini}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
\endlist
+ \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
On Windows, the following files are used:
@@ -3380,7 +3416,7 @@ void QSettings::setPath(Format format, Scope scope, const QString &path)
PathHash *pathHash = pathHashFunc();
if (pathHash->isEmpty())
initDefaultPaths(&locker);
- pathHash->insert(pathHashKey(format, scope), path + QDir::separator());
+ pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
}
/*!
diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp
index 0e3520441e..2a08ee2e64 100644
--- a/src/corelib/io/qsettings_mac.cpp
+++ b/src/corelib/io/qsettings_mac.cpp
@@ -211,7 +211,7 @@ static QCFType<CFPropertyListRef> macValue(const QVariant &value)
default:
QString string = QSettingsPrivate::variantToString(value);
if (string.contains(QChar::Null))
- result = string.toUtf8().toCFData();
+ result = std::move(string).toUtf8().toCFData();
else
result = string.toCFString();
}
@@ -419,25 +419,19 @@ QMacSettingsPrivate::QMacSettingsPrivate(QSettings::Scope scope, const QString &
curPos = nextDot + 1;
}
javaPackageName.prepend(domainName.midRef(curPos));
- javaPackageName = javaPackageName.toLower();
+ javaPackageName = std::move(javaPackageName).toLower();
if (curPos == 0)
javaPackageName.prepend(QLatin1String("com."));
suiteId = javaPackageName;
- if (scope == QSettings::SystemScope)
- spec |= F_System;
-
- if (application.isEmpty()) {
- spec |= F_Organization;
- } else {
- javaPackageName += QLatin1Char('.');
- javaPackageName += application;
+ if (!application.isEmpty()) {
+ javaPackageName += QLatin1Char('.') + application;
applicationId = javaPackageName;
}
numDomains = 0;
- for (int i = (spec & F_System) ? 1 : 0; i < 2; ++i) {
- for (int j = (spec & F_Organization) ? 1 : 0; j < 3; ++j) {
+ for (int i = (scope == QSettings::SystemScope) ? 1 : 0; i < 2; ++i) {
+ for (int j = (application.isEmpty()) ? 1 : 0; j < 3; ++j) {
SearchDomain &domain = domains[numDomains++];
domain.userName = (i == 0) ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser;
if (j == 0)
@@ -578,7 +572,7 @@ bool QMacSettingsPrivate::isWritable() const
QString QMacSettingsPrivate::fileName() const
{
QString result;
- if ((spec & F_System) == 0)
+ if (scope == QSettings::UserScope)
result = QDir::homePath();
result += QLatin1String("/Library/Preferences/");
result += QString::fromCFString(domains[0].applicationOrSuiteId);
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index e6d3413bab..639605d8c4 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -236,19 +236,6 @@ public:
QTextCodec *codec);
static QStringList splitArgs(const QString &s, int idx);
- /*
- The numeric values of these enums define their search order. For example,
- F_User | F_Organization is searched before F_System | F_Application,
- because their values are respectively 1 and 2.
- */
- enum {
- F_Application = 0x0,
- F_Organization = 0x1,
- F_User = 0x0,
- F_System = 0x2,
- NumConfFiles = 4
- };
-
QSettings::Format format;
QSettings::Scope scope;
QString organizationName;
@@ -258,7 +245,6 @@ public:
protected:
QStack<QSettingsGroup> groupStack;
QString groupPrefix;
- int spec;
bool fallbacks;
bool pendingChanges;
mutable QSettings::Status status;
@@ -293,7 +279,7 @@ public:
private:
void initFormat();
void initAccess();
- void syncConfFile(int confFileNo);
+ void syncConfFile(QConfFile *confFile);
bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map);
#ifdef Q_OS_MAC
bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const;
@@ -302,7 +288,7 @@ private:
void ensureAllSectionsParsed(QConfFile *confFile) const;
void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const;
- QScopedSharedPointer<QConfFile> confFiles[NumConfFiles];
+ QVector<QConfFile *> confFiles;
QSettings::ReadFunc readFunc;
QSettings::WriteFunc writeFunc;
QString extension;
diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp
index 1c10548cbc..edcae16776 100644
--- a/src/corelib/io/qsettings_win.cpp
+++ b/src/corelib/io/qsettings_win.cpp
@@ -138,21 +138,6 @@ static void mergeKeySets(NameSet *dest, const QStringList &src)
** Wrappers for the insane windows registry API
*/
-static QString errorCodeToString(DWORD errorCode)
-{
- wchar_t *data = 0;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, data, 0, 0);
- QString result = QString::fromWCharArray(data);
-
- if (data != 0)
- LocalFree(data);
-
- if (result.endsWith(QLatin1Char('\n')))
- result.truncate(result.length() - 1);
-
- return result;
-}
-
// Open a key with the specified "perms".
// "access" is to explicitly use the 32- or 64-bit branch.
static HKEY openKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access = 0)
@@ -184,7 +169,7 @@ static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSub
return resultHandle;
//qWarning("QSettings: Failed to create subkey \"%s\": %s",
- // rSubKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ // qPrintable(rSubKey), qPrintable(qt_error_string(int(res))));
return 0;
}
@@ -224,7 +209,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
&numKeys, &maxKeySize, 0, 0, 0);
if (res != ERROR_SUCCESS) {
- qWarning("QSettings: RegQueryInfoKey() failed: %s", errorCodeToString(res).toLatin1().data());
+ qWarning("QSettings: RegQueryInfoKey() failed: %s", qPrintable(qt_error_string(int(res))));
return result;
}
@@ -258,7 +243,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
item = QString::fromWCharArray((const wchar_t *)buff.constData(), l);
if (res != ERROR_SUCCESS) {
- qWarning("QSettings: RegEnumValue failed: %s", errorCodeToString(res).toLatin1().data());
+ qWarning("QSettings: RegEnumValue failed: %s", qPrintable(qt_error_string(int(res))));
continue;
}
if (item.isEmpty())
@@ -313,7 +298,7 @@ static void deleteChildGroups(HKEY parentHandle, REGSAM access = 0)
LONG res = RegDeleteKey(parentHandle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on subkey \"%s\": %s",
- group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(group), qPrintable(qt_error_string(int(res))));
return;
}
}
@@ -613,7 +598,7 @@ QWinSettingsPrivate::~QWinSettingsPrivate()
DWORD res = RegDeleteKey(writeHandle(), reinterpret_cast<const wchar_t *>(emptyKey.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: Failed to delete key \"%s\": %s",
- regList.at(0).key().toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(regList.at(0).key()), qPrintable(qt_error_string(int(res))));
}
}
@@ -652,7 +637,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
LONG res = RegDeleteValue(handle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteValue failed on subkey \"%s\": %s",
- group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(group), qPrintable(qt_error_string(int(res))));
}
}
} else {
@@ -660,7 +645,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on key \"%s\": %s",
- rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(rKey), qPrintable(qt_error_string(int(res))));
}
}
RegCloseKey(handle);
@@ -758,7 +743,7 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
deleteWriteHandleOnExit = false;
} else {
qWarning("QSettings: failed to set subkey \"%s\": %s",
- rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(rKey), qPrintable(qt_error_string(int(res))));
setStatus(QSettings::AccessError);
}
diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp
index 3773b72606..27f0552a31 100644
--- a/src/corelib/io/qstorageinfo.cpp
+++ b/src/corelib/io/qstorageinfo.cpp
@@ -260,7 +260,7 @@ QByteArray QStorageInfo::fileSystemType() const
devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC
path starting with \c \\\\?\\ for local storages (in other words, the volume GUID).
- \sa rootPath()
+ \sa rootPath(), subvolume()
*/
QByteArray QStorageInfo::device() const
{
@@ -268,6 +268,26 @@ QByteArray QStorageInfo::device() const
}
/*!
+ \since 5.9
+ Returns the subvolume name for this volume.
+
+ Some filesystem types allow multiple subvolumes inside one device, which
+ may be mounted in different paths. If the subvolume could be detected, it
+ is returned here. The format of the subvolume name is specific to each
+ filesystem type.
+
+ If this volume was not mounted from a subvolume of a larger filesystem or
+ if the subvolume could not be detected, this function returns an empty byte
+ array.
+
+ \sa device()
+*/
+QByteArray QStorageInfo::subvolume() const
+{
+ return d->subvolume;
+}
+
+/*!
Returns the human-readable name of a filesystem, usually called \c label.
Not all filesystems support this feature. In this case, the value returned by
diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h
index 8941c11a16..e2d9747ceb 100644
--- a/src/corelib/io/qstorageinfo.h
+++ b/src/corelib/io/qstorageinfo.h
@@ -71,6 +71,7 @@ public:
QString rootPath() const;
QByteArray device() const;
+ QByteArray subvolume() const;
QByteArray fileSystemType() const;
QString name() const;
QString displayName() const;
@@ -100,7 +101,7 @@ inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
{
if (first.d == second.d)
return true;
- return first.device() == second.device();
+ return first.device() == second.device() && first.rootPath() == second.rootPath();
}
inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second)
diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h
index a14fa8480a..ec5bb785e3 100644
--- a/src/corelib/io/qstorageinfo_p.h
+++ b/src/corelib/io/qstorageinfo_p.h
@@ -85,6 +85,7 @@ protected:
public:
QString rootPath;
QByteArray device;
+ QByteArray subvolume;
QByteArray fileSystemType;
QString name;
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index ae5c42ffd1..b9c9883609 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -120,6 +120,7 @@ public:
inline QString rootPath() const;
inline QByteArray fileSystemType() const;
inline QByteArray device() const;
+ inline QByteArray options() const;
private:
#if defined(Q_OS_BSD4)
QT_STATFSBUF *stat_buf;
@@ -133,6 +134,7 @@ private:
QByteArray m_rootPath;
QByteArray m_fileSystemType;
QByteArray m_device;
+ QByteArray m_options;
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
FILE *fp;
mntent mnt;
@@ -228,6 +230,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(stat_buf[currentIndex].f_mntfromname);
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
#elif defined(Q_OS_SOLARIS)
static const char pathMounted[] = "/etc/mnttab";
@@ -301,6 +308,7 @@ inline bool QStorageIterator::next()
m_device = data.at(0);
m_rootPath = data.at(1);
m_fileSystemType = data.at(2);
+ m_options = data.at(3);
return true;
}
@@ -320,6 +328,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
+inline QByteArray QStorageIterator::options() const
+{
+ return m_options;
+}
+
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
static const char pathMounted[] = "/etc/mtab";
@@ -363,6 +376,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(mnt.mnt_fsname);
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray(mnt.mnt_opts);
+}
+
#elif defined(Q_OS_HAIKU)
inline QStorageIterator::QStorageIterator()
{
@@ -420,6 +438,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
#else
inline QStorageIterator::QStorageIterator()
@@ -455,7 +478,36 @@ inline QByteArray QStorageIterator::device() const
return QByteArray();
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
+#endif
+
+static QByteArray extractSubvolume(const QStorageIterator &it)
+{
+#ifdef Q_OS_LINUX
+ if (it.fileSystemType() == "btrfs") {
+ const QByteArrayList opts = it.options().split(',');
+ QByteArray id;
+ for (const QByteArray &opt : opts) {
+ static const char subvol[] = "subvol=";
+ static const char subvolid[] = "subvolid=";
+ if (opt.startsWith(subvol))
+ return std::move(opt).mid(strlen(subvol));
+ if (opt.startsWith(subvolid))
+ id = std::move(opt).mid(strlen(subvolid));
+ }
+
+ // if we didn't find the subvolume name, return the subvolume ID
+ return id;
+ }
+#else
+ Q_UNUSED(it);
#endif
+ return QByteArray();
+}
void QStorageInfoPrivate::initRootPath()
{
@@ -483,6 +535,7 @@ void QStorageInfoPrivate::initRootPath()
rootPath = mountDir;
device = it.device();
fileSystemType = fsName;
+ subvolume = extractSubvolume(it);
}
}
}
diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp
index 6e50a8513e..b2bf9fce97 100644
--- a/src/corelib/io/qtemporarydir.cpp
+++ b/src/corelib/io/qtemporarydir.cpp
@@ -305,6 +305,33 @@ QString QTemporaryDir::path() const
}
/*!
+ \since 5.9
+
+ Returns the path name of a file in the temporary directory.
+ Does \e not check if the file actually exists in the directory.
+ Redundant multiple separators or "." and ".." directories in
+ \a fileName are not removed (see QDir::cleanPath()). Absolute
+ paths are not allowed.
+*/
+QString QTemporaryDir::filePath(const QString &fileName) const
+{
+ if (QDir::isAbsolutePath(fileName)) {
+ qWarning("QTemporaryDir::filePath: Absolute paths are not allowed: %s", qUtf8Printable(fileName));
+ return QString();
+ }
+
+ if (!d_ptr->success)
+ return QString();
+
+ QString ret = d_ptr->pathOrError;
+ if (!fileName.isEmpty()) {
+ ret += QLatin1Char('/');
+ ret += fileName;
+ }
+ return ret;
+}
+
+/*!
Returns \c true if the QTemporaryDir is in auto remove
mode. Auto-remove mode will automatically delete the directory from
disk upon destruction. This makes it very easy to create your
diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h
index 2e70d34ae4..3f6b70a2eb 100644
--- a/src/corelib/io/qtemporarydir.h
+++ b/src/corelib/io/qtemporarydir.h
@@ -65,6 +65,7 @@ public:
bool remove();
QString path() const;
+ QString filePath(const QString &fileName) const;
private:
QScopedPointer<QTemporaryDirPrivate> d_ptr;
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 4fdb1505ff..9b565bff9d 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -2547,6 +2547,7 @@ QTextStream &QTextStream::operator<<(double f)
}
uint flags = 0;
+ const QLocale::NumberOptions numberOptions = locale().numberOptions();
if (numberFlags() & ShowBase)
flags |= QLocaleData::ShowBase;
if (numberFlags() & ForceSign)
@@ -2555,12 +2556,18 @@ QTextStream &QTextStream::operator<<(double f)
flags |= QLocaleData::UppercaseBase;
if (numberFlags() & UppercaseDigits)
flags |= QLocaleData::CapitalEorX;
- if (numberFlags() & ForcePoint)
- flags |= QLocaleData::Alternate;
- if (locale() != QLocale::c() && !(locale().numberOptions() & QLocale::OmitGroupSeparator))
+ if (numberFlags() & ForcePoint) {
+ flags |= QLocaleData::ForcePoint;
+
+ // Only for backwards compatibility
+ flags |= QLocaleData::AddTrailingZeroes | QLocaleData::ShowBase;
+ }
+ if (locale() != QLocale::c() && !(numberOptions & QLocale::OmitGroupSeparator))
flags |= QLocaleData::ThousandsGroup;
- if (!(locale().numberOptions() & QLocale::OmitLeadingZeroInExponent))
+ if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
const QLocaleData *dd = d->locale.d->m_data;
QString num = dd->doubleToString(f, d->params.realNumberPrecision, form, -1, flags);
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 3df7070557..9663235a67 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -3182,8 +3182,7 @@ QUrl QUrl::resolved(const QUrl &relative) const
if (!relative.d) return *this;
QUrl t;
- // Compatibility hack (mostly for qtdeclarative) : treat "file:relative.txt" as relative even though QUrl::isRelative() says false
- if (!relative.d->scheme.isEmpty() && (!relative.isLocalFile() || QDir::isAbsolutePath(relative.d->path))) {
+ if (!relative.d->scheme.isEmpty()) {
t = relative;
t.detach();
} else {
@@ -3419,8 +3418,7 @@ QUrl QUrl::adjusted(QUrl::FormattingOptions options) const
QByteArray QUrl::toEncoded(FormattingOptions options) const
{
options &= ~(FullyDecoded | FullyEncoded);
- QString stringForm = toString(options | FullyEncoded);
- return stringForm.toLatin1();
+ return toString(options | FullyEncoded).toLatin1();
}
/*!
@@ -3537,8 +3535,7 @@ QString QUrl::fromAce(const QByteArray &domain)
*/
QByteArray QUrl::toAce(const QString &domain)
{
- QString result = qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/);
- return result.toLatin1();
+ return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/).toLatin1();
}
/*!
diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h
index a554a3b07e..c16825a033 100644
--- a/src/corelib/io/qurl.h
+++ b/src/corelib/io/qurl.h
@@ -69,8 +69,8 @@ public:
Q_DECL_CONSTEXPR inline QUrlTwoFlags(E1 f) : i(f) {}
Q_DECL_CONSTEXPR inline QUrlTwoFlags(E2 f) : i(f) {}
Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlag f) : i(f) {}
- Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E1> f) : i(f.operator int()) {}
- Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E2> f) : i(f.operator int()) {}
+ Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E1> f) : i(f.operator typename QFlags<E1>::Int()) {}
+ Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E2> f) : i(f.operator typename QFlags<E2>::Int()) {}
Q_DECL_CONSTEXPR inline QUrlTwoFlags(Zero = 0) : i(0) {}
inline QUrlTwoFlags &operator&=(int mask) { i &= mask; return *this; }
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp
index 6848a408f6..0c87dd5659 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.cpp
+++ b/src/corelib/itemmodels/qabstractitemmodel.cpp
@@ -2044,7 +2044,7 @@ Qt::DropActions QAbstractItemModel::supportedDropActions() const
Qt::DropActions QAbstractItemModel::supportedDragActions() const
{
Q_D(const QAbstractItemModel);
- if (d->supportedDragActions != -1)
+ if (d->supportedDragActions != Qt::IgnoreAction)
return d->supportedDragActions;
return supportedDropActions();
}
diff --git a/src/corelib/itemmodels/qitemselectionmodel.cpp b/src/corelib/itemmodels/qitemselectionmodel.cpp
index 6390d5f389..6c7101d41f 100644
--- a/src/corelib/itemmodels/qitemselectionmodel.cpp
+++ b/src/corelib/itemmodels/qitemselectionmodel.cpp
@@ -274,8 +274,6 @@ QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &
*/
/*!
- \fn bool QItemSelectionRange::operator<(const QItemSelectionRange &other) const
-
Returns \c true if the selection range is less than the \a other
range given; otherwise returns \c false.
@@ -284,6 +282,33 @@ QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &
class can be used with QMap.
*/
+bool QItemSelectionRange::operator<(const QItemSelectionRange &other) const
+{
+ // ### Qt 6: This is inconsistent with op== and needs to be fixed, nay,
+ // ### removed, but cannot, because it was inline up to and including 5.9
+
+ // Comparing parents will compare the models, but if two equivalent ranges
+ // in two different models have invalid parents, they would appear the same
+ if (other.tl.model() == tl.model()) {
+ // parent has to be calculated, so we only do so once.
+ const QModelIndex topLeftParent = tl.parent();
+ const QModelIndex otherTopLeftParent = other.tl.parent();
+ if (topLeftParent == otherTopLeftParent) {
+ if (other.tl.row() == tl.row()) {
+ if (other.tl.column() == tl.column()) {
+ if (other.br.row() == br.row()) {
+ return br.column() < other.br.column();
+ }
+ return br.row() < other.br.row();
+ }
+ return tl.column() < other.tl.column();
+ }
+ return tl.row() < other.tl.row();
+ }
+ return topLeftParent < otherTopLeftParent;
+ }
+ return tl.model() < other.tl.model();
+}
/*!
\fn bool QItemSelectionRange::isValid() const
diff --git a/src/corelib/itemmodels/qitemselectionmodel.h b/src/corelib/itemmodels/qitemselectionmodel.h
index c22ac6dbe5..2421610bce 100644
--- a/src/corelib/itemmodels/qitemselectionmodel.h
+++ b/src/corelib/itemmodels/qitemselectionmodel.h
@@ -116,30 +116,7 @@ public:
{ return (tl == other.tl && br == other.br); }
inline bool operator!=(const QItemSelectionRange &other) const
{ return !operator==(other); }
- inline bool operator<(const QItemSelectionRange &other) const
- {
- // Comparing parents will compare the models, but if two equivalent ranges
- // in two different models have invalid parents, they would appear the same
- if (other.tl.model() == tl.model()) {
- // parent has to be calculated, so we only do so once.
- const QModelIndex topLeftParent = tl.parent();
- const QModelIndex otherTopLeftParent = other.tl.parent();
- if (topLeftParent == otherTopLeftParent) {
- if (other.tl.row() == tl.row()) {
- if (other.tl.column() == tl.column()) {
- if (other.br.row() == br.row()) {
- return br.column() < other.br.column();
- }
- return br.row() < other.br.row();
- }
- return tl.column() < other.tl.column();
- }
- return tl.row() < other.tl.row();
- }
- return topLeftParent < otherTopLeftParent;
- }
- return tl.model() < other.tl.model();
- }
+ bool operator<(const QItemSelectionRange &other) const;
inline bool isValid() const
{
diff --git a/src/corelib/itemmodels/qstringlistmodel.h b/src/corelib/itemmodels/qstringlistmodel.h
index ff59e0e76c..3bda848f48 100644
--- a/src/corelib/itemmodels/qstringlistmodel.h
+++ b/src/corelib/itemmodels/qstringlistmodel.h
@@ -58,7 +58,7 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex sibling(int row, int column, const QModelIndex &idx) const Q_DECL_OVERRIDE;
- QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index 61d0f2bdf1..0e6ff17b8f 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -88,6 +88,8 @@ win32 {
SOURCES += kernel/qeventdispatcher_win.cpp
HEADERS += kernel/qeventdispatcher_win_p.h
}
+
+ !winrt: LIBS_PRIVATE += -lversion
}
winrt {
@@ -119,8 +121,8 @@ mac {
osx: LIBS_PRIVATE += -framework CoreServices -framework AppKit
- uikit {
- # We need UIKit for UIDevice
+ ios|tvos {
+ # We need UIKit for UIApplication in qeventdispatcher_cf.mm
LIBS_PRIVATE += -framework UIKit
}
@@ -173,6 +175,9 @@ unix|integrity {
SOURCES += kernel/qsharedmemory_android.cpp \
kernel/qsystemsemaphore_android.cpp
}
+
+ # This is needed by QMetaType::typeName array implementation
+ integrity: QMAKE_CXXFLAGS += --pending_instantiations=128
}
vxworks {
diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h
index f92e418ebf..68d9bf180f 100644
--- a/src/corelib/kernel/qabstracteventdispatcher.h
+++ b/src/corelib/kernel/qabstracteventdispatcher.h
@@ -95,7 +95,7 @@ public:
virtual int remainingTime(int timerId) = 0;
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
virtual bool registerEventNotifier(QWinEventNotifier *notifier) = 0;
virtual void unregisterEventNotifier(QWinEventNotifier *notifier) = 0;
#endif
diff --git a/src/corelib/kernel/qcore_foundation.mm b/src/corelib/kernel/qcore_foundation.mm
index 7f591a22c7..56eabc4b8c 100644
--- a/src/corelib/kernel/qcore_foundation.mm
+++ b/src/corelib/kernel/qcore_foundation.mm
@@ -46,6 +46,13 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qrect.h>
+#if QT_CONFIG(timezone) && !defined(QT_NO_SYSTEMLOCALE)
+#include <QtCore/qtimezone.h>
+#include <QtCore/private/qtimezoneprivate_p.h>
+#include <QtCore/private/qcore_mac_p.h>
+#endif
+
+#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
#if defined(QT_PLATFORM_UIKIT)
@@ -321,6 +328,8 @@ NSUUID *QUuid::toNSUUID() const
*/
QUrl QUrl::fromCFURL(CFURLRef url)
{
+ if (!url)
+ return QUrl();
return QUrl(QString::fromCFString(CFURLGetString(url)));
}
@@ -348,6 +357,8 @@ CFURLRef QUrl::toCFURL() const
*/
QUrl QUrl::fromNSURL(const NSURL *url)
{
+ if (!url)
+ return QUrl();
return QUrl(QString::fromNSString([url absoluteString]));
}
@@ -422,6 +433,67 @@ NSDate *QDateTime::toNSDate() const
// ----------------------------------------------------------------------------
+#if QT_CONFIG(timezone) && !defined(QT_NO_SYSTEMLOCALE)
+/*!
+ \since 5.9
+
+ Constructs a new QTimeZone containing a copy of the CFTimeZone \a timeZone.
+
+ \sa toCFTimeZone()
+*/
+QTimeZone QTimeZone::fromCFTimeZone(CFTimeZoneRef timeZone)
+{
+ if (!timeZone)
+ return QTimeZone();
+ return QTimeZone(QString::fromCFString(CFTimeZoneGetName(timeZone)).toLatin1());
+}
+
+/*!
+ \since 5.9
+
+ Creates a CFTimeZone from a QTimeZone. The caller owns the CFTimeZone object
+ and is responsible for releasing it.
+
+ \sa fromCFTimeZone()
+*/
+CFTimeZoneRef QTimeZone::toCFTimeZone() const
+{
+#ifndef QT_NO_DYNAMIC_CAST
+ Q_ASSERT(dynamic_cast<const QMacTimeZonePrivate *>(d.data()));
+#endif
+ const QMacTimeZonePrivate *p = static_cast<const QMacTimeZonePrivate *>(d.data());
+ return reinterpret_cast<CFTimeZoneRef>([p->nsTimeZone() copy]);
+}
+
+/*!
+ \since 5.9
+
+ Constructs a new QTimeZone containing a copy of the NSTimeZone \a timeZone.
+
+ \sa toNSTimeZone()
+*/
+QTimeZone QTimeZone::fromNSTimeZone(const NSTimeZone *timeZone)
+{
+ if (!timeZone)
+ return QTimeZone();
+ return QTimeZone(QString::fromNSString(timeZone.name).toLatin1());
+}
+
+/*!
+ \since 5.9
+
+ Creates an NSTimeZone from a QTimeZone. The NSTimeZone object is autoreleased.
+
+ \sa fromNSTimeZone()
+*/
+NSTimeZone *QTimeZone::toNSTimeZone() const
+{
+ return [static_cast<NSTimeZone *>(toCFTimeZone()) autorelease];
+}
+#endif
+
+// ----------------------------------------------------------------------------
+
/*!
\since 5.8
diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm
index d7e8d4847a..231afb991c 100644
--- a/src/corelib/kernel/qcore_mac_objc.mm
+++ b/src/corelib/kernel/qcore_mac_objc.mm
@@ -47,14 +47,8 @@
#include <qdebug.h>
-#if defined(Q_OS_IOS)
-#import <UIKit/UIKit.h>
-#endif
-
QT_BEGIN_NAMESPACE
-typedef qint16 (*GestaltFunction)(quint32 selector, qint32 *response);
-
// -------------------------------------------------------------------------
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
@@ -87,54 +81,6 @@ QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TY
// -------------------------------------------------------------------------
-QAppleOperatingSystemVersion qt_apple_os_version()
-{
- QAppleOperatingSystemVersion v = {0, 0, 0};
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_8_0) || defined(Q_OS_TVOS) || defined(Q_OS_WATCHOS)
- if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) {
- NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion;
- v.major = osv.majorVersion;
- v.minor = osv.minorVersion;
- v.patch = osv.patchVersion;
- return v;
- }
-#endif
- // Use temporary variables so we can return 0.0.0 (unknown version)
- // in case of an error partway through determining the OS version
- qint32 major = 0, minor = 0, patch = 0;
-#if QT_MAC_DEPLOYMENT_TARGET_BELOW(__MAC_10_10, __IPHONE_8_0)
-#if defined(Q_OS_IOS)
- @autoreleasepool {
- NSArray *parts = [UIDevice.currentDevice.systemVersion componentsSeparatedByString:@"."];
- major = parts.count > 0 ? [[parts objectAtIndex:0] intValue] : 0;
- minor = parts.count > 1 ? [[parts objectAtIndex:1] intValue] : 0;
- patch = parts.count > 2 ? [[parts objectAtIndex:2] intValue] : 0;
- }
-#elif defined(Q_OS_OSX)
- static GestaltFunction pGestalt = 0;
- if (!pGestalt) {
- CFBundleRef b = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreServices"));
- pGestalt = reinterpret_cast<GestaltFunction>(CFBundleGetFunctionPointerForName(b,
- CFSTR("Gestalt")));
- }
- if (!pGestalt)
- return v;
- if (pGestalt('sys1', &major) != 0)
- return v;
- if (pGestalt('sys2', &minor) != 0)
- return v;
- if (pGestalt('sys3', &patch) != 0)
- return v;
-#endif
-#endif
- v.major = major;
- v.minor = minor;
- v.patch = patch;
- return v;
-}
-
-// -------------------------------------------------------------------------
-
QMacAutoReleasePool::QMacAutoReleasePool()
: pool([[NSAutoreleasePool alloc] init])
{
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index cb709f9d4b..d0edef33a2 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -131,12 +131,6 @@ private:
QString string;
};
-typedef struct {
- int major, minor, patch;
-} QAppleOperatingSystemVersion;
-
-QAppleOperatingSystemVersion qt_apple_os_version();
-
#ifdef Q_OS_OSX
Q_CORE_EXPORT QChar qt_mac_qtKey2CocoaKey(Qt::Key key);
Q_CORE_EXPORT Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode);
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index baf140b3b2..e4b1562b8b 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -95,6 +95,11 @@
#endif
#endif // QT_NO_QOBJECT
+#if defined(Q_OS_ANDROID)
+# include <private/qjni_p.h>
+# include <private/qjnihelpers_p.h>
+#endif
+
#ifdef Q_OS_MAC
# include "qcore_mac_p.h"
#endif
@@ -144,11 +149,13 @@ int QCoreApplicationPrivate::app_compile_version = 0x050000; //we don't know exa
bool QCoreApplicationPrivate::setuidAllowed = false;
#if !defined(Q_OS_WIN)
-#ifdef Q_OS_MAC
-QString QCoreApplicationPrivate::macMenuBarName()
+#ifdef Q_OS_DARWIN
+QString QCoreApplicationPrivate::infoDictionaryStringProperty(const QString &propertyName)
{
QString bundleName;
- CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), CFSTR("CFBundleName"));
+ QCFString cfPropertyName = propertyName.toCFString();
+ CFTypeRef string = CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(),
+ cfPropertyName);
if (string)
bundleName = QString::fromCFString(static_cast<CFStringRef>(string));
return bundleName;
@@ -157,8 +164,8 @@ QString QCoreApplicationPrivate::macMenuBarName()
QString QCoreApplicationPrivate::appName() const
{
QString applicationName;
-#ifdef Q_OS_MAC
- applicationName = macMenuBarName();
+#ifdef Q_OS_DARWIN
+ applicationName = infoDictionaryStringProperty(QStringLiteral("CFBundleName"));
#endif
if (applicationName.isEmpty() && argv[0]) {
char *p = strrchr(argv[0], '/');
@@ -167,6 +174,34 @@ QString QCoreApplicationPrivate::appName() const
return applicationName;
}
+QString QCoreApplicationPrivate::appVersion() const
+{
+ QString applicationVersion;
+#ifndef QT_BOOTSTRAPPED
+# ifdef Q_OS_DARWIN
+ applicationVersion = infoDictionaryStringProperty(QStringLiteral("CFBundleVersion"));
+# elif defined(Q_OS_ANDROID)
+ QJNIObjectPrivate context(QtAndroidPrivate::context());
+ if (context.isValid()) {
+ QJNIObjectPrivate pm = context.callObjectMethod(
+ "getPackageManager", "()Landroid/content/pm/PackageManager;");
+ QJNIObjectPrivate pn = context.callObjectMethod<jstring>("getPackageName");
+ if (pm.isValid() && pn.isValid()) {
+ QJNIObjectPrivate packageInfo = pm.callObjectMethod(
+ "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;",
+ pn.object(), 0);
+ if (packageInfo.isValid()) {
+ QJNIObjectPrivate versionName = packageInfo.getObjectField(
+ "versionName", "Ljava/lang/String;");
+ if (versionName.isValid())
+ return versionName.toString();
+ }
+ }
+ }
+# endif
+#endif
+ return applicationVersion;
+}
#endif
QString *QCoreApplicationPrivate::cachedApplicationFilePath = 0;
@@ -323,6 +358,7 @@ uint QCoreApplicationPrivate::attribs =
struct QCoreApplicationData {
QCoreApplicationData() Q_DECL_NOTHROW {
applicationNameSet = false;
+ applicationVersionSet = false;
}
~QCoreApplicationData() {
#ifndef QT_NO_QOBJECT
@@ -338,6 +374,7 @@ struct QCoreApplicationData {
QString application; // application name, initially from argv[0], can then be modified.
QString applicationVersion;
bool applicationNameSet; // true if setApplicationName was called
+ bool applicationVersionSet; // true if setApplicationVersion was called
#if QT_CONFIG(library)
QScopedPointer<QStringList> app_libpaths;
@@ -519,12 +556,10 @@ void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver)
QThread *thr = receiver->thread();
Q_ASSERT_X(currentThread == thr || !thr,
"QCoreApplication::sendEvent",
- QString::fromLatin1("Cannot send events to objects owned by a different thread. "
- "Current thread %1. Receiver '%2' (of type '%3') was created in thread %4")
- .arg(QString::number((quintptr) currentThread, 16))
- .arg(receiver->objectName())
- .arg(QLatin1String(receiver->metaObject()->className()))
- .arg(QString::number((quintptr) thr, 16))
+ QString::asprintf("Cannot send events to objects owned by a different thread. "
+ "Current thread 0x%p. Receiver '%ls' (of type '%s') was created in thread 0x%p",
+ currentThread, qUtf16Printable(receiver->objectName()),
+ receiver->metaObject()->className(), thr)
.toLocal8Bit().data());
Q_UNUSED(currentThread);
Q_UNUSED(thr);
@@ -729,10 +764,13 @@ void QCoreApplicationPrivate::init()
Q_ASSERT_X(!QCoreApplication::self, "QCoreApplication", "there should be only one application object");
QCoreApplication::self = q;
- // Store app name (so it's still available after QCoreApplication is destroyed)
+ // Store app name/version (so they're still available after QCoreApplication is destroyed)
if (!coreappdata()->applicationNameSet)
coreappdata()->application = appName();
+ if (!coreappdata()->applicationVersionSet)
+ coreappdata()->applicationVersion = appVersion();
+
QLoggingRegistry::instance()->init();
#if QT_CONFIG(library)
@@ -2390,6 +2428,29 @@ Q_CORE_EXPORT QString qt_applicationName_noFallback()
\since 4.4
\brief the version of this application
+ If not set, the application version defaults to a platform-specific value
+ determined from the main application executable or package (since Qt 5.9):
+
+ \table
+ \header
+ \li Platform
+ \li Source
+ \row
+ \li Windows (classic desktop)
+ \li PRODUCTVERSION parameter of the VERSIONINFO resource
+ \row
+ \li Universal Windows Platform
+ \li version attribute of the application package manifest
+ \row
+ \li macOS, iOS, tvOS, watchOS
+ \li CFBundleVersion property of the information property list
+ \row
+ \li Android
+ \li android:versionName property of the AndroidManifest.xml manifest element
+ \endtable
+
+ On other platforms, the default is the empty string.
+
\sa applicationName, organizationName, organizationDomain
*/
/*!
@@ -2400,9 +2461,13 @@ Q_CORE_EXPORT QString qt_applicationName_noFallback()
*/
void QCoreApplication::setApplicationVersion(const QString &version)
{
- if (coreappdata()->applicationVersion == version)
+ coreappdata()->applicationVersionSet = !version.isEmpty();
+ QString newVersion = version;
+ if (newVersion.isEmpty() && QCoreApplication::self)
+ newVersion = QCoreApplication::self->d_func()->appVersion();
+ if (coreappdata()->applicationVersion == newVersion)
return;
- coreappdata()->applicationVersion = version;
+ coreappdata()->applicationVersion = newVersion;
#ifndef QT_NO_QOBJECT
if (QCoreApplication::self)
emit QCoreApplication::self->applicationVersionChanged();
@@ -2411,7 +2476,7 @@ void QCoreApplication::setApplicationVersion(const QString &version)
QString QCoreApplication::applicationVersion()
{
- return coreappdata()->applicationVersion;
+ return coreappdata() ? coreappdata()->applicationVersion : QString();
}
#if QT_CONFIG(library)
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index 3601add098..c646786296 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -83,9 +83,10 @@ public:
void init();
QString appName() const;
+ QString appVersion() const;
-#ifdef Q_OS_MAC
- static QString macMenuBarName();
+#ifdef Q_OS_DARWIN
+ static QString infoDictionaryStringProperty(const QString &propertyName);
#endif
static void initLocale();
diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp
index a9ca82c757..50888dd0aa 100644
--- a/src/corelib/kernel/qcoreapplication_win.cpp
+++ b/src/corelib/kernel/qcoreapplication_win.cpp
@@ -51,27 +51,20 @@
#include <ctype.h>
#include <qt_windows.h>
+#ifdef Q_OS_WINRT
+#include <qfunctions_winrt.h>
+#include <wrl.h>
+#include <Windows.ApplicationModel.core.h>
+#include <windows.foundation.h>
+using namespace ABI::Windows::ApplicationModel;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+#endif
+
QT_BEGIN_NAMESPACE
int appCmdShow = 0;
-// GetModuleFileName only exists for MSVC2015 and upwards for WinRT, meaning
-// Windows 10 (Mobile). Hence take the first argument passed to the
-// QCoreApplication contructor for older versions as a fallback on older platforms.
-#if defined(Q_OS_WINRT) && _MSC_VER < 1900
-
-Q_CORE_EXPORT QString qAppFileName()
-{
- return QFileInfo(QCoreApplication::arguments().constFirst()).filePath();
-}
-
-QString QCoreApplicationPrivate::appName() const
-{
- return QFileInfo(QCoreApplication::arguments().constFirst()).baseName();
-}
-
-#else // !(defined(Q_OS_WINRT) && _MSC_VER < 1900)
-
Q_CORE_EXPORT QString qAppFileName() // get application file name
{
// We do MAX_PATH + 2 here, and request with MAX_PATH + 1, so we can handle all paths
@@ -118,7 +111,63 @@ QString QCoreApplicationPrivate::appName() const
return QFileInfo(qAppFileName()).baseName();
}
-#endif // !(defined(Q_OS_WINRT) && _MSC_VER < 1900)
+QString QCoreApplicationPrivate::appVersion() const
+{
+ QString applicationVersion;
+#ifndef QT_BOOTSTRAPPED
+# ifdef Q_OS_WINRT
+ HRESULT hr;
+
+ ComPtr<IPackageStatics> packageFactory;
+ hr = RoGetActivationFactory(
+ HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Package).Get(),
+ IID_PPV_ARGS(&packageFactory));
+ RETURN_IF_FAILED("Failed to create package instance", return QString());
+
+ ComPtr<IPackage> package;
+ packageFactory->get_Current(&package);
+ RETURN_IF_FAILED("Failed to get current application package", return QString());
+
+ ComPtr<IPackageId> packageId;
+ package->get_Id(&packageId);
+ RETURN_IF_FAILED("Failed to get current application package ID", return QString());
+
+ PackageVersion version;
+ packageId->get_Version(&version);
+ RETURN_IF_FAILED("Failed to get current application package version", return QString());
+
+ applicationVersion = QStringLiteral("%1.%2.%3.%4")
+ .arg(version.Major)
+ .arg(version.Minor)
+ .arg(version.Build)
+ .arg(version.Revision);
+# else
+ const QString appFileName = qAppFileName();
+ QVarLengthArray<wchar_t> buffer(appFileName.size() + 1);
+ buffer[appFileName.toWCharArray(buffer.data())] = 0;
+
+ DWORD versionInfoSize = GetFileVersionInfoSize(buffer.data(), nullptr);
+ if (versionInfoSize) {
+ QVarLengthArray<BYTE> info(static_cast<int>(versionInfoSize));
+ if (GetFileVersionInfo(buffer.data(), 0, versionInfoSize, info.data())) {
+ UINT size;
+ DWORD *fi;
+
+ if (VerQueryValue(info.data(), __TEXT("\\"),
+ reinterpret_cast<void **>(&fi), &size) && size) {
+ const VS_FIXEDFILEINFO *verInfo = reinterpret_cast<const VS_FIXEDFILEINFO *>(fi);
+ applicationVersion = QStringLiteral("%1.%2.%3.%4")
+ .arg(HIWORD(verInfo->dwProductVersionMS))
+ .arg(LOWORD(verInfo->dwProductVersionMS))
+ .arg(HIWORD(verInfo->dwProductVersionLS))
+ .arg(LOWORD(verInfo->dwProductVersionLS));
+ }
+ }
+ }
+# endif
+#endif
+ return applicationVersion;
+}
#ifndef Q_OS_WINRT
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index 64e73d23c5..4efc38ac89 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -216,6 +216,7 @@ QT_BEGIN_NAMESPACE
\omitvalue OkRequest
\value TabletEnterProximity Wacom tablet enter proximity event (QTabletEvent), sent to QApplication.
\value TabletLeaveProximity Wacom tablet leave proximity event (QTabletEvent), sent to QApplication.
+ \value TabletTrackingChange The Wacom tablet tracking state has changed (since Qt 5.9).
\omitvalue ThemeChange
\value ThreadChange The object is moved to another thread. This is the last event sent to this object in the previous thread. See QObject::moveToThread().
\value Timer Regular timer events (QTimerEvent).
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index 7e962f816e..ac974ba411 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -284,6 +284,8 @@ public:
Pointer = 218, // QQuickPointerEvent; ### Qt 6: QPointerEvent
+ TabletTrackingChange = 219, // tablet tracking state has changed
+
// 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event
diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp
index 1f554c9f2e..a2ec813f11 100644
--- a/src/corelib/kernel/qdeadlinetimer.cpp
+++ b/src/corelib/kernel/qdeadlinetimer.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2016 Intel Corporation.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -175,9 +181,9 @@ Q_DECL_CONST_FUNCTION static inline QPair<qint64, qint64> toSecsAndNSecs(qint64
*/
/*!
- \fn QDeadlineTimer::QDeadlineTimer(ForeverConstant foreverConstant, Qt::TimerType timerType)
+ \fn QDeadlineTimer::QDeadlineTimer(ForeverConstant forever, Qt::TimerType timerType)
- QDeadlineTimer objects created with parameter \a foreverConstant never expire.
+ QDeadlineTimer objects created with parameter \a forever never expire.
For such objects, remainingTime() will return -1, deadline() will return the
maximum value, and isForever() will return true.
@@ -343,54 +349,6 @@ void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::Time
*/
/*!
- \fn std::chrono::nanoseconds remainingTimeAsDuration() const
-
- Returns a \c{std::chrono::duration} object of type \c{Duration} containing
- the remaining time in this QDeadlineTimer, if it still has time left. If
- the deadline has passed, this returns \c{Duration::zero()}, whereas if the
- object is set to never expire, it returns \c{Duration::max()} (instead of
- -1).
-
- It is not possible to obtain the overdue time for expired timers with this
- function. To do that, see deadline().
-
- \note The overload of this function without template parameter always
- returns milliseconds.
-
- \sa setRemainingTime(), deadline<Clock, Duration>()
-*/
-
-/*!
- \overload
- \fn std::chrono::time_point<Clock, Duration> QDeadlineTimer::deadline() const
-
- Returns the absolute time point for the deadline stored in QDeadlineTimer
- object as a \c{std::chrono::time_point} object. The template parameter
- \c{Clock} is mandatory and indicates which of the C++ timekeeping clocks to
- use as a reference. The value will be in the past if this QDeadlineTimer
- has expired.
-
- If this QDeadlineTimer never expires, this function returns
- \c{std::chrono::time_point<Clock, Duration>::max()}.
-
- This function can be used to calculate the amount of time a timer is
- overdue, by subtracting the current time point of the reference clock, as
- in the following example:
-
- \code
- auto realTimeLeft = std::chrono::nanoseconds::max();
- auto tp = deadline.deadline<std::chrono::steady_clock>();
- if (tp != std::chrono::steady_clock::max())
- realTimeLeft = tp - std::chrono::steady_clock::now();
- \endcode
-
- \note Timers that were created as expired have an indetermine time point in
- the past as their deadline, so the above calculation may not work.
-
- \sa remainingTime(), deadlineNSecs(), setDeadline()
-*/
-
-/*!
\fn bool QDeadlineTimer::isForever() const
Returns true if this QDeadlineTimer object never expires, false otherwise.
@@ -791,6 +749,30 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) Q_DECL_
To subtract times of precision greater than 1 millisecond, use addNSecs().
*/
+/*!
+ \fn void QDeadlineTimer::swap(QDeadlineTimer &other)
+
+ Swaps this deadline timer with the \a other deadline timer.
+ */
+
+/*!
+ \fn QDeadlineTimer & QDeadlineTimer::operator=(std::chrono::time_point<Clock, Duration> deadline_)
+
+ Assigns \a deadline_ to this deadline timer.
+ */
+
+/*!
+ \fn QDeadlineTimer & QDeadlineTimer::operator=(std::chrono::duration<Rep, Period> remaining)
+
+ Sets this deadline timer to the \a remaining time.
+ */
+
+/*!
+ \fn std::chrono::nanoseconds QDeadlineTimer::remainingTimeAsDuration() const
+
+ Returns the time remaining before the deadline.
+ */
+
// the rest of the functions are in qelapsedtimer_xxx.cpp
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qdeadlinetimer.h b/src/corelib/kernel/qdeadlinetimer.h
index aa0f735fcc..ddab0191ad 100644
--- a/src/corelib/kernel/qdeadlinetimer.h
+++ b/src/corelib/kernel/qdeadlinetimer.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2016 Intel Corporation.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm
index 4defae559e..608dea5426 100644
--- a/src/corelib/kernel/qeventdispatcher_cf.mm
+++ b/src/corelib/kernel/qeventdispatcher_cf.mm
@@ -81,7 +81,8 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(RunLoopModeTracker);
#elif defined(Q_OS_WATCHOS)
object:[WKExtension sharedExtension]];
#else
- object:[UIApplication sharedApplication]];
+ // Use performSelector so this can work in an App Extension
+ object:[[UIApplication class] performSelector:@selector(sharedApplication)]];
#endif
}
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index fd9d41647d..74fa2d8d50 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -42,6 +42,7 @@
#include "qcoreapplication.h"
#include <private/qsystemlibrary_p.h>
+#include "qoperatingsystemversion.h"
#include "qpair.h"
#include "qset.h"
#include "qsocketnotifier.h"
@@ -230,7 +231,7 @@ static inline UINT inputTimerMask()
// QTBUG 28513, QTBUG-29097, QTBUG-29435: QS_TOUCH, QS_POINTER became part of
// QS_INPUT in Windows Kit 8. They should not be used when running on pre-Windows 8.
#if WINVER > 0x0601
- if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS8)
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8)
result &= ~(QS_TOUCH | QS_POINTER);
#endif // WINVER > 0x0601
return result;
@@ -1041,4 +1042,11 @@ void QEventDispatcherWin32::sendPostedEvents()
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
}
+HWND QEventDispatcherWin32::internalHwnd()
+{
+ Q_D(QEventDispatcherWin32);
+ createInternalHwnd();
+ return d->internalHwnd;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h
index df1513a43a..423dc5b169 100644
--- a/src/corelib/kernel/qeventdispatcher_win_p.h
+++ b/src/corelib/kernel/qeventdispatcher_win_p.h
@@ -106,6 +106,8 @@ public:
bool event(QEvent *e);
+ HWND internalHwnd();
+
protected:
QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent = 0);
virtual void sendPostedEvents();
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index fe204bbee2..93bc477e7d 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -52,6 +52,18 @@
QT_BEGIN_NAMESPACE
+namespace QtAndroidPrivate {
+ // *Listener virtual function implementations.
+ // Defined out-of-line to pin the vtable/type_info.
+ ActivityResultListener::~ActivityResultListener() {}
+ NewIntentListener::~NewIntentListener() {}
+ ResumePauseListener::~ResumePauseListener() {}
+ void ResumePauseListener::handlePause() {}
+ void ResumePauseListener::handleResume() {}
+ GenericMotionEventListener::~GenericMotionEventListener() {}
+ KeyEventListener::~KeyEventListener() {}
+}
+
static JavaVM *g_javaVM = Q_NULLPTR;
static jobject g_jActivity = Q_NULLPTR;
static jobject g_jService = Q_NULLPTR;
diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h
index 478f62a5c7..62f9358513 100644
--- a/src/corelib/kernel/qjnihelpers_p.h
+++ b/src/corelib/kernel/qjnihelpers_p.h
@@ -65,36 +65,36 @@ namespace QtAndroidPrivate
class Q_CORE_EXPORT ActivityResultListener
{
public:
- virtual ~ActivityResultListener() {}
+ virtual ~ActivityResultListener();
virtual bool handleActivityResult(jint requestCode, jint resultCode, jobject data) = 0;
};
class Q_CORE_EXPORT NewIntentListener
{
public:
- virtual ~NewIntentListener() {}
+ virtual ~NewIntentListener();
virtual bool handleNewIntent(JNIEnv *env, jobject intent) = 0;
};
class Q_CORE_EXPORT ResumePauseListener
{
public:
- virtual ~ResumePauseListener() {}
- virtual void handlePause() {};
- virtual void handleResume() {};
+ virtual ~ResumePauseListener();
+ virtual void handlePause();
+ virtual void handleResume();
};
class Q_CORE_EXPORT GenericMotionEventListener
{
public:
- virtual ~GenericMotionEventListener() {}
+ virtual ~GenericMotionEventListener();
virtual bool handleGenericMotionEvent(jobject event) = 0;
};
class Q_CORE_EXPORT KeyEventListener
{
public:
- virtual ~KeyEventListener() {}
+ virtual ~KeyEventListener();
virtual bool handleKeyEvent(jobject event) = 0;
};
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index 1c540f64c7..e247c48703 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -143,21 +143,17 @@ public:
}
bool operator==(const QArgumentType &other) const
{
- if (_type)
+ if (_type && other._type)
return _type == other._type;
- else if (other._type)
- return false;
else
- return _name == other._name;
+ return name() == other.name();
}
bool operator!=(const QArgumentType &other) const
{
- if (_type)
+ if (_type && other._type)
return _type != other._type;
- else if (other._type)
- return true;
else
- return _name != other._name;
+ return name() != other.name();
}
private:
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 718c42ba55..b75f2ad9dc 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -825,9 +825,91 @@ void QMetaType::registerStreamOperators(int idx, SaveOperator saveOp,
}
#endif // QT_NO_DATASTREAM
+#if defined(Q_COMPILER_CONSTEXPR) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900)
+// We don't officially support constexpr in MSVC 2015, but the limited support it
+// has is enough for the code below.
+
+# define STRINGIFY_TYPE_NAME(MetaTypeName, TypeId, RealName) \
+ #RealName "\0"
+# define CALCULATE_TYPE_LEN(MetaTypeName, TypeId, RealName) \
+ short(sizeof(#RealName)),
+# define MAP_TYPE_ID_TO_IDX(MetaTypeName, TypeId, RealName) \
+ TypeId,
+
+namespace {
+// All type names in one long string.
+constexpr char metaTypeStrings[] = QT_FOR_EACH_STATIC_TYPE(STRINGIFY_TYPE_NAME);
+
+// The sizes of the strings in the metaTypeStrings string (including terminating null)
+constexpr short metaTypeNameSizes[] = {
+ QT_FOR_EACH_STATIC_TYPE(CALCULATE_TYPE_LEN)
+};
+
+// The type IDs, in the order of the metaTypeStrings data
+constexpr short metaTypeIds[] = {
+ QT_FOR_EACH_STATIC_TYPE(MAP_TYPE_ID_TO_IDX)
+};
+
+constexpr int MetaTypeNameCount = sizeof(metaTypeNameSizes) / sizeof(metaTypeNameSizes[0]);
+
+template <typename IntegerSequence> struct MetaTypeOffsets;
+template <int... TypeIds> struct MetaTypeOffsets<QtPrivate::IndexesList<TypeIds...>>
+{
+ // This would have been a lot easier if the meta types that the macro
+ // QT_FOR_EACH_STATIC_TYPE declared were in sorted, ascending order, but
+ // they're not (i.e., the first one declared is QMetaType::Void == 43,
+ // followed by QMetaType::Bool == 1)... As a consequence, we need to use
+ // the C++11 constexpr function calculateOffsetForTypeId below in order to
+ // create the offset array.
+
+ static constexpr int findTypeId(int typeId, int i = 0)
+ {
+ return i >= MetaTypeNameCount ? -1 :
+ metaTypeIds[i] == typeId ? i : findTypeId(typeId, i + 1);
+ }
+
+ static constexpr short calculateOffsetForIdx(int i)
+ {
+ return i < 0 ? -1 :
+ i == 0 ? 0 : metaTypeNameSizes[i - 1] + calculateOffsetForIdx(i - 1);
+ }
+
+ static constexpr short calculateOffsetForTypeId(int typeId)
+ {
+ return calculateOffsetForIdx(findTypeId(typeId));
+#if 0
+ // same as, but this is only valid in C++14:
+ short offset = 0;
+ for (int i = 0; i < MetaTypeNameCount; ++i) {
+ if (metaTypeIds[i] == typeId)
+ return offset;
+ offset += metaTypeNameSizes[i];
+ }
+ return -1;
+#endif
+ }
+
+ short offsets[sizeof...(TypeIds)];
+ constexpr MetaTypeOffsets() : offsets{calculateOffsetForTypeId(TypeIds)...} {}
+
+ const char *operator[](int typeId) const Q_DECL_NOTHROW
+ {
+ short o = offsets[typeId];
+ return o < 0 ? nullptr : metaTypeStrings + o;
+ }
+};
+} // anonymous namespace
+
+constexpr MetaTypeOffsets<QtPrivate::Indexes<QMetaType::HighestInternalId + 1>::Value> metaTypeNames {};
+# undef STRINGIFY_TYPE_NAME
+# undef CALCULATE_TYPE_LEN
+# undef MAP_TYPE_ID_TO_IDX
+#endif
+
/*!
- Returns the type name associated with the given \a typeId, or 0 if no
- matching type was found. The returned pointer must not be deleted.
+ Returns the type name associated with the given \a typeId, or a null
+ pointer if no matching type was found. The returned pointer must not be
+ deleted.
\sa type(), isRegistered(), Type
*/
@@ -837,14 +919,18 @@ const char *QMetaType::typeName(int typeId)
#define QT_METATYPE_TYPEID_TYPENAME_CONVERTER(MetaTypeName, TypeId, RealName) \
case QMetaType::MetaTypeName: return #RealName; break;
- switch (QMetaType::Type(type)) {
- QT_FOR_EACH_STATIC_TYPE(QT_METATYPE_TYPEID_TYPENAME_CONVERTER)
- case QMetaType::UnknownType:
- case QMetaType::User:
- break;
- }
-
- if (Q_UNLIKELY(type < QMetaType::User)) {
+ if (Q_LIKELY(type <= QMetaType::HighestInternalId)) {
+#if defined(Q_COMPILER_CONSTEXPR) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900)
+ return metaTypeNames[typeId];
+#else
+ switch (QMetaType::Type(type)) {
+ QT_FOR_EACH_STATIC_TYPE(QT_METATYPE_TYPEID_TYPENAME_CONVERTER)
+ case QMetaType::UnknownType:
+ case QMetaType::User:
+ break;
+ }
+#endif
+ } else if (Q_UNLIKELY(type < QMetaType::User)) {
return nullptr; // It can happen when someone cast int to QVariant::Type, we should not crash...
}
@@ -1014,7 +1100,7 @@ int QMetaType::registerNormalizedType(const NS(QByteArray) &normalizedTypeName,
normalizedTypeName.size());
int previousSize = 0;
- int previousFlags = 0;
+ QMetaType::TypeFlags::Int previousFlags = 0;
if (idx == UnknownType) {
QWriteLocker locker(customTypesLock());
int posInVector = -1;
@@ -1264,6 +1350,7 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data)
case QMetaType::QJsonDocument:
return false;
case QMetaType::Nullptr:
+ stream << *static_cast<const std::nullptr_t *>(data);
return true;
case QMetaType::Long:
stream << qlonglong(*static_cast<const long *>(data));
@@ -1487,6 +1574,7 @@ bool QMetaType::load(QDataStream &stream, int type, void *data)
case QMetaType::QJsonDocument:
return false;
case QMetaType::Nullptr:
+ stream >> *static_cast<std::nullptr_t *>(data);
return true;
case QMetaType::Long: {
qlonglong l;
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 5a90314735..d88f469e0f 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -1413,17 +1413,17 @@ namespace QtPrivate
static inline const QMetaObject *value() { return Q_NULLPTR; }
};
template<typename T>
- struct MetaObjectForType<T*, typename QEnableIf<IsPointerToTypeDerivedFromQObject<T*>::Value>::Type>
+ struct MetaObjectForType<T*, typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type>
{
static inline const QMetaObject *value() { return &T::staticMetaObject; }
};
template<typename T>
- struct MetaObjectForType<T, typename QEnableIf<IsGadgetHelper<T>::Value>::Type>
+ struct MetaObjectForType<T, typename std::enable_if<IsGadgetHelper<T>::Value>::type>
{
static inline const QMetaObject *value() { return &T::staticMetaObject; }
};
template<typename T>
- struct MetaObjectForType<T, typename QEnableIf<IsQEnumHelper<T>::Value>::Type >
+ struct MetaObjectForType<T, typename std::enable_if<IsQEnumHelper<T>::Value>::type >
{
static inline const QMetaObject *value() { return qt_getEnumMetaObject(T()); }
};
@@ -2009,7 +2009,7 @@ struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
}; \
template<typename T> \
struct MetaTypeSmartPointerHelper<SMART_POINTER<T> , \
- typename QEnableIf<IsPointerToTypeDerivedFromQObject<T*>::Value >::Type> \
+ typename std::enable_if<IsPointerToTypeDerivedFromQObject<T*>::Value>::type> \
{ \
static bool registerConverter(int id) \
{ \
diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h
index dd0bce2645..6f1334d082 100644
--- a/src/corelib/kernel/qmetatype_p.h
+++ b/src/corelib/kernel/qmetatype_p.h
@@ -129,7 +129,7 @@ public:
QMetaType::Constructor constructor;
QMetaType::Destructor destructor;
int size;
- quint32 flags; // same as QMetaType::TypeFlags
+ QMetaType::TypeFlags::Int flags;
const QMetaObject *metaObject;
};
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index b1de62bceb..1b05962c07 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -147,12 +147,13 @@ static inline QMutex *signalSlotLock(const QObject *o)
uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]);
}
-// ### Qt >= 5.6, remove qt_add/removeObject
+#if QT_VERSION < 0x60000
extern "C" Q_CORE_EXPORT void qt_addObject(QObject *)
{}
extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *)
{}
+#endif
struct QConnectionSenderSwitcher {
QObject *receiver;
@@ -754,30 +755,6 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
\sa {Object Trees & Ownership}
*/
-/*!
- \relates QObject
-
- Returns a pointer to the object named \a name that inherits \a
- type and with a given \a parent.
-
- Returns 0 if there is no such child.
-
- \snippet code/src_corelib_kernel_qobject.cpp 0
-*/
-
-void *qt_find_obj_child(QObject *parent, const char *type, const QString &name)
-{
- QObjectList list = parent->children();
- if (list.size() == 0) return 0;
- for (int i = 0; i < list.size(); ++i) {
- QObject *obj = list.at(i);
- if (name == obj->objectName() && obj->inherits(type))
- return obj;
- }
- return 0;
-}
-
-
/*****************************************************************************
QObject member functions
*****************************************************************************/
@@ -835,7 +812,9 @@ QObject::QObject(QObject *parent)
QT_RETHROW;
}
}
+#if QT_VERSION < 0x60000
qt_addObject(this);
+#endif
if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
}
@@ -868,7 +847,9 @@ QObject::QObject(QObjectPrivate &dd, QObject *parent)
QT_RETHROW;
}
}
+#if QT_VERSION < 0x60000
qt_addObject(this);
+#endif
if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
}
@@ -1040,7 +1021,9 @@ QObject::~QObject()
if (!d->children.isEmpty())
d->deleteChildren();
+#if QT_VERSION < 0x60000
qt_removeObject(this);
+#endif
if (Q_UNLIKELY(qtHookData[QHooks::RemoveQObject]))
reinterpret_cast<QHooks::RemoveQObjectCallback>(qtHookData[QHooks::RemoveQObject])(this);
@@ -1651,6 +1634,45 @@ int QObject::startTimer(int interval, Qt::TimerType timerType)
}
/*!
+ \since 5.9
+ \overload
+ \fn int QObject::startTimer(std::chrono::milliseconds time, Qt::TimerType timerType)
+
+ Starts a timer and returns a timer identifier, or returns zero if
+ it could not start a timer.
+
+ A timer event will occur every \a time interval until killTimer()
+ is called. If \a time is equal to \c{std::chrono::duration::zero()},
+ then the timer event occurs once every time there are no more window
+ system events to process.
+
+ The virtual timerEvent() function is called with the QTimerEvent
+ event parameter class when a timer event occurs. Reimplement this
+ function to get timer events.
+
+ If multiple timers are running, the QTimerEvent::timerId() can be
+ used to find out which timer was activated.
+
+ Example:
+
+ \snippet code/src_corelib_kernel_qobject.cpp 8
+
+ Note that QTimer's accuracy depends on the underlying operating system and
+ hardware. The \a timerType argument allows you to customize the accuracy of
+ the timer. See Qt::TimerType for information on the different timer types.
+ Most platforms support an accuracy of 20 milliseconds; some provide more.
+ If Qt is unable to deliver the requested number of timer events, it will
+ silently discard some.
+
+ The QTimer class provides a high-level programming interface with
+ single-shot timers and timer signals instead of events. There is
+ also a QBasicTimer class that is more lightweight than QTimer and
+ less clumsy than using timer IDs directly.
+
+ \sa timerEvent(), killTimer(), QTimer::singleShot()
+*/
+
+/*!
Kills the timer with timer identifier, \a id.
The timer identifier is returned by startTimer() when a timer
@@ -2631,7 +2653,8 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM
call qRegisterMetaType() to register the data type before you
establish the connection.
- \sa disconnect(), sender(), qRegisterMetaType(), Q_DECLARE_METATYPE()
+ \sa disconnect(), sender(), qRegisterMetaType(), Q_DECLARE_METATYPE(),
+ {Differences between String-Based and Functor-Based Connections}
*/
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
@@ -3944,9 +3967,8 @@ QList<QByteArray> QObject::dynamicPropertyNames() const
QObject debugging output routines.
*****************************************************************************/
-static void dumpRecursive(int level, QObject *object)
+static void dumpRecursive(int level, const QObject *object)
{
-#if defined(QT_DEBUG)
if (object) {
QByteArray buf;
buf.fill(' ', level / 2 * 8);
@@ -3975,45 +3997,65 @@ static void dumpRecursive(int level, QObject *object)
dumpRecursive(level+1, children.at(i));
}
}
-#else
- Q_UNUSED(level)
- Q_UNUSED(object)
-#endif
}
/*!
- Dumps a tree of children to the debug output.
+ \overload
+ \obsolete
- This function is useful for debugging, but does nothing if the
- library has been compiled in release mode (i.e. without debugging
- information).
+ Dumps a tree of children to the debug output.
\sa dumpObjectInfo()
*/
void QObject::dumpObjectTree()
{
+ const_cast<const QObject *>(this)->dumpObjectTree();
+}
+
+/*!
+ Dumps a tree of children to the debug output.
+
+ \note before Qt 5.9, this function was not const.
+
+ \sa dumpObjectInfo()
+*/
+
+void QObject::dumpObjectTree() const
+{
dumpRecursive(0, this);
}
/*!
+ \overload
+ \obsolete
+
Dumps information about signal connections, etc. for this object
to the debug output.
- This function is useful for debugging, but does nothing if the
- library has been compiled in release mode (i.e. without debugging
- information).
-
\sa dumpObjectTree()
*/
void QObject::dumpObjectInfo()
{
-#if defined(QT_DEBUG)
+ const_cast<const QObject *>(this)->dumpObjectInfo();
+}
+
+/*!
+ Dumps information about signal connections, etc. for this object
+ to the debug output.
+
+ \note before Qt 5.9, this function was not const.
+
+ \sa dumpObjectTree()
+*/
+
+void QObject::dumpObjectInfo() const
+{
qDebug("OBJECT %s::%s", metaObject()->className(),
objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
- Q_D(QObject);
+ Q_D(const QObject);
QMutexLocker locker(signalSlotLock(this));
// first, look for connections where this object is the sender
@@ -4069,7 +4111,6 @@ void QObject::dumpObjectInfo()
} else {
qDebug(" <None>");
}
-#endif
}
#ifndef QT_NO_USERDATA
@@ -4616,11 +4657,9 @@ void qDeleteInEventHandler(QObject *o)
Overloaded functions can be resolved with help of \l qOverload.
- \note The number of arguments in the signal or slot are limited to 6 if
- the compiler does not support C++11 variadic templates.
+ \sa {Differences between String-Based and Functor-Based Connections}
*/
-
/*!
\fn QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
@@ -4643,7 +4682,7 @@ void qDeleteInEventHandler(QObject *o)
\snippet code/src_corelib_kernel_qobject.cpp 45
- If your compiler support C++11 lambda expressions, you can use them:
+ Lambda expressions can also be used:
\snippet code/src_corelib_kernel_qobject.cpp 46
@@ -4653,9 +4692,6 @@ void qDeleteInEventHandler(QObject *o)
Overloaded functions can be resolved with help of \l qOverload.
- \note If the compiler does not support C++11 variadic templates, the number
- of arguments in the signal or slot are limited to 6, and the functor object
- must not have an overloaded or templated operator().
*/
/*!
@@ -4686,7 +4722,7 @@ void qDeleteInEventHandler(QObject *o)
\snippet code/src_corelib_kernel_qobject.cpp 50
- If your compiler support C++11 lambda expressions, you can use them:
+ Lambda expressions can also be used:
\snippet code/src_corelib_kernel_qobject.cpp 51
@@ -4696,10 +4732,6 @@ void qDeleteInEventHandler(QObject *o)
are still alive when the signal is emitted.
Overloaded functions can be resolved with help of \l qOverload.
-
- \note If the compiler does not support C++11 variadic templates, the number
- of arguments in the signal or slot are limited to 6, and the functor object
- must not have an overloaded or templated operator().
*/
/*!
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 69b70ad6ec..6941c55896 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -55,6 +55,10 @@
#include <QtCore/qobject_impl.h>
+#if QT_HAS_INCLUDE(<chrono>)
+# include <chrono>
+#endif
+
QT_BEGIN_NAMESPACE
@@ -150,6 +154,13 @@ public:
void moveToThread(QThread *thread);
int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
+#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC)
+ Q_ALWAYS_INLINE
+ int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)
+ {
+ return startTimer(int(time.count()), timerType);
+ }
+#endif
void killTimer(int id);
template<typename T>
@@ -250,7 +261,7 @@ public:
//connect to a function pointer (not a member)
template <typename Func1, typename Func2>
- static inline typename QtPrivate::QEnableIf<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::Type
+ static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
{
return connect(sender, signal, sender, slot, Qt::DirectConnection);
@@ -258,8 +269,8 @@ public:
//connect to a function pointer (not a member)
template <typename Func1, typename Func2>
- static inline typename QtPrivate::QEnableIf<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0 &&
- !QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction, QMetaObject::Connection>::Type
+ static inline typename std::enable_if<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0 &&
+ !QtPrivate::FunctionPointer<Func2>::IsPointerToMemberFunction, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
@@ -290,7 +301,7 @@ public:
//connect to a functor
template <typename Func1, typename Func2>
- static inline typename QtPrivate::QEnableIf<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::Type
+ static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
{
return connect(sender, signal, sender, slot, Qt::DirectConnection);
@@ -298,7 +309,7 @@ public:
//connect to a functor, with a "context" object defining in which event loop is going to be executed
template <typename Func1, typename Func2>
- static inline typename QtPrivate::QEnableIf<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::Type
+ static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::type
connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
{
@@ -375,8 +386,12 @@ public:
#endif //Q_QDOC
- void dumpObjectTree();
- void dumpObjectInfo();
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ void dumpObjectTree(); // ### Qt 6: remove
+ void dumpObjectInfo(); // ### Qt 6: remove
+#endif
+ void dumpObjectTree() const;
+ void dumpObjectInfo() const;
#ifndef QT_NO_PROPERTIES
bool setProperty(const char *name, const QVariant &value);
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 5cdbef443b..ea4046df55 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -147,34 +147,8 @@ class QString;
# define QT_TR_FUNCTIONS
#endif
-#if defined(QT_NO_QOBJECT_CHECK)
-/* qmake ignore Q_OBJECT */
-#define Q_OBJECT_CHECK
-#else
-
-/* This is a compile time check that ensures that any class cast with qobject_cast
- actually contains a Q_OBJECT macro. Note: qobject_cast will fail if a QObject
- subclass doesn't contain Q_OBJECT.
-
- In qt_check_for_QOBJECT_macro, we call a dummy templated function with two
- parameters, the first being "this" and the other the target of the qobject
- cast. If the types are not identical, we know that a Q_OBJECT macro is missing.
-
- If you get a compiler error here, make sure that the class you are casting
- to contains a Q_OBJECT macro.
-*/
-
-/* qmake ignore Q_OBJECT */
-#define Q_OBJECT_CHECK \
- template <typename ThisObject> inline void qt_check_for_QOBJECT_macro(const ThisObject &_q_argument) const \
- { int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i + 1; }
-
-template <typename T>
-inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }
-
-template <typename T1, typename T2>
-inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
-#endif // QT_NO_QOBJECT_CHECK
+// ### Qt6: remove
+#define Q_OBJECT_CHECK /* empty, unused since Qt 5.2 */
#if defined(Q_CC_INTEL)
// Cannot redefine the visibility of a method in an exported class
@@ -200,7 +174,6 @@ inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
/* qmake ignore Q_OBJECT */
#define Q_OBJECT \
public: \
- Q_OBJECT_CHECK \
QT_WARNING_PUSH \
Q_OBJECT_NO_OVERRIDE_WARNING \
static const QMetaObject staticMetaObject; \
@@ -267,6 +240,11 @@ private: \
#define Q_SLOT Q_SLOT
#endif //Q_MOC_RUN
+#ifdef Q_CLANG_QDOC
+#undef Q_GADGET
+#define Q_GADGET
+#endif
+
#ifndef QT_NO_META_MACROS
// macro for onaming members
#ifdef METHOD
diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h
index 1768e8ccc6..3f5f2e78bb 100644
--- a/src/corelib/kernel/qobjectdefs_impl.h
+++ b/src/corelib/kernel/qobjectdefs_impl.h
@@ -50,8 +50,6 @@
#pragma qt_sync_stop_processing
#endif
-#include <type_traits>
-
QT_BEGIN_NAMESPACE
@@ -92,14 +90,9 @@ namespace QtPrivate {
explicit ApplyReturnValue(void *data_) : data(data_) {}
};
template<typename T, typename U>
- void operator,(const T &value, const ApplyReturnValue<U> &container) {
- if (container.data)
- *reinterpret_cast<U*>(container.data) = value;
- }
- template<typename T, typename U>
void operator,(T &&value, const ApplyReturnValue<U> &container) {
if (container.data)
- *reinterpret_cast<U*>(container.data) = value;
+ *reinterpret_cast<U *>(container.data) = std::forward<T>(value);
}
template<typename T>
void operator,(T, const ApplyReturnValue<void> &) {}
diff --git a/src/corelib/kernel/qppsobject.cpp b/src/corelib/kernel/qppsobject.cpp
index dd01d48cc0..d58715d12b 100644
--- a/src/corelib/kernel/qppsobject.cpp
+++ b/src/corelib/kernel/qppsobject.cpp
@@ -492,8 +492,7 @@ void QPpsObjectPrivate::encodeObject(pps_encoder_t *encoder, const QVariantMap &
///////////////////////////////////////////////////////////////////////////////
QPpsObject::QPpsObject(const QString &path, QObject *parent)
- : QObject(parent),
- d_ptr(new QPpsObjectPrivate(path))
+ : QObject(*new QPpsObjectPrivate(path), parent)
{
}
diff --git a/src/corelib/kernel/qppsobject_p.h b/src/corelib/kernel/qppsobject_p.h
index 86f4528c93..c7b99c8e42 100644
--- a/src/corelib/kernel/qppsobject_p.h
+++ b/src/corelib/kernel/qppsobject_p.h
@@ -118,7 +118,6 @@ Q_SIGNALS:
void readyRead();
private:
- QScopedPointer<QPpsObjectPrivate> d_ptr;
Q_DECLARE_PRIVATE(QPpsObject)
Q_DISABLE_COPY(QPpsObject)
};
diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp
index 07d4930332..be42a369c2 100644
--- a/src/corelib/kernel/qsharedmemory_win.cpp
+++ b/src/corelib/kernel/qsharedmemory_win.cpp
@@ -64,11 +64,6 @@ void QSharedMemoryPrivate::setErrorString(QLatin1String function)
errorString = QSharedMemory::tr("%1: already exists").arg(function);
break;
case ERROR_FILE_NOT_FOUND:
-#if defined(Q_OS_WINRT) && _MSC_VER < 1900
- // This happens on WinRT only if no file is present as CreateFileMappingW
- // bails out with this error code
- case ERROR_INVALID_PARAMETER:
-#endif
error = QSharedMemory::NotFound;
errorString = QSharedMemory::tr("%1: doesn't exist").arg(function);
break;
@@ -103,16 +98,9 @@ HANDLE QSharedMemoryPrivate::handle()
errorString = QSharedMemory::tr("%1: unable to make key").arg(function);
return 0;
}
-#if defined(Q_OS_WINPHONE)
- Q_UNIMPLEMENTED();
- hand = 0;
-#elif defined(Q_OS_WINRT)
-#if _MSC_VER >= 1900
+#if defined(Q_OS_WINRT)
hand = OpenFileMappingFromApp(FILE_MAP_ALL_ACCESS, FALSE, reinterpret_cast<PCWSTR>(nativeKey.utf16()));
#else
- hand = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, (PCWSTR)nativeKey.utf16());
-#endif
-#else
hand = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, (wchar_t*)nativeKey.utf16());
#endif
if (!hand) {
@@ -144,11 +132,7 @@ bool QSharedMemoryPrivate::create(int size)
}
// Create the file mapping.
-#if defined(Q_OS_WINPHONE)
- Q_UNIMPLEMENTED();
- Q_UNUSED(size)
- hand = 0;
-#elif defined(Q_OS_WINRT)
+#if defined(Q_OS_WINRT)
hand = CreateFileMappingFromApp(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, size, (PCWSTR)nativeKey.utf16());
#else
hand = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, size, (wchar_t*)nativeKey.utf16());
@@ -166,12 +150,7 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
{
// Grab a pointer to the memory block
int permissions = (mode == QSharedMemory::ReadOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS);
-#if defined(Q_OS_WINPHONE)
- Q_UNIMPLEMENTED();
- Q_UNUSED(mode)
- Q_UNUSED(permissions)
- memory = 0;
-#elif defined(Q_OS_WINRT)
+#if defined(Q_OS_WINRT)
memory = (void *)MapViewOfFileFromApp(handle(), permissions, 0, 0);
#else
memory = (void *)MapViewOfFile(handle(), permissions, 0, 0, 0);
@@ -199,15 +178,10 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode)
bool QSharedMemoryPrivate::detach()
{
// umap memory
-#if defined(Q_OS_WINPHONE)
- Q_UNIMPLEMENTED();
- return false;
-#else
if (!UnmapViewOfFile(memory)) {
setErrorString(QLatin1String("QSharedMemory::detach"));
return false;
}
-#endif
memory = 0;
size = 0;
diff --git a/src/corelib/kernel/qsystemsemaphore_systemv.cpp b/src/corelib/kernel/qsystemsemaphore_systemv.cpp
index 1967899a58..83da09da44 100644
--- a/src/corelib/kernel/qsystemsemaphore_systemv.cpp
+++ b/src/corelib/kernel/qsystemsemaphore_systemv.cpp
@@ -72,7 +72,13 @@ QT_BEGIN_NAMESPACE
key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode)
{
if (key.isEmpty()){
- errorString = QCoreApplication::tr("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:"));
+ errorString =
+#if QT_CONFIG(translation)
+ QCoreApplication::tr("%1: key is empty", "QSystemSemaphore")
+#else
+ QString::fromLatin1("%1: key is empty")
+#endif
+ .arg(QLatin1String("QSystemSemaphore::handle:"));
error = QSystemSemaphore::KeyError;
return -1;
}
@@ -84,16 +90,30 @@ key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode)
// Create the file needed for ftok
int built = QSharedMemoryPrivate::createUnixKeyFile(fileName);
if (-1 == built) {
- errorString = QCoreApplication::tr("%1: unable to make key", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:"));
+ errorString =
+#if QT_CONFIG(translation)
+ QCoreApplication::tr("%1: unable to make key", "QSystemSemaphore")
+#else
+ QString::fromLatin1("%1: unable to make key")
+#endif
+ .arg(QLatin1String("QSystemSemaphore::handle:"));
error = QSystemSemaphore::KeyError;
return -1;
}
createdFile = (1 == built);
+#if !defined(QT_NO_SHAREDMEMORY) && !defined(QT_POSIX_IPC) && !defined(Q_OS_ANDROID)
// Get the unix key for the created file
unix_key = qt_safe_ftok(QFile::encodeName(fileName), 'Q');
+#endif
if (-1 == unix_key) {
- errorString = QCoreApplication::tr("%1: ftok failed", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle:"));
+ errorString =
+#if QT_CONFIG(translation)
+ QCoreApplication::tr("%1: ftok failed", "QSystemSemaphore")
+#else
+ QString::fromLatin1("%1: ftok failed")
+#endif
+ .arg(QLatin1String("QSystemSemaphore::handle:"));
error = QSystemSemaphore::KeyError;
return -1;
}
diff --git a/src/corelib/kernel/qtcore_eval.cpp b/src/corelib/kernel/qtcore_eval.cpp
index 787db8a8a6..86992ce10b 100644
--- a/src/corelib/kernel/qtcore_eval.cpp
+++ b/src/corelib/kernel/qtcore_eval.cpp
@@ -207,7 +207,9 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include <qlabel.h>
#include <qlayout.h>
#include <qmessagebox.h>
+#if QT_CONFIG(pushbutton)
#include <qpushbutton.h>
+#endif
#include <qtimer.h>
#include <qapplication.h>
QT_END_INCLUDE_NAMESPACE
diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h
index 9303f82544..6e61ca10cb 100644
--- a/src/corelib/kernel/qtimer.h
+++ b/src/corelib/kernel/qtimer.h
@@ -118,30 +118,30 @@ public:
}
// singleShot to a functor or function pointer (without context)
template <typename Duration, typename Func1>
- static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, void>::Type
+ static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
+ !std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, Func1 slot)
{
singleShot(interval, defaultTypeFor(interval), nullptr, slot);
}
template <typename Duration, typename Func1>
- static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, void>::Type
+ static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
+ !std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, Qt::TimerType timerType, Func1 slot)
{
singleShot(interval, timerType, nullptr, slot);
}
// singleShot to a functor or function pointer (with context)
template <typename Duration, typename Func1>
- static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, void>::Type
+ static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
+ !std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, QObject *context, Func1 slot)
{
singleShot(interval, defaultTypeFor(interval), context, slot);
}
template <typename Duration, typename Func1>
- static inline typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, void>::Type
+ static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
+ !std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, Qt::TimerType timerType, QObject *context, Func1 slot)
{
//compilation error if the slot has arguments.
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 8ad61be8ee..bca3ac9582 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -2916,7 +2916,7 @@ static const quint32 qCanConvertMatrix[QVariant::LastCoreType + 1] =
static const size_t qCanConvertMatrixMaximumTargetType = 8 * sizeof(*qCanConvertMatrix);
#ifndef QT_BOOTSTRAPPED
-/*!
+/*
Returns \c true if from inherits to.
*/
static bool canConvertMetaObject(const QMetaObject *from, const QMetaObject *to)
diff --git a/src/corelib/kernel/qwineventnotifier.h b/src/corelib/kernel/qwineventnotifier.h
index f17fa059a1..f29f325d13 100644
--- a/src/corelib/kernel/qwineventnotifier.h
+++ b/src/corelib/kernel/qwineventnotifier.h
@@ -42,7 +42,7 @@
#include "QtCore/qobject.h"
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/mimetypes/qmimeglobpattern_p.h b/src/corelib/mimetypes/qmimeglobpattern_p.h
index c8b70464fd..21332e71bc 100644
--- a/src/corelib/mimetypes/qmimeglobpattern_p.h
+++ b/src/corelib/mimetypes/qmimeglobpattern_p.h
@@ -83,11 +83,9 @@ public:
static const unsigned MinWeight = 1;
explicit QMimeGlobPattern(const QString &thePattern, const QString &theMimeType, unsigned theWeight = DefaultWeight, Qt::CaseSensitivity s = Qt::CaseInsensitive) :
- m_pattern(thePattern), m_mimeType(theMimeType), m_weight(theWeight), m_caseSensitivity(s)
+ m_pattern(s == Qt::CaseInsensitive ? thePattern.toLower() : thePattern),
+ m_mimeType(theMimeType), m_weight(theWeight), m_caseSensitivity(s)
{
- if (s == Qt::CaseInsensitive) {
- m_pattern = m_pattern.toLower();
- }
}
void swap(QMimeGlobPattern &other) Q_DECL_NOTHROW
diff --git a/src/corelib/mimetypes/qmimetypeparser.cpp b/src/corelib/mimetypes/qmimetypeparser.cpp
index 7693055cc1..20b4461b03 100644
--- a/src/corelib/mimetypes/qmimetypeparser.cpp
+++ b/src/corelib/mimetypes/qmimetypeparser.cpp
@@ -165,7 +165,8 @@ bool QMimeTypeParserBase::parseNumber(const QStringRef &n, int *target, QString
bool ok;
*target = n.toInt(&ok);
if (Q_UNLIKELY(!ok)) {
- *errorMessage = QLatin1String("Not a number '") + n + QLatin1String("'.");
+ if (errorMessage)
+ *errorMessage = QLatin1String("Not a number '") + n + QLatin1String("'.");
return false;
}
return true;
diff --git a/src/corelib/plugin/qelfparser_p.cpp b/src/corelib/plugin/qelfparser_p.cpp
index 85478e376e..7a42b0d023 100644
--- a/src/corelib/plugin/qelfparser_p.cpp
+++ b/src/corelib/plugin/qelfparser_p.cpp
@@ -71,7 +71,7 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (fdlen < 64){
if (lib)
- lib->errorString = QLibrary::tr("'%1' is not an ELF object (%2)").arg(library).arg(QLatin1String("file too small"));
+ lib->errorString = QLibrary::tr("'%1' is not an ELF object (%2)").arg(library, QLibrary::tr("file too small"));
return NotElf;
}
const char *data = dataStart;
@@ -83,7 +83,7 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
// 32 or 64 bit
if (data[4] != 1 && data[4] != 2) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("odd cpu architecture"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("odd cpu architecture"));
return Corrupt;
}
m_bits = (data[4] << 5);
@@ -93,13 +93,13 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
*/
if ((sizeof(void*) == 4 && m_bits != 32) || (sizeof(void*) == 8 && m_bits != 64)) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("wrong cpu architecture"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("wrong cpu architecture"));
return Corrupt;
}
// endian
if (data[5] == 0) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("odd endianness"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("odd endianness"));
return Corrupt;
}
m_endian = (data[5] == 1 ? ElfLittleEndian : ElfBigEndian);
@@ -119,7 +119,7 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (e_shsize > fdlen) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("unexpected e_shsize"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("unexpected e_shsize"));
return Corrupt;
}
@@ -131,7 +131,7 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (e_shentsize % 4){
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library).arg(QLatin1String("unexpected e_shentsize"));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, QLibrary::tr("unexpected e_shentsize"));
return Corrupt;
}
data += sizeof(qelfhalf_t); // e_shentsize
@@ -141,10 +141,12 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
data += sizeof(qelfhalf_t); // e_shtrndx
if ((quint32)(e_shnum * e_shentsize) > fdlen) {
- if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("announced %2 sections, each %3 bytes, exceed file size"))
- .arg(e_shnum).arg(e_shentsize);
+ if (lib) {
+ const QString message =
+ QLibrary::tr("announced %n section(s), each %1 byte(s), exceed file size",
+ nullptr, int(e_shnum)).arg(e_shentsize);
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library, message);
+ }
return Corrupt;
}
@@ -157,9 +159,9 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if ((soff + e_shentsize) > fdlen || soff % 4 || soff == 0) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("shstrtab section header seems to be at %1"))
- .arg(QString::number(soff, 16));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("shstrtab section header seems to be at %1")
+ .arg(QString::number(soff, 16)));
return Corrupt;
}
@@ -168,9 +170,9 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if ((quint32)(m_stringTableFileOffset + e_shentsize) >= fdlen || m_stringTableFileOffset == 0) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("string table seems to be at %1"))
- .arg(QString::number(soff, 16));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("string table seems to be at %1")
+ .arg(QString::number(soff, 16)));
return Corrupt;
}
@@ -190,9 +192,9 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (m_stringTableFileOffset + sh.name > fdlen) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("section name %2 of %3 behind end of file"))
- .arg(i).arg(e_shnum);
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("section name %1 of %2 behind end of file")
+ .arg(i).arg(e_shnum));
return Corrupt;
}
@@ -204,8 +206,8 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (!(sh.type & 0x1)) {
if (shnam[1] == 'r') {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("empty .rodata. not a library."));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("empty .rodata. not a library."));
return Corrupt;
}
#if defined(QELFPARSER_DEBUG)
@@ -217,8 +219,8 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
if (sh.offset == 0 || (sh.offset + sh.size) > fdlen || sh.size < 1) {
if (lib)
- lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)").arg(library)
- .arg(QLatin1String("missing section data. This is not a library."));
+ lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
+ .arg(library, QLibrary::tr("missing section data. This is not a library."));
return Corrupt;
}
*pos = sh.offset;
diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp
index 6c1253ea08..3c4fbaf348 100644
--- a/src/corelib/plugin/qlibrary_unix.cpp
+++ b/src/corelib/plugin/qlibrary_unix.cpp
@@ -242,7 +242,7 @@ bool QLibraryPrivate::load_sys()
}
#endif
if (!pHnd) {
- errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qdlerror());
+ errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName, qdlerror());
}
if (pHnd) {
qualifiedFileName = attempt;
@@ -262,10 +262,10 @@ bool QLibraryPrivate::unload_sys()
char *error = dlerror(); // QtDeclarative auto test "qqmlenginecleanup" for instance
if (!qstrcmp(error, "Shared objects still referenced")) // On QNX that's only "informative"
return true;
- errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName)
- .arg(QLatin1String(error));
+ errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName,
+ QLatin1String(error));
#else
- errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName).arg(qdlerror());
+ errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName, qdlerror());
#endif
return false;
}
@@ -298,7 +298,7 @@ QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol)
#endif
if (!address) {
errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg(
- QString::fromLatin1(symbol)).arg(fileName).arg(qdlerror());
+ QString::fromLatin1(symbol), fileName, qdlerror());
} else {
errorString.clear();
}
diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp
index f11ac6548b..0afce7fcf0 100644
--- a/src/corelib/plugin/quuid.cpp
+++ b/src/corelib/plugin/quuid.cpp
@@ -968,10 +968,10 @@ QUuid QUuid::createUuid()
if (!uuidseed.hasLocalData())
{
int *pseed = new int;
- static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(2);
+ static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
qsrand(*pseed = QDateTime::currentSecsSinceEpoch()
+ quintptr(&pseed)
- + serial.fetchAndAddRelaxed(1));
+ + 2 + serial.fetchAndAddRelaxed(1));
uuidseed.setLocalData(pseed);
}
#else
diff --git a/src/corelib/statemachine/qfinalstate_p.h b/src/corelib/statemachine/qfinalstate_p.h
index 57de703fe9..65598f6c19 100644
--- a/src/corelib/statemachine/qfinalstate_p.h
+++ b/src/corelib/statemachine/qfinalstate_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index d7cdec9aac..1d80da55c9 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -2331,6 +2331,7 @@ void QStateMachinePrivate::unregisterAllTransitions()
unregisterSignalTransition(t);
}
}
+#if QT_CONFIG(qeventtransition)
{
QList<QEventTransition*> transitions = rootState()->findChildren<QEventTransition*>();
for (int i = 0; i < transitions.size(); ++i) {
@@ -2339,6 +2340,7 @@ void QStateMachinePrivate::unregisterAllTransitions()
unregisterEventTransition(t);
}
}
+#endif
}
#if QT_CONFIG(qeventtransition)
diff --git a/src/corelib/thread/qgenericatomic.h b/src/corelib/thread/qgenericatomic.h
index 06bb4bc8f1..5c4c02a2ec 100644
--- a/src/corelib/thread/qgenericatomic.h
+++ b/src/corelib/thread/qgenericatomic.h
@@ -283,7 +283,7 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndRelaxed(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndAndRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
// implement fetchAndAnd on top of testAndSet
T tmp = BaseClass::load(_q_value);
@@ -294,7 +294,7 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndAcquire(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndAndAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
T tmp = BaseClass::fetchAndAndRelaxed(_q_value, operand);
BaseClass::acquireMemoryFence(_q_value);
@@ -302,21 +302,21 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndRelease(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndAndRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::releaseMemoryFence(_q_value);
return BaseClass::fetchAndAndRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndOrdered(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndAndOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::orderedMemoryFence(_q_value);
return BaseClass::fetchAndAndRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrRelaxed(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndOrRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
// implement fetchAndOr on top of testAndSet
T tmp = BaseClass::load(_q_value);
@@ -327,7 +327,7 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrAcquire(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndOrAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
T tmp = BaseClass::fetchAndOrRelaxed(_q_value, operand);
BaseClass::acquireMemoryFence(_q_value);
@@ -335,21 +335,21 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrRelease(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndOrRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::releaseMemoryFence(_q_value);
return BaseClass::fetchAndOrRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrOrdered(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndOrOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::orderedMemoryFence(_q_value);
return BaseClass::fetchAndOrRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorRelaxed(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndXorRelaxed(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
// implement fetchAndXor on top of testAndSet
T tmp = BaseClass::load(_q_value);
@@ -360,7 +360,7 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorAcquire(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndXorAcquire(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
T tmp = BaseClass::fetchAndXorRelaxed(_q_value, operand);
BaseClass::acquireMemoryFence(_q_value);
@@ -368,14 +368,14 @@ template <typename BaseClass> struct QGenericAtomicOps
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorRelease(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndXorRelease(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::releaseMemoryFence(_q_value);
return BaseClass::fetchAndXorRelaxed(_q_value, operand);
}
template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorOrdered(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW
+ T fetchAndXorOrdered(T &_q_value, typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type operand) Q_DECL_NOTHROW
{
BaseClass::orderedMemoryFence(_q_value);
return BaseClass::fetchAndXorRelaxed(_q_value, operand);
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
index 29095f8b51..7e3610f0b3 100644
--- a/src/corelib/thread/qmutex.cpp
+++ b/src/corelib/thread/qmutex.cpp
@@ -266,8 +266,8 @@ bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
/*! \fn bool QMutex::try_lock()
\since 5.8
- This function returns \c true if the lock was obtained; otherwise it
- returns \c false.
+ Attempts to lock the mutex. This function returns \c true if the lock
+ was obtained; otherwise it returns \c false.
This function is provided for compatibility with the Standard Library
concept \c Lockable. It is equivalent to tryLock().
@@ -342,16 +342,23 @@ void QMutex::unlock() Q_DECL_NOTHROW
unlockInternal();
}
+
+/*!
+ \fn bool QMutex::isRecursive() const
+ \since 5.7
+
+ Returns \c true if the mutex is recursive.
+*/
+
bool QBasicMutex::isRecursive() Q_DECL_NOTHROW
{
return QT_PREPEND_NAMESPACE(isRecursive)(d_ptr.loadAcquire());
}
/*!
- \overload
\since 5.7
- Returns \c true if the mutex is recursive
+ Returns \c true if the mutex is recursive.
*/
bool QBasicMutex::isRecursive() const Q_DECL_NOTHROW
{
diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h
index 056ebdeaa5..12987f16c3 100644
--- a/src/corelib/thread/qmutex.h
+++ b/src/corelib/thread/qmutex.h
@@ -54,7 +54,7 @@ class tst_QMutex;
QT_BEGIN_NAMESPACE
-#if !defined(QT_NO_THREAD) && !defined(Q_QDOC)
+#if !defined(QT_NO_THREAD) || defined(Q_CLANG_QDOC)
#ifdef Q_OS_LINUX
# define QT_MUTEX_LOCK_NOEXCEPT Q_DECL_NOTHROW
@@ -189,6 +189,7 @@ private:
class Q_CORE_EXPORT QMutexLocker
{
public:
+#ifndef Q_CLANG_QDOC
inline explicit QMutexLocker(QBasicMutex *m) QT_MUTEX_LOCK_NOEXCEPT
{
Q_ASSERT_X((reinterpret_cast<quintptr>(m) & quintptr(1u)) == quintptr(0),
@@ -200,6 +201,9 @@ public:
val |= 1;
}
}
+#else
+ QMutexLocker(QMutex *) { }
+#endif
inline ~QMutexLocker() { unlock(); }
inline void unlock() Q_DECL_NOTHROW
@@ -240,7 +244,7 @@ private:
quintptr val;
};
-#else // QT_NO_THREAD or Q_QDOC
+#else // QT_NO_THREAD && !Q_CLANG_QDOC
class Q_CORE_EXPORT QMutex
{
@@ -255,7 +259,7 @@ public:
inline void unlock() Q_DECL_NOTHROW {}
inline bool isRecursive() const Q_DECL_NOTHROW { return true; }
-#if QT_HAS_INCLUDE(<chrono>) || defined(Q_QDOC)
+#if QT_HAS_INCLUDE(<chrono>)
template <class Rep, class Period>
inline bool try_lock_for(std::chrono::duration<Rep, Period> duration) Q_DECL_NOTHROW
{
@@ -291,7 +295,7 @@ private:
typedef QMutex QBasicMutex;
-#endif // QT_NO_THREAD or Q_QDOC
+#endif // QT_NO_THREAD && !Q_CLANG_QDOC
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index c08038cf90..0828400733 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -149,6 +149,14 @@ QThreadPrivate::QThreadPrivate(QThreadData *d)
exited(false), returnCode(-1),
stackSize(0), priority(QThread::InheritPriority), data(d)
{
+
+// INTEGRITY doesn't support self-extending stack. The default stack size for
+// a pthread on INTEGRITY is too small so we have to increase the default size
+// to 128K.
+#ifdef Q_OS_INTEGRITY
+ stackSize = 128 * 1024;
+#endif
+
#if defined (Q_OS_WIN)
handle = 0;
# ifndef Q_OS_WINRT
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index 6d00aa42ff..f359d25a73 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -211,25 +211,25 @@ static void clear_thread_data()
}
template <typename T>
-static typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, Qt::HANDLE>::Type to_HANDLE(T id)
+static typename std::enable_if<QTypeInfo<T>::isIntegral, Qt::HANDLE>::type to_HANDLE(T id)
{
return reinterpret_cast<Qt::HANDLE>(static_cast<intptr_t>(id));
}
template <typename T>
-static typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type from_HANDLE(Qt::HANDLE id)
+static typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type from_HANDLE(Qt::HANDLE id)
{
return static_cast<T>(reinterpret_cast<intptr_t>(id));
}
template <typename T>
-static typename QtPrivate::QEnableIf<QTypeInfo<T>::isPointer, Qt::HANDLE>::Type to_HANDLE(T id)
+static typename std::enable_if<QTypeInfo<T>::isPointer, Qt::HANDLE>::type to_HANDLE(T id)
{
return id;
}
template <typename T>
-static typename QtPrivate::QEnableIf<QTypeInfo<T>::isPointer, T>::Type from_HANDLE(Qt::HANDLE id)
+static typename std::enable_if<QTypeInfo<T>::isPointer, T>::type from_HANDLE(Qt::HANDLE id)
{
return static_cast<T>(id);
}
diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp
index 7ce757064f..e45aaec103 100644
--- a/src/corelib/thread/qthreadpool.cpp
+++ b/src/corelib/thread/qthreadpool.cpp
@@ -245,7 +245,8 @@ void QThreadPoolPrivate::startThread(QRunnable *runnable)
{
QScopedPointer <QThreadPoolThread> thread(new QThreadPoolThread(this));
thread->setObjectName(QLatin1String("Thread (pooled)"));
- allThreads.insert(thread.data());
+ Q_ASSERT(!allThreads.contains(thread.data())); // if this assert hits, we have an ABA problem (deleted threads don't get removed here)
+ allThreads.append(thread.data());
++activeThreads;
if (runnable->autoDelete())
@@ -265,7 +266,7 @@ void QThreadPoolPrivate::reset()
while (!allThreads.empty()) {
// move the contents of the set out so that we can iterate without the lock
- QSet<QThreadPoolThread *> allThreadsCopy;
+ QList<QThreadPoolThread *> allThreadsCopy;
allThreadsCopy.swap(allThreads);
locker.unlock();
@@ -315,22 +316,39 @@ void QThreadPoolPrivate::clear()
}
/*!
- \internal
- Searches for \a runnable in the queue, removes it from the queue and
- returns \c true if it was found in the queue
+ \since 5.9
+
+ Attempts to remove the specified \a runnable from the queue if it is not yet started.
+ If the runnable had not been started, returns \c true, and ownership of \a runnable
+ is transferred to the caller (even when \c{runnable->autoDelete() == true}).
+ Otherwise returns \c false.
+
+ \note If \c{runnable->autoDelete() == true}, this function may remove the wrong
+ runnable. This is known as the \l{https://en.wikipedia.org/wiki/ABA_problem}{ABA problem}:
+ the original \a runnable may already have executed and has since been deleted.
+ The memory is re-used for another runnable, which then gets removed instead of
+ the intended one. For this reason, we recommend calling this function only for
+ runnables that are not auto-deleting.
+
+ \sa start(), QRunnable::autoDelete()
*/
-bool QThreadPoolPrivate::stealRunnable(QRunnable *runnable)
+bool QThreadPool::tryTake(QRunnable *runnable)
{
+ Q_D(QThreadPool);
+
if (runnable == 0)
return false;
{
- QMutexLocker locker(&mutex);
- QVector<QPair<QRunnable *, int> >::iterator it = queue.begin();
- QVector<QPair<QRunnable *, int> >::iterator end = queue.end();
+ QMutexLocker locker(&d->mutex);
+
+ auto it = d->queue.begin();
+ auto end = d->queue.end();
while (it != end) {
if (it->first == runnable) {
- queue.erase(it);
+ d->queue.erase(it);
+ if (runnable->autoDelete())
+ --runnable->ref; // undo ++ref in start()
return true;
}
++it;
@@ -348,10 +366,10 @@ bool QThreadPoolPrivate::stealRunnable(QRunnable *runnable)
*/
void QThreadPoolPrivate::stealAndRunRunnable(QRunnable *runnable)
{
- if (!stealRunnable(runnable))
+ Q_Q(QThreadPool);
+ if (!q->tryTake(runnable))
return;
- const bool autoDelete = runnable->autoDelete();
- bool del = autoDelete && !--runnable->ref;
+ const bool del = runnable->autoDelete() && !runnable->ref; // tryTake already deref'ed
runnable->run();
@@ -641,24 +659,23 @@ void QThreadPool::clear()
d->clear();
}
+#if QT_DEPRECATED_SINCE(5, 9)
/*!
\since 5.5
+ \obsolete use tryTake() instead, but note the different deletion rules.
Removes the specified \a runnable from the queue if it is not yet started.
The runnables for which \l{QRunnable::autoDelete()}{runnable->autoDelete()}
returns \c true are deleted.
- \sa start()
+ \sa start(), tryTake()
*/
void QThreadPool::cancel(QRunnable *runnable)
{
- Q_D(QThreadPool);
- if (!d->stealRunnable(runnable))
- return;
- if (runnable->autoDelete() && !--runnable->ref) {
+ if (tryTake(runnable) && runnable->autoDelete() && !runnable->ref) // tryTake already deref'ed
delete runnable;
- }
}
+#endif
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthreadpool.h b/src/corelib/thread/qthreadpool.h
index 0ad63c5ac3..74a8c28fc8 100644
--- a/src/corelib/thread/qthreadpool.h
+++ b/src/corelib/thread/qthreadpool.h
@@ -83,7 +83,12 @@ public:
bool waitForDone(int msecs = -1);
void clear();
+
+#if QT_DEPRECATED_SINCE(5, 9)
+ QT_DEPRECATED_X("use tryTake(), but note the different deletion rules")
void cancel(QRunnable *runnable);
+#endif
+ bool tryTake(QRunnable *runnable) Q_REQUIRED_RESULT;
};
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h
index 5694bc8b10..4a9f9e5cfa 100644
--- a/src/corelib/thread/qthreadpool_p.h
+++ b/src/corelib/thread/qthreadpool_p.h
@@ -82,11 +82,10 @@ public:
void reset();
bool waitForDone(int msecs);
void clear();
- bool stealRunnable(QRunnable *runnable);
void stealAndRunRunnable(QRunnable *runnable);
mutable QMutex mutex;
- QSet<QThreadPoolThread *> allThreads;
+ QList<QThreadPoolThread *> allThreads;
QQueue<QThreadPoolThread *> waitingThreads;
QQueue<QThreadPoolThread *> expiredThreads;
QVector<QPair<QRunnable *, int> > queue;
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 55af7256be..a04536b18b 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -63,6 +63,29 @@ QT_WARNING_POP
static const QArrayData &qt_array_empty = qt_array[0];
static const QArrayData &qt_array_unsharable_empty = qt_array[1];
+static inline size_t calculateBlockSize(size_t &capacity, size_t objectSize, size_t headerSize,
+ uint options)
+{
+ // Calculate the byte size
+ // allocSize = objectSize * capacity + headerSize, but checked for overflow
+ // plus padded to grow in size
+ if (options & QArrayData::Grow) {
+ auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
+ capacity = r.elementCount;
+ return r.size;
+ } else {
+ return qCalculateBlockSize(capacity, objectSize, headerSize);
+ }
+}
+
+static QArrayData *reallocateData(QArrayData *header, size_t allocSize, uint options)
+{
+ header = static_cast<QArrayData *>(::realloc(header, allocSize));
+ if (header)
+ header->capacityReserved = bool(options & QArrayData::CapacityReserved);
+ return header;
+}
+
QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
size_t capacity, AllocationOptions options) Q_DECL_NOTHROW
{
@@ -91,18 +114,7 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
if (headerSize > size_t(MaxAllocSize))
return 0;
- // Calculate the byte size
- // allocSize = objectSize * capacity + headerSize, but checked for overflow
- // plus padded to grow in size
- size_t allocSize;
- if (options & Grow) {
- auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
- capacity = r.elementCount;
- allocSize = r.size;
- } else {
- allocSize = qCalculateBlockSize(capacity, objectSize, headerSize);
- }
-
+ size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));
if (header) {
quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)
@@ -122,6 +134,21 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,
return header;
}
+QArrayData *QArrayData::reallocateUnaligned(QArrayData *data, size_t objectSize, size_t capacity,
+ AllocationOptions options) Q_DECL_NOTHROW
+{
+ Q_ASSERT(data);
+ Q_ASSERT(data->isMutable());
+ Q_ASSERT(!data->ref.isShared());
+
+ size_t headerSize = sizeof(QArrayData);
+ size_t allocSize = calculateBlockSize(capacity, objectSize, headerSize, options);
+ QArrayData *header = static_cast<QArrayData *>(reallocateData(data, allocSize, options));
+ if (header)
+ header->alloc = capacity;
+ return header;
+}
+
void QArrayData::deallocate(QArrayData *data, size_t objectSize,
size_t alignment) Q_DECL_NOTHROW
{
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index 5a369baf08..bc20932cca 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -115,6 +115,9 @@ struct Q_CORE_EXPORT QArrayData
static QArrayData *allocate(size_t objectSize, size_t alignment,
size_t capacity, AllocationOptions options = Default)
Q_DECL_NOTHROW Q_REQUIRED_RESULT;
+ static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize,
+ size_t newCapacity, AllocationOptions newOptions = Default)
+ Q_DECL_NOTHROW Q_REQUIRED_RESULT;
static void deallocate(QArrayData *data, size_t objectSize,
size_t alignment) Q_DECL_NOTHROW;
@@ -222,6 +225,14 @@ struct QTypedArrayData
Q_ALIGNOF(AlignmentDummy), capacity, options));
}
+ static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity,
+ AllocationOptions options = Default)
+ {
+ Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
+ return static_cast<QTypedArrayData *>(QArrayData::reallocateUnaligned(data, sizeof(T),
+ capacity, options));
+ }
+
static void deallocate(QArrayData *data)
{
Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index 6bb8280ca8..ae83e6986e 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -145,7 +145,7 @@ struct QGenericArrayOps
T *const begin = this->begin();
do {
- new (begin + this->size) T();
+ new (begin + this->size) T;
} while (uint(++this->size) != newSize);
}
@@ -411,18 +411,18 @@ struct QArrayOpsSelector
template <class T>
struct QArrayOpsSelector<T,
- typename QEnableIf<
- !QTypeInfo<T>::isComplex && !QTypeInfo<T>::isStatic
- >::Type>
+ typename std::enable_if<
+ !QTypeInfoQuery<T>::isComplex && QTypeInfoQuery<T>::isRelocatable
+ >::type>
{
typedef QPodArrayOps<T> Type;
};
template <class T>
struct QArrayOpsSelector<T,
- typename QEnableIf<
- QTypeInfo<T>::isComplex && !QTypeInfo<T>::isStatic
- >::Type>
+ typename std::enable_if<
+ QTypeInfoQuery<T>::isComplex && QTypeInfoQuery<T>::isRelocatable
+ >::type>
{
typedef QMovableArrayOps<T> Type;
};
diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp
index 9298472305..329cc358d4 100644
--- a/src/corelib/tools/qbytearray.cpp
+++ b/src/corelib/tools/qbytearray.cpp
@@ -541,15 +541,40 @@ static const quint16 crc_tbl[16] = {
Returns the CRC-16 checksum of the first \a len bytes of \a data.
- The checksum is independent of the byte order (endianness).
+ The checksum is independent of the byte order (endianness) and will be
+ calculated accorded to the algorithm published in ISO 3309 (Qt::ChecksumIso3309).
\note This function is a 16-bit cache conserving (16 entry table)
implementation of the CRC-16-CCITT algorithm.
*/
-
quint16 qChecksum(const char *data, uint len)
{
- quint16 crc = 0xffff;
+ return qChecksum(data, len, Qt::ChecksumIso3309);
+}
+
+/*!
+ \relates QByteArray
+ \since 5.9
+
+ Returns the CRC-16 checksum of the first \a len bytes of \a data.
+
+ The checksum is independent of the byte order (endianness) and will
+ be calculated accorded to the algorithm published in \a standard.
+
+ \note This function is a 16-bit cache conserving (16 entry table)
+ implementation of the CRC-16-CCITT algorithm.
+*/
+quint16 qChecksum(const char *data, uint len, Qt::ChecksumType standard)
+{
+ quint16 crc = 0x0000;
+ switch (standard) {
+ case Qt::ChecksumIso3309:
+ crc = 0xffff;
+ break;
+ case Qt::ChecksumItuV41:
+ crc = 0x6363;
+ break;
+ }
uchar c;
const uchar *p = reinterpret_cast<const uchar *>(data);
while (len--) {
@@ -558,7 +583,14 @@ quint16 qChecksum(const char *data, uint len)
c >>= 4;
crc = ((crc >> 4) & 0x0fff) ^ crc_tbl[((crc ^ c) & 15)];
}
- return ~crc & 0xffff;
+ switch (standard) {
+ case Qt::ChecksumIso3309:
+ crc = ~crc;
+ break;
+ case Qt::ChecksumItuV41:
+ break;
+ }
+ return crc & 0xffff;
}
/*!
@@ -663,6 +695,20 @@ QByteArray qCompress(const uchar* data, int nbytes, int compressionLevel)
*/
#ifndef QT_NO_COMPRESS
+namespace {
+struct QByteArrayDataDeleter
+{
+ static inline void cleanup(QTypedArrayData<char> *d)
+ { if (d) QTypedArrayData<char>::deallocate(d); }
+};
+}
+
+static QByteArray invalidCompressedData()
+{
+ qWarning("qUncompress: Input data is corrupted");
+ return QByteArray();
+}
+
QByteArray qUncompress(const uchar* data, int nbytes)
{
if (!data) {
@@ -677,53 +723,29 @@ QByteArray qUncompress(const uchar* data, int nbytes)
ulong expectedSize = uint((data[0] << 24) | (data[1] << 16) |
(data[2] << 8) | (data[3] ));
ulong len = qMax(expectedSize, 1ul);
- QScopedPointer<QByteArray::Data, QScopedPointerPodDeleter> d;
+ const ulong maxPossibleSize = MaxAllocSize - sizeof(QByteArray::Data);
+ if (Q_UNLIKELY(len >= maxPossibleSize)) {
+ // QByteArray does not support that huge size anyway.
+ return invalidCompressedData();
+ }
+
+ QScopedPointer<QByteArray::Data, QByteArrayDataDeleter> d(QByteArray::Data::allocate(expectedSize + 1));
+ if (Q_UNLIKELY(d.data() == nullptr))
+ return invalidCompressedData();
+ d->size = expectedSize;
forever {
ulong alloc = len;
- if (len >= (1u << 31u) - sizeof(QByteArray::Data)) {
- //QByteArray does not support that huge size anyway.
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(d.data(), sizeof(QByteArray::Data) + alloc + 1));
- if (!p) {
- // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS
- qWarning("qUncompress: could not allocate enough memory to uncompress data");
- return QByteArray();
- }
- d.take(); // realloc was successful
- d.reset(p);
- d->offset = sizeof(QByteArrayData);
- d->size = 0; // Shut up valgrind "uninitialized variable" warning
int res = ::uncompress((uchar*)d->data(), &len,
data+4, nbytes-4);
switch (res) {
case Z_OK:
- if (len != alloc) {
- if (len >= (1u << 31u) - sizeof(QByteArray::Data)) {
- //QByteArray does not support that huge size anyway.
- qWarning("qUncompress: Input data is corrupted");
- return QByteArray();
- }
- QByteArray::Data *p = static_cast<QByteArray::Data *>(::realloc(d.data(), sizeof(QByteArray::Data) + len + 1));
- if (!p) {
- // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS
- qWarning("qUncompress: could not allocate enough memory to uncompress data");
- return QByteArray();
- }
- d.take(); // realloc was successful
- d.reset(p);
- }
- d->ref.initializeOwned();
+ Q_ASSERT(len <= alloc);
+ Q_UNUSED(alloc);
d->size = len;
- d->alloc = uint(len) + 1u;
- d->capacityReserved = false;
- d->offset = sizeof(QByteArrayData);
d->data()[len] = 0;
-
{
QByteArrayDataPtr dataPtr = { d.take() };
return QByteArray(dataPtr);
@@ -735,6 +757,17 @@ QByteArray qUncompress(const uchar* data, int nbytes)
case Z_BUF_ERROR:
len *= 2;
+ if (Q_UNLIKELY(len >= maxPossibleSize)) {
+ // QByteArray does not support that huge size anyway.
+ return invalidCompressedData();
+ } else {
+ // grow the block
+ QByteArray::Data *p = QByteArray::Data::reallocateUnaligned(d.data(), len + 1);
+ if (Q_UNLIKELY(p == nullptr))
+ return invalidCompressedData();
+ d.take(); // don't free
+ d.reset(p);
+ }
continue;
case Z_DATA_ERROR:
@@ -1707,19 +1740,8 @@ void QByteArray::reallocData(uint alloc, Data::AllocationOptions options)
Data::deallocate(d);
d = x;
} else {
- size_t blockSize;
- if (options & Data::Grow) {
- auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data));
- blockSize = r.size;
- alloc = uint(r.elementCount);
- } else {
- blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data));
- }
-
- Data *x = static_cast<Data *>(::realloc(d, blockSize));
+ Data *x = Data::reallocateUnaligned(d, alloc, options);
Q_CHECK_PTR(x);
- x->alloc = alloc;
- x->capacityReserved = (options & Data::CapacityReserved) ? 1 : 0;
d = x;
}
}
@@ -4365,12 +4387,41 @@ QByteArray QByteArray::fromHex(const QByteArray &hexEncoded)
*/
QByteArray QByteArray::toHex() const
{
- QByteArray hex(d->size * 2, Qt::Uninitialized);
+ return toHex('\0');
+}
+
+/*! \overload
+ \since 5.9
+
+ Returns a hex encoded copy of the byte array. The hex encoding uses the numbers 0-9 and
+ the letters a-f.
+
+ If \a separator is not '\0', the separator character is inserted between the hex bytes.
+
+ Example:
+ \code
+ QByteArray macAddress = QByteArray::fromHex("123456abcdef");
+ macAddress.toHex(':'); // returns "12:34:56:ab:cd:ef"
+ macAddress.toHex(0); // returns "123456abcdef"
+ \endcode
+
+ \sa fromHex()
+*/
+QByteArray QByteArray::toHex(char separator) const
+{
+ if (!d->size)
+ return QByteArray();
+
+ const int length = separator ? (d->size * 3 - 1) : (d->size * 2);
+ QByteArray hex(length, Qt::Uninitialized);
char *hexData = hex.data();
const uchar *data = (const uchar *)d->data();
- for (int i = 0; i < d->size; ++i) {
- hexData[i*2] = QtMiscUtils::toHexLower(data[i] >> 4);
- hexData[i*2+1] = QtMiscUtils::toHexLower(data[i] & 0xf);
+ for (int i = 0, o = 0; i < d->size; ++i) {
+ hexData[o++] = QtMiscUtils::toHexLower(data[i] >> 4);
+ hexData[o++] = QtMiscUtils::toHexLower(data[i] & 0xf);
+
+ if ((separator) && (o < length))
+ hexData[o++] = separator;
}
return hex;
}
diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h
index 477402d6de..06a50e5990 100644
--- a/src/corelib/tools/qbytearray.h
+++ b/src/corelib/tools/qbytearray.h
@@ -105,8 +105,8 @@ Q_CORE_EXPORT int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap);
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt, ...);
// qChecksum: Internet checksum
-
-Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len);
+Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len); // ### Qt 6: Remove
+Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len, Qt::ChecksumType standard); // ### Qt 6: Use Qt::ChecksumType standard = Qt::ChecksumIso3309
class QByteRef;
class QString;
@@ -140,8 +140,6 @@ struct QByteArrayDataPtr
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QByteArrayData)) \
/**/
-#if defined(Q_COMPILER_LAMBDA)
-
# define QByteArrayLiteral(str) \
([]() -> QByteArray { \
enum { Size = sizeof(str) - 1 }; \
@@ -154,14 +152,6 @@ struct QByteArrayDataPtr
}()) \
/**/
-#endif
-
-#ifndef QByteArrayLiteral
-// no lambdas, not GCC, just return a temporary QByteArray
-
-# define QByteArrayLiteral(str) QByteArray(str, sizeof(str) - 1)
-#endif
-
class Q_CORE_EXPORT QByteArray
{
private:
@@ -252,7 +242,7 @@ public:
void truncate(int pos);
void chop(int n);
-#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
+#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
# if defined(Q_CC_GNU)
// required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941
# pragma push_macro("Q_REQUIRED_RESULT")
@@ -357,6 +347,7 @@ public:
QByteArray toBase64(Base64Options options) const;
QByteArray toBase64() const; // ### Qt6 merge with previous
QByteArray toHex() const;
+ QByteArray toHex(char separator) const; // ### Qt6 merge with previous
QByteArray toPercentEncoding(const QByteArray &exclude = QByteArray(),
const QByteArray &include = QByteArray(),
char percent = '%') const;
diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp
index d06ca1292a..76af726ef9 100644
--- a/src/corelib/tools/qbytearraymatcher.cpp
+++ b/src/corelib/tools/qbytearraymatcher.cpp
@@ -323,4 +323,112 @@ int qFindByteArray(
return -1;
}
+/*!
+ \class QStaticByteArrayMatcherBase
+ \since 5.9
+ \internal
+ \brief Non-template base class of QStaticByteArrayMatcher.
+*/
+
+/*!
+ \class QStaticByteArrayMatcher
+ \since 5.9
+ \inmodule QtCore
+ \brief The QStaticByteArrayMatcher class is a compile-time version of QByteArrayMatcher
+
+ \ingroup tools
+ \ingroup string-processing
+
+ This class is useful when you have a sequence of bytes that you
+ want to repeatedly match against some byte arrays (perhaps in a
+ loop), or when you want to search for the same sequence of bytes
+ multiple times in the same byte array. Using a matcher object and
+ indexIn() is faster than matching a plain QByteArray with
+ QByteArray::indexOf(), in particular if repeated matching takes place.
+
+ Unlike QByteArrayMatcher, this class calculates the internal
+ representation at \e{compile-time}, if your compiler supports
+ C++14-level \c{constexpr} (C++11 is not sufficient), so it can
+ even benefit if you are doing one-off byte array matches.
+
+ Create the QStaticByteArrayMatcher by calling qMakeStaticByteArrayMatcher(),
+ passing it the C string literal you want to search for. Store the return
+ value of that function in a \c{static const auto} variable, so you don't need
+ to pass the \c{N} template parameter explicitly:
+
+ \code
+ static const auto matcher = qMakeStaticByteArrayMatcher("needle");
+ \endcode
+
+ Then call indexIn() on the QByteArray in which you want to search, just like
+ with QByteArrayMatcher.
+
+ Since this class is designed to do all the up-front calculations at compile-time,
+ it does not offer a setPattern() method.
+
+ \sa QByteArrayMatcher, QStringMatcher
+*/
+
+/*!
+ \fn int QStaticByteArrayMatcher::indexIn(const char *haystack, int hlen, int from = 0) const
+
+ Searches the char string \a haystack, which has length \a hlen, from
+ byte position \a from (default 0, i.e. from the first byte), for
+ the byte array pattern() that was set in the constructor.
+
+ Returns the position where the pattern() matched in \a haystack, or -1 if no match was found.
+*/
+
+/*!
+ \fn int QStaticByteArrayMatcher::indexIn(const QByteArray &haystack, int from = 0) const
+
+ Searches the char string \a haystack, from byte position \a from
+ (default 0, i.e. from the first byte), for the byte array pattern()
+ that was set in the constructor.
+
+ Returns the position where the pattern() matched in \a haystack, or -1 if no match was found.
+*/
+
+/*!
+ \fn QByteArray QStaticByteArrayMatcher::pattern() const
+
+ Returns the byte array pattern that this byte array matcher will
+ search for.
+
+ \sa setPattern()
+*/
+
+/*!
+ \internal
+*/
+int QStaticByteArrayMatcherBase::indexOfIn(const char *needle, uint nlen, const char *haystack, int hlen, int from) const Q_DECL_NOTHROW
+{
+ if (from < 0)
+ from = 0;
+ return bm_find(reinterpret_cast<const uchar *>(haystack), hlen, from,
+ reinterpret_cast<const uchar *>(needle), nlen, m_skiptable.data);
+}
+
+/*!
+ \fn QStaticByteArrayMatcher::QStaticByteArrayMatcher(const char (&pattern)[N])
+ \internal
+*/
+
+/*!
+ \fn qMakeStaticByteArrayMatcher(const char (&pattern)[N])
+ \since 5.9
+ \relates QStaticByteArrayMatcher
+
+ Return a QStaticByteArrayMatcher with the correct \c{N} determined
+ automatically from the \a pattern passed.
+
+ To take full advantage of this function, assign the result to an
+ \c{auto} variable:
+
+ \code
+ static const auto matcher = qMakeStaticByteArrayMatcher("needle");
+ \endcode
+*/
+
+
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qbytearraymatcher.h b/src/corelib/tools/qbytearraymatcher.h
index aac62715a1..c1c0c3a660 100644
--- a/src/corelib/tools/qbytearraymatcher.h
+++ b/src/corelib/tools/qbytearraymatcher.h
@@ -83,6 +83,87 @@ private:
};
};
+class QStaticByteArrayMatcherBase
+{
+ Q_DECL_ALIGN(16)
+ struct Skiptable {
+ uchar data[256];
+ } m_skiptable;
+protected:
+ explicit Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcherBase(const char *pattern, uint n) Q_DECL_NOTHROW
+ : m_skiptable(generate(pattern, n)) {}
+ // compiler-generated copy/more ctors/assignment operators are ok!
+ // compiler-generated dtor is ok!
+
+ Q_CORE_EXPORT int indexOfIn(const char *needle, uint nlen, const char *haystack, int hlen, int from) const Q_DECL_NOTHROW;
+
+private:
+ static Q_DECL_RELAXED_CONSTEXPR Skiptable generate(const char *pattern, uint n) Q_DECL_NOTHROW
+ {
+ const auto uchar_max = (std::numeric_limits<uchar>::max)();
+ uchar max = n > uchar_max ? uchar_max : n;
+ Skiptable table = {
+ // this verbose initialization code aims to avoid some opaque error messages
+ // even on powerful compilers such as GCC 5.3. Even though for GCC a loop
+ // format can be found that v5.3 groks, it's probably better to go with this
+ // for the time being:
+ {
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ max, max, max, max, max, max, max, max, max, max, max, max, max, max, max, max,
+ }
+ };
+ pattern += n - max;
+ while (max--)
+ table.data[uchar(*pattern++)] = max;
+ return table;
+ }
+};
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_MSVC(4351) // MSVC 2013: "new behavior: elements of array ... will be default initialized"
+ // remove once we drop MSVC 2013 support
+template <uint N>
+class QStaticByteArrayMatcher : QStaticByteArrayMatcherBase
+{
+ char m_pattern[N];
+ Q_STATIC_ASSERT_X(N > 2, "QStaticByteArrayMatcher makes no sense for finding a single-char pattern");
+public:
+ explicit Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcher(const char (&patternToMatch)[N]) Q_DECL_NOTHROW
+ : QStaticByteArrayMatcherBase(patternToMatch, N - 1), m_pattern()
+ {
+ for (uint i = 0; i < N; ++i)
+ m_pattern[i] = patternToMatch[i];
+ }
+
+ int indexIn(const QByteArray &haystack, int from = 0) const Q_DECL_NOTHROW
+ { return this->indexOfIn(m_pattern, N - 1, haystack.data(), haystack.size(), from); }
+ int indexIn(const char *haystack, int hlen, int from = 0) const Q_DECL_NOTHROW
+ { return this->indexOfIn(m_pattern, N - 1, haystack, hlen, from); }
+
+ QByteArray pattern() const { return QByteArray(m_pattern, int(N - 1)); }
+};
+
+QT_WARNING_POP
+
+template <uint N>
+Q_DECL_RELAXED_CONSTEXPR QStaticByteArrayMatcher<N> qMakeStaticByteArrayMatcher(const char (&pattern)[N]) Q_DECL_NOTHROW
+{ return QStaticByteArrayMatcher<N>(pattern); }
+
QT_END_NAMESPACE
#endif // QBYTEARRAYMATCHER_H
diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp
index 5f918aab0f..1d3293e85e 100644
--- a/src/corelib/tools/qchar.cpp
+++ b/src/corelib/tools/qchar.cpp
@@ -101,7 +101,7 @@ QT_BEGIN_NAMESPACE
In Qt, Unicode characters are 16-bit entities without any markup
or structure. This class represents such an entity. It is
lightweight, so it can be used everywhere. Most compilers treat
- it like a \c{unsigned short}.
+ it like an \c{unsigned short}.
QChar provides a full complement of testing/classification
functions, converting to and from other formats, converting from
@@ -424,7 +424,7 @@ QT_BEGIN_NAMESPACE
\enum QChar::Direction
This enum type defines the Unicode direction attributes. See the
- \l{http://www.unicode.org/}{Unicode Standard} for a description
+ \l{http://www.unicode.org/reports/tr9/tr9-35.html#Table_Bidirectional_Character_Types}{Unicode Standard} for a description
of the values.
In order to conform to C/C++ naming conventions "Dir" is prepended
diff --git a/src/corelib/tools/qcollator.h b/src/corelib/tools/qcollator.h
index 5ff74fd69a..d81c7c85e3 100644
--- a/src/corelib/tools/qcollator.h
+++ b/src/corelib/tools/qcollator.h
@@ -69,7 +69,7 @@ public:
protected:
QCollatorSortKey(QCollatorSortKeyPrivate*);
- QSharedDataPointer<QCollatorSortKeyPrivate> d;
+ QExplicitlySharedDataPointer<QCollatorSortKeyPrivate> d;
private:
QCollatorSortKey();
diff --git a/src/corelib/tools/qcollator_icu.cpp b/src/corelib/tools/qcollator_icu.cpp
index 1e94798c5b..ad98a187c5 100644
--- a/src/corelib/tools/qcollator_icu.cpp
+++ b/src/corelib/tools/qcollator_icu.cpp
@@ -39,6 +39,7 @@
****************************************************************************/
#include "qcollator_p.h"
+#include "qlocale_p.h"
#include "qstringlist.h"
#include "qstring.h"
@@ -56,7 +57,7 @@ void QCollatorPrivate::init()
cleanup();
UErrorCode status = U_ZERO_ERROR;
- QByteArray name = locale.bcp47Name().replace(QLatin1Char('-'), QLatin1Char('_')).toLatin1();
+ QByteArray name = QLocalePrivate::get(locale)->bcp47Name('_');
collator = ucol_open(name.constData(), &status);
if (U_FAILURE(status)) {
qWarning("Could not create collator: %d", status);
@@ -144,7 +145,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
string.size(), (uint8_t *)result.data(), result.size());
}
result.truncate(size);
- return QCollatorSortKey(new QCollatorSortKeyPrivate(result));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(result)));
}
return QCollatorSortKey(new QCollatorSortKeyPrivate(QByteArray()));
diff --git a/src/corelib/tools/qcollator_macx.cpp b/src/corelib/tools/qcollator_macx.cpp
index b4d93e58d4..d468272430 100644
--- a/src/corelib/tools/qcollator_macx.cpp
+++ b/src/corelib/tools/qcollator_macx.cpp
@@ -38,9 +38,12 @@
****************************************************************************/
#include "qcollator_p.h"
+#include "qlocale_p.h"
#include "qstringlist.h"
#include "qstring.h"
+
#include <QtCore/private/qcore_mac_p.h>
+
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFLocale.h>
@@ -53,7 +56,7 @@ void QCollatorPrivate::init()
{
cleanup();
LocaleRef localeRef;
- int rc = LocaleRefFromLocaleString(locale.bcp47Name().toLocal8Bit(), &localeRef);
+ int rc = LocaleRefFromLocaleString(QLocalePrivate::get(locale)->bcp47Name().constData(), &localeRef);
if (rc != 0)
qWarning("couldn't initialize the locale");
@@ -128,7 +131,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
ret.size(), &actualSize, ret.data());
}
ret[actualSize] = 0;
- return QCollatorSortKey(new QCollatorSortKeyPrivate(ret));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(ret)));
}
int QCollatorSortKey::compare(const QCollatorSortKey &key) const
diff --git a/src/corelib/tools/qcollator_p.h b/src/corelib/tools/qcollator_p.h
index 423ba0325a..c03a3431db 100644
--- a/src/corelib/tools/qcollator_p.h
+++ b/src/corelib/tools/qcollator_p.h
@@ -85,7 +85,7 @@ typedef QVector<wchar_t> CollatorKeyType;
typedef int CollatorType;
#endif
-class Q_CORE_EXPORT QCollatorPrivate
+class QCollatorPrivate
{
public:
QAtomicInt ref;
@@ -127,13 +127,14 @@ private:
Q_DISABLE_COPY(QCollatorPrivate)
};
-class Q_CORE_EXPORT QCollatorSortKeyPrivate : public QSharedData
+class QCollatorSortKeyPrivate : public QSharedData
{
friend class QCollator;
public:
- QCollatorSortKeyPrivate(const CollatorKeyType &key)
+ template <typename...T>
+ explicit QCollatorSortKeyPrivate(T &&...args)
: QSharedData()
- , m_key(key)
+ , m_key(std::forward<T>(args)...)
{
}
diff --git a/src/corelib/tools/qcollator_posix.cpp b/src/corelib/tools/qcollator_posix.cpp
index da424970e6..42413a4a82 100644
--- a/src/corelib/tools/qcollator_posix.cpp
+++ b/src/corelib/tools/qcollator_posix.cpp
@@ -110,7 +110,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
}
result.resize(size+1);
result[size] = 0;
- return QCollatorSortKey(new QCollatorSortKeyPrivate(result));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(result)));
}
int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
diff --git a/src/corelib/tools/qcollator_win.cpp b/src/corelib/tools/qcollator_win.cpp
index fcd8d069eb..bce896278e 100644
--- a/src/corelib/tools/qcollator_win.cpp
+++ b/src/corelib/tools/qcollator_win.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qcollator_p.h"
+#include "qlocale_p.h"
#include "qstringlist.h"
#include "qstring.h"
@@ -61,7 +62,7 @@ void QCollatorPrivate::init()
collator = 0;
#ifndef USE_COMPARESTRINGEX
- localeID = qt_inIsoNametoLCID(locale.bcp47Name().toUtf8().constData());
+ localeID = qt_inIsoNametoLCID(QLocalePrivate::get(locale)->bcp47Name().constData());
#else
localeName = locale.bcp47Name();
#endif
@@ -146,7 +147,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
if (finalSize == 0) {
qWarning() << "there were problems when generating the ::sortKey by LCMapStringW with error:" << GetLastError();
}
- return QCollatorSortKey(new QCollatorSortKeyPrivate(ret));
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(std::move(ret)));
}
int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp
index bf92be2dd4..bcdbc5af2a 100644
--- a/src/corelib/tools/qdatetime.cpp
+++ b/src/corelib/tools/qdatetime.cpp
@@ -929,7 +929,7 @@ QString QDate::toString(Qt::DateFormat format) const
*/
QString QDate::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
@@ -1333,6 +1333,7 @@ QDate QDate::fromString(const QString &string, const QString &format)
QDate date;
#if QT_CONFIG(timezone)
QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format))
dt.fromString(string, &date, 0);
#else
@@ -1676,7 +1677,7 @@ QString QTime::toString(Qt::DateFormat format) const
*/
QString QTime::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
/*!
@@ -1970,7 +1971,7 @@ QTime QTime::fromString(const QString& string, Qt::DateFormat format)
case Qt::ISODateWithMs:
case Qt::TextDate:
default:
- return fromIsoTimeString(&string, format, 0);
+ return fromIsoTimeString(QStringRef(&string), format, 0);
}
}
@@ -2030,6 +2031,7 @@ QTime QTime::fromString(const QString &string, const QString &format)
QTime time;
#if QT_CONFIG(timezone)
QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format))
dt.fromString(string, 0, &time);
#else
@@ -2285,10 +2287,11 @@ static bool qt_localtime(qint64 msecsSinceEpoch, QDate *localDate, QTime *localT
tm local;
bool valid = false;
-#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
// localtime() is required to work as if tzset() was called before it.
// localtime_r() does not have this requirement, so make an explicit call.
+ // The explicit call should also request the timezone info be re-parsed.
qt_tzset();
+#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
// Use the reentrant version of localtime() where available
// as is thread-safe and doesn't use a shared static data area
tm *res = 0;
@@ -2574,6 +2577,13 @@ static inline Qt::TimeSpec getSpec(const QDateTimeData &d)
return extractSpec(getStatus(d));
}
+#if QT_CONFIG(timezone)
+void QDateTimePrivate::setUtcOffsetByTZ(qint64 atMSecsSinceEpoch)
+{
+ m_offsetFromUtc = m_timeZone.d->offsetFromUtc(atMSecsSinceEpoch);
+}
+#endif
+
// Refresh the LocalTime validity and offset
static void refreshDateTime(QDateTimeData &d)
{
@@ -2589,10 +2599,12 @@ static void refreshDateTime(QDateTimeData &d)
#if QT_CONFIG(timezone)
// If not valid time zone then is invalid
if (spec == Qt::TimeZone) {
- if (!d->m_timeZone.isValid())
+ if (!d->m_timeZone.isValid()) {
status &= ~QDateTimePrivate::ValidDateTime;
- else
- epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, d->m_timeZone, &testDate, &testTime);
+ } else {
+ epochMSecs = QDateTimePrivate::zoneMSecsToEpochMSecs(msecs, d->m_timeZone, extractDaylightStatus(status), &testDate, &testTime);
+ d->setUtcOffsetByTZ(epochMSecs);
+ }
}
#endif // timezone
@@ -2916,11 +2928,13 @@ inline QDateTime::Data QDateTimePrivate::create(const QDate &toDate, const QTime
}
// Convert a TimeZone time expressed in zone msecs encoding into a UTC epoch msecs
+// DST transitions are disambiguated by hint.
inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QTimeZone &zone,
+ DaylightStatus hint,
QDate *localDate, QTime *localTime)
{
// Get the effective data from QTimeZone
- QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs);
+ QTimeZonePrivate::Data data = zone.d->dataForLocalTime(zoneMSecs, int(hint));
// Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
// but all affected times afterwards will have DST applied.
if (data.atMSecsSinceEpoch >= 0) {
@@ -3533,7 +3547,8 @@ qint64 QDateTime::toMSecsSinceEpoch() const
#if !QT_CONFIG(timezone)
return 0;
#else
- return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone);
+ return QDateTimePrivate::zoneMSecsToEpochMSecs(d->m_msecs, d->m_timeZone,
+ extractDaylightStatus(getStatus(d)));
#endif
}
Q_UNREACHABLE();
@@ -3632,10 +3647,16 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
// Docs state any LocalTime before 1970-01-01 will *not* have any DST applied
// but all affected times afterwards will have DST applied.
d.detach();
- if (msecs >= 0)
+ if (msecs >= 0) {
+ status = mergeDaylightStatus(status,
+ d->m_timeZone.d->isDaylightTime(msecs)
+ ? QDateTimePrivate::DaylightTime
+ : QDateTimePrivate::StandardTime);
d->m_offsetFromUtc = d->m_timeZone.d->offsetFromUtc(msecs);
- else
+ } else {
+ status = mergeDaylightStatus(status, QDateTimePrivate::StandardTime);
d->m_offsetFromUtc = d->m_timeZone.d->standardTimeOffset(msecs);
+ }
msecs = msecs + (d->m_offsetFromUtc * 1000);
status = status
| QDateTimePrivate::ValidDate
@@ -3783,15 +3804,20 @@ QString QDateTime::toString(Qt::DateFormat format) const
#ifndef QT_NO_TEXTDATE
case Qt::TextDate: {
const QPair<QDate, QTime> p = getDateTime(d);
- const QDate &dt = p.first;
- const QTime &tm = p.second;
- //We cant use date.toString(Qt::TextDate) as we need to insert the time before the year
- buf = QString::fromLatin1("%1 %2 %3 %4 %5").arg(dt.shortDayName(dt.dayOfWeek()))
- .arg(dt.shortMonthName(dt.month()))
- .arg(dt.day())
- .arg(tm.toString(Qt::TextDate))
- .arg(dt.year());
- if (timeSpec() != Qt::LocalTime) {
+ buf = p.first.toString(Qt::TextDate);
+ // Insert time between date's day and year:
+ buf.insert(buf.lastIndexOf(QLatin1Char(' ')),
+ QLatin1Char(' ') + p.second.toString(Qt::TextDate));
+ // Append zone/offset indicator, as appropriate:
+ switch (timeSpec()) {
+ case Qt::LocalTime:
+ break;
+# if QT_CONFIG(timezone)
+ case Qt::TimeZone:
+ buf += QLatin1Char(' ') + d->m_timeZone.abbreviation(*this);
+ break;
+# endif
+ default:
buf += QLatin1String(" GMT");
if (getSpec(d) == Qt::OffsetFromUTC)
buf += toOffsetString(Qt::TextDate, offsetFromUtc());
@@ -3814,6 +3840,9 @@ QString QDateTime::toString(Qt::DateFormat format) const
buf += QLatin1Char('Z');
break;
case Qt::OffsetFromUTC:
+#if QT_CONFIG(timezone)
+ case Qt::TimeZone:
+#endif
buf += toOffsetString(Qt::ISODate, offsetFromUtc());
break;
default:
@@ -3899,7 +3928,7 @@ QString QDateTime::toString(Qt::DateFormat format) const
*/
QString QDateTime::toString(const QString& format) const
{
- return QLocale::system().toString(*this, format);
+ return QLocale::system().toString(*this, format); // QLocale::c() ### Qt6
}
#endif //QT_NO_DATESTRING
@@ -3923,7 +3952,10 @@ static inline void massageAdjustedDateTime(const QDateTimeData &d, QDate *date,
localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time);
#if QT_CONFIG(timezone)
} else if (spec == Qt::TimeZone) {
- QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time), d->m_timeZone, date, time);
+ QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time),
+ d->m_timeZone,
+ QDateTimePrivate::UnknownDaylightTime,
+ date, time);
#endif // timezone
}
}
@@ -4953,6 +4985,7 @@ QDateTime QDateTime::fromString(const QString &string, const QString &format)
QDate date;
QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString);
+ // dt.setDefaultLocale(QLocale::c()); ### Qt 6
if (dt.parseFormat(format) && dt.fromString(string, &date, &time))
return QDateTime(date, time);
#else
diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h
index eb33dddbb7..4d30d4192b 100644
--- a/src/corelib/tools/qdatetime_p.h
+++ b/src/corelib/tools/qdatetime_p.h
@@ -134,11 +134,12 @@ public:
#if QT_CONFIG(timezone)
static qint64 zoneMSecsToEpochMSecs(qint64 msecs, const QTimeZone &zone,
+ DaylightStatus hint = UnknownDaylightTime,
QDate *localDate = 0, QTime *localTime = 0);
-#endif // timezone
- static inline qint64 minJd() { return QDate::minJd(); }
- static inline qint64 maxJd() { return QDate::maxJd(); }
+ // Inlined for its one caller in qdatetime.cpp
+ inline void setUtcOffsetByTZ(qint64 atMSecsSinceEpoch);
+#endif // timezone
};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h
index efed5d36ee..ba06de8f9e 100644
--- a/src/corelib/tools/qeasingcurve.h
+++ b/src/corelib/tools/qeasingcurve.h
@@ -125,7 +125,7 @@ private:
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QEasingCurve &);
#endif
};
-Q_DECLARE_TYPEINFO(QEasingCurve, Q_MOVABLE_TYPE);
+Q_DECLARE_SHARED(QEasingCurve)
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QEasingCurve &item);
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index abec9ebb79..334bd52f1e 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -199,14 +199,14 @@ static uint crc32(...)
}
#endif
-static inline uint hash(const uchar *p, int len, uint seed) Q_DECL_NOTHROW
+static inline uint hash(const uchar *p, size_t len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
if (hasFastCrc32())
- return crc32(p, size_t(len), h);
+ return crc32(p, len, h);
- for (int i = 0; i < len; ++i)
+ for (size_t i = 0; i < len; ++i)
h = 31 * h + p[i];
return h;
@@ -217,14 +217,14 @@ uint qHashBits(const void *p, size_t len, uint seed) Q_DECL_NOTHROW
return hash(static_cast<const uchar*>(p), int(len), seed);
}
-static inline uint hash(const QChar *p, int len, uint seed) Q_DECL_NOTHROW
+static inline uint hash(const QChar *p, size_t len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
if (hasFastCrc32())
- return crc32(p, size_t(len), h);
+ return crc32(p, len, h);
- for (int i = 0; i < len; ++i)
+ for (size_t i = 0; i < len; ++i)
h = 31 * h + p[i].unicode();
return h;
@@ -232,23 +232,24 @@ static inline uint hash(const QChar *p, int len, uint seed) Q_DECL_NOTHROW
uint qHash(const QByteArray &key, uint seed) Q_DECL_NOTHROW
{
- return hash(reinterpret_cast<const uchar *>(key.constData()), key.size(), seed);
+ return hash(reinterpret_cast<const uchar *>(key.constData()), size_t(key.size()), seed);
}
uint qHash(const QString &key, uint seed) Q_DECL_NOTHROW
{
- return hash(key.unicode(), key.size(), seed);
+ return hash(key.unicode(), size_t(key.size()), seed);
}
uint qHash(const QStringRef &key, uint seed) Q_DECL_NOTHROW
{
- return hash(key.unicode(), key.size(), seed);
+ return hash(key.unicode(), size_t(key.size()), seed);
}
uint qHash(const QBitArray &bitArray, uint seed) Q_DECL_NOTHROW
{
int m = bitArray.d.size() - 1;
- uint result = hash(reinterpret_cast<const uchar *>(bitArray.d.constData()), qMax(0, m), seed);
+ uint result = hash(reinterpret_cast<const uchar *>(bitArray.d.constData()),
+ size_t(qMax(0, m)), seed);
// deal with the last 0 to 7 bits manually, because we can't trust that
// the padding is initialized to 0 in bitArray.d
@@ -260,7 +261,7 @@ uint qHash(const QBitArray &bitArray, uint seed) Q_DECL_NOTHROW
uint qHash(QLatin1String key, uint seed) Q_DECL_NOTHROW
{
- return hash(reinterpret_cast<const uchar *>(key.data()), key.size(), seed);
+ return hash(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
}
/*!
@@ -324,7 +325,7 @@ static uint qt_create_qhash_seed()
/*
The QHash seed itself.
*/
-Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1);
+static QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1);
/*!
\internal
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 66b5e75a1a..c59f789cb2 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -432,6 +432,7 @@ public:
typedef const Key *pointer;
typedef const Key &reference;
+ key_iterator() = default;
explicit key_iterator(const_iterator o) : i(o) { }
const Key &operator*() const { return i.key(); }
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 5995be47a9..e2706de9ee 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -126,6 +126,7 @@ class QList
public:
struct MemoryLayout
: std::conditional<
+ // must stay isStatic until ### Qt 6 for BC reasons (don't use !isRelocatable)!
QTypeInfo<T>::isStatic || QTypeInfo<T>::isLarge,
QListData::IndirectLayout,
typename std::conditional<
diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp
index c183224c82..bde4bf553e 100644
--- a/src/corelib/tools/qlocale.cpp
+++ b/src/corelib/tools/qlocale.cpp
@@ -972,7 +972,7 @@ QLocale::NumberOptions QLocale::numberOptions() const
*/
QString QLocale::quoteString(const QString &str, QuotationStyle style) const
{
- return quoteString(&str, style);
+ return quoteString(QStringRef(&str), style);
}
/*!
@@ -2058,6 +2058,8 @@ QString QLocale::toString(double i, char f, int prec) const
flags |= QLocaleData::ThousandsGroup;
if (!(d->m_numberOptions & OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (d->m_numberOptions & IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
return d->m_data->doubleToString(i, prec, form, -1, flags);
}
@@ -2819,7 +2821,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
reinterpret_cast<ushort *>(digits.data())[i] += z;
}
- bool always_show_decpt = (flags & Alternate || flags & ForcePoint);
+ bool always_show_decpt = (flags & ForcePoint);
switch (form) {
case DFExponent: {
num_str = exponentForm(_zero, decimal, exponential, group, plus, minus,
@@ -2834,7 +2836,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
break;
}
case DFSignificantDigits: {
- PrecisionMode mode = (flags & Alternate) ?
+ PrecisionMode mode = (flags & AddTrailingZeroes) ?
PMSignificantDigits : PMChopTrailingZeros;
int cutoff = precision < 0 ? 6 : precision;
@@ -2889,7 +2891,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q
num_str.prepend(QLatin1Char(' '));
if (flags & QLocaleData::CapitalEorX)
- num_str = num_str.toUpper();
+ num_str = std::move(num_str).toUpper();
return num_str;
}
@@ -2939,7 +2941,7 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
for (int i = num_str.length()/* - cnt_thousand_sep*/; i < precision; ++i)
num_str.prepend(base == 10 ? zero : QChar::fromLatin1('0'));
- if ((flags & Alternate || flags & ShowBase)
+ if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str[0].unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
@@ -2960,10 +2962,10 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
--num_pad_chars;
// leave space for optional '0x' in hex form
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && (flags & ShowBase))
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
- else if (base == 2 && (flags & Alternate || flags & ShowBase))
+ else if (base == 2 && (flags & ShowBase))
num_pad_chars -= 2;
for (int i = 0; i < num_pad_chars; ++i)
@@ -2971,11 +2973,11 @@ QString QLocaleData::longLongToString(const QChar zero, const QChar group,
}
if (flags & CapitalEorX)
- num_str = num_str.toUpper();
+ num_str = std::move(num_str).toUpper();
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
- if (base == 2 && (flags & Alternate || flags & ShowBase))
+ if (base == 2 && (flags & ShowBase))
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
// add sign
@@ -3024,7 +3026,7 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
if (zeroPadding > 0)
num_str.prepend(QString(zeroPadding, resultZero));
- if ((flags & Alternate || flags & ShowBase)
+ if ((flags & ShowBase)
&& base == 8
&& (num_str.isEmpty() || num_str.at(0).unicode() != QLatin1Char('0')))
num_str.prepend(QLatin1Char('0'));
@@ -3039,10 +3041,10 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
int num_pad_chars = width - num_str.length();
// leave space for optional '0x' in hex form
- if (base == 16 && flags & Alternate)
+ if (base == 16 && flags & ShowBase)
num_pad_chars -= 2;
// leave space for optional '0b' in binary form
- else if (base == 2 && flags & Alternate)
+ else if (base == 2 && flags & ShowBase)
num_pad_chars -= 2;
if (num_pad_chars > 0)
@@ -3050,11 +3052,11 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group,
}
if (flags & CapitalEorX)
- num_str = num_str.toUpper();
+ num_str = std::move(num_str).toUpper();
- if (base == 16 && (flags & Alternate || flags & ShowBase))
+ if (base == 16 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0X" : "0x"));
- else if (base == 2 && (flags & Alternate || flags & ShowBase))
+ else if (base == 2 && flags & ShowBase)
num_str.prepend(QLatin1String(flags & UppercaseBase ? "0B" : "0b"));
// add sign
@@ -3115,25 +3117,37 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
out = in.toLatin1();
else
break;
+ } else if (out == '.') {
+ // Fail if more than one decimal point or point after e
+ if (decpt_idx != -1 || exponent_idx != -1)
+ return false;
+ decpt_idx = idx;
+ } else if (out == 'e' || out == 'E') {
+ exponent_idx = idx;
}
if (number_options & QLocale::RejectLeadingZeroInExponent) {
- if (out == 'e' || out == 'E') {
- exponent_idx = idx;
- } else if (exponent_idx != -1) {
- if (out >= '1' && out <= '9')
- exponent_idx = -1; // leading digit is not 0, forget exponent_idx
- else if (out == '0' && idx < l - 1)
+ if (exponent_idx != -1 && out == '0' && idx < l - 1) {
+ // After the exponent there can only be '+', '-' or digits.
+ // If we find a '0' directly after some non-digit, then that is a leading zero.
+ if (result->last() < '0' || result->last() > '9')
return false;
}
}
+ if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
+ // If we've seen a decimal point and the last character after the exponent is 0, then
+ // that is a trailing zero.
+ if (decpt_idx >= 0 && idx == exponent_idx && result->last() == '0')
+ return false;
+ }
+
if (!(number_options & QLocale::RejectGroupSeparator)) {
if (start_of_digits_idx == -1 && out >= '0' && out <= '9') {
start_of_digits_idx = idx;
} else if (out == ',') {
- // Don't allow group chars after the decimal point
- if (decpt_idx != -1)
+ // Don't allow group chars after the decimal point or exponent
+ if (decpt_idx != -1 || exponent_idx != -1)
return false;
// check distance from the last separator or from the beginning of the digits
@@ -3150,12 +3164,6 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
++idx;
continue;
} else if (out == '.' || out == 'e' || out == 'E') {
- // Fail if more than one decimal point
- if (out == '.' && decpt_idx != -1)
- return false;
- if (decpt_idx == -1)
- decpt_idx = idx;
-
// check distance from the last separator
// ### FIXME: Some locales allow other groupings! See https://en.wikipedia.org/wiki/Thousands_separator
if (last_separator_idx != -1 && idx - last_separator_idx != 4)
@@ -3181,6 +3189,12 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOpti
return false;
}
+ if (number_options & QLocale::RejectTrailingZeroesAfterDot) {
+ // In decimal form, the last character can be a trailing zero if we've seen a decpt.
+ if (decpt_idx != -1 && exponent_idx == -1 && result->last() == '0')
+ return false;
+ }
+
result->append('\0');
return idx == l;
}
diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h
index 657fce9fa1..bd89e48234 100644
--- a/src/corelib/tools/qlocale.h
+++ b/src/corelib/tools/qlocale.h
@@ -897,7 +897,9 @@ public:
OmitGroupSeparator = 0x01,
RejectGroupSeparator = 0x02,
OmitLeadingZeroInExponent = 0x04,
- RejectLeadingZeroInExponent = 0x08
+ RejectLeadingZeroInExponent = 0x08,
+ IncludeTrailingZeroesAfterDot = 0x10,
+ RejectTrailingZeroesAfterDot = 0x20
};
Q_DECLARE_FLAGS(NumberOptions, NumberOption)
diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc
index 8c5711fb5e..d419172356 100644
--- a/src/corelib/tools/qlocale.qdoc
+++ b/src/corelib/tools/qlocale.qdoc
@@ -949,7 +949,8 @@
setNumberOptions().
\value DefaultNumberOptions This option represents the default behavior, with
- group separators and with one leading zero in single digit exponents.
+ group separators, with one leading zero in single digit exponents, and
+ without trailing zeroes after the decimal dot.
\value OmitGroupSeparator If this option is set, the number-to-string functions
will not insert group separators in their return values. The default
is to insert group separators.
@@ -964,6 +965,14 @@
functions will fail if they encounter an exponent padded with zeroes when
parsing a floating point number in scientific notation. The default is to
accept such padding.
+ \value IncludeTrailingZeroesAfterDot If this option is set, the number-to-string
+ functions will pad numbers with zeroes to the requested precision in "g"
+ or "most concise" mode, even if the number of significant digits is lower
+ than the requested precision. The default is to omit trailing zeroes.
+ \value RejectTrailingZeroesAfterDot If this option is set, the string-to-number
+ functions will fail if they encounter trailing zeroes after the decimal
+ dot when parsing a number in scientific or decimal representation. The
+ default is to accept trailing zeroes.
\sa setNumberOptions(), numberOptions()
*/
diff --git a/src/corelib/tools/qlocale_mac.mm b/src/corelib/tools/qlocale_mac.mm
index 8587716446..c5519bfabf 100644
--- a/src/corelib/tools/qlocale_mac.mm
+++ b/src/corelib/tools/qlocale_mac.mm
@@ -43,9 +43,11 @@
#include "qvariant.h"
#include "qdatetime.h"
-#if !defined(QWS) && defined(Q_OS_MAC)
-# include "private/qcore_mac_p.h"
-# include <CoreFoundation/CoreFoundation.h>
+#ifdef Q_OS_DARWIN
+#include "qtimezone.h"
+#include "private/qcore_mac_p.h"
+#include <CoreFoundation/CoreFoundation.h>
+QT_REQUIRE_CONFIG(timezone);
#endif
QT_BEGIN_NAMESPACE
@@ -121,16 +123,7 @@ static QString macDayName(int day, bool short_format)
static QString macDateToString(const QDate &date, bool short_format)
{
- CFGregorianDate macGDate;
- macGDate.year = date.year();
- macGDate.month = date.month();
- macGDate.day = date.day();
- macGDate.hour = 0;
- macGDate.minute = 0;
- macGDate.second = 0.0;
- QCFType<CFDateRef> myDate
- = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate,
- QCFType<CFTimeZoneRef>(CFTimeZoneCopyDefault())));
+ QCFType<CFDateRef> myDate = QDateTime(date, QTime()).toCFDate();
QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent();
CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle;
QCFType<CFDateFormatterRef> myFormatter
@@ -142,19 +135,7 @@ static QString macDateToString(const QDate &date, bool short_format)
static QString macTimeToString(const QTime &time, bool short_format)
{
- CFGregorianDate macGDate;
- // Assume this is local time and the current date
- QDate dt = QDate::currentDate();
- macGDate.year = dt.year();
- macGDate.month = dt.month();
- macGDate.day = dt.day();
- macGDate.hour = time.hour();
- macGDate.minute = time.minute();
- macGDate.second = time.second();
- QCFType<CFDateRef> myDate
- = CFDateCreate(0, CFGregorianDateGetAbsoluteTime(macGDate,
- QCFType<CFTimeZoneRef>(CFTimeZoneCopyDefault())));
-
+ QCFType<CFDateRef> myDate = QDateTime(QDate::currentDate(), time).toCFDate();
QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent();
CFDateFormatterStyle style = short_format ? kCFDateFormatterShortStyle : kCFDateFormatterLongStyle;
QCFType<CFDateFormatterRef> myFormatter = CFDateFormatterCreate(kCFAllocatorDefault,
diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h
index 20eff8fd64..f7adb021b6 100644
--- a/src/corelib/tools/qlocale_p.h
+++ b/src/corelib/tools/qlocale_p.h
@@ -193,7 +193,7 @@ public:
enum Flags {
NoFlags = 0,
- Alternate = 0x01,
+ AddTrailingZeroes = 0x01,
ZeroPadded = 0x02,
LeftAdjusted = 0x04,
BlankBeforePositive = 0x08,
@@ -204,7 +204,7 @@ public:
ShowBase = 0x80,
UppercaseBase = 0x100,
ZeroPadExponent = 0x200,
- ForcePoint = Alternate
+ ForcePoint = 0x400
};
enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode };
@@ -332,6 +332,9 @@ public:
return retval;
}
+ static QLocalePrivate *get(QLocale &l) { return l.d; }
+ static const QLocalePrivate *get(const QLocale &l) { return l.d; }
+
QChar decimal() const { return QChar(m_data->m_decimal); }
QChar group() const { return QChar(m_data->m_group); }
QChar list() const { return QChar(m_data->m_list); }
diff --git a/src/corelib/tools/qlocale_win.cpp b/src/corelib/tools/qlocale_win.cpp
index b5f97b5fe8..2475859abd 100644
--- a/src/corelib/tools/qlocale_win.cpp
+++ b/src/corelib/tools/qlocale_win.cpp
@@ -691,7 +691,7 @@ QString QSystemLocalePrivate::winToQtFormat(const QString &sys_fmt)
if (text == QLatin1String("'"))
result += QLatin1String("''");
else
- result += QString(QLatin1Char('\'') + text + QLatin1Char('\''));
+ result += QLatin1Char('\'') + text + QLatin1Char('\'');
continue;
}
@@ -1037,7 +1037,7 @@ static QString winIso639LangName(LPWSTR id)
if (!lang_code.isEmpty()) {
const char *endptr;
bool ok;
- QByteArray latin1_lang_code = lang_code.toLatin1();
+ QByteArray latin1_lang_code = std::move(lang_code).toLatin1();
int i = qstrtoull(latin1_lang_code, &endptr, 16, &ok);
if (ok && *endptr == '\0') {
switch (i) {
@@ -1120,15 +1120,12 @@ static QByteArray getWinLocaleName(LPWSTR id)
id = lcName;
}
#endif // Q_OS_WINRT
- QString resultuage = winIso639LangName(id);
+ QString resultusage = winIso639LangName(id);
QString country = winIso3116CtryName(id);
- result = resultuage.toLatin1();
- if (!country.isEmpty()) {
- result += '_';
- result += country.toLatin1();
- }
+ if (!country.isEmpty())
+ resultusage += QLatin1Char('_') + country;
- return result;
+ return std::move(resultusage).toLatin1();
}
Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id)
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index da77ba4458..a3b11eddcf 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -99,10 +99,10 @@ struct Q_CORE_EXPORT QMapNodeBase
void setParent(QMapNodeBase *pp) { p = (p & Mask) | quintptr(pp); }
template <typename T>
- static typename QtPrivate::QEnableIf<QTypeInfo<T>::isComplex>::Type
+ static typename std::enable_if<QTypeInfo<T>::isComplex>::type
callDestructorIfNecessary(T &t) Q_DECL_NOTHROW { Q_UNUSED(t); t.~T(); } // Q_UNUSED: silence MSVC unused 't' warning
template <typename T>
- static typename QtPrivate::QEnableIf<!QTypeInfo<T>::isComplex>::Type
+ static typename std::enable_if<!QTypeInfo<T>::isComplex>::type
callDestructorIfNecessary(T &) Q_DECL_NOTHROW {}
};
@@ -533,6 +533,7 @@ public:
typedef const Key *pointer;
typedef const Key &reference;
+ key_iterator() = default;
explicit key_iterator(const_iterator o) : i(o) { }
const Key &operator*() const { return i.key(); }
diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp
index 4a30daa72c..88b696f53a 100644
--- a/src/corelib/tools/qregularexpression.cpp
+++ b/src/corelib/tools/qregularexpression.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2015 Giuseppe D'Angelo <dangelog@gmail.com>.
-** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+** Copyright (C) 2016 Giuseppe D'Angelo <dangelog@gmail.com>.
+** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -45,7 +45,7 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qhashfunctions.h>
-#include <QtCore/qmutex.h>
+#include <QtCore/qreadwritelock.h>
#include <QtCore/qvector.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qdebug.h>
@@ -54,7 +54,9 @@
#include <QtCore/qatomic.h>
#include <QtCore/qdatastream.h>
-#include <pcre.h>
+#define PCRE2_CODE_UNIT_WIDTH 16
+
+#include <pcre2.h>
QT_BEGIN_NAMESPACE
@@ -443,19 +445,25 @@ QT_BEGIN_NAMESPACE
Other differences are outlined below.
- \section2 Exact matching
+ \section2 Porting from QRegExp::exactMatch()
QRegExp::exactMatch() in Qt 4 served two purposes: it exactly matched
a regular expression against a subject string, and it implemented partial
- matching. In fact, if an exact match was not found, one could still find
- out how much of the subject string was matched by the regular expression
- by calling QRegExp::matchedLength(). If the returned length was equal
- to the subject string's length, then one could desume that a partial match
- was found.
+ matching.
- QRegularExpression supports partial matching explicitly by means of the
- appropriate MatchType. If instead you simply want to be sure that the
- subject string matches the regular expression exactly, you can wrap the
+ \section3 Porting from QRegExp's Exact Matching
+
+ Exact matching indicates whether the regular expression matches the entire
+ subject string. For example, the classes yield on the subject string \c{"abc123"}:
+
+ \table
+ \header \li \li QRegExp::exactMatch() \li QRegularExpressionMatch::hasMatch()
+ \row \li \c{"\\d+"} \li \b false \li \b true
+ \row \li \c{"[a-z]+\\d+"} \li \b true \li \b true
+ \endtable
+
+ Exact matching is not reflected in QRegularExpression. If you want to be
+ sure that the subject string matches the regular expression exactly, you can wrap the
pattern between a couple of anchoring expressions. Simply
putting the pattern between the \c{^} and the \c{$} anchors is enough
in most cases:
@@ -477,6 +485,17 @@ QT_BEGIN_NAMESPACE
Note the usage of the non-capturing group in order to preserve the meaning
of the branch operator inside the pattern.
+ \section3 Porting from QRegExp's Partial Matching
+
+ When using QRegExp::exactMatch(), if an exact match was not found, one
+ could still find out how much of the subject string was matched by the
+ regular expression by calling QRegExp::matchedLength(). If the returned length
+ was equal to the subject string's length, then one could conclude that a partial
+ match was found.
+
+ QRegularExpression supports partial matching explicitly by means of the
+ appropriate MatchType.
+
\section2 Global matching
Due to limitations of the QRegExp API it was impossible to implement global
@@ -548,7 +567,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtCore
\reentrant
- \brief The QRegularExpressionMatch class provides the results of matching
+ \brief The QRegularExpressionMatch class provides the results of a matching
a QRegularExpression against a string.
\since 5.0
@@ -789,19 +808,19 @@ static int convertToPcreOptions(QRegularExpression::PatternOptions patternOption
int options = 0;
if (patternOptions & QRegularExpression::CaseInsensitiveOption)
- options |= PCRE_CASELESS;
+ options |= PCRE2_CASELESS;
if (patternOptions & QRegularExpression::DotMatchesEverythingOption)
- options |= PCRE_DOTALL;
+ options |= PCRE2_DOTALL;
if (patternOptions & QRegularExpression::MultilineOption)
- options |= PCRE_MULTILINE;
+ options |= PCRE2_MULTILINE;
if (patternOptions & QRegularExpression::ExtendedPatternSyntaxOption)
- options |= PCRE_EXTENDED;
+ options |= PCRE2_EXTENDED;
if (patternOptions & QRegularExpression::InvertedGreedinessOption)
- options |= PCRE_UNGREEDY;
+ options |= PCRE2_UNGREEDY;
if (patternOptions & QRegularExpression::DontCaptureOption)
- options |= PCRE_NO_AUTO_CAPTURE;
+ options |= PCRE2_NO_AUTO_CAPTURE;
if (patternOptions & QRegularExpression::UseUnicodePropertiesOption)
- options |= PCRE_UCP;
+ options |= PCRE2_UCP;
return options;
}
@@ -814,7 +833,9 @@ static int convertToPcreOptions(QRegularExpression::MatchOptions matchOptions)
int options = 0;
if (matchOptions & QRegularExpression::AnchoredMatchOption)
- options |= PCRE_ANCHORED;
+ options |= PCRE2_ANCHORED;
+ if (matchOptions & QRegularExpression::DontCheckSubjectStringMatchOption)
+ options |= PCRE2_NO_UTF_CHECK;
return options;
}
@@ -856,20 +877,16 @@ struct QRegularExpressionPrivate : QSharedData
QRegularExpression::PatternOptions patternOptions;
QString pattern;
- // *All* of the following members are set managed while holding this mutex,
+ // *All* of the following members are managed while holding this mutex,
// except for isDirty which is set to true by QRegularExpression setters
// (right after a detach happened).
- // On the other hand, after the compilation and studying,
- // it's safe to *use* (i.e. read) them from multiple threads at the same time.
- // Therefore, doMatch doesn't need to lock this mutex.
- QMutex mutex;
+ mutable QReadWriteLock mutex;
- // The PCRE pointers are reference-counted by the QRegularExpressionPrivate
+ // The PCRE code pointer is reference-counted by the QRegularExpressionPrivate
// objects themselves; when the private is copied (i.e. a detach happened)
// they are set to 0
- pcre16 *compiledPattern;
- QAtomicPointer<pcre16_extra> studyData;
- const char *errorString;
+ pcre2_code_16 *compiledPattern;
+ int errorCode;
int errorOffset;
int capturingCount;
unsigned int usedCount;
@@ -884,8 +901,7 @@ struct QRegularExpressionMatchPrivate : QSharedData
int subjectStart,
int subjectLength,
QRegularExpression::MatchType matchType,
- QRegularExpression::MatchOptions matchOptions,
- int capturingCount = 0);
+ QRegularExpression::MatchOptions matchOptions);
QRegularExpressionMatch nextMatch() const;
@@ -934,10 +950,13 @@ QRegularExpression::QRegularExpression(QRegularExpressionPrivate &dd)
\internal
*/
QRegularExpressionPrivate::QRegularExpressionPrivate()
- : patternOptions(0), pattern(),
+ : QSharedData(),
+ patternOptions(0),
+ pattern(),
mutex(),
- compiledPattern(0), studyData(0),
- errorString(0), errorOffset(-1),
+ compiledPattern(0),
+ errorCode(0),
+ errorOffset(-1),
capturingCount(0),
usedCount(0),
usingCrLfNewlines(false),
@@ -964,13 +983,16 @@ QRegularExpressionPrivate::~QRegularExpressionPrivate()
*/
QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPrivate &other)
: QSharedData(other),
- patternOptions(other.patternOptions), pattern(other.pattern),
+ patternOptions(other.patternOptions),
+ pattern(other.pattern),
mutex(),
- compiledPattern(0), studyData(0),
- errorString(0),
- errorOffset(-1), capturingCount(0),
+ compiledPattern(0),
+ errorCode(0),
+ errorOffset(-1),
+ capturingCount(0),
usedCount(0),
- usingCrLfNewlines(false), isDirty(true)
+ usingCrLfNewlines(false),
+ isDirty(true)
{
}
@@ -979,14 +1001,13 @@ QRegularExpressionPrivate::QRegularExpressionPrivate(const QRegularExpressionPri
*/
void QRegularExpressionPrivate::cleanCompiledPattern()
{
- pcre16_free(compiledPattern);
- pcre16_free_study(studyData.load());
- usedCount = 0;
+ pcre2_code_free_16(compiledPattern);
compiledPattern = 0;
- studyData.store(0);
- usingCrLfNewlines = false;
+ errorCode = 0;
errorOffset = -1;
capturingCount = 0;
+ usedCount = 0;
+ usingCrLfNewlines = false;
}
/*!
@@ -994,7 +1015,7 @@ void QRegularExpressionPrivate::cleanCompiledPattern()
*/
void QRegularExpressionPrivate::compilePattern()
{
- QMutexLocker lock(&mutex);
+ const QWriteLocker lock(&mutex);
if (!isDirty)
return;
@@ -1003,18 +1024,23 @@ void QRegularExpressionPrivate::compilePattern()
cleanCompiledPattern();
int options = convertToPcreOptions(patternOptions);
- options |= PCRE_UTF16;
+ options |= PCRE2_UTF;
- int errorCode;
- compiledPattern = pcre16_compile2(pattern.utf16(), options,
- &errorCode, &errorString, &errorOffset, 0);
+ PCRE2_SIZE patternErrorOffset;
+ compiledPattern = pcre2_compile_16(pattern.utf16(),
+ pattern.length(),
+ options,
+ &errorCode,
+ &patternErrorOffset,
+ NULL);
- if (!compiledPattern)
+ if (!compiledPattern) {
+ errorOffset = static_cast<int>(patternErrorOffset);
return;
-
- Q_ASSERT(errorCode == 0);
- Q_ASSERT(studyData.load() == 0); // studying (=>optimizing) is always done later
- errorOffset = -1;
+ } else {
+ // ignore whatever PCRE2 wrote into errorCode -- leave it to 0 to mean "no error"
+ errorCode = 0;
+ }
getPatternInfo();
}
@@ -1025,53 +1051,31 @@ void QRegularExpressionPrivate::compilePattern()
void QRegularExpressionPrivate::getPatternInfo()
{
Q_ASSERT(compiledPattern);
- Q_ASSERT(studyData.load() == 0);
- pcre16_fullinfo(compiledPattern, 0, PCRE_INFO_CAPTURECOUNT, &capturingCount);
+ pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_CAPTURECOUNT, &capturingCount);
// detect the settings for the newline
- unsigned long int patternNewlineSetting;
- pcre16_fullinfo(compiledPattern, 0, PCRE_INFO_OPTIONS, &patternNewlineSetting);
- patternNewlineSetting &= PCRE_NEWLINE_CR | PCRE_NEWLINE_LF | PCRE_NEWLINE_CRLF
- | PCRE_NEWLINE_ANY | PCRE_NEWLINE_ANYCRLF;
- if (patternNewlineSetting == 0) {
+ unsigned int patternNewlineSetting;
+ if (pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_NEWLINE, &patternNewlineSetting) != 0) {
// no option was specified in the regexp, grab PCRE build defaults
- int pcreNewlineSetting;
- pcre16_config(PCRE_CONFIG_NEWLINE, &pcreNewlineSetting);
- switch (pcreNewlineSetting) {
- case 13:
- patternNewlineSetting = PCRE_NEWLINE_CR; break;
- case 10:
- patternNewlineSetting = PCRE_NEWLINE_LF; break;
- case 3338: // (13<<8 | 10)
- patternNewlineSetting = PCRE_NEWLINE_CRLF; break;
- case -2:
- patternNewlineSetting = PCRE_NEWLINE_ANYCRLF; break;
- case -1:
- patternNewlineSetting = PCRE_NEWLINE_ANY; break;
- default:
- qWarning("QRegularExpressionPrivate::compilePattern(): "
- "PCRE_CONFIG_NEWLINE returned an unknown newline");
- break;
- }
+ pcre2_config_16(PCRE2_CONFIG_NEWLINE, &patternNewlineSetting);
}
- usingCrLfNewlines = (patternNewlineSetting == PCRE_NEWLINE_CRLF) ||
- (patternNewlineSetting == PCRE_NEWLINE_ANY) ||
- (patternNewlineSetting == PCRE_NEWLINE_ANYCRLF);
+ usingCrLfNewlines = (patternNewlineSetting == PCRE2_NEWLINE_CRLF) ||
+ (patternNewlineSetting == PCRE2_NEWLINE_ANY) ||
+ (patternNewlineSetting == PCRE2_NEWLINE_ANYCRLF);
- int hasJOptionChanged;
- pcre16_fullinfo(compiledPattern, 0, PCRE_INFO_JCHANGED, &hasJOptionChanged);
- if (hasJOptionChanged) {
- qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%s'\n"
- " is using the (?J) option; duplicate capturing group names are not supported by Qt",
+ unsigned int hasJOptionChanged;
+ pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_JCHANGED, &hasJOptionChanged);
+ if (Q_UNLIKELY(hasJOptionChanged)) {
+ qWarning("QRegularExpressionPrivate::getPatternInfo(): the pattern '%s'\n is using the (?J) option; duplicate capturing group names are not supported by Qt",
qPrintable(pattern));
}
}
/*
- Simple "smartpointer" wrapper around a pcre_jit_stack, to be used with
+ Simple "smartpointer" wrapper around a pcre2_jit_stack_16, to be used with
QThreadStorage.
*/
class QPcreJitStackPointer
@@ -1086,7 +1090,7 @@ public:
{
// The default JIT stack size in PCRE is 32K,
// we allocate from 32K up to 512K.
- stack = pcre16_jit_stack_alloc(32*1024, 512*1024);
+ stack = pcre2_jit_stack_create_16(32 * 1024, 512 * 1024, NULL);
}
/*!
\internal
@@ -1094,10 +1098,10 @@ public:
~QPcreJitStackPointer()
{
if (stack)
- pcre16_jit_stack_free(stack);
+ pcre2_jit_stack_free_16(stack);
}
- pcre16_jit_stack *stack;
+ pcre2_jit_stack_16 *stack;
};
Q_GLOBAL_STATIC(QThreadStorage<QPcreJitStackPointer *>, jitStacks)
@@ -1105,7 +1109,7 @@ Q_GLOBAL_STATIC(QThreadStorage<QPcreJitStackPointer *>, jitStacks)
/*!
\internal
*/
-static pcre16_jit_stack *qtPcreCallback(void *)
+static pcre2_jit_stack_16 *qtPcreCallback(void *)
{
if (jitStacks()->hasLocalData())
return jitStacks()->localData()->stack;
@@ -1135,53 +1139,32 @@ static bool isJitEnabled()
/*!
\internal
- The purpose of the function is to call pcre16_study (which allows some
- optimizations to be performed, including JIT-compiling the pattern), and
- setting the studyData member variable to the result of the study. It gets
- called by doMatch() every time a match is performed. As of now, the
- optimizations on the pattern are performed after a certain number of usages
- (i.e. the qt_qregularexpression_optimize_after_use_count constant) unless
- the DontAutomaticallyOptimizeOption option is set on the QRegularExpression
- object, or anyhow by calling optimize() (which will pass
- ImmediateOptimizeOption).
+ The purpose of the function is to call pcre2_jit_compile_16, which
+ JIT-compiles the pattern.
- Notice that although the method is protected by a mutex, one thread may
- invoke this function and return immediately (i.e. not study the pattern,
- leaving studyData to NULL); but before calling pcre16_exec to perform the
- match, another thread performs the studying and sets studyData to something
- else. Although the assignment to studyData is itself atomic, the release of
- the memory pointed by studyData isn't. Therefore, we work on a local copy
- (localStudyData) before using storeRelease on studyData. In doMatch there's
- the corresponding loadAcquire.
+ It gets called by doMatch() every time a match is performed.
+
+ As of now, the optimizations on the pattern are performed after a certain
+ number of usages (i.e. the qt_qregularexpression_optimize_after_use_count
+ constant) unless the DontAutomaticallyOptimizeOption option is set on the
+ QRegularExpression object, or anyhow by calling optimize() (which will pass
+ ImmediateOptimizeOption).
*/
void QRegularExpressionPrivate::optimizePattern(OptimizePatternOption option)
{
Q_ASSERT(compiledPattern);
- QMutexLocker lock(&mutex);
+ static const bool enableJit = isJitEnabled();
- if (studyData.load()) // already optimized
+ if (!enableJit)
return;
+ const QWriteLocker lock(&mutex);
+
if ((option == LazyOptimizeOption) && (++usedCount != qt_qregularexpression_optimize_after_use_count))
return;
- static const bool enableJit = isJitEnabled();
-
- int studyOptions = 0;
- if (enableJit)
- studyOptions |= (PCRE_STUDY_JIT_COMPILE | PCRE_STUDY_JIT_PARTIAL_SOFT_COMPILE | PCRE_STUDY_JIT_PARTIAL_HARD_COMPILE);
-
- const char *err;
- pcre16_extra * const localStudyData = pcre16_study(compiledPattern, studyOptions, &err);
-
- if (localStudyData && localStudyData->flags & PCRE_EXTRA_EXECUTABLE_JIT)
- pcre16_assign_jit_stack(localStudyData, qtPcreCallback, 0);
-
- if (!localStudyData && err)
- qWarning("QRegularExpressionPrivate::optimizePattern(): pcre_study failed: %s", err);
-
- studyData.storeRelease(localStudyData);
+ pcre2_jit_compile_16(compiledPattern, PCRE2_JIT_COMPLETE | PCRE2_JIT_PARTIAL_SOFT | PCRE2_JIT_PARTIAL_HARD);
}
/*!
@@ -1197,7 +1180,7 @@ int QRegularExpressionPrivate::captureIndexForName(const QString &name) const
if (!compiledPattern)
return -1;
- int index = pcre16_get_stringnumber(compiledPattern, name.utf16());
+ int index = pcre2_substring_number_from_name_16(compiledPattern, name.utf16());
if (index >= 0)
return index;
@@ -1207,24 +1190,25 @@ int QRegularExpressionPrivate::captureIndexForName(const QString &name) const
/*!
\internal
- This is a simple wrapper for pcre16_exec for handling the case in which the
+ This is a simple wrapper for pcre2_match_16 for handling the case in which the
JIT runs out of memory. In that case, we allocate a thread-local JIT stack
- and re-run pcre16_exec.
+ and re-run pcre2_match_16.
*/
-static int pcre16SafeExec(const pcre16 *code, const pcre16_extra *extra,
- const unsigned short *subject, int length,
- int startOffset, int options,
- int *ovector, int ovecsize)
+static int safe_pcre2_match_16(const pcre2_code_16 *code,
+ const unsigned short *subject, int length,
+ int startOffset, int options,
+ pcre2_match_data_16 *matchData,
+ pcre2_match_context_16 *matchContext)
{
- int result = pcre16_exec(code, extra, subject, length,
- startOffset, options, ovector, ovecsize);
+ int result = pcre2_match_16(code, subject, length,
+ startOffset, options, matchData, matchContext);
- if (result == PCRE_ERROR_JIT_STACKLIMIT && !jitStacks()->hasLocalData()) {
+ if (result == PCRE2_ERROR_JIT_STACKLIMIT && !jitStacks()->hasLocalData()) {
QPcreJitStackPointer *p = new QPcreJitStackPointer;
jitStacks()->setLocalData(p);
- result = pcre16_exec(code, extra, subject, length,
- startOffset, options, ovector, ovecsize);
+ result = pcre2_match_16(code, subject, length,
+ startOffset, options, matchData, matchContext);
}
return result;
@@ -1273,29 +1257,24 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
QRegularExpression re(*const_cast<QRegularExpressionPrivate *>(this));
+ QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject,
+ subjectStart, subjectLength,
+ matchType, matchOptions);
+
if (offset < 0 || offset > subjectLength)
- return new QRegularExpressionMatchPrivate(re, subject, subjectStart, subjectLength, matchType, matchOptions);
+ return priv;
- if (!compiledPattern) {
+ if (Q_UNLIKELY(!compiledPattern)) {
qWarning("QRegularExpressionPrivate::doMatch(): called on an invalid QRegularExpression object");
- return new QRegularExpressionMatchPrivate(re, subject, subjectStart, subjectLength, matchType, matchOptions);
+ return priv;
}
// skip optimizing and doing the actual matching if NoMatch type was requested
if (matchType == QRegularExpression::NoMatch) {
- QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject,
- subjectStart, subjectLength,
- matchType, matchOptions);
priv->isValid = true;
return priv;
}
- // capturingCount doesn't include the implicit "0" capturing group
- QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject,
- subjectStart, subjectLength,
- matchType, matchOptions,
- capturingCount + 1);
-
if (!(patternOptions & QRegularExpression::DontAutomaticallyOptimizeOption)) {
const OptimizePatternOption optimizePatternOption =
(patternOptions & QRegularExpression::OptimizeOnFirstUsageOption)
@@ -1306,22 +1285,15 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
const_cast<QRegularExpressionPrivate *>(this)->optimizePattern(optimizePatternOption);
}
- // work with a local copy of the study data, as we are running pcre_exec
- // potentially more than once, and we don't want to run call it
- // with different study data
- const pcre16_extra * const currentStudyData = studyData.loadAcquire();
-
int pcreOptions = convertToPcreOptions(matchOptions);
if (matchType == QRegularExpression::PartialPreferCompleteMatch)
- pcreOptions |= PCRE_PARTIAL_SOFT;
+ pcreOptions |= PCRE2_PARTIAL_SOFT;
else if (matchType == QRegularExpression::PartialPreferFirstMatch)
- pcreOptions |= PCRE_PARTIAL_HARD;
+ pcreOptions |= PCRE2_PARTIAL_HARD;
- if (checkSubjectStringOption == DontCheckSubjectString
- || matchOptions & QRegularExpression::DontCheckSubjectStringMatchOption) {
- pcreOptions |= PCRE_NO_UTF16_CHECK;
- }
+ if (checkSubjectStringOption == DontCheckSubjectString)
+ pcreOptions |= PCRE2_NO_UTF_CHECK;
bool previousMatchWasEmpty = false;
if (previous && previous->hasMatch &&
@@ -1329,25 +1301,28 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
previousMatchWasEmpty = true;
}
- int * const captureOffsets = priv->capturedOffsets.data();
- const int captureOffsetsCount = priv->capturedOffsets.size();
+ pcre2_match_context_16 *matchContext = pcre2_match_context_create_16(NULL);
+ pcre2_jit_stack_assign_16(matchContext, &qtPcreCallback, NULL);
+ pcre2_match_data_16 *matchData = pcre2_match_data_create_from_pattern_16(compiledPattern, NULL);
const unsigned short * const subjectUtf16 = subject.utf16() + subjectStart;
int result;
+ QReadLocker lock(&mutex);
+
if (!previousMatchWasEmpty) {
- result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, subjectLength,
- offset, pcreOptions,
- captureOffsets, captureOffsetsCount);
+ result = safe_pcre2_match_16(compiledPattern,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions,
+ matchData, matchContext);
} else {
- result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, subjectLength,
- offset, pcreOptions | PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED,
- captureOffsets, captureOffsetsCount);
+ result = safe_pcre2_match_16(compiledPattern,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions | PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED,
+ matchData, matchContext);
- if (result == PCRE_ERROR_NOMATCH) {
+ if (result == PCRE2_ERROR_NOMATCH) {
++offset;
if (usingCrLfNewlines
@@ -1360,13 +1335,15 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
++offset;
}
- result = pcre16SafeExec(compiledPattern, currentStudyData,
- subjectUtf16, subjectLength,
- offset, pcreOptions,
- captureOffsets, captureOffsetsCount);
+ result = safe_pcre2_match_16(compiledPattern,
+ subjectUtf16, subjectLength,
+ offset, pcreOptions,
+ matchData, matchContext);
}
}
+ lock.unlock();
+
#ifdef QREGULAREXPRESSION_DEBUG
qDebug() << "Matching" << pattern << "against" << subject
<< "starting at" << subjectStart << "len" << subjectLength
@@ -1386,10 +1363,10 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
priv->capturedOffsets.resize(result * 2);
} else {
// no match, partial match or error
- priv->hasPartialMatch = (result == PCRE_ERROR_PARTIAL);
- priv->isValid = (result == PCRE_ERROR_NOMATCH || result == PCRE_ERROR_PARTIAL);
+ priv->hasPartialMatch = (result == PCRE2_ERROR_PARTIAL);
+ priv->isValid = (result == PCRE2_ERROR_NOMATCH || result == PCRE2_ERROR_PARTIAL);
- if (result == PCRE_ERROR_PARTIAL) {
+ if (result == PCRE2_ERROR_PARTIAL) {
// partial match:
// leave the start and end capture offsets (i.e. cap(0))
priv->capturedCount = 1;
@@ -1401,6 +1378,35 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString
}
}
+ // copy the captured substrings offsets, if any
+ if (priv->capturedCount) {
+ PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(matchData);
+ int * const capturedOffsets = priv->capturedOffsets.data();
+
+ for (int i = 0; i < priv->capturedCount * 2; ++i)
+ capturedOffsets[i] = static_cast<int>(ovector[i]);
+
+ // For partial matches, PCRE2 and PCRE1 differ in behavior when lookbehinds
+ // are involved. PCRE2 reports the real begin of the match and the maximum
+ // used lookbehind as distinct information; PCRE1 instead automatically
+ // adjusted ovector[0] to include the maximum lookbehind.
+ //
+ // For instance, given the pattern "\bstring\b", and the subject "a str":
+ // * PCRE1 reports partial, capturing " str"
+ // * PCRE2 reports partial, capturing "str" with a lookbehind of 1
+ //
+ // To keep behavior, emulate PCRE1 here.
+ // (Eventually, we could expose the lookbehind info in a future patch.)
+ if (result == PCRE2_ERROR_PARTIAL) {
+ unsigned int maximumLookBehind;
+ pcre2_pattern_info_16(compiledPattern, PCRE2_INFO_MAXLOOKBEHIND, &maximumLookBehind);
+ capturedOffsets[0] -= maximumLookBehind;
+ }
+ }
+
+ pcre2_match_data_free_16(matchData);
+ pcre2_match_context_free_16(matchContext);
+
return priv;
}
@@ -1412,19 +1418,13 @@ QRegularExpressionMatchPrivate::QRegularExpressionMatchPrivate(const QRegularExp
int subjectStart,
int subjectLength,
QRegularExpression::MatchType matchType,
- QRegularExpression::MatchOptions matchOptions,
- int capturingCount)
+ QRegularExpression::MatchOptions matchOptions)
: regularExpression(re), subject(subject),
subjectStart(subjectStart), subjectLength(subjectLength),
matchType(matchType), matchOptions(matchOptions),
capturedCount(0),
hasMatch(false), hasPartialMatch(false), isValid(false)
{
- Q_ASSERT(capturingCount >= 0);
- if (capturingCount > 0) {
- const int captureOffsetsCount = capturingCount * 3;
- capturedOffsets.resize(captureOffsetsCount);
- }
}
@@ -1632,13 +1632,13 @@ QStringList QRegularExpression::namedCaptureGroups() const
// contains one ushort followed by the name, NUL terminated.
// The ushort is the numerical index of the name in the pattern.
// The length of each entry is namedCapturingTableEntrySize.
- ushort *namedCapturingTable;
- int namedCapturingTableEntryCount;
- int namedCapturingTableEntrySize;
+ PCRE2_SPTR16 *namedCapturingTable;
+ unsigned int namedCapturingTableEntryCount;
+ unsigned int namedCapturingTableEntrySize;
- pcre16_fullinfo(d->compiledPattern, 0, PCRE_INFO_NAMETABLE, &namedCapturingTable);
- pcre16_fullinfo(d->compiledPattern, 0, PCRE_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
- pcre16_fullinfo(d->compiledPattern, 0, PCRE_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
+ pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMETABLE, &namedCapturingTable);
+ pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMECOUNT, &namedCapturingTableEntryCount);
+ pcre2_pattern_info_16(d->compiledPattern, PCRE2_INFO_NAMEENTRYSIZE, &namedCapturingTableEntrySize);
QStringList result;
@@ -1647,9 +1647,9 @@ QStringList QRegularExpression::namedCaptureGroups() const
for (int i = 0; i < d->capturingCount + 1; ++i)
result.append(QString());
- for (int i = 0; i < namedCapturingTableEntryCount; ++i) {
- const ushort * const currentNamedCapturingTableRow = namedCapturingTable +
- namedCapturingTableEntrySize * i;
+ for (unsigned int i = 0; i < namedCapturingTableEntryCount; ++i) {
+ const ushort * const currentNamedCapturingTableRow =
+ reinterpret_cast<const ushort *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
const int index = *currentNamedCapturingTableRow;
result[index] = QString::fromUtf16(currentNamedCapturingTableRow + 1);
@@ -1680,8 +1680,19 @@ bool QRegularExpression::isValid() const
QString QRegularExpression::errorString() const
{
d.data()->compilePattern();
- if (d->errorString)
- return QCoreApplication::translate("QRegularExpression", d->errorString);
+ if (d->errorCode) {
+ QString errorString;
+ int errorStringLength;
+ do {
+ errorString.resize(errorString.length() + 64);
+ errorStringLength = pcre2_get_error_message_16(d->errorCode,
+ reinterpret_cast<ushort *>(errorString.data()),
+ errorString.length());
+ } while (errorStringLength < 0);
+ errorString.resize(errorStringLength);
+
+ return QCoreApplication::translate("QRegularExpression", std::move(errorString).toLatin1().constData());
+ }
return QCoreApplication::translate("QRegularExpression", "no error");
}
@@ -2583,7 +2594,8 @@ QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match)
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2012 University of Cambridge
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2015 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -2625,80 +2637,149 @@ static const char *pcreCompileErrorCodes[] =
QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"),
QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in character class"),
QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "nothing to repeat"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "quantifier does not follow a repeatable item"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"),
QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (? or (?-"),
QT_TRANSLATE_NOOP("QRegularExpression", "POSIX named classes are supported only within a class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "missing )"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing closing parenthesis"),
QT_TRANSLATE_NOOP("QRegularExpression", "reference to non-existent subpattern"),
- QT_TRANSLATE_NOOP("QRegularExpression", "erroffset passed as NULL"),
- QT_TRANSLATE_NOOP("QRegularExpression", "unknown option bit(s) set"),
- QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after comment"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern passed as NULL"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unrecognised compile-time option bit(s)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after (?# comment"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too large"),
- QT_TRANSLATE_NOOP("QRegularExpression", "failed to get memory"),
- QT_TRANSLATE_NOOP("QRegularExpression", "unmatched parentheses"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "failed to allocate heap memory"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unmatched closing parenthesis"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: code overflow"),
- QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?<"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "letter or underscore expected after (?< or (?'"),
QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is not fixed length"),
QT_TRANSLATE_NOOP("QRegularExpression", "malformed number or name after (?("),
QT_TRANSLATE_NOOP("QRegularExpression", "conditional group contains more than two branches"),
- QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?("),
+ QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?( or (?(?C)"),
QT_TRANSLATE_NOOP("QRegularExpression", "(?R or (?[+-]digits must be followed by )"),
QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"),
- QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"),
- QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE is not compiled with PCRE_UTF8 support"),
- QT_TRANSLATE_NOOP("QRegularExpression", "character value in \\x{...} sequence is too large"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "internal error in pcre2_study(): should not occur"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have Unicode support"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\x{} or \\o{} is too large"),
QT_TRANSLATE_NOOP("QRegularExpression", "invalid condition (?(0)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "\\C not allowed in lookbehind assertion"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "\\C is not allowed in a lookbehind assertion"),
QT_TRANSLATE_NOOP("QRegularExpression", "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u"),
- QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is > 255"),
- QT_TRANSLATE_NOOP("QRegularExpression", "closing ) for (?C expected"),
- QT_TRANSLATE_NOOP("QRegularExpression", "recursive call could loop indefinitely"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is greater than 255"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "closing parenthesis for (?C expected"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in (*VERB) name"),
QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?P"),
QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-8 string"),
- QT_TRANSLATE_NOOP("QRegularExpression", "support for \\P, \\p, and \\X has not been compiled"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name (PCRE2_DUPNAMES not set)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "group name must start with a non-digit"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE2 does not have support for \\P, \\p, or \\X"),
QT_TRANSLATE_NOOP("QRegularExpression", "malformed \\P or \\p sequence"),
QT_TRANSLATE_NOOP("QRegularExpression", "unknown property name after \\P or \\p"),
- QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum 32 characters)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum 10000)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 (not in UTF-8 mode)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum " "10000" " characters)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum " "256" ")"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 in 8-bit non-UTF-8 mode"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: overran compiling workspace"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: previously-checked referenced subpattern not found"),
QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE group contains more than one branch"),
- QT_TRANSLATE_NOOP("QRegularExpression", "repeating a DEFINE group is not allowed"),
- QT_TRANSLATE_NOOP("QRegularExpression", "inconsistent NEWLINE options"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown newline setting"),
QT_TRANSLATE_NOOP("QRegularExpression", "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number"),
QT_TRANSLATE_NOOP("QRegularExpression", "a numbered reference must not be zero"),
QT_TRANSLATE_NOOP("QRegularExpression", "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized or malformed"),
QT_TRANSLATE_NOOP("QRegularExpression", "number is too big"),
QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"),
QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+"),
- QT_TRANSLATE_NOOP("QRegularExpression", "] is an invalid data character in JavaScript compatibility mode"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
QT_TRANSLATE_NOOP("QRegularExpression", "different names for subpatterns of the same number are not allowed"),
QT_TRANSLATE_NOOP("QRegularExpression", "(*MARK) must have an argument"),
- QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE is not compiled with PCRE_UCP support"),
- QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by an ASCII character"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a printable ASCII character"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by a letter or one of [\\]^_?"),
QT_TRANSLATE_NOOP("QRegularExpression", "\\k is not followed by a braced, angle-bracketed, or quoted name"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in find_fixedlength()"),
QT_TRANSLATE_NOOP("QRegularExpression", "\\N is not supported in a class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "too many forward references"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "SPARE ERROR"),
QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-16 string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using UTF is disabled by the application"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using UCP is disabled by the application"),
QT_TRANSLATE_NOOP("QRegularExpression", "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "character value in \\u.... sequence is too large"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-32 string"),
- QT_TRANSLATE_NOOP("QRegularExpression", "setting UTF is disabled by the application"),
- QT_TRANSLATE_NOOP("QRegularExpression", "non-hex character in \\x{} (closing brace missing?)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "non-octal character in \\o{} (closing brace missing?)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "missing opening brace after \\o"),
- QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested"),
- QT_TRANSLATE_NOOP("QRegularExpression", "invalid range in character class"),
- QT_TRANSLATE_NOOP("QRegularExpression", "group name must start with a non-digit"),
- QT_TRANSLATE_NOOP("QRegularExpression", "parentheses are too deeply nested (stack check)"),
- QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{}")
+ QT_TRANSLATE_NOOP("QRegularExpression", "character code point value in \\u.... sequence is too large"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "digits missing in \\x{} or \\o{}"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in (?(VERSION condition"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in auto_possessify()"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating delimiter for callout with string argument"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized string delimiter follows (?C"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled by the application"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "(?| and/or (?J: or (?x: parentheses are too deeply nested"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "using \\C is disabled in this PCRE2 library"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too complicated"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is too long"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern string is longer than the limit set by the application"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "no error"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "no match"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "partial match"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 1 byte missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 2 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 3 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 4 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5 bytes missing at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 2 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 3 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 4 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 5 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: byte 6 top bits not 0x80"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 5-byte character is not allowed (RFC 3629)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: 6-byte character is not allowed (RFC 3629)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points greater than 0x10ffff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: code points 0xd800-0xdfff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 2-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 3-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 4-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 5-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: overlong 6-byte sequence"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: isolated byte with 0x80 bit set"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-8 error: illegal byte (0xfe or 0xff)"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: missing low surrogate at end"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: invalid low surrogate"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-16 error: isolated low surrogate"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points 0xd800-0xdfff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "UTF-32 error: code points greater than 0x10ffff are not defined"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad data value"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "patterns do not all use the same character tables"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "magic number missing"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern compiled in wrong mode: 8/16/32-bit error"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad offset value"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad option value"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "invalid replacement string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad offset into UTF string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "callout error code"), /* Never returned by PCRE2 itself */
+ QT_TRANSLATE_NOOP("QRegularExpression", "invalid data in workspace for DFA restart"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "too much recursion for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "backreference condition or recursion test is not supported for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "function is not supported for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "pattern contains an item that is not supported for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "workspace size exceeded in DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "internal error - pattern overwritten?"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad JIT option"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "JIT stack limit reached"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "match limit exceeded"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "no more memory"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "unknown substring"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "non-unique substring name"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "NULL argument passed"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "nested recursion at the same subject position"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "recursion limit exceeded"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not available"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "requested value is not set"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "offset limit set without PCRE2_USE_OFFSET_LIMIT"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad escape sequence in replacement string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "expected closing curly bracket in replacement string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "bad substitution in replacement string"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "match with end before start is not supported"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "too many replacements (more than INT_MAX)")
};
#endif // #if 0
diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp
index cb11e72435..8fa378e935 100644
--- a/src/corelib/tools/qringbuffer.cpp
+++ b/src/corelib/tools/qringbuffer.cpp
@@ -132,7 +132,6 @@ char *QRingBuffer::reserve(qint64 bytes)
char *writePtr = buffers.last().data() + tail;
bufferSize += bytes;
- Q_ASSERT(bytes < MaxByteArraySize);
tail += int(bytes);
return writePtr;
}
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index 5738413bfb..0d42c8a212 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -974,13 +974,13 @@ qobject_cast(const QWeakPointer<T> &src)
}
template<typename T>
-QWeakPointer<typename QtPrivate::QEnableIf<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::Type>
+QWeakPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type>
qWeakPointerFromVariant(const QVariant &variant)
{
return QWeakPointer<T>(qobject_cast<T*>(QtSharedPointer::weakPointerFromVariant_internal(variant).data()));
}
template<typename T>
-QSharedPointer<typename QtPrivate::QEnableIf<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::Type>
+QSharedPointer<typename std::enable_if<QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value, T>::type>
qSharedPointerFromVariant(const QVariant &variant)
{
return qSharedPointerObjectCast<T>(QtSharedPointer::sharedPointerFromVariant_internal(variant));
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 247119d178..48f3d64c4a 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -211,7 +211,8 @@ void qt_from_latin1(ushort *dst, const char *str, size_t size) Q_DECL_NOTHROW
{
/* SIMD:
* Unpacking with SSE has been shown to improve performance on recent CPUs
- * The same method gives no improvement with NEON.
+ * The same method gives no improvement with NEON. On Aarch64, clang will do the vectorization
+ * itself in exactly the same way as one would do it with intrinsics.
*/
#if defined(__SSE2__)
const char *e = str + size;
@@ -491,6 +492,30 @@ static int ucstrncmp(const QChar *a, const QChar *b, int l)
return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
# endif
#endif
+#if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64
+ if (l >= 8) {
+ const QChar *end = a + l;
+ const uint16x8_t mask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
+ while (a + 7 < end) {
+ uint16x8_t da = vld1q_u16(reinterpret_cast<const uint16_t *>(a));
+ uint16x8_t db = vld1q_u16(reinterpret_cast<const uint16_t *>(b));
+
+ uint8_t r = ~(uint8_t)vaddvq_u16(vandq_u16(vceqq_u16(da, db), mask));
+ if (r) {
+ // found a different QChar
+ uint idx = qCountTrailingZeroBits(r);
+ return (int)a[idx].unicode() - (int)b[idx].unicode();
+ }
+ a += 8;
+ b += 8;
+ }
+ l &= 7;
+ }
+ const auto &lambda = [=](int i) -> int {
+ return a[i].unicode() - b[i].unicode();
+ };
+ return UnrollTailLoop<7>::exec(l, 0, lambda, lambda);
+#endif // __ARM_NEON__
if (!l)
return 0;
@@ -703,6 +728,18 @@ static int findChar(const QChar *str, int len, QChar ch, int from,
[=](int i) { return n - s + i; });
# endif
#endif
+#if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64
+ const uint16x8_t vmask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
+ const uint16x8_t ch_vec = vdupq_n_u16(c);
+ for (const ushort *next = n + 8; next <= e; n = next, next += 8) {
+ uint16x8_t data = vld1q_u16(n);
+ uint mask = vaddvq_u16(vandq_u16(vceqq_u16(data, ch_vec), vmask));
+ if (ushort(mask)) {
+ // found a match
+ return n - s + qCountTrailingZeroBits(mask);
+ }
+ }
+#endif // aarch64
--n;
while (++n != e)
if (*n == c)
@@ -742,7 +779,9 @@ inline char qToLower(char ch)
}
+#if QT_DEPRECATED_SINCE(5, 9)
const QString::Null QString::null = { };
+#endif
/*!
\macro QT_RESTRICTED_CAST_FROM_ASCII
@@ -1617,7 +1656,7 @@ QString::QString(QChar ch)
\internal
*/
-/*! \fn QString &QString::operator=(const Null &)
+/*! \fn QString &QString::operator=(const QString::Null &)
\internal
*/
@@ -1767,17 +1806,11 @@ void QString::resize(int size, QChar fillChar)
void QString::reallocData(uint alloc, bool grow)
{
- size_t blockSize;
- if (grow) {
- auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data));
- blockSize = r.size;
- alloc = uint(r.elementCount);
- } else {
- blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data));
- }
+ auto allocOptions = d->detachFlags();
+ if (grow)
+ allocOptions |= QArrayData::Grow;
if (d->ref.isShared() || IS_RAW_DATA(d)) {
- Data::AllocationOptions allocOptions(d->capacityReserved ? Data::CapacityReserved : 0);
Data *x = Data::allocate(alloc, allocOptions);
Q_CHECK_PTR(x);
x->size = qMin(int(alloc) - 1, d->size);
@@ -1787,11 +1820,9 @@ void QString::reallocData(uint alloc, bool grow)
Data::deallocate(d);
d = x;
} else {
- Data *p = static_cast<Data *>(::realloc(d, blockSize));
+ Data *p = Data::reallocateUnaligned(d, alloc, allocOptions);
Q_CHECK_PTR(p);
d = p;
- d->alloc = alloc;
- d->offset = sizeof(QStringData);
}
}
@@ -4466,11 +4497,11 @@ bool QString::startsWith(const QStringRef &s, Qt::CaseSensitivity cs) const
\sa startsWith()
*/
-bool QString::endsWith(const QString& s, Qt::CaseSensitivity cs) const
+bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs) const
{
return qt_ends_with(isNull() ? 0 : unicode(), size(),
s.isNull() ? 0 : s.unicode(), s.size(), cs);
- }
+}
/*!
\since 4.8
@@ -4606,6 +4637,8 @@ QByteArray QString::toLatin1_helper_inplace(QString &s)
QByteArray QString::toLocal8Bit_helper(const QChar *data, int size)
{
+ if (!data)
+ return QByteArray();
#ifndef QT_NO_TEXTCODEC
QTextCodec *localeCodec = QTextCodec::codecForLocale();
if (localeCodec)
@@ -4887,6 +4920,7 @@ QString QString::fromUcs4(const uint *unicode, int size)
return QUtf32::convertToUnicode((const char *)unicode, size*4, 0);
}
+
/*!
Resizes the string to \a size characters and copies \a unicode
into the string.
@@ -5981,7 +6015,10 @@ static uint parse_flag_characters(const char * &c) Q_DECL_NOTHROW
uint flags = QLocaleData::ZeroPadExponent;
while (true) {
switch (*c) {
- case '#': flags |= QLocaleData::Alternate; break;
+ case '#':
+ flags |= QLocaleData::ShowBase | QLocaleData::AddTrailingZeroes
+ | QLocaleData::ForcePoint;
+ break;
case '0': flags |= QLocaleData::ZeroPadded; break;
case '-': flags |= QLocaleData::LeftAdjusted; break;
case ' ': flags |= QLocaleData::BlankBeforePositive; break;
@@ -6239,7 +6276,7 @@ QString QString::vasprintf(const char *cformat, va_list ap)
case 'p': {
void *arg = va_arg(ap, void*);
const quint64 i = reinterpret_cast<quintptr>(arg);
- flags |= QLocaleData::Alternate;
+ flags |= QLocaleData::ShowBase;
subst = QLocaleData::c()->unsLongLongToString(i, precision, 16, width, flags);
++c;
break;
@@ -7814,10 +7851,13 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha
if (d.locale_occurrences > 0) {
QLocale locale;
- if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
+ const QLocale::NumberOptions numberOptions = locale.numberOptions();
+ if (!(numberOptions & QLocale::OmitGroupSeparator))
flags |= QLocaleData::ThousandsGroup;
- if (!(locale.numberOptions() & QLocale::OmitLeadingZeroInExponent))
+ if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
flags |= QLocaleData::ZeroPadExponent;
+ if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
+ flags |= QLocaleData::AddTrailingZeroes;
locale_arg = locale.d->m_data->doubleToString(a, prec, form, fieldWidth, flags);
}
@@ -8025,33 +8065,12 @@ bool QString::isSimpleText() const
/*! \fn bool QString::isRightToLeft() const
Returns \c true if the string is read right to left.
+
+ \sa QStringRef::isRightToLeft()
*/
bool QString::isRightToLeft() const
{
- const ushort *p = d->data();
- const ushort * const end = p + d->size;
- while (p < end) {
- uint ucs4 = *p;
- if (QChar::isHighSurrogate(ucs4) && p < end - 1) {
- ushort low = p[1];
- if (QChar::isLowSurrogate(low)) {
- ucs4 = QChar::surrogateToUcs4(ucs4, low);
- ++p;
- }
- }
- switch (QChar::direction(ucs4))
- {
- case QChar::DirL:
- return false;
- case QChar::DirR:
- case QChar::DirAL:
- return true;
- default:
- break;
- }
- ++p;
- }
- return false;
+ return QStringRef(this).isRightToLeft();
}
/*! \fn QChar *QString::data()
@@ -9007,7 +9026,7 @@ ownership of it, no memory is freed when instances are destroyed.
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in
the string.
- \sa cbegin(), end(), rbegin(), rend()
+ \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
*/
/*!
@@ -9016,7 +9035,16 @@ ownership of it, no memory is freed when instances are destroyed.
Same as begin().
- \sa begin(), cend(), rbegin(), rend()
+ \sa begin(), constBegin(), cend(), constEnd(), rbegin(), rend()
+*/
+
+/*!
+ \fn QStringRef::const_iterator QStringRef::constBegin() const
+ \since 5.9
+
+ Same as begin().
+
+ \sa begin(), cend(), constEnd(), rbegin(), rend()
*/
/*!
@@ -9026,7 +9054,7 @@ ownership of it, no memory is freed when instances are destroyed.
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
character after the last character in the list.
- \sa cbegin(), end(), rbegin(), rend()
+ \sa cbegin(), constBegin(), end(), constEnd(), rbegin(), rend()
*/
/*! \fn QStringRef::const_iterator QStringRef::cend() const
@@ -9034,7 +9062,15 @@ ownership of it, no memory is freed when instances are destroyed.
Same as end().
- \sa end(), cbegin(), rbegin(), rend()
+ \sa end(), constEnd(), cbegin(), constBegin(), rbegin(), rend()
+*/
+
+/*! \fn QStringRef::const_iterator QStringRef::constEnd() const
+ \since 5.9
+
+ Same as end().
+
+ \sa end(), cend(), cbegin(), constBegin(), rbegin(), rend()
*/
/*!
@@ -9585,9 +9621,7 @@ QStringRef QStringRef::left(int n) const
*/
QStringRef QString::leftRef(int n) const
{
- if (uint(n) >= uint(d->size))
- n = d->size;
- return QStringRef(this, 0, n);
+ return QStringRef(this).left(n);
}
/*!
@@ -9624,9 +9658,7 @@ QStringRef QStringRef::right(int n) const
*/
QStringRef QString::rightRef(int n) const
{
- if (uint(n) >= uint(d->size))
- n = d->size;
- return QStringRef(this, d->size - n, n);
+ return QStringRef(this).right(n);
}
/*!
@@ -9685,19 +9717,7 @@ QStringRef QStringRef::mid(int pos, int n) const
*/
QStringRef QString::midRef(int position, int n) const
{
- using namespace QtPrivate;
- switch (QContainerImplHelper::mid(d->size, &position, &n)) {
- case QContainerImplHelper::Null:
- return QStringRef();
- case QContainerImplHelper::Empty:
- return QStringRef(this, 0, 0);
- case QContainerImplHelper::Full:
- return QStringRef(this, 0, d->size);
- case QContainerImplHelper::Subset:
- return QStringRef(this, position, n);
- }
- Q_UNREACHABLE();
- return QStringRef();
+ return QStringRef(this).mid(position, n);
}
/*!
@@ -9944,6 +9964,41 @@ int QStringRef::count(const QStringRef &str, Qt::CaseSensitivity cs) const
}
/*!
+ \since 5.9
+
+ Returns \c true if the string is read right to left.
+
+ \sa QString::isRightToLeft()
+*/
+bool QStringRef::isRightToLeft() const
+{
+ const ushort *p = reinterpret_cast<const ushort*>(unicode());
+ const ushort * const end = p + size();
+ while (p < end) {
+ uint ucs4 = *p;
+ if (QChar::isHighSurrogate(ucs4) && p < end - 1) {
+ ushort low = p[1];
+ if (QChar::isLowSurrogate(low)) {
+ ucs4 = QChar::surrogateToUcs4(ucs4, low);
+ ++p;
+ }
+ }
+ switch (QChar::direction(ucs4))
+ {
+ case QChar::DirL:
+ return false;
+ case QChar::DirR:
+ case QChar::DirAL:
+ return true;
+ default:
+ break;
+ }
+ ++p;
+ }
+ return false;
+}
+
+/*!
\since 4.8
Returns \c true if the string reference starts with \a str; otherwise
@@ -10309,6 +10364,8 @@ static inline bool qt_ends_with(const QChar *haystack, int haystackLen,
*/
QByteArray QStringRef::toLatin1() const
{
+ if (isNull())
+ return QByteArray();
return QString::toLatin1_helper(unicode(), length());
}
@@ -10347,9 +10404,11 @@ QByteArray QStringRef::toLatin1() const
QByteArray QStringRef::toLocal8Bit() const
{
#ifndef QT_NO_TEXTCODEC
- QTextCodec *localeCodec = QTextCodec::codecForLocale();
- if (localeCodec)
- return localeCodec->fromUnicode(unicode(), length());
+ if (!isNull()) {
+ QTextCodec *localeCodec = QTextCodec::codecForLocale();
+ if (localeCodec)
+ return localeCodec->fromUnicode(unicode(), length());
+ }
#endif // QT_NO_TEXTCODEC
return toLatin1();
}
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index b50b2ee4e5..1bd436c387 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ -144,15 +144,10 @@ typedef QLatin1String QLatin1Literal;
typedef QTypedArrayData<ushort> QStringData;
-#if defined(Q_COMPILER_UNICODE_STRINGS)
-
-#define QT_UNICODE_LITERAL_II(str) u"" str
-typedef char16_t qunicodechar;
-
-#elif defined(Q_OS_WIN) \
- || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) \
- || (!defined(__SIZEOF_WCHAR_T__) && defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536))
-// wchar_t is 2 bytes
+#if defined(Q_OS_WIN) && !defined(Q_COMPILER_UNICODE_STRINGS)
+// fall back to wchar_t if the a Windows compiler does not
+// support Unicode string literals, assuming wchar_t is 2 bytes
+// on that platform (sanity-checked by static_assert further below)
#if defined(Q_CC_MSVC)
# define QT_UNICODE_LITERAL_II(str) L##str
@@ -162,21 +157,22 @@ typedef char16_t qunicodechar;
typedef wchar_t qunicodechar;
#else
+// all our supported compilers support Unicode string literals,
+// even if their Q_COMPILER_UNICODE_STRING has been revoked due
+// to lacking stdlib support. But QStringLiteral only needs the
+// core language feature, so just use u"" here unconditionally:
-#define QT_NO_UNICODE_LITERAL
-typedef ushort qunicodechar;
+#define QT_UNICODE_LITERAL_II(str) u"" str
+typedef char16_t qunicodechar;
#endif
Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
"qunicodechar must typedef an integral type of size 2");
-#ifndef QT_NO_UNICODE_LITERAL
-# define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
-# if defined(Q_COMPILER_LAMBDA)
-
-# define QStringLiteral(str) \
- ([]() -> QString { \
+#define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
+#define QStringLiteral(str) \
+ ([]() Q_DECL_NOEXCEPT -> QString { \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
static const QStaticStringData<Size> qstring_literal = { \
Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \
@@ -187,17 +183,6 @@ Q_STATIC_ASSERT_X(sizeof(qunicodechar) == 2,
}()) \
/**/
-# endif
-#endif // QT_NO_UNICODE_LITERAL
-
-#ifndef QStringLiteral
-// no lambdas, not GCC, or GCC in C++98 mode with 4-byte wchar_t
-// fallback, return a temporary QString
-// source code is assumed to be encoded in UTF-8
-
-# define QStringLiteral(str) QString::fromUtf8("" str "", sizeof(str) - 1)
-#endif
-
#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
{ Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset } \
/**/
@@ -397,7 +382,7 @@ public:
QString leftJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const Q_REQUIRED_RESULT;
QString rightJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const Q_REQUIRED_RESULT;
-#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
+#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
# if defined(Q_CC_GNU)
// required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941
# pragma push_macro("Q_REQUIRED_RESULT")
@@ -522,7 +507,7 @@ public:
const ushort *utf16() const;
-#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP)
+#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) && !defined(Q_CLANG_QDOC)
QByteArray toLatin1() const & Q_REQUIRED_RESULT
{ return toLatin1_helper(*this); }
QByteArray toLatin1() && Q_REQUIRED_RESULT
@@ -532,9 +517,9 @@ public:
QByteArray toUtf8() && Q_REQUIRED_RESULT
{ return toUtf8_helper(*this); }
QByteArray toLocal8Bit() const & Q_REQUIRED_RESULT
- { return toLocal8Bit_helper(constData(), size()); }
+ { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }
QByteArray toLocal8Bit() && Q_REQUIRED_RESULT
- { return toLocal8Bit_helper(constData(), size()); }
+ { return toLocal8Bit_helper(isNull() ? nullptr : constData(), size()); }
#else
QByteArray toLatin1() const Q_REQUIRED_RESULT;
QByteArray toUtf8() const Q_REQUIRED_RESULT;
@@ -785,10 +770,13 @@ public:
NSString *toNSString() const Q_DECL_NS_RETURNS_AUTORELEASED;
#endif
// compatibility
+#if QT_DEPRECATED_SINCE(5, 9)
struct Null { };
+ QT_DEPRECATED_X("use QString()")
static const Null null;
inline QString(const Null &): d(Data::sharedNull()) {}
inline QString &operator=(const Null &) { *this = QString(); return *this; }
+#endif
inline bool isNull() const { return d == Data::sharedNull(); }
@@ -1149,13 +1137,18 @@ inline bool QString::contains(QLatin1String s, Qt::CaseSensitivity cs) const
inline bool QString::contains(QChar c, Qt::CaseSensitivity cs) const
{ return indexOf(c, 0, cs) != -1; }
-
+#if QT_DEPRECATED_SINCE(5, 9)
inline bool operator==(QString::Null, QString::Null) { return true; }
+QT_DEPRECATED_X("use QString::isNull()")
inline bool operator==(QString::Null, const QString &s) { return s.isNull(); }
+QT_DEPRECATED_X("use QString::isNull()")
inline bool operator==(const QString &s, QString::Null) { return s.isNull(); }
inline bool operator!=(QString::Null, QString::Null) { return false; }
+QT_DEPRECATED_X("use !QString::isNull()")
inline bool operator!=(QString::Null, const QString &s) { return !s.isNull(); }
+QT_DEPRECATED_X("use !QString::isNull()")
inline bool operator!=(const QString &s, QString::Null) { return !s.isNull(); }
+#endif
inline bool operator==(QLatin1String s1, QLatin1String s2) Q_DECL_NOTHROW
{ return s1.size() == s2.size() && (!s1.size() || !memcmp(s1.latin1(), s2.latin1(), s1.size())); }
@@ -1400,7 +1393,8 @@ public:
QStringRef(QStringRef &&other) Q_DECL_NOTHROW : m_string(other.m_string), m_position(other.m_position), m_size(other.m_size) {}
QStringRef &operator=(QStringRef &&other) Q_DECL_NOTHROW { return *this = other; }
#endif
- QStringRef &operator=(const QStringRef &other) Q_DECL_NOTHROW {
+ QStringRef &operator=(const QStringRef &other) Q_DECL_NOTHROW
+ {
m_string = other.m_string; m_position = other.m_position;
m_size = other.m_size; return *this;
}
@@ -1449,6 +1443,8 @@ public:
m_size -= n;
}
+ bool isRightToLeft() const;
+
bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
@@ -1461,7 +1457,8 @@ public:
inline QStringRef &operator=(const QString *string);
- inline const QChar *unicode() const {
+ inline const QChar *unicode() const
+ {
if (!m_string)
return reinterpret_cast<const QChar *>(QString::Data::sharedNull()->data());
return m_string->unicode() + m_position;
@@ -1471,8 +1468,10 @@ public:
inline const_iterator begin() const { return unicode(); }
inline const_iterator cbegin() const { return unicode(); }
+ inline const_iterator constBegin() const { return unicode(); }
inline const_iterator end() const { return unicode() + size(); }
inline const_iterator cend() const { return unicode() + size(); }
+ inline const_iterator constEnd() const { return unicode() + size(); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
inline const_reverse_iterator crbegin() const { return rbegin(); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
diff --git a/src/corelib/tools/qstring_compat.cpp b/src/corelib/tools/qstring_compat.cpp
index 300f8467b1..45bb816e4b 100644
--- a/src/corelib/tools/qstring_compat.cpp
+++ b/src/corelib/tools/qstring_compat.cpp
@@ -80,7 +80,7 @@ QByteArray QString::toLatin1() const
QByteArray QString::toLocal8Bit() const
{
- return toLocal8Bit_helper(constData(), size());
+ return toLocal8Bit_helper(isNull() ? nullptr : constData(), size());
}
QByteArray QString::toUtf8() const
diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h
index b2832b5fbe..9a40abcfed 100644
--- a/src/corelib/tools/qstringbuilder.h
+++ b/src/corelib/tools/qstringbuilder.h
@@ -277,9 +277,9 @@ template <> struct QConcatenable<QStringRef> : private QAbstractConcatenable
}
};
-template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
+template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
{
- typedef char type[N];
+ typedef const char type[N];
typedef QByteArray ConvertTo;
enum { ExactSize = false };
static int size(const char[N]) { return N - 1; }
@@ -296,23 +296,9 @@ template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
}
};
-template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable
+template <int N> struct QConcatenable<char[N]> : QConcatenable<const char[N]>
{
- typedef const char type[N];
- typedef QByteArray ConvertTo;
- enum { ExactSize = false };
- static int size(const char[N]) { return N - 1; }
-#ifndef QT_NO_CAST_FROM_ASCII
- static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
- {
- QAbstractConcatenable::convertFromAscii(a, N - 1, out);
- }
-#endif
- static inline void appendTo(const char a[N], char *&out)
- {
- while (*a)
- *out++ = *a++;
- }
+ typedef char type[N];
};
template <> struct QConcatenable<const char *> : private QAbstractConcatenable
diff --git a/src/corelib/tools/qtimezone.h b/src/corelib/tools/qtimezone.h
index 083f87f39f..bd87139f5b 100644
--- a/src/corelib/tools/qtimezone.h
+++ b/src/corelib/tools/qtimezone.h
@@ -47,6 +47,11 @@
QT_REQUIRE_CONFIG(timezone);
+#if (defined(Q_OS_DARWIN) || defined(Q_QDOC)) && !defined(QT_NO_SYSTEMLOCALE)
+Q_FORWARD_DECLARE_CF_TYPE(CFTimeZone);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
+#endif
+
QT_BEGIN_NAMESPACE
class QTimeZonePrivate;
@@ -142,6 +147,13 @@ public:
static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId,
QLocale::Country country);
+#if (defined(Q_OS_DARWIN) || defined(Q_QDOC)) && !defined(QT_NO_SYSTEMLOCALE)
+ static QTimeZone fromCFTimeZone(CFTimeZoneRef timeZone);
+ CFTimeZoneRef toCFTimeZone() const Q_DECL_CF_RETURNS_RETAINED;
+ static QTimeZone fromNSTimeZone(const NSTimeZone *timeZone);
+ NSTimeZone *toNSTimeZone() const Q_DECL_NS_RETURNS_AUTORELEASED;
+#endif
+
private:
QTimeZone(QTimeZonePrivate &dd);
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/tools/qtimezoneprivate.cpp b/src/corelib/tools/qtimezoneprivate.cpp
index 2ff03eddec..7b780ecf7d 100644
--- a/src/corelib/tools/qtimezoneprivate.cpp
+++ b/src/corelib/tools/qtimezoneprivate.cpp
@@ -49,10 +49,6 @@
QT_BEGIN_NAMESPACE
-enum {
- MSECS_TRAN_WINDOW = 21600000 // 6 hour window for possible recent transitions
-};
-
/*
Static utilities for looking up Windows ID tables
*/
@@ -140,7 +136,7 @@ QTimeZonePrivate::~QTimeZonePrivate()
{
}
-QTimeZonePrivate *QTimeZonePrivate::clone()
+QTimeZonePrivate *QTimeZonePrivate::clone() const
{
return new QTimeZonePrivate(*this);
}
@@ -248,67 +244,206 @@ QTimeZonePrivate::Data QTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
}
// Private only method for use by QDateTime to convert local msecs to epoch msecs
-// TODO Could be platform optimised if needed
-QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs) const
+QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, int hint) const
{
- if (!hasDaylightTime() ||!hasTransitions()) {
- // No DST means same offset for all local msecs
- // Having DST but no transitions means we can't calculate, so use nearest
- return data(forLocalMSecs - (standardTimeOffset(forLocalMSecs) * 1000));
- }
+ if (!hasDaylightTime()) // No DST means same offset for all local msecs
+ return data(forLocalMSecs - standardTimeOffset(forLocalMSecs) * 1000);
- // Get the transition for the local msecs which most of the time should be the right one
- // Only around the transition times might it not be the right one
- Data tran = previousTransition(forLocalMSecs);
- Data nextTran;
-
- // If the local msecs is less than the real local time of the transition
- // then get the previous transition to use instead
- if (forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
- while (tran.atMSecsSinceEpoch != invalidMSecs()
- && forLocalMSecs < tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000)) {
- nextTran = tran;
- tran = previousTransition(tran.atMSecsSinceEpoch);
- }
- } else {
- // The zone msecs is after the transition, so check it is before the next tran
- // If not try use the next transition instead
- nextTran = nextTransition(tran.atMSecsSinceEpoch);
+ /*
+ We need a UTC time at which to ask for the offset, in order to be able to
+ add that offset to forLocalMSecs, to get the UTC time we
+ need. Fortunately, no time-zone offset is more than 14 hours; and DST
+ transitions happen (much) more than thirty-two hours apart. So sampling
+ offset sixteen hours each side gives us information we can be sure
+ brackets the correct time and at most one DST transition.
+ */
+ const qint64 sixteenHoursInMSecs(16 * 3600 * 1000);
+ /*
+ Offsets are Local - UTC, positive to the east of Greenwich, negative to
+ the west; DST offset always exceeds standard offset, when DST applies.
+ When we have offsets on either side of a transition, the lower one is
+ standard, the higher is DST.
+
+ Non-DST transitions (jurisdictions changing time-zone and time-zones
+ changing their standard offset, typically) are described below as if they
+ were DST transitions (since these are more usual and familiar); the code
+ mostly concerns itself with offsets from UTC, described in terms of the
+ common case for changes in that. If there is no actual change in offset
+ (e.g. a DST transition cancelled by a standard offset change), this code
+ should handle it gracefully; without transitions, it'll see early == late
+ and take the easy path; with transitions, tran and nextTran get the
+ correct UTC time as atMSecsSinceEpoch so comparing to nextStart selects
+ the right one. In all other cases, the transition changes offset and the
+ reasoning that applies to DST applies just the same. Aside from hinting,
+ the only thing that looks at DST-ness at all, other than inferred from
+ offset changes, is the case without transition data handling an invalid
+ time in the gap that a transition passed over.
+
+ The handling of hint (see below) is apt to go wrong in non-DST
+ transitions. There isn't really a great deal we can hope to do about that
+ without adding yet more unreliable complexity to the heuristics in use for
+ already obscure corner-cases.
+ */
+
+ /*
+ The hint (really a QDateTimePrivate::DaylightStatus) is > 0 if caller
+ thinks we're in DST, 0 if in standard. A value of -2 means never-DST, so
+ should have been handled above; if it slips through, it's wrong but we
+ should probably treat it as standard anyway (never-DST means
+ always-standard, after all). If the hint turns out to be wrong, fall back
+ on trying the other possibility: which makes it harmless to treat -1
+ (meaning unknown) as standard (i.e. try standard first, then try DST). In
+ practice, away from a transition, the only difference hint makes is to
+ which candidate we try first: if the hint is wrong (or unknown and
+ standard fails), we'll try the other candidate and it'll work.
+
+ For the obscure (and invalid) case where forLocalMSecs falls in a
+ spring-forward's missing hour, a common case is that we started with a
+ date/time for which the hint was valid and adjusted it naively; for that
+ case, we should correct the adjustment by shunting across the transition
+ into where hint is wrong. So half-way through the gap, arrived at from
+ the DST side, should be read as an hour earlier, in standard time; but, if
+ arrived at from the standard side, should be read as an hour later, in
+ DST. (This shall be wrong in some cases; for example, when a country
+ changes its transition dates and changing a date/time by more than six
+ months lands it on a transition. However, these cases are even more
+ obscure than those where the heuristic is good.)
+ */
+
+ if (hasTransitions()) {
+ /*
+ We have transitions.
+
+ Each transition gives the offsets to use until the next; so we need the
+ most recent transition before the time forLocalMSecs describes. If it
+ describes a time *in* a transition, we'll need both that transition and
+ the one before it. So find one transition that's probably after (and not
+ much before, otherwise) and another that's definitely before, then work
+ out which one to use. When both or neither work on forLocalMSecs, use
+ hint to disambiguate.
+ */
+
+ // Get a transition definitely before the local MSecs; usually all we need.
+ // Only around the transition times might we need another.
+ Data tran = previousTransition(forLocalMSecs - sixteenHoursInMSecs);
+ Q_ASSERT(forLocalMSecs < 0 || // Pre-epoch TZ info may be unavailable
+ forLocalMSecs >= tran.atMSecsSinceEpoch + tran.offsetFromUtc * 1000);
+ Data nextTran = nextTransition(tran.atMSecsSinceEpoch);
+ /*
+ Now walk those forward until they bracket forLocalMSecs with transitions.
+
+ One of the transitions should then be telling us the right offset to use.
+ In a transition, we need the transition before it (to describe the run-up
+ to the transition) and the transition itself; so we need to stop when
+ nextTran is that transition.
+ */
while (nextTran.atMSecsSinceEpoch != invalidMSecs()
- && forLocalMSecs >= nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)) {
+ && forLocalMSecs > nextTran.atMSecsSinceEpoch + nextTran.offsetFromUtc * 1000) {
+ Data newTran = nextTransition(nextTran.atMSecsSinceEpoch);
+ if (newTran.atMSecsSinceEpoch == invalidMSecs()
+ || newTran.atMSecsSinceEpoch + newTran.offsetFromUtc * 1000
+ > forLocalMSecs + sixteenHoursInMSecs) {
+ // Definitely not a relevant tansition: too far in the future.
+ break;
+ }
tran = nextTran;
- nextTran = nextTransition(tran.atMSecsSinceEpoch);
+ nextTran = newTran;
}
+
+ // Check we do *really* have transitions for this zone:
+ if (tran.atMSecsSinceEpoch != invalidMSecs()) {
+
+ /*
+ So now tran is definitely before and nextTran is either after or only
+ slightly before. The one with the larger offset is in DST; the other in
+ standard time. Our hint tells us which of those to use (defaulting to
+ standard if no hint): try it first; if that fails, try the other; if both
+ fail life's tricky.
+ */
+ Q_ASSERT(forLocalMSecs < 0
+ || forLocalMSecs > tran.atMSecsSinceEpoch + tran.offsetFromUtc * 1000);
+ const qint64 nextStart = nextTran.atMSecsSinceEpoch;
+ // Work out the UTC values it might make sense to return:
+ nextTran.atMSecsSinceEpoch = forLocalMSecs - nextTran.offsetFromUtc * 1000;
+ tran.atMSecsSinceEpoch = forLocalMSecs - tran.offsetFromUtc * 1000;
+
+ const bool nextIsDst = tran.offsetFromUtc < nextTran.offsetFromUtc;
+ // If that agrees with hint > 0, our first guess is to use nextTran; else tran.
+ const bool nextFirst = nextIsDst == (hint > 0) && nextStart != invalidMSecs();
+ for (int i = 0; i < 2; i++) {
+ /*
+ On the first pass, the case we consider is what hint told us to expect
+ (except when hint was -1 and didn't actually tell us what to expect),
+ so it's likely right. We only get a second pass if the first failed,
+ by which time the second case, that we're trying, is likely right. If
+ an overwhelming majority of calls have hint == -1, the Q_LIKELY here
+ shall be wrong half the time; otherwise, its errors shall be rarer
+ than that.
+ */
+ if (nextFirst ? i == 0 : i) {
+ Q_ASSERT(nextStart != invalidMSecs());
+ if (Q_LIKELY(nextStart <= nextTran.atMSecsSinceEpoch))
+ return nextTran;
+ } else {
+ // If next is invalid, nextFirst is false, to route us here first:
+ if (nextStart == invalidMSecs() || Q_LIKELY(nextStart > tran.atMSecsSinceEpoch))
+ return tran;
+ }
+ }
+
+ /*
+ Neither is valid (e.g. in a spring-forward's gap) and
+ nextTran.atMSecsSinceEpoch < nextStart <= tran.atMSecsSinceEpoch, so
+ 0 < tran.atMSecsSinceEpoch - nextTran.atMSecsSinceEpoch
+ = (nextTran.offsetFromUtc - tran.offsetFromUtc) * 1000
+ */
+ int dstStep = nextTran.offsetFromUtc - tran.offsetFromUtc;
+ Q_ASSERT(dstStep > 0); // How else could we get here ?
+ if (nextFirst) { // hint thought we needed nextTran, so use tran
+ tran.atMSecsSinceEpoch -= dstStep;
+ return tran;
+ }
+ nextTran.atMSecsSinceEpoch += dstStep;
+ return nextTran;
+ }
+ // System has transitions but not for this zone.
+ // Try falling back to offsetFromUtc
}
- if (tran.daylightTimeOffset == 0) {
- // If tran is in StandardTime, then need to check if falls close to either DST transition.
- // If it does, then it may need adjusting for missing hour or for second occurrence
- qint64 diffPrevTran = forLocalMSecs
- - (tran.atMSecsSinceEpoch + (tran.offsetFromUtc * 1000));
- qint64 diffNextTran = nextTran.atMSecsSinceEpoch + (nextTran.offsetFromUtc * 1000)
- - forLocalMSecs;
- if (diffPrevTran >= 0 && diffPrevTran < MSECS_TRAN_WINDOW) {
- // If tran picked is for standard time check if changed from DST in last 6 hours,
- // as the local msecs may be ambiguous and represent two valid utc msecs.
- // If in last 6 hours then get prev tran and if diff falls within the DST offset
- // then use the prev tran as we default to the FirstOccurrence
- // TODO Check if faster to just always get prev tran, or if faster using 6 hour check.
- Data dstTran = previousTransition(tran.atMSecsSinceEpoch);
- if (dstTran.atMSecsSinceEpoch != invalidMSecs()
- && dstTran.daylightTimeOffset > 0 && diffPrevTran < (dstTran.daylightTimeOffset * 1000))
- tran = dstTran;
- } else if (diffNextTran >= 0 && diffNextTran <= (nextTran.daylightTimeOffset * 1000)) {
- // If time falls within last hour of standard time then is actually the missing hour
- // So return the next tran instead and adjust the local time to be valid
- tran = nextTran;
- forLocalMSecs = forLocalMSecs + (nextTran.daylightTimeOffset * 1000);
+ /* Bracket and refine to discover offset. */
+ qint64 utcEpochMSecs;
+
+ int early = offsetFromUtc(forLocalMSecs - sixteenHoursInMSecs);
+ int late = offsetFromUtc(forLocalMSecs + sixteenHoursInMSecs);
+ if (Q_LIKELY(early == late)) { // > 99% of the time
+ utcEpochMSecs = forLocalMSecs - early * 1000;
+ } else {
+ // Close to a DST transition: early > late is near a fall-back,
+ // early < late is near a spring-forward.
+ const int offsetInDst = qMax(early, late);
+ const int offsetInStd = qMin(early, late);
+ // Candidate values for utcEpochMSecs (if forLocalMSecs is valid):
+ const qint64 forDst = forLocalMSecs - offsetInDst * 1000;
+ const qint64 forStd = forLocalMSecs - offsetInStd * 1000;
+ // Best guess at the answer:
+ const qint64 hinted = hint > 0 ? forDst : forStd;
+ if (Q_LIKELY(offsetFromUtc(hinted) == (hint > 0 ? offsetInDst : offsetInStd))) {
+ utcEpochMSecs = hinted;
+ } else if (hint <= 0 && offsetFromUtc(forDst) == offsetInDst) {
+ utcEpochMSecs = forDst;
+ } else if (hint > 0 && offsetFromUtc(forStd) == offsetInStd) {
+ utcEpochMSecs = forStd;
+ } else {
+ // Invalid forLocalMSecs: in spring-forward gap.
+ const int dstStep = daylightTimeOffset(early < late ?
+ forLocalMSecs + sixteenHoursInMSecs :
+ forLocalMSecs - sixteenHoursInMSecs);
+ Q_ASSERT(dstStep); // There can't be a transition without it !
+ utcEpochMSecs = (hint > 0) ? forStd - dstStep : forDst + dstStep;
}
}
- // tran should now hold the right transition offset to use
- tran.atMSecsSinceEpoch = forLocalMSecs - (tran.offsetFromUtc * 1000);
- return tran;
+ return data(utcEpochMSecs);
}
bool QTimeZonePrivate::hasTransitions() const
@@ -649,7 +784,7 @@ QUtcTimeZonePrivate::~QUtcTimeZonePrivate()
{
}
-QTimeZonePrivate *QUtcTimeZonePrivate::clone()
+QUtcTimeZonePrivate *QUtcTimeZonePrivate::clone() const
{
return new QUtcTimeZonePrivate(*this);
}
diff --git a/src/corelib/tools/qtimezoneprivate_android.cpp b/src/corelib/tools/qtimezoneprivate_android.cpp
index 53bf90f01d..c3f8c3e0d9 100644
--- a/src/corelib/tools/qtimezoneprivate_android.cpp
+++ b/src/corelib/tools/qtimezoneprivate_android.cpp
@@ -88,7 +88,7 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId)
m_id = ianaId;
}
-QTimeZonePrivate *QAndroidTimeZonePrivate::clone()
+QAndroidTimeZonePrivate *QAndroidTimeZonePrivate::clone() const
{
return new QAndroidTimeZonePrivate(*this);
}
@@ -207,58 +207,6 @@ QTimeZonePrivate::Data QAndroidTimeZonePrivate::previousTransition(qint64 before
return invalidData();
}
-// Since Android does not provide an API to access transitions,
-// dataForLocalTime needs to be reimplemented without direct use of transitions
-QTimeZonePrivate::Data QAndroidTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs) const
-{
- if (!androidTimeZone.isValid()) {
- return invalidData();
- } else {
- qint64 UTCepochMSecs;
-
- // compare the UTC time with standard offset against normal DST offset of one hour
- qint64 standardUTCMSecs(forLocalMSecs - (standardTimeOffset(forLocalMSecs) * 1000));
- qint64 daylightUTCMsecs;
-
- // Check if daylight-saving time applies,
- // checking also for DST boundaries
- if (isDaylightTime(standardUTCMSecs)) {
- // If DST does apply, then standardUTCMSecs will be an hour or so ahead of the real epoch time
- // so check that time
- daylightUTCMsecs = standardUTCMSecs - daylightTimeOffset(standardUTCMSecs)*1000;
- if (isDaylightTime(daylightUTCMsecs)) {
- // DST confirmed
- UTCepochMSecs = daylightUTCMsecs;
- } else {
- // DST has just finished
- UTCepochMSecs = standardUTCMSecs;
- }
- } else {
- // Standard time indicated, but check for a false negative.
- // Would a standard one-hour DST offset indicate DST?
- daylightUTCMsecs = standardUTCMSecs - 3600000; // 3600000 MSECS_PER_HOUR
- if (isDaylightTime(daylightUTCMsecs)) {
- // DST may have just started,
- // but double check against timezone's own DST offset
- // (don't necessarily assume a one-hour offset)
- daylightUTCMsecs = standardUTCMSecs - daylightTimeOffset(daylightUTCMsecs)*1000;
- if (isDaylightTime(daylightUTCMsecs)) {
- // DST confirmed
- UTCepochMSecs = daylightUTCMsecs;
- } else {
- // false positive, apply standard time after all
- UTCepochMSecs = standardUTCMSecs;
- }
- } else {
- // confirmed standard time
- UTCepochMSecs = standardUTCMSecs;
- }
- }
-
- return data(UTCepochMSecs);
- }
-}
-
QByteArray QAndroidTimeZonePrivate::systemTimeZoneId() const
{
QJNIObjectPrivate androidSystemTimeZone = QJNIObjectPrivate::callStaticObjectMethod("java.util.TimeZone", "getDefault", "()Ljava/util/TimeZone;");
diff --git a/src/corelib/tools/qtimezoneprivate_icu.cpp b/src/corelib/tools/qtimezoneprivate_icu.cpp
index c088fe7694..a7226f2720 100644
--- a/src/corelib/tools/qtimezoneprivate_icu.cpp
+++ b/src/corelib/tools/qtimezoneprivate_icu.cpp
@@ -98,7 +98,7 @@ static QByteArray ucalDefaultTimeZoneId()
// If successful on first or second go, resize and return
if (U_SUCCESS(status)) {
result.resize(size);
- return result.toUtf8();
+ return std::move(result).toUtf8();
}
return QByteArray();
@@ -305,7 +305,7 @@ QIcuTimeZonePrivate::~QIcuTimeZonePrivate()
ucal_close(m_ucal);
}
-QTimeZonePrivate *QIcuTimeZonePrivate::clone()
+QIcuTimeZonePrivate *QIcuTimeZonePrivate::clone() const
{
return new QIcuTimeZonePrivate(*this);
}
diff --git a/src/corelib/tools/qtimezoneprivate_mac.mm b/src/corelib/tools/qtimezoneprivate_mac.mm
index 5dfffeaf36..4e9a432fbf 100644
--- a/src/corelib/tools/qtimezoneprivate_mac.mm
+++ b/src/corelib/tools/qtimezoneprivate_mac.mm
@@ -82,7 +82,7 @@ QMacTimeZonePrivate::~QMacTimeZonePrivate()
[m_nstz release];
}
-QTimeZonePrivate *QMacTimeZonePrivate::clone()
+QMacTimeZonePrivate *QMacTimeZonePrivate::clone() const
{
return new QMacTimeZonePrivate(*this);
}
@@ -273,4 +273,9 @@ QList<QByteArray> QMacTimeZonePrivate::availableTimeZoneIds() const
return list;
}
+NSTimeZone *QMacTimeZonePrivate::nsTimeZone() const
+{
+ return m_nstz;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h
index d06784b0f9..0038908160 100644
--- a/src/corelib/tools/qtimezoneprivate_p.h
+++ b/src/corelib/tools/qtimezoneprivate_p.h
@@ -60,13 +60,9 @@
#include <unicode/ucal.h>
#endif
-#ifdef Q_OS_MAC
-#ifdef __OBJC__
-@class NSTimeZone;
-#else
-class NSTimeZone;
-#endif // __OBJC__
-#endif // Q_OS_MAC
+#ifdef Q_OS_DARWIN
+Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
+#endif // Q_OS_DARWIN
#ifdef Q_OS_WIN
#include <qt_windows.h>
@@ -78,7 +74,7 @@ class NSTimeZone;
QT_BEGIN_NAMESPACE
-class Q_CORE_EXPORT QTimeZonePrivate : public QSharedData
+class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData
{
public:
//Version of QTimeZone::OffsetData struct using msecs for efficiency
@@ -96,7 +92,7 @@ public:
QTimeZonePrivate(const QTimeZonePrivate &other);
virtual ~QTimeZonePrivate();
- virtual QTimeZonePrivate *clone();
+ virtual QTimeZonePrivate *clone() const;
bool operator==(const QTimeZonePrivate &other) const;
bool operator!=(const QTimeZonePrivate &other) const;
@@ -123,7 +119,7 @@ public:
virtual bool isDaylightTime(qint64 atMSecsSinceEpoch) const;
virtual Data data(qint64 forMSecsSinceEpoch) const;
- virtual Data dataForLocalTime(qint64 forLocalMSecs) const;
+ Data dataForLocalTime(qint64 forLocalMSecs, int hint) const;
virtual bool hasTransitions() const;
virtual Data nextTransition(qint64 afterMSecsSinceEpoch) const;
@@ -191,7 +187,7 @@ public:
QUtcTimeZonePrivate(const QUtcTimeZonePrivate &other);
virtual ~QUtcTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QUtcTimeZonePrivate *clone() const override;
Data data(qint64 forMSecsSinceEpoch) const Q_DECL_OVERRIDE;
@@ -238,7 +234,7 @@ public:
QIcuTimeZonePrivate(const QIcuTimeZonePrivate &other);
~QIcuTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QIcuTimeZonePrivate *clone() const override;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const Q_DECL_OVERRIDE;
@@ -291,15 +287,15 @@ Q_DECL_CONSTEXPR inline bool operator!=(const QTzTransitionRule &lhs, const QTzT
class Q_AUTOTEST_EXPORT QTzTimeZonePrivate Q_DECL_FINAL : public QTimeZonePrivate
{
+ QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default;
public:
// Create default time zone
QTzTimeZonePrivate();
// Create named time zone
QTzTimeZonePrivate(const QByteArray &ianaId);
- QTzTimeZonePrivate(const QTzTimeZonePrivate &other);
~QTzTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QTzTimeZonePrivate *clone() const override;
QLocale::Country country() const Q_DECL_OVERRIDE;
QString comment() const Q_DECL_OVERRIDE;
@@ -355,7 +351,7 @@ public:
QMacTimeZonePrivate(const QMacTimeZonePrivate &other);
~QMacTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QMacTimeZonePrivate *clone() const override;
QString comment() const Q_DECL_OVERRIDE;
@@ -380,6 +376,8 @@ public:
QList<QByteArray> availableTimeZoneIds() const Q_DECL_OVERRIDE;
+ NSTimeZone *nsTimeZone() const;
+
private:
void init(const QByteArray &zoneId);
@@ -406,7 +404,7 @@ public:
QWinTimeZonePrivate(const QWinTimeZonePrivate &other);
~QWinTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QWinTimeZonePrivate *clone() const override;
QString comment() const Q_DECL_OVERRIDE;
@@ -456,7 +454,7 @@ public:
QAndroidTimeZonePrivate(const QAndroidTimeZonePrivate &other);
~QAndroidTimeZonePrivate();
- QTimeZonePrivate *clone() Q_DECL_OVERRIDE;
+ QAndroidTimeZonePrivate *clone() const override;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const Q_DECL_OVERRIDE;
@@ -475,8 +473,6 @@ public:
Data nextTransition(qint64 afterMSecsSinceEpoch) const Q_DECL_OVERRIDE;
Data previousTransition(qint64 beforeMSecsSinceEpoch) const Q_DECL_OVERRIDE;
- Data dataForLocalTime(qint64 forLocalMSecs) const Q_DECL_OVERRIDE;
-
QByteArray systemTimeZoneId() const Q_DECL_OVERRIDE;
QList<QByteArray> availableTimeZoneIds() const Q_DECL_OVERRIDE;
diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp
index 10b61c3a40..1714c9802f 100644
--- a/src/corelib/tools/qtimezoneprivate_tz.cpp
+++ b/src/corelib/tools/qtimezoneprivate_tz.cpp
@@ -199,7 +199,7 @@ static QVector<QTzTransition> parseTzTransitions(QDataStream &ds, int tzh_timecn
}
} else {
// Parse tzh_timecnt x 4-byte transition times
- int val;
+ qint32 val;
for (int i = 0; i < tzh_timecnt && ds.status() == QDataStream::Ok; ++i) {
ds >> val;
transitions[i].tz_time = val;
@@ -452,13 +452,31 @@ static inline bool asciiIsLetter(char ch)
return ch >= 'a' && ch <= 'z';
}
+namespace {
+
+struct PosixZone
+{
+ enum {
+ InvalidOffset = INT_MIN,
+ };
+
+ QString name;
+ int offset;
+
+ static PosixZone invalid() { return {QString(), InvalidOffset}; }
+ static PosixZone parse(const char *&pos, const char *end);
+
+ bool hasValidOffset() const Q_DECL_NOTHROW { return offset != InvalidOffset; }
+};
+
+} // unnamed namespace
+
// Returns the zone name, the offset (in seconds) and advances \a begin to
// where the parsing ended. Returns a zone of INT_MIN in case an offset
// couldn't be read.
-static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const char *end)
+PosixZone PosixZone::parse(const char *&pos, const char *end)
{
static const char offsetChars[] = "0123456789:";
- QPair<QString, int> result = qMakePair(QString(), INT_MIN);
const char *nameBegin = pos;
const char *nameEnd;
@@ -480,7 +498,7 @@ static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const c
pos = nameEnd;
}
if (nameEnd - nameBegin < 3)
- return result; // name must be at least 3 characters long
+ return invalid(); // name must be at least 3 characters long
// zone offset, form [+-]hh:mm:ss
const char *zoneBegin = pos;
@@ -493,11 +511,10 @@ static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const c
++zoneEnd;
}
- result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin);
- if (zoneEnd > zoneBegin)
- result.second = parsePosixOffset(zoneBegin, zoneEnd);
+ QString name = QString::fromUtf8(nameBegin, nameEnd - nameBegin);
+ const int offset = zoneEnd > zoneBegin ? parsePosixOffset(zoneBegin, zoneEnd) : InvalidOffset;
pos = zoneEnd;
- return result;
+ return {std::move(name), offset};
}
static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule,
@@ -517,19 +534,19 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
// See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
QList<QByteArray> parts = posixRule.split(',');
- QPair<QString, int> stdZone, dstZone;
+ PosixZone stdZone, dstZone;
{
const QByteArray &zoneinfo = parts.at(0);
const char *begin = zoneinfo.constBegin();
- stdZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
- if (stdZone.second == INT_MIN) {
- stdZone.second = 0; // reset to UTC if we failed to parse
+ stdZone = PosixZone::parse(begin, zoneinfo.constEnd());
+ if (!stdZone.hasValidOffset()) {
+ stdZone.offset = 0; // reset to UTC if we failed to parse
} else if (begin < zoneinfo.constEnd()) {
- dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());
- if (dstZone.second == INT_MIN) {
+ dstZone = PosixZone::parse(begin, zoneinfo.constEnd());
+ if (!dstZone.hasValidOffset()) {
// if the dst offset isn't provided, it is 1 hour ahead of the standard offset
- dstZone.second = stdZone.second + (60 * 60);
+ dstZone.offset = stdZone.offset + (60 * 60);
}
}
}
@@ -538,10 +555,10 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
if (parts.count() == 1) {
QTimeZonePrivate::Data data;
data.atMSecsSinceEpoch = lastTranMSecs;
- data.offsetFromUtc = stdZone.second;
- data.standardTimeOffset = stdZone.second;
+ data.offsetFromUtc = stdZone.offset;
+ data.standardTimeOffset = stdZone.offset;
data.daylightTimeOffset = 0;
- data.abbreviation = stdZone.first;
+ data.abbreviation = stdZone.name;
result << data;
return result;
}
@@ -568,18 +585,18 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
for (int year = startYear; year <= endYear; ++year) {
QTimeZonePrivate::Data dstData;
QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC);
- dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.second * 1000);
- dstData.offsetFromUtc = dstZone.second;
- dstData.standardTimeOffset = stdZone.second;
- dstData.daylightTimeOffset = dstZone.second - stdZone.second;
- dstData.abbreviation = dstZone.first;
+ dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.offset * 1000);
+ dstData.offsetFromUtc = dstZone.offset;
+ dstData.standardTimeOffset = stdZone.offset;
+ dstData.daylightTimeOffset = dstZone.offset - stdZone.offset;
+ dstData.abbreviation = dstZone.name;
QTimeZonePrivate::Data stdData;
QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC);
- stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000);
- stdData.offsetFromUtc = stdZone.second;
- stdData.standardTimeOffset = stdZone.second;
+ stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.offset * 1000);
+ stdData.offsetFromUtc = stdZone.offset;
+ stdData.standardTimeOffset = stdZone.offset;
stdData.daylightTimeOffset = 0;
- stdData.abbreviation = stdZone.first;
+ stdData.abbreviation = stdZone.name;
// Part of the high year will overflow
if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) {
if (dstData.atMSecsSinceEpoch > 0) {
@@ -598,37 +615,21 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra
// Create the system default time zone
QTzTimeZonePrivate::QTzTimeZonePrivate()
-#if QT_CONFIG(icu)
- : m_icu(0)
-#endif
{
init(systemTimeZoneId());
}
// Create a named time zone
QTzTimeZonePrivate::QTzTimeZonePrivate(const QByteArray &ianaId)
-#if QT_CONFIG(icu)
- : m_icu(0)
-#endif
{
init(ianaId);
}
-QTzTimeZonePrivate::QTzTimeZonePrivate(const QTzTimeZonePrivate &other)
- : QTimeZonePrivate(other), m_tranTimes(other.m_tranTimes),
- m_tranRules(other.m_tranRules), m_abbreviations(other.m_abbreviations),
-#if QT_CONFIG(icu)
- m_icu(other.m_icu),
-#endif
- m_posixRule(other.m_posixRule)
-{
-}
-
QTzTimeZonePrivate::~QTzTimeZonePrivate()
{
}
-QTimeZonePrivate *QTzTimeZonePrivate::clone()
+QTzTimeZonePrivate *QTzTimeZonePrivate::clone() const
{
return new QTzTimeZonePrivate(*this);
}
@@ -725,19 +726,61 @@ void QTzTimeZonePrivate::init(const QByteArray &ianaId)
}
}
- // Now for each transition time calculate our rule and save them
- m_tranTimes.reserve(tranList.count());
- for (const QTzTransition &tz_tran : qAsConst(tranList)) {
+ // Now for each transition time calculate and store our rule:
+ const int tranCount = tranList.count();;
+ m_tranTimes.reserve(tranCount);
+ // The DST offset when in effect: usually stable, usually an hour:
+ int lastDstOff = 3600;
+ for (int i = 0; i < tranCount; i++) {
+ const QTzTransition &tz_tran = tranList.at(i);
QTzTransitionTime tran;
QTzTransitionRule rule;
const QTzType tz_type = typeList.at(tz_tran.tz_typeind);
// Calculate the associated Rule
- if (!tz_type.tz_isdst)
+ if (!tz_type.tz_isdst) {
utcOffset = tz_type.tz_gmtoff;
+ } else if (Q_UNLIKELY(tz_type.tz_gmtoff != utcOffset + lastDstOff)) {
+ /*
+ This might be a genuine change in DST offset, but could also be
+ DST starting at the same time as the standard offset changed. See
+ if DST's end gives a more plausible utcOffset (i.e. one closer to
+ the last we saw, or a simple whole hour):
+ */
+ // Standard offset inferred from net offset and expected DST offset:
+ const int inferStd = tz_type.tz_gmtoff - lastDstOff; // != utcOffset
+ for (int j = i + 1; j < tranCount; j++) {
+ const QTzType new_type = typeList.at(tranList.at(j).tz_typeind);
+ if (!new_type.tz_isdst) {
+ const int newUtc = new_type.tz_gmtoff;
+ if (newUtc == utcOffset) {
+ // DST-end can't help us, avoid lots of messy checks.
+ // else: See if the end matches the familiar DST offset:
+ } else if (newUtc == inferStd) {
+ utcOffset = newUtc;
+ // else: let either end shift us to one hour as DST offset:
+ } else if (tz_type.tz_gmtoff - 3600 == utcOffset) {
+ // Start does it
+ } else if (tz_type.tz_gmtoff - 3600 == newUtc) {
+ utcOffset = newUtc; // End does it
+ // else: prefer whichever end gives DST offset closer to
+ // last, but consider any offset > 0 "closer" than any <= 0:
+ } else if (newUtc < tz_type.tz_gmtoff
+ ? (utcOffset >= tz_type.tz_gmtoff
+ || qAbs(newUtc - inferStd) < qAbs(utcOffset - inferStd))
+ : (utcOffset >= tz_type.tz_gmtoff
+ && qAbs(newUtc - inferStd) < qAbs(utcOffset - inferStd))) {
+ utcOffset = newUtc;
+ }
+ break;
+ }
+ }
+ lastDstOff = tz_type.tz_gmtoff - utcOffset;
+ }
rule.stdOffset = utcOffset;
rule.dstOffset = tz_type.tz_gmtoff - utcOffset;
rule.abbreviationIndex = tz_type.tz_abbrind;
+
// If the rule already exist then use that, otherwise add it
int ruleIndex = m_tranRules.indexOf(rule);
if (ruleIndex == -1) {
diff --git a/src/corelib/tools/qtimezoneprivate_win.cpp b/src/corelib/tools/qtimezoneprivate_win.cpp
index 4febeda537..f963e10333 100644
--- a/src/corelib/tools/qtimezoneprivate_win.cpp
+++ b/src/corelib/tools/qtimezoneprivate_win.cpp
@@ -299,7 +299,7 @@ static QByteArray windowsSystemZoneId()
id = readRegistryString(key, L"TimeZoneKeyName");
RegCloseKey(key);
if (!id.isEmpty())
- return id.toUtf8();
+ return std::move(id).toUtf8();
}
// On XP we have to iterate over the zones until we find a match on
@@ -415,7 +415,7 @@ QWinTimeZonePrivate::~QWinTimeZonePrivate()
{
}
-QTimeZonePrivate *QWinTimeZonePrivate::clone()
+QWinTimeZonePrivate *QWinTimeZonePrivate::clone() const
{
return new QWinTimeZonePrivate(*this);
}
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index 8b9df7c12b..d99eebd4b9 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -165,6 +165,16 @@ public:
}
}
+ void append(T &&t) {
+ if (s == a)
+ realloc(s, s << 1);
+ const int idx = s++;
+ if (QTypeInfo<T>::isComplex)
+ new (ptr + idx) T(std::move(t));
+ else
+ ptr[idx] = std::move(t);
+ }
+
void append(const T *buf, int size);
inline QVarLengthArray<T, Prealloc> &operator<<(const T &t)
{ append(t); return *this; }
@@ -218,6 +228,7 @@ public:
// STL compatibility:
inline bool empty() const { return isEmpty(); }
inline void push_back(const T &t) { append(t); }
+ void push_back(T &&t) { append(std::move(t)); }
inline void pop_back() { removeLast(); }
inline T &front() { return first(); }
inline const T &front() const { return first(); }
@@ -363,7 +374,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int a
a = Prealloc;
}
s = 0;
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
QT_TRY {
// copy all the old elements
while (s < copySize) {
@@ -456,7 +467,7 @@ Q_OUTOFLINE_TEMPLATE typename QVarLengthArray<T, Prealloc>::iterator QVarLengthA
if (n != 0) {
resize(s + n);
const T copy(t);
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
T *b = ptr + offset;
T *j = ptr + s;
T *i = j - n;
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index 5e53a969e8..127afcd069 100644
--- a/src/corelib/tools/qvarlengtharray.qdoc
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -303,6 +303,34 @@
*/
/*!
+ \fn void QVarLengthArray::append(T &&t)
+ \overload append
+ \since 5.9
+
+ \note Unlike the lvalue overload of append(), passing a reference to
+ an object that is already an element of \c *this leads to undefined
+ behavior:
+
+ \code
+ vla.append(std::move(vla[0])); // BUG: passing an object that is already in the container
+ \endcode
+*/
+
+/*!
+ \fn void QVarLengthArray::push_back(T &&t)
+ \overload push_back
+ \since 5.9
+
+ \note Unlike the lvalue overload of push_back(), passing a reference to
+ an object that is already an element of \c *this leads to undefined
+ behavior:
+
+ \code
+ vla.push_back(std::move(vla[0])); // BUG: passing an object that is already in the container
+ \endcode
+*/
+
+/*!
\fn inline void QVarLengthArray::removeLast()
\since 4.5
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index e345163c2f..57e80ae125 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -554,7 +554,7 @@ void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::Allo
T *srcEnd = asize > d->size ? d->end() : d->begin() + asize;
T *dst = x->begin();
- if (QTypeInfo<T>::isStatic || (isShared && QTypeInfo<T>::isComplex)) {
+ if (!QTypeInfoQuery<T>::isRelocatable || (isShared && QTypeInfo<T>::isComplex)) {
// we can not move the data, we need to copy construct it
while (srcBegin != srcEnd) {
new (dst++) T(*srcBegin++);
@@ -599,7 +599,7 @@ void QVector<T>::reallocData(const int asize, const int aalloc, QArrayData::Allo
}
if (d != x) {
if (!d->ref.deref()) {
- if (QTypeInfo<T>::isStatic || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
+ if (!QTypeInfoQuery<T>::isRelocatable || !aalloc || (isShared && QTypeInfo<T>::isComplex)) {
// data was copy constructed, we need to call destructors
// or if !alloc we did nothing to the old 'd'.
freeData(d);
@@ -698,7 +698,7 @@ typename QVector<T>::iterator QVector<T>::insert(iterator before, size_type n, c
const T copy(t);
if (!isDetached() || d->size + n > int(d->alloc))
reallocData(d->size, d->size + n, QArrayData::Grow);
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
T *b = d->end();
T *i = d->end() + n;
while (i != b)
@@ -747,7 +747,7 @@ typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend)
detach();
abegin = d->begin() + itemsUntouched;
aend = abegin + itemsToErase;
- if (QTypeInfo<T>::isStatic) {
+ if (!QTypeInfoQuery<T>::isRelocatable) {
iterator moveBegin = abegin + itemsToErase;
iterator moveEnd = d->end();
while (moveBegin != moveEnd) {
diff --git a/src/corelib/tools/qvsnprintf.cpp b/src/corelib/tools/qvsnprintf.cpp
index 472b1f282c..43a21771a1 100644
--- a/src/corelib/tools/qvsnprintf.cpp
+++ b/src/corelib/tools/qvsnprintf.cpp
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_VSNPRINTF
+#if !defined(QT_VSNPRINTF) || defined(Q_CLANG_QDOC)
/*!
\relates QByteArray
diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri
index 1c9b34dacd..b93ec824ed 100644
--- a/src/corelib/tools/tools.pri
+++ b/src/corelib/tools/tools.pri
@@ -125,7 +125,6 @@ else:unix {
}
else:win32 {
SOURCES += tools/qlocale_win.cpp
- winphone: LIBS_PRIVATE += -lWindowsPhoneGlobalizationUtil
winrt-*-msvc2013: LIBS += advapi32.lib
} else:integrity {
SOURCES += tools/qlocale_unix.cpp
@@ -172,7 +171,7 @@ qtConfig(timezone) {
}
qtConfig(regularexpression) {
- QMAKE_USE_PRIVATE += pcre
+ QMAKE_USE_PRIVATE += pcre2
HEADERS += tools/qregularexpression.h
SOURCES += tools/qregularexpression.cpp
diff --git a/src/corelib/xml/qxmlutils_p.h b/src/corelib/xml/qxmlutils_p.h
index d8d25e0efe..6db347b3ee 100644
--- a/src/corelib/xml/qxmlutils_p.h
+++ b/src/corelib/xml/qxmlutils_p.h
@@ -73,7 +73,7 @@ public:
static bool isNameChar(const QChar c);
static bool isLetter(const QChar c);
static bool isNCName(const QStringRef &ncName);
- static inline bool isNCName(const QString &ncName) { return isNCName(&ncName); }
+ static inline bool isNCName(const QString &ncName) { return isNCName(QStringRef(&ncName)); }
static bool isPublicID(const QString &candidate);
private:
diff --git a/src/dbus/Qt5DBusMacros.cmake b/src/dbus/Qt5DBusMacros.cmake
index 2364c6710c..ef3eb73276 100644
--- a/src/dbus/Qt5DBusMacros.cmake
+++ b/src/dbus/Qt5DBusMacros.cmake
@@ -92,7 +92,6 @@ function(QT5_GENERATE_DBUS_INTERFACE _header) # _customName OPTIONS -some -optio
cmake_parse_arguments(_DBUS_INTERFACE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(_customName ${_DBUS_INTERFACE_UNPARSED_ARGUMENTS})
- set(_qt4_dbus_options ${_DBUS_INTERFACE_OPTIONS})
get_filename_component(_in_file ${_header} ABSOLUTE)
get_filename_component(_basename ${_header} NAME_WE)
@@ -112,7 +111,7 @@ function(QT5_GENERATE_DBUS_INTERFACE _header) # _customName OPTIONS -some -optio
endif()
add_custom_command(OUTPUT ${_target}
- COMMAND ${Qt5DBus_QDBUSCPP2XML_EXECUTABLE} ${_qt4_dbus_options} ${_in_file} -o ${_target}
+ COMMAND ${Qt5DBus_QDBUSCPP2XML_EXECUTABLE} ${_DBUS_INTERFACE_OPTIONS} ${_in_file} -o ${_target}
DEPENDS ${_in_file} VERBATIM
)
endfunction()
diff --git a/src/dbus/qdbusconnection.h b/src/dbus/qdbusconnection.h
index d9a894b637..ba28938b60 100644
--- a/src/dbus/qdbusconnection.h
+++ b/src/dbus/qdbusconnection.h
@@ -73,10 +73,9 @@ class QDBusConnectionPrivate;
class Q_DBUS_EXPORT QDBusConnection
{
Q_GADGET
- Q_ENUMS(BusType UnregisterMode)
- Q_FLAGS(RegisterOptions)
public:
enum BusType { SessionBus, SystemBus, ActivationBus };
+ Q_ENUM(BusType)
enum RegisterOption {
ExportAdaptors = 0x01,
@@ -106,11 +105,13 @@ public:
// Reserved = 0xff000000
};
Q_DECLARE_FLAGS(RegisterOptions, RegisterOption)
+ Q_FLAG(RegisterOptions)
enum UnregisterMode {
UnregisterNode,
UnregisterTree
};
+ Q_ENUM(UnregisterMode)
enum VirtualObjectRegisterOption {
SingleNode = 0x0,
diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
index 875bcd1421..d323088779 100644
--- a/src/dbus/qdbusconnection_p.h
+++ b/src/dbus/qdbusconnection_p.h
@@ -348,9 +348,6 @@ public:
QObject *receiver, const char *signal, int minMIdx,
bool buildSignature);
static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *);
- static bool checkReplyForDelivery(QDBusConnectionPrivate *target, QObject *object,
- int idx, const QList<int> &metaTypes,
- const QDBusMessage &msg);
static QDBusCallDeliveryEvent *prepareReply(QDBusConnectionPrivate *target, QObject *object,
int idx, const QVector<int> &metaTypes,
const QDBusMessage &msg);
diff --git a/src/dbus/qdbusconnectioninterface.h b/src/dbus/qdbusconnectioninterface.h
index 7b694a1f96..37f35dbe81 100644
--- a/src/dbus/qdbusconnectioninterface.h
+++ b/src/dbus/qdbusconnectioninterface.h
@@ -61,7 +61,6 @@ class QByteArray;
class Q_DBUS_EXPORT QDBusConnectionInterface: public QDBusAbstractInterface
{
Q_OBJECT
- Q_ENUMS(ServiceQueueOptions ServiceReplacementOptions RegisterServiceReply)
friend class QDBusConnectionPrivate;
static inline const char *staticInterfaceName();
@@ -76,15 +75,18 @@ public:
QueueService,
ReplaceExistingService
};
+ Q_ENUM(ServiceQueueOptions)
enum ServiceReplacementOptions {
DontAllowReplacement,
AllowReplacement
};
+ Q_ENUM(ServiceReplacementOptions)
enum RegisterServiceReply {
ServiceNotRegistered = 0,
ServiceRegistered,
ServiceQueued
};
+ Q_ENUM(RegisterServiceReply)
public Q_SLOTS:
QDBusReply<QStringList> registeredServiceNames() const;
diff --git a/src/dbus/qdbusinternalfilters.cpp b/src/dbus/qdbusinternalfilters.cpp
index 03e04bb2f5..0927f326f2 100644
--- a/src/dbus/qdbusinternalfilters.cpp
+++ b/src/dbus/qdbusinternalfilters.cpp
@@ -204,8 +204,7 @@ static inline QDBusMessage interfaceNotFoundError(const QDBusMessage &msg, const
{
return msg.createErrorReply(QDBusError::UnknownInterface,
QString::fromLatin1("Interface %1 was not found in object %2")
- .arg(interface_name)
- .arg(msg.path()));
+ .arg(interface_name, msg.path()));
}
static inline QDBusMessage
diff --git a/src/dbus/qdbusutil_p.h b/src/dbus/qdbusutil_p.h
index 931a374ad9..2f187687b8 100644
--- a/src/dbus/qdbusutil_p.h
+++ b/src/dbus/qdbusutil_p.h
@@ -69,17 +69,17 @@ namespace Q_DBUS_NO_EXPORT QDBusUtil
Q_DBUS_EXPORT bool isValidInterfaceName(const QString &ifaceName);
Q_DBUS_EXPORT bool isValidUniqueConnectionName(const QStringRef &busName);
- bool inline isValidUniqueConnectionName(const QString &busName) { return isValidUniqueConnectionName(QStringRef(&busName)); }
+ inline bool isValidUniqueConnectionName(const QString &busName) { return isValidUniqueConnectionName(QStringRef(&busName)); }
Q_DBUS_EXPORT bool isValidBusName(const QString &busName);
Q_DBUS_EXPORT bool isValidMemberName(const QStringRef &memberName);
- bool inline isValidMemberName(const QString &memberName) { return isValidMemberName(QStringRef(&memberName)); }
+ inline bool isValidMemberName(const QString &memberName) { return isValidMemberName(QStringRef(&memberName)); }
Q_DBUS_EXPORT bool isValidErrorName(const QString &errorName);
Q_DBUS_EXPORT bool isValidPartOfObjectPath(const QStringRef &path);
- bool inline isValidPartOfObjectPath(const QString &path) { return isValidPartOfObjectPath(QStringRef(&path)); }
+ inline bool isValidPartOfObjectPath(const QString &path) { return isValidPartOfObjectPath(QStringRef(&path)); }
Q_DBUS_EXPORT bool isValidObjectPath(const QString &path);
diff --git a/src/dbus/qdbusxmlgenerator.cpp b/src/dbus/qdbusxmlgenerator.cpp
index d239a69f73..e3c503aa0f 100644
--- a/src/dbus/qdbusxmlgenerator.cpp
+++ b/src/dbus/qdbusxmlgenerator.cpp
@@ -149,9 +149,8 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method
if (!isScriptable && !(flags & (isSignal ? QDBusConnection::ExportNonScriptableSignals : QDBusConnection::ExportNonScriptableInvokables | QDBusConnection::ExportNonScriptableSlots)))
continue;
- QString xml = QString::fromLatin1(" <%1 name=\"%2\">\n")
- .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
- .arg(QString::fromLatin1(mm.name()));
+ QString xml = QString::asprintf(" <%s name=\"%s\">\n",
+ isSignal ? "signal" : "method", mm.name().constData());
// check the return type first
int typeId = mm.returnType();
@@ -205,10 +204,8 @@ static QString generateInterfaceXml(const QMetaObject *mo, int flags, int method
bool isOutput = isSignal || j > inputCount;
const char *signature = QDBusMetaType::typeToSignature(types.at(j));
- xml += QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n")
- .arg(name)
- .arg(QLatin1String(signature))
- .arg(isOutput ? QLatin1String("out") : QLatin1String("in"));
+ xml += QString::asprintf(" <arg %lstype=\"%s\" direction=\"%s\"/>\n",
+ qUtf16Printable(name), signature, isOutput ? "out" : "in");
// do we need to describe this argument?
if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) {
diff --git a/src/gui/accessible/qaccessiblecache.cpp b/src/gui/accessible/qaccessiblecache.cpp
index 43c4b15cb0..097634c0a3 100644
--- a/src/gui/accessible/qaccessiblecache.cpp
+++ b/src/gui/accessible/qaccessiblecache.cpp
@@ -49,11 +49,21 @@ QT_BEGIN_NAMESPACE
\brief Maintains a cache of accessible interfaces.
*/
-Q_GLOBAL_STATIC(QAccessibleCache, qAccessibleCache)
+static QAccessibleCache *accessibleCache = nullptr;
+
+static void cleanupAccessibleCache()
+{
+ delete accessibleCache;
+ accessibleCache = Q_NULLPTR;
+}
QAccessibleCache *QAccessibleCache::instance()
{
- return qAccessibleCache;
+ if (!accessibleCache) {
+ accessibleCache = new QAccessibleCache;
+ qAddPostRoutine(cleanupAccessibleCache);
+ }
+ return accessibleCache;
}
/*
diff --git a/src/gui/configure.json b/src/gui/configure.json
index 1c4a499298..48579b309a 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -7,6 +7,7 @@
"commandline": {
"options": {
+ "accessibility": "boolean",
"angle": "boolean",
"direct2d": "boolean",
"directfb": "boolean",
@@ -32,6 +33,7 @@
"opengl": { "type": "optionalString", "values": [ "no", "yes", "desktop", "es2", "dynamic" ] },
"opengl-es-2": { "type": "void", "name": "opengl", "value": "es2" },
"opengles3": "boolean",
+ "openvg": "boolean",
"qpa": { "type": "string", "name": "qpa_default_platform" },
"qpa-platform-guard": "boolean",
"sm": { "type": "boolean", "name": "sessionmanager" },
@@ -169,7 +171,7 @@
"label": "Mir client libraries",
"test": "qpa/mirclient",
"sources": [
- { "type": "pkgConfig", "args": "egl mirclient ubuntu-platform-api" }
+ { "type": "pkgConfig", "args": "egl mirclient ubuntu-platform-api libcontent-hub >= 0.2.0" }
]
},
"mtdev": {
@@ -195,6 +197,14 @@
{ "type": "makeSpec", "spec": "OPENGL_ES2" }
]
},
+ "openvg": {
+ "label": "OpenVG",
+ "test": "unix/openvg",
+ "sources": [
+ { "type": "pkgConfig", "args": "vg" },
+ { "type": "makeSpec", "spec": "OPENVG" }
+ ]
+ },
"tslib": {
"label": "tslib",
"test": "unix/tslib",
@@ -497,7 +507,7 @@
"kms": {
"label": "KMS",
"condition": "libs.drm",
- "output": [ "publicQtConfig" ]
+ "output": [ "publicQtConfig", "privateFeature" ]
},
"libinput": {
"label": "libinput",
@@ -518,12 +528,19 @@
"linuxfb": {
"label": "LinuxFB",
"section": "Platform plugins",
- "condition": "tests.linuxfb",
+ "condition": "tests.linuxfb && features.regularexpression",
+ "output": [ "privateFeature" ]
+ },
+ "vnc": {
+ "label": "VNC",
+ "section": "Platform plugins",
+ "condition": "config.unix && !config.android && !config.darwin && features.regularexpression",
"output": [ "privateFeature" ]
},
"mirclient": {
"label": "Mir client",
"section": "Platform plugins",
+ "autoDetect": false,
"condition": "libs.mirclient",
"output": [ "privateFeature" ]
},
@@ -582,9 +599,14 @@
"condition": "features.opengl-desktop || features.opengl-dynamic || features.opengles2",
"output": [ "publicFeature", "feature" ]
},
+ "openvg": {
+ "label": "OpenVG",
+ "condition": "libs.openvg",
+ "output": [ "publicFeature" ]
+ },
"egl": {
"label": "EGL",
- "condition": "features.opengl && (features.angle || libs.egl)",
+ "condition": "(features.opengl || features.openvg) && (features.angle || libs.egl)",
"output": [ "privateFeature", "feature" ]
},
"egl_x11": {
@@ -866,7 +888,6 @@
"label": "QImageIOPlugin",
"purpose": "Provides a base for writing a image format plugins.",
"section": "Images",
- "condition": "features.library",
"output": [ "publicFeature", "feature" ]
},
"movie": {
@@ -952,6 +973,7 @@
"label": "QSystemTrayIcon",
"purpose": "Provides an icon for an application in the system tray.",
"section": "Utilities",
+ "condition": "features.temporaryfile",
"output": [ "publicFeature", "feature" ]
},
"accessibility": {
@@ -1021,6 +1043,11 @@ Specify -opengl desktop to use regular OpenGL."
"message": "The OpenGL functionality tests failed!
You might need to modify the include and library search paths by editing QMAKE_INCDIR_OPENGL[_ES2],
QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your platform."
+ },
+ {
+ "type": "warning",
+ "condition": "!features.accessibility",
+ "message": "Accessibility disabled. This configuration of Qt is unsupported."
}
],
@@ -1028,6 +1055,7 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla
{
"section": "Qt Gui",
"entries": [
+ "accessibility",
"freetype",
"system-freetype",
"harfbuzz",
@@ -1039,6 +1067,8 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla
"gif", "ico", "jpeg", "system-jpeg", "png", "system-png"
]
},
+ "egl",
+ "openvg",
{
"section": "OpenGL",
"entries": [
@@ -1047,7 +1077,6 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla
"args": "angle",
"condition": "config.win32"
},
- "egl",
"opengl-desktop",
{
"type": "feature",
@@ -1083,8 +1112,9 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla
"eglfs_viv", "eglfs_viv_wl", "eglfs_egldevice", "eglfs_gbm", "eglfs_mali", "eglfs_brcm", "egl_x11"
]
},
- "linuxfb", "mirclient",
+ "linuxfb", "vnc", "mirclient",
{
+ "type": "feature",
"message": "INTEGRITY framebuffer",
"condition": "config.integrity",
"args": "integrityfb"
diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf
index b07d39fa37..94574a314c 100644
--- a/src/gui/doc/qtgui.qdocconf
+++ b/src/gui/doc/qtgui.qdocconf
@@ -44,7 +44,8 @@ depends += \
headerdirs += ..
sourcedirs += .. \
- ../../../examples/gui/doc/src
+ ../../../examples/gui/doc/src \
+ src/includes
exampledirs += ../../../examples/gui \
snippets
diff --git a/src/gui/doc/src/external-resources.qdoc b/src/gui/doc/src/external-resources.qdoc
index 6a423323ea..480a4057be 100644
--- a/src/gui/doc/src/external-resources.qdoc
+++ b/src/gui/doc/src/external-resources.qdoc
@@ -49,4 +49,14 @@
/*!
\externalpage http://www.opengl.org/wiki/Tessellation_Shader
\title OpenGL Tessellation Shaders
-*/ \ No newline at end of file
+*/
+
+/*!
+ \externalpage https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
+ \title Icon Theme Specification
+*/
+
+/*!
+ \externalpage https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#directory_layout
+ \title Icon Theme Specification - Directory Layout
+*/
diff --git a/src/gui/doc/src/includes/qiconengine-virtualhookhelper.qdocinc b/src/gui/doc/src/includes/qiconengine-virtualhookhelper.qdocinc
new file mode 100644
index 0000000000..b17d2bd66f
--- /dev/null
+++ b/src/gui/doc/src/includes/qiconengine-virtualhookhelper.qdocinc
@@ -0,0 +1,3 @@
+\note This is a helper method and the actual work is done by the
+virtual_hook() method, hence this method depends on icon engine support
+and may not work with all icon engines.
diff --git a/src/gui/gui.pro b/src/gui/gui.pro
index 5f8cbe2cbe..cfdb5e889b 100644
--- a/src/gui/gui.pro
+++ b/src/gui/gui.pro
@@ -3,7 +3,7 @@ QT = core-private
qtConfig(opengl.*): MODULE_CONFIG = opengl
-DEFINES += QT_NO_USING_NAMESPACE
+DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH
QMAKE_DOCS = $$PWD/doc/qtgui.qdocconf
@@ -57,13 +57,13 @@ win32: CMAKE_WINDOWS_BUILD = True
qtConfig(angle) {
CMAKE_GL_INCDIRS = $$CMAKE_INCLUDE_DIR
CMAKE_ANGLE_EGL_DLL_RELEASE = libEGL.dll
- CMAKE_ANGLE_EGL_IMPLIB_RELEASE = libEGL.lib
+ CMAKE_ANGLE_EGL_IMPLIB_RELEASE = libEGL.$${QMAKE_EXTENSION_STATICLIB}
CMAKE_ANGLE_GLES2_DLL_RELEASE = libGLESv2.dll
- CMAKE_ANGLE_GLES2_IMPLIB_RELEASE = libGLESv2.lib
+ CMAKE_ANGLE_GLES2_IMPLIB_RELEASE = libGLESv2.$${QMAKE_EXTENSION_STATICLIB}
CMAKE_ANGLE_EGL_DLL_DEBUG = libEGLd.dll
- CMAKE_ANGLE_EGL_IMPLIB_DEBUG = libEGLd.lib
+ CMAKE_ANGLE_EGL_IMPLIB_DEBUG = libEGLd.$${QMAKE_EXTENSION_STATICLIB}
CMAKE_ANGLE_GLES2_DLL_DEBUG = libGLESv2d.dll
- CMAKE_ANGLE_GLES2_IMPLIB_DEBUG = libGLESv2d.lib
+ CMAKE_ANGLE_GLES2_IMPLIB_DEBUG = libGLESv2d.$${QMAKE_EXTENSION_STATICLIB}
CMAKE_QT_OPENGL_IMPLEMENTATION = GLESv2
} else {
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp
index 0d2f55b1c2..07dcf8b726 100644
--- a/src/gui/image/qicon.cpp
+++ b/src/gui/image/qicon.cpp
@@ -97,7 +97,11 @@ QT_BEGIN_NAMESPACE
\value On Display the pixmap when the widget is in an "on" state
*/
-static QBasicAtomicInt serialNumCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
+static int nextSerialNumCounter()
+{
+ static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
+ return 1 + serial.fetchAndAddRelaxed(1);
+}
static void qt_cleanup_icon_cache();
namespace {
@@ -137,9 +141,9 @@ static qreal qt_effective_device_pixel_ratio(QWindow *window = 0)
return qApp->devicePixelRatio(); // Don't know which window to target.
}
-QIconPrivate::QIconPrivate()
- : engine(0), ref(1),
- serialNum(serialNumCounter.fetchAndAddRelaxed(1)),
+QIconPrivate::QIconPrivate(QIconEngine *e)
+ : engine(e), ref(1),
+ serialNum(nextSerialNumCounter()),
detach_no(0),
is_mask(false)
{
@@ -605,6 +609,51 @@ QFactoryLoader *qt_iconEngineFactoryLoader()
\note QIcon needs a QGuiApplication instance before the icon is created.
+ \section1 High DPI Icons
+
+ There are two ways that QIcon supports \l {High DPI Displays}{high DPI}
+ icons: via \l addFile() and \l fromTheme().
+
+ \l addFile() is useful if you have your own custom directory structure and do
+ not need to use the \l {Icon Theme Specification}{freedesktop.org Icon Theme
+ Specification}. Icons created via this approach use Qt's \l {High Resolution
+ Versions of Images}{"@nx" high DPI syntax}.
+
+ Using \l fromTheme() is necessary if you plan on following the Icon Theme
+ Specification. To make QIcon use the high DPI version of an image, add an
+ additional entry to the appropriate \c index.theme file:
+
+ \badcode
+ [Icon Theme]
+ Name=Test
+ Comment=Test Theme
+
+ Directories=32x32/actions,32x32@2/actions
+
+ [32x32/actions]
+ Size=32
+ Context=Actions
+ Type=Fixed
+
+ # High DPI version of the entry above.
+ [32x32@2/actions]
+ Size=32
+ Scale=2
+ Type=Fixed
+ \endcode
+
+ Your icon theme directory would then look something like this:
+
+ \badcode
+ ├── 32x32
+ │ └── actions
+ │ └── appointment-new.png
+ ├── 32x32@2
+ │ └── actions
+ │ └── appointment-new.png
+ └── index.theme
+ \endcode
+
\sa {fowler}{GUI Design Handbook: Iconic Label}, {Icons Example}
*/
@@ -651,7 +700,7 @@ QIcon::QIcon(const QIcon &other)
the relevant file must be found relative to the runtime working
directory.
- The file name can be either refer to an actual file on disk or to
+ The file name can refer to an actual file on disk or to
one of the application's embedded resources. See the
\l{resources.html}{Resource System} overview for details on how to
embed images and other resource files in the application's
@@ -673,9 +722,8 @@ QIcon::QIcon(const QString &fileName)
ownership of the engine.
*/
QIcon::QIcon(QIconEngine *engine)
- :d(new QIconPrivate)
+ :d(new QIconPrivate(engine))
{
- d->engine = engine;
}
/*!
@@ -848,9 +896,10 @@ QPixmap QIcon::pixmap(QWindow *window, const QSize &size, Mode mode, State state
}
// Try get a pixmap that is big enough to be displayed at device pixel resolution.
- QPixmap pixmap = d->engine->pixmap(size * devicePixelRatio, mode, state);
- pixmap.setDevicePixelRatio(d->pixmapDevicePixelRatio(devicePixelRatio, size, pixmap.size()));
- return pixmap;
+ QIconEngine::ScaledPixmapArgument scalePixmapArg = { size * devicePixelRatio, mode, state, devicePixelRatio, QPixmap() };
+ d->engine->virtual_hook(QIconEngine::ScaledPixmapHook, reinterpret_cast<void*>(&scalePixmapArg));
+ scalePixmapArg.pixmap.setDevicePixelRatio(d->pixmapDevicePixelRatio(devicePixelRatio, size, scalePixmapArg.pixmap.size()));
+ return scalePixmapArg.pixmap;
}
/*!
@@ -950,8 +999,7 @@ void QIcon::detach()
d = 0;
return;
} else if (d->ref.load() != 1) {
- QIconPrivate *x = new QIconPrivate;
- x->engine = d->engine->clone();
+ QIconPrivate *x = new QIconPrivate(d->engine->clone());
if (!d->ref.deref())
delete d;
d = x;
@@ -974,10 +1022,8 @@ void QIcon::addPixmap(const QPixmap &pixmap, Mode mode, State state)
if (pixmap.isNull())
return;
detach();
- if (!d) {
- d = new QIconPrivate;
- d->engine = new QPixmapIconEngine;
- }
+ if (!d)
+ d = new QIconPrivate(new QPixmapIconEngine);
d->engine->addPixmap(pixmap, mode, state);
}
@@ -1003,7 +1049,7 @@ static QIconEngine *iconEngineFromSuffix(const QString &fileName, const QString
the relevant file must be found relative to the runtime working
directory.
- The file name can be either refer to an actual file on disk or to
+ The file name can refer to an actual file on disk or to
one of the application's embedded resources. See the
\l{resources.html}{Resource System} overview for details on how to
embed images and other resource files in the application's
@@ -1037,8 +1083,7 @@ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State
if (!engine)
engine = iconEngineFromSuffix(fileName, QMimeDatabase().mimeTypeForFile(info).preferredSuffix());
#endif // !QT_NO_MIMETYPE
- d = new QIconPrivate;
- d->engine = engine ? engine : new QPixmapIconEngine;
+ d = new QIconPrivate(engine ? engine : new QPixmapIconEngine);
}
d->engine->addFile(fileName, size, mode, state);
@@ -1240,12 +1285,10 @@ bool QIcon::hasThemeIcon(const QString &name)
*/
void QIcon::setIsMask(bool isMask)
{
- if (!d) {
- d = new QIconPrivate;
- d->engine = new QPixmapIconEngine;
- } else {
+ if (!d)
+ d = new QIconPrivate(new QPixmapIconEngine);
+ else
detach();
- }
d->is_mask = isMask;
}
@@ -1326,22 +1369,17 @@ QDataStream &operator>>(QDataStream &s, QIcon &icon)
QString key;
s >> key;
if (key == QLatin1String("QPixmapIconEngine")) {
- icon.d = new QIconPrivate;
- QIconEngine *engine = new QPixmapIconEngine;
- icon.d->engine = engine;
- engine->read(s);
+ icon.d = new QIconPrivate(new QPixmapIconEngine);
+ icon.d->engine->read(s);
} else if (key == QLatin1String("QIconLoaderEngine")) {
- icon.d = new QIconPrivate;
- QIconEngine *engine = new QIconLoaderEngine();
- icon.d->engine = engine;
- engine->read(s);
+ icon.d = new QIconPrivate(new QIconLoaderEngine());
+ icon.d->engine->read(s);
} else {
const int index = loader()->indexOf(key);
if (index != -1) {
if (QIconEnginePlugin *factory = qobject_cast<QIconEnginePlugin*>(loader()->instance(index))) {
if (QIconEngine *engine= factory->create()) {
- icon.d = new QIconPrivate;
- icon.d->engine = engine;
+ icon.d = new QIconPrivate(engine);
engine->read(s);
} // factory
} // instance
diff --git a/src/gui/image/qicon_p.h b/src/gui/image/qicon_p.h
index a978a72192..aa358e88af 100644
--- a/src/gui/image/qicon_p.h
+++ b/src/gui/image/qicon_p.h
@@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE
class QIconPrivate
{
public:
- QIconPrivate();
+ explicit QIconPrivate(QIconEngine *e);
~QIconPrivate() {
delete engine;
diff --git a/src/gui/image/qiconengine.cpp b/src/gui/image/qiconengine.cpp
index 0ba9844f7a..1f8e5f321a 100644
--- a/src/gui/image/qiconengine.cpp
+++ b/src/gui/image/qiconengine.cpp
@@ -169,6 +169,12 @@ void QIconEngine::addFile(const QString &/*fileName*/, const QSize &/*size*/, QI
bool that can be set to true if the icon is null. This enum value
was added in Qt 5.7.
+ \value ScaledPixmapHook Provides a way to get a pixmap that is scaled
+ according to the given scale (typically equal to the \l {Glossary Of High
+ DPI Terms}{device pixel ratio}). The \a data argument of the virtual_hook()
+ function is a \l ScaledPixmapArgument pointer that contains both the input and
+ output arguments. This enum value was added in Qt 5.9.
+
\sa virtual_hook()
*/
@@ -207,6 +213,60 @@ void QIconEngine::addFile(const QString &/*fileName*/, const QSize &/*size*/, QI
vectorial format normally return an empty list.
*/
+/*!
+ \class QIconEngine::ScaledPixmapArgument
+ \since 5.9
+
+ \inmodule QtGui
+
+ This struct represents arguments to the virtual_hook() function when
+ the \a id parameter is QIconEngine::ScaledPixmapHook.
+
+ The struct provides a way for icons created via \l QIcon::fromTheme()
+ to return pixmaps that are designed for the current \l {Glossary Of High
+ DPI Terms}{device pixel ratio}. The scale for such an icon is specified
+ using the \l {Icon Theme Specification - Directory Layout}{Scale directory key}
+ in the appropriate \c index.theme file.
+
+ Icons created via other approaches will return the same result as a call to
+ \l pixmap() would, and continue to benefit from Qt's \l {High Resolution
+ Versions of Images}{"@nx" high DPI syntax}.
+
+ \sa virtual_hook(), QIconEngine::IconEngineHook, {High DPI Icons}
+ */
+
+/*!
+ \variable QIconEngine::ScaledPixmapArgument::size
+ \brief The requested size of the pixmap.
+*/
+
+/*!
+ \variable QIconEngine::ScaledPixmapArgument::mode
+ \brief The requested mode of the pixmap.
+
+ \sa QIcon::Mode
+*/
+
+/*!
+ \variable QIconEngine::ScaledPixmapArgument::state
+ \brief The requested state of the pixmap.
+
+ \sa QIcon::State
+*/
+
+/*!
+ \variable QIconEngine::ScaledPixmapArgument::scale
+ \brief The requested scale of the pixmap.
+*/
+
+/*!
+ \variable QIconEngine::ScaledPixmapArgument::pixmap
+
+ \brief The pixmap that is the best match for the given \l size, \l mode, \l
+ \state, and \l scale. This is an output parameter that is set after calling
+ \l virtual_hook().
+*/
+
/*!
Returns a key that identifies this icon engine.
@@ -262,6 +322,13 @@ void QIconEngine::virtual_hook(int id, void *data)
arg.sizes.clear();
break;
}
+ case QIconEngine::ScaledPixmapHook: {
+ // We don't have any notion of scale besides "@nx", so just call pixmap() here.
+ QIconEngine::ScaledPixmapArgument &arg =
+ *reinterpret_cast<QIconEngine::ScaledPixmapArgument*>(data);
+ arg.pixmap = pixmap(arg.size, arg.mode, arg.state);
+ break;
+ }
default:
break;
}
@@ -273,9 +340,7 @@ void QIconEngine::virtual_hook(int id, void *data)
Returns sizes of all images that are contained in the engine for the
specific \a mode and \a state.
- \note This is a helper method and the actual work is done by
- virtual_hook() method, hence this method depends on icon engine support
- and may not work with all icon engines.
+ \include qiconengine-virtualhookhelper.qdocinc
*/
QList<QSize> QIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state) const
{
@@ -291,9 +356,7 @@ QList<QSize> QIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state) c
Returns the name used to create the engine, if available.
- \note This is a helper method and the actual work is done by
- virtual_hook() method, hence this method depends on icon engine support
- and may not work with all icon engines.
+ \include qiconengine-virtualhookhelper.qdocinc
*/
QString QIconEngine::iconName() const
{
@@ -306,6 +369,8 @@ QString QIconEngine::iconName() const
\since 5.7
Returns true if this icon engine represent a null QIcon.
+
+ \include qiconengine-virtualhookhelper.qdocinc
*/
bool QIconEngine::isNull() const
{
@@ -314,4 +379,29 @@ bool QIconEngine::isNull() const
return isNull;
}
+/*!
+ \since 5.9
+
+ Returns a pixmap for the given \a size, \a mode, \a state and \a scale.
+
+ The \a scale argument is typically equal to the \l {Glossary Of High DPI
+ Terms}{device pixel ratio} of the display.
+
+ \include qiconengine-virtualhookhelper.qdocinc
+
+ \note Some engines may cast \a scale to an integer.
+
+ \sa ScaledPixmapArgument
+*/
+QPixmap QIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
+{
+ ScaledPixmapArgument arg;
+ arg.size = size;
+ arg.mode = mode;
+ arg.state = state;
+ arg.scale = scale;
+ const_cast<QIconEngine *>(this)->virtual_hook(QIconEngine::ScaledPixmapHook, reinterpret_cast<void*>(&arg));
+ return arg.pixmap;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/image/qiconengine.h b/src/gui/image/qiconengine.h
index 783770cd30..0c67ef2686 100644
--- a/src/gui/image/qiconengine.h
+++ b/src/gui/image/qiconengine.h
@@ -65,7 +65,7 @@ public:
virtual bool read(QDataStream &in);
virtual bool write(QDataStream &out) const;
- enum IconEngineHook { AvailableSizesHook = 1, IconNameHook, IsNullHook };
+ enum IconEngineHook { AvailableSizesHook = 1, IconNameHook, IsNullHook, ScaledPixmapHook };
struct AvailableSizesArgument
{
@@ -79,6 +79,16 @@ public:
virtual QString iconName() const;
bool isNull() const; // ### Qt6 make virtual
+ QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale); // ### Qt6 make virtual
+
+ struct ScaledPixmapArgument
+ {
+ QSize size;
+ QIcon::Mode mode;
+ QIcon::State state;
+ qreal scale;
+ QPixmap pixmap;
+ };
virtual void virtual_hook(int id, void *data);
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
index 324f13a17b..d72c05a3c5 100644
--- a/src/gui/image/qiconloader.cpp
+++ b/src/gui/image/qiconloader.cpp
@@ -47,6 +47,7 @@
#include <qpa/qplatformtheme.h>
#include <QtGui/QIconEngine>
#include <QtGui/QPalette>
+#include <QtCore/qmath.h>
#include <QtCore/QList>
#include <QtCore/QDir>
#include <QtCore/QSettings>
@@ -347,6 +348,10 @@ QIconTheme::QIconTheme(const QString &themeName)
dirInfo.maxSize = indexReader.value(directoryKey +
QLatin1String("/MaxSize"),
size).toInt();
+
+ dirInfo.scale = indexReader.value(directoryKey +
+ QLatin1String("/Scale"),
+ 1).toInt();
m_keyList.append(dirInfo);
}
}
@@ -553,8 +558,11 @@ void QIconLoaderEngine::paint(QPainter *painter, const QRect &rect,
* This algorithm is defined by the freedesktop spec:
* http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
*/
-static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize)
+static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize, int iconscale)
{
+ if (dir.scale != iconscale)
+ return false;
+
if (dir.type == QIconDirInfo::Fixed) {
return dir.size == iconsize;
@@ -575,24 +583,25 @@ static bool directoryMatchesSize(const QIconDirInfo &dir, int iconsize)
* This algorithm is defined by the freedesktop spec:
* http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
*/
-static int directorySizeDistance(const QIconDirInfo &dir, int iconsize)
+static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int iconscale)
{
+ const int scaledIconSize = iconsize * iconscale;
if (dir.type == QIconDirInfo::Fixed) {
- return qAbs(dir.size - iconsize);
+ return qAbs(dir.size * dir.scale - scaledIconSize);
} else if (dir.type == QIconDirInfo::Scalable) {
- if (iconsize < dir.minSize)
- return dir.minSize - iconsize;
- else if (iconsize > dir.maxSize)
- return iconsize - dir.maxSize;
+ if (scaledIconSize < dir.minSize * dir.scale)
+ return dir.minSize * dir.scale - scaledIconSize;
+ else if (scaledIconSize > dir.maxSize * dir.scale)
+ return scaledIconSize - dir.maxSize * dir.scale;
else
return 0;
} else if (dir.type == QIconDirInfo::Threshold) {
- if (iconsize < dir.size - dir.threshold)
- return dir.minSize - iconsize;
- else if (iconsize > dir.size + dir.threshold)
- return iconsize - dir.maxSize;
+ if (scaledIconSize < (dir.size - dir.threshold) * dir.scale)
+ return dir.minSize * dir.scale - scaledIconSize;
+ else if (scaledIconSize > (dir.size + dir.threshold) * dir.scale)
+ return scaledIconSize - dir.maxSize * dir.scale;
else return 0;
}
@@ -600,7 +609,7 @@ static int directorySizeDistance(const QIconDirInfo &dir, int iconsize)
return INT_MAX;
}
-QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
+QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size, int scale)
{
int iconsize = qMin(size.width(), size.height());
@@ -612,7 +621,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
// Search for exact matches first
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_info.entries.at(i);
- if (directoryMatchesSize(entry->dir, iconsize)) {
+ if (directoryMatchesSize(entry->dir, iconsize, scale)) {
return entry;
}
}
@@ -622,7 +631,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size)
QIconLoaderEngineEntry *closestMatch = 0;
for (int i = 0; i < numEntries; ++i) {
QIconLoaderEngineEntry *entry = m_info.entries.at(i);
- int distance = directorySizeDistance(entry->dir, iconsize);
+ int distance = directorySizeDistance(entry->dir, iconsize, scale);
if (distance < minimalSize) {
minimalSize = distance;
closestMatch = entry;
@@ -665,6 +674,8 @@ QPixmap PixmapEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State st
basePixmap.load(filename);
QSize actualSize = basePixmap.size();
+ // If the size of the best match we have (basePixmap) is larger than the
+ // requested size, we downscale it to match.
if (!actualSize.isNull() && (actualSize.width() > size.width() || actualSize.height() > size.height()))
actualSize.scale(size, Qt::KeepAspectRatio);
@@ -748,6 +759,15 @@ void QIconLoaderEngine::virtual_hook(int id, void *data)
*reinterpret_cast<bool*>(data) = m_info.entries.isEmpty();
}
break;
+ case QIconEngine::ScaledPixmapHook:
+ {
+ QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast<QIconEngine::ScaledPixmapArgument*>(data);
+ // QIcon::pixmap() multiplies size by the device pixel ratio.
+ const int integerScale = qCeil(arg.scale);
+ QIconLoaderEngineEntry *entry = entryForSize(arg.size / integerScale, integerScale);
+ arg.pixmap = entry ? entry->pixmap(arg.size, arg.mode, arg.state) : QPixmap();
+ }
+ break;
default:
QIconEngine::virtual_hook(id, data);
}
diff --git a/src/gui/image/qiconloader_p.h b/src/gui/image/qiconloader_p.h
index ed7b7ff7ae..5f3a3ef948 100644
--- a/src/gui/image/qiconloader_p.h
+++ b/src/gui/image/qiconloader_p.h
@@ -76,12 +76,14 @@ struct QIconDirInfo
maxSize(0),
minSize(0),
threshold(0),
+ scale(1),
type(Threshold) {}
QString path;
short size;
short maxSize;
short minSize;
short threshold;
+ short scale;
Type type;
};
Q_DECLARE_TYPEINFO(QIconDirInfo, Q_MOVABLE_TYPE);
@@ -135,7 +137,8 @@ private:
bool hasIcon() const;
void ensureLoaded();
void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
- QIconLoaderEngineEntry *entryForSize(const QSize &size);
+ QIconLoaderEngineEntry *entryForSize(const QSize &size, int scale = 1);
+
QIconLoaderEngine(const QIconLoaderEngine &other);
QThemeIconInfo m_info;
QString m_iconName;
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 9e9f01a46a..c1ea053204 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -89,12 +89,16 @@ static QImage rotated90(const QImage &src);
static QImage rotated180(const QImage &src);
static QImage rotated270(const QImage &src);
-QBasicAtomicInt qimage_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
+static int next_qimage_serial_number()
+{
+ static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
+ return 1 + serial.fetchAndAddRelaxed(1);
+}
QImageData::QImageData()
: ref(0), width(0), height(0), depth(0), nbytes(0), devicePixelRatio(1.0), data(0),
format(QImage::Format_ARGB32), bytes_per_line(0),
- ser_no(qimage_serial_number.fetchAndAddRelaxed(1)),
+ ser_no(next_qimage_serial_number()),
detach_no(0),
dpmx(qt_defaultDpiX() * 100 / qreal(2.54)),
dpmy(qt_defaultDpiY() * 100 / qreal(2.54)),
@@ -2121,6 +2125,44 @@ QImage QImage::convertToFormat(Format format, const QVector<QRgb> &colorTable, Q
}
/*!
+ \since 5.9
+
+ Changes the format of the image without changing the data. Only
+ works between formats of the same depth.
+
+ Returns \c true if successful.
+
+ This function can be used to change images with alpha-channels to
+ their corresponding opaque formats if the data is known to be opaque-only,
+ or to change the format of a given image buffer before overwriting
+ it with new data.
+
+ \warning The function does not check if the image data is valid in the
+ new format and will still return \c true if the depths are compatible.
+ Operations on an image with invalid data are undefined.
+
+ \warning If the image is not detached, this will cause the data to be
+ copied.
+
+ \sa isDetached(), hasAlphaChannel(), convertToFormat()
+*/
+
+bool QImage::reinterpretAsFormat(Format format)
+{
+ if (!d)
+ return false;
+ if (d->format == format)
+ return true;
+ if (qt_depthForFormat(format) != qt_depthForFormat(d->format))
+ return false;
+ if (!isDetached()) // Detach only if shared, not for read-only data.
+ detach();
+
+ d->format = format;
+ return true;
+}
+
+/*!
\fn bool QImage::valid(const QPoint &pos) const
Returns \c true if \a pos is a valid coordinate pair within the
@@ -4458,7 +4500,8 @@ QImage QImage::smoothScaled(int w, int h) const {
return src;
}
-static QImage rotated90(const QImage &image) {
+static QImage rotated90(const QImage &image)
+{
QImage out(image.height(), image.width(), image.format());
out.setDotsPerMeterX(image.dotsPerMeterY());
out.setDotsPerMeterY(image.dotsPerMeterX());
@@ -4466,49 +4509,10 @@ static QImage rotated90(const QImage &image) {
out.setColorTable(image.colorTable());
int w = image.width();
int h = image.height();
- switch (image.format()) {
- case QImage::Format_RGB32:
- case QImage::Format_ARGB32:
- case QImage::Format_ARGB32_Premultiplied:
- case QImage::Format_RGBX8888:
- case QImage::Format_RGBA8888:
- case QImage::Format_RGBA8888_Premultiplied:
- case QImage::Format_BGR30:
- case QImage::Format_A2BGR30_Premultiplied:
- case QImage::Format_RGB30:
- case QImage::Format_A2RGB30_Premultiplied:
- qt_memrotate270(reinterpret_cast<const quint32*>(image.bits()),
- w, h, image.bytesPerLine(),
- reinterpret_cast<quint32*>(out.bits()),
- out.bytesPerLine());
- break;
- case QImage::Format_RGB666:
- case QImage::Format_ARGB6666_Premultiplied:
- case QImage::Format_ARGB8565_Premultiplied:
- case QImage::Format_ARGB8555_Premultiplied:
- case QImage::Format_RGB888:
- qt_memrotate270(reinterpret_cast<const quint24*>(image.bits()),
- w, h, image.bytesPerLine(),
- reinterpret_cast<quint24*>(out.bits()),
- out.bytesPerLine());
- break;
- case QImage::Format_RGB555:
- case QImage::Format_RGB16:
- case QImage::Format_ARGB4444_Premultiplied:
- qt_memrotate270(reinterpret_cast<const quint16*>(image.bits()),
- w, h, image.bytesPerLine(),
- reinterpret_cast<quint16*>(out.bits()),
- out.bytesPerLine());
- break;
- case QImage::Format_Alpha8:
- case QImage::Format_Grayscale8:
- case QImage::Format_Indexed8:
- qt_memrotate270(reinterpret_cast<const quint8*>(image.bits()),
- w, h, image.bytesPerLine(),
- reinterpret_cast<quint8*>(out.bits()),
- out.bytesPerLine());
- break;
- default:
+ const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][2];
+ if (memrotate) {
+ memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
+ } else {
for (int y=0; y<h; ++y) {
if (image.colorCount())
for (int x=0; x<w; ++x)
@@ -4517,18 +4521,29 @@ static QImage rotated90(const QImage &image) {
for (int x=0; x<w; ++x)
out.setPixel(h-y-1, x, image.pixel(x, y));
}
- break;
}
return out;
}
+static QImage rotated180(const QImage &image)
+{
+ const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][1];
+ if (!memrotate)
+ return image.mirrored(true, true);
-static QImage rotated180(const QImage &image) {
- return image.mirrored(true, true);
+ QImage out(image.width(), image.height(), image.format());
+ out.setDotsPerMeterX(image.dotsPerMeterY());
+ out.setDotsPerMeterY(image.dotsPerMeterX());
+ if (image.colorCount() > 0)
+ out.setColorTable(image.colorTable());
+ int w = image.width();
+ int h = image.height();
+ memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
+ return out;
}
-
-static QImage rotated270(const QImage &image) {
+static QImage rotated270(const QImage &image)
+{
QImage out(image.height(), image.width(), image.format());
out.setDotsPerMeterX(image.dotsPerMeterY());
out.setDotsPerMeterY(image.dotsPerMeterX());
@@ -4536,49 +4551,10 @@ static QImage rotated270(const QImage &image) {
out.setColorTable(image.colorTable());
int w = image.width();
int h = image.height();
- switch (image.format()) {
- case QImage::Format_RGB32:
- case QImage::Format_ARGB32:
- case QImage::Format_ARGB32_Premultiplied:
- case QImage::Format_RGBX8888:
- case QImage::Format_RGBA8888:
- case QImage::Format_RGBA8888_Premultiplied:
- case QImage::Format_BGR30:
- case QImage::Format_A2BGR30_Premultiplied:
- case QImage::Format_RGB30:
- case QImage::Format_A2RGB30_Premultiplied:
- qt_memrotate90(reinterpret_cast<const quint32*>(image.bits()),
- w, h, image.bytesPerLine(),
- reinterpret_cast<quint32*>(out.bits()),
- out.bytesPerLine());
- break;
- case QImage::Format_RGB666:
- case QImage::Format_ARGB6666_Premultiplied:
- case QImage::Format_ARGB8565_Premultiplied:
- case QImage::Format_ARGB8555_Premultiplied:
- case QImage::Format_RGB888:
- qt_memrotate90(reinterpret_cast<const quint24*>(image.bits()),
- w, h, image.bytesPerLine(),
- reinterpret_cast<quint24*>(out.bits()),
- out.bytesPerLine());
- break;
- case QImage::Format_RGB555:
- case QImage::Format_RGB16:
- case QImage::Format_ARGB4444_Premultiplied:
- qt_memrotate90(reinterpret_cast<const quint16*>(image.bits()),
- w, h, image.bytesPerLine(),
- reinterpret_cast<quint16*>(out.bits()),
- out.bytesPerLine());
- break;
- case QImage::Format_Alpha8:
- case QImage::Format_Grayscale8:
- case QImage::Format_Indexed8:
- qt_memrotate90(reinterpret_cast<const quint8*>(image.bits()),
- w, h, image.bytesPerLine(),
- reinterpret_cast<quint8*>(out.bits()),
- out.bytesPerLine());
- break;
- default:
+ const MemRotateFunc memrotate = qMemRotateFunctions[qPixelLayouts[image.format()].bpp][0];
+ if (memrotate) {
+ memrotate(image.constBits(), w, h, image.bytesPerLine(), out.bits(), out.bytesPerLine());
+ } else {
for (int y=0; y<h; ++y) {
if (image.colorCount())
for (int x=0; x<w; ++x)
@@ -4587,7 +4563,6 @@ static QImage rotated270(const QImage &image) {
for (int x=0; x<w; ++x)
out.setPixel(y, w-x-1, image.pixel(x, y));
}
- break;
}
return out;
}
diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h
index fd2298561e..204e7a54b2 100644
--- a/src/gui/image/qimage.h
+++ b/src/gui/image/qimage.h
@@ -192,6 +192,7 @@ public:
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags = Qt::AutoColor) const Q_REQUIRED_RESULT;
#endif
QImage convertToFormat(Format f, const QVector<QRgb> &colorTable, Qt::ImageConversionFlags flags = Qt::AutoColor) const Q_REQUIRED_RESULT;
+ bool reinterpretAsFormat(Format f);
int width() const;
int height() const;
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 9c9db9a245..50fad1566c 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -39,12 +39,29 @@
#include <private/qdrawhelper_p.h>
#include <private/qguiapplication_p.h>
+#include <private/qcolorprofile_p.h>
#include <private/qsimd_p.h>
#include <private/qimage_p.h>
#include <qendian.h>
QT_BEGIN_NAMESPACE
+struct QDefaultColorTables
+{
+ QDefaultColorTables()
+ : gray(256), alpha(256)
+ {
+ for (int i = 0; i < 256; ++i) {
+ gray[i] = qRgb(i, i, i);
+ alpha[i] = qRgba(0, 0, 0, i);
+ }
+ }
+
+ QVector<QRgb> gray, alpha;
+};
+
+Q_GLOBAL_STATIC(QDefaultColorTables, defaultColorTables);
+
// table to flip bits
static const uchar bitflip[256] = {
/*
@@ -82,23 +99,17 @@ const uchar *qt_get_bitflip_array()
void qGamma_correct_back_to_linear_cs(QImage *image)
{
- const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables();
- if (!tables)
+ const QColorProfile *cp = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
+ if (!cp)
return;
- const uchar *gamma = tables->qt_pow_rgb_gamma;
// gamma correct the pixels back to linear color space...
int h = image->height();
int w = image->width();
for (int y=0; y<h; ++y) {
- uint *pixels = (uint *) image->scanLine(y);
- for (int x=0; x<w; ++x) {
- uint p = pixels[x];
- uint r = gamma[qRed(p)];
- uint g = gamma[qGreen(p)];
- uint b = gamma[qBlue(p)];
- pixels[x] = (r << 16) | (g << 8) | b | 0xff000000;
- }
+ QRgb *pixels = reinterpret_cast<QRgb *>(image->scanLine(y));
+ for (int x=0; x<w; ++x)
+ pixels[x] = cp->toLinear(pixels[x]);
}
}
@@ -1957,11 +1968,7 @@ static void convert_Alpha8_to_Indexed8(QImageData *dest, const QImageData *src,
memcpy(dest->data, src->data, src->bytes_per_line * src->height);
- QVector<QRgb> colors(256);
- for (int i=0; i<256; ++i)
- colors[i] = qRgba(0, 0, 0, i);
-
- dest->colortable = colors;
+ dest->colortable = defaultColorTables->alpha;
}
static void convert_Grayscale8_to_Indexed8(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
@@ -1971,22 +1978,15 @@ static void convert_Grayscale8_to_Indexed8(QImageData *dest, const QImageData *s
memcpy(dest->data, src->data, src->bytes_per_line * src->height);
- QVector<QRgb> colors(256);
- for (int i=0; i<256; ++i)
- colors[i] = qRgb(i, i, i);
- dest->colortable = colors;
+ dest->colortable = defaultColorTables->gray;
}
static bool convert_Alpha8_to_Indexed8_inplace(QImageData *data, Qt::ImageConversionFlags)
{
Q_ASSERT(data->format == QImage::Format_Alpha8);
- QVector<QRgb> colors(256);
- for (int i=0; i<256; ++i)
- colors[i] = qRgba(0, 0, 0, i);
-
- data->colortable = colors;
+ data->colortable = defaultColorTables->alpha;
data->format = QImage::Format_Indexed8;
return true;
@@ -1996,11 +1996,7 @@ static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageCo
{
Q_ASSERT(data->format == QImage::Format_Grayscale8);
- QVector<QRgb> colors(256);
- for (int i=0; i<256; ++i)
- colors[i] = qRgb(i, i, i);
-
- data->colortable = colors;
+ data->colortable = defaultColorTables->gray;
data->format = QImage::Format_Indexed8;
return true;
diff --git a/src/gui/image/qimage_darwin.mm b/src/gui/image/qimage_darwin.mm
index 2d38468cc5..3764bef06b 100644
--- a/src/gui/image/qimage_darwin.mm
+++ b/src/gui/image/qimage_darwin.mm
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 4390e46fde..d01f0d640b 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -190,32 +190,42 @@ enum _qt_BuiltInFormatType {
_qt_NoFormat = -1
};
+#if !defined(QT_NO_IMAGEFORMAT_PPM)
+# define MAX_MT_SIZE 20
+#elif !defined(QT_NO_IMAGEFORMAT_XBM) || !defined(QT_NO_IMAGEFORMAT_XPM)
+# define MAX_MT_SIZE 10
+#else
+# define MAX_MT_SIZE 4
+#endif
+
struct _qt_BuiltInFormatStruct
{
- const char *extension;
- const char *mimeType;
+ char extension[4];
+ char mimeType[MAX_MT_SIZE];
};
+#undef MAX_MT_SIZE
+
static const _qt_BuiltInFormatStruct _qt_BuiltInFormats[] = {
#ifndef QT_NO_IMAGEFORMAT_PNG
- {"png", "image/png"},
+ {"png", "png"},
#endif
#ifndef QT_NO_IMAGEFORMAT_BMP
- {"bmp", "image/bmp"},
+ {"bmp", "bmp"},
#endif
#ifndef QT_NO_IMAGEFORMAT_PPM
- {"ppm", "image/x-portable-pixmap"},
- {"pgm", "image/x-portable-graymap"},
- {"pbm", "image/x-portable-bitmap"},
+ {"ppm", "x-portable-pixmap"},
+ {"pgm", "x-portable-graymap"},
+ {"pbm", "x-portable-bitmap"},
#endif
#ifndef QT_NO_IMAGEFORMAT_XBM
- {"xbm", "image/x-xbitmap"},
+ {"xbm", "x-xbitmap"},
#endif
#ifndef QT_NO_IMAGEFORMAT_XPM
- {"xpm", "image/x-xpixmap"},
+ {"xpm", "x-xpixmap"},
#endif
- {"", ""}
};
+Q_STATIC_ASSERT(_qt_NumFormats == sizeof _qt_BuiltInFormats / sizeof *_qt_BuiltInFormats);
static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
const QByteArray &format,
@@ -461,7 +471,8 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
--numFormats;
++currentFormat;
- currentFormat %= _qt_NumFormats;
+ if (currentFormat >= _qt_NumFormats)
+ currentFormat = 0;
}
}
@@ -1604,8 +1615,8 @@ QList<QByteArray> QImageReader::supportedMimeTypes()
{
QList<QByteArray> mimeTypes;
mimeTypes.reserve(_qt_NumFormats);
- for (int i = 0; i < _qt_NumFormats; ++i)
- mimeTypes << _qt_BuiltInFormats[i].mimeType;
+ for (const auto &fmt : _qt_BuiltInFormats)
+ mimeTypes.append(QByteArrayLiteral("image/") + fmt.mimeType);
#ifndef QT_NO_IMAGEFORMATPLUGIN
supportedImageHandlerMimeTypes(loader(), QImageIOPlugin::CanRead, &mimeTypes);
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
index f3af2738af..ab15d8ee29 100644
--- a/src/gui/image/qimagewriter.cpp
+++ b/src/gui/image/qimagewriter.cpp
@@ -283,8 +283,13 @@ bool QImageWriterPrivate::canWriteHelper()
errorString = QImageWriter::tr("Device is not set");
return false;
}
- if (!device->isOpen())
- device->open(QIODevice::WriteOnly);
+ if (!device->isOpen()) {
+ if (!device->open(QIODevice::WriteOnly)) {
+ imageWriterError = QImageWriter::DeviceError;
+ errorString = QImageWriter::tr("Cannot open device for writing: %1").arg(device->errorString());
+ return false;
+ }
+ }
if (!device->isWritable()) {
imageWriterError = QImageWriter::DeviceError;
errorString = QImageWriter::tr("Device not writable");
@@ -705,6 +710,11 @@ bool QImageWriter::canWrite() const
if (QFile *file = qobject_cast<QFile *>(d->device)) {
const bool remove = !file->isOpen() && !file->exists();
const bool result = d->canWriteHelper();
+
+ // This looks strange (why remove if it doesn't exist?) but the issue
+ // here is that canWriteHelper will create the file in the process of
+ // checking if the write can succeed. If it subsequently fails, we
+ // should remove that empty file.
if (!result && remove)
file->remove();
return result;
diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp
index 741f7713da..7eb61adb2d 100644
--- a/src/gui/image/qpixmap_raster.cpp
+++ b/src/gui/image/qpixmap_raster.cpp
@@ -51,7 +51,6 @@
#include <QImageReader>
#include <QGuiApplication>
#include <QScreen>
-#include <private/qimage_p.h>
#include <private/qsimd_p.h>
#include <private/qdrawhelper_p.h>
#include <qpa/qplatformscreen.h>
@@ -135,7 +134,7 @@ bool QRasterPlatformPixmap::fromData(const uchar *buffer, uint len, const char *
if (image.isNull())
return false;
- createPixmapForImage(image, flags, /* inplace = */true);
+ createPixmapForImage(std::move(image), flags);
return !isNull();
}
@@ -143,13 +142,13 @@ void QRasterPlatformPixmap::fromImage(const QImage &sourceImage,
Qt::ImageConversionFlags flags)
{
QImage image = sourceImage;
- createPixmapForImage(image, flags, /* inplace = */false);
+ createPixmapForImage(std::move(image), flags);
}
void QRasterPlatformPixmap::fromImageInPlace(QImage &sourceImage,
Qt::ImageConversionFlags flags)
{
- createPixmapForImage(sourceImage, flags, /* inplace = */true);
+ createPixmapForImage(std::move(sourceImage), flags);
}
void QRasterPlatformPixmap::fromImageReader(QImageReader *imageReader,
@@ -160,7 +159,7 @@ void QRasterPlatformPixmap::fromImageReader(QImageReader *imageReader,
if (image.isNull())
return;
- createPixmapForImage(image, flags, /* inplace = */true);
+ createPixmapForImage(std::move(image), flags);
}
// from qbackingstore.cpp
@@ -301,7 +300,7 @@ int QRasterPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric metric) const
return 0;
}
-void QRasterPlatformPixmap::createPixmapForImage(QImage &sourceImage, Qt::ImageConversionFlags flags, bool inPlace)
+void QRasterPlatformPixmap::createPixmapForImage(QImage sourceImage, Qt::ImageConversionFlags flags)
{
QImage::Format format;
if (flags & Qt::NoFormatConversion)
@@ -335,16 +334,10 @@ void QRasterPlatformPixmap::createPixmapForImage(QImage &sourceImage, Qt::ImageC
if (format == QImage::Format_RGB32 && (sourceImage.format() == QImage::Format_ARGB32
|| sourceImage.format() == QImage::Format_ARGB32_Premultiplied))
{
- inPlace = inPlace && sourceImage.isDetached();
- image = sourceImage;
- if (!inPlace)
- image.detach();
- if (image.d)
- image.d->format = QImage::Format_RGB32;
- } else if (inPlace && sourceImage.d->convertInPlace(format, flags)) {
- image = sourceImage;
+ image = std::move(sourceImage);
+ image.reinterpretAsFormat(QImage::Format_RGB32);
} else {
- image = sourceImage.convertToFormat(format, flags);
+ image = std::move(sourceImage).convertToFormat(format, flags);
}
if (image.d) {
@@ -356,8 +349,6 @@ void QRasterPlatformPixmap::createPixmapForImage(QImage &sourceImage, Qt::ImageC
}
is_null = (w <= 0 || h <= 0);
- if (image.d)
- image.d->devicePixelRatio = sourceImage.devicePixelRatio();
//ensure the pixmap and the image resulting from toImage() have the same cacheKey();
setSerialNumber(image.cacheKey() >> 32);
if (image.d)
diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h
index 95e018eb35..6ea965a324 100644
--- a/src/gui/image/qpixmap_raster_p.h
+++ b/src/gui/image/qpixmap_raster_p.h
@@ -85,7 +85,7 @@ public:
protected:
int metric(QPaintDevice::PaintDeviceMetric metric) const Q_DECL_OVERRIDE;
- void createPixmapForImage(QImage &sourceImage, Qt::ImageConversionFlags flags, bool inPlace);
+ void createPixmapForImage(QImage sourceImage, Qt::ImageConversionFlags flags);
void setImage(const QImage &image);
QImage image;
static QImage::Format systemOpaqueFormat();
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp
index d55a26b2a4..1d19c165fc 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -745,7 +745,7 @@ static void set_text(const QImage &image, png_structp png_ptr, png_infop info_pt
#ifdef PNG_iTXt_SUPPORTED
bool needsItxt = false;
- foreach(const QChar c, it.value()) {
+ for (const QChar c : it.value()) {
uchar ch = c.cell();
if (c.row() || (ch < 0x20 && ch != '\n') || (ch > 0x7e && ch < 0xa0)) {
needsItxt = true;
diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp
index 42d3684aea..e9f5a905f0 100644
--- a/src/gui/image/qppmhandler.cpp
+++ b/src/gui/image/qppmhandler.cpp
@@ -45,6 +45,7 @@
#include <qvariant.h>
#include <qvector.h>
#include <ctype.h>
+#include <qrgba64.h>
QT_BEGIN_NAMESPACE
@@ -120,6 +121,11 @@ static bool read_pbm_header(QIODevice *device, char& type, int& w, int& h, int&
return true;
}
+static inline QRgb scale_pbm_color(quint16 mx, quint16 rv, quint16 gv, quint16 bv)
+{
+ return QRgba64::fromRgba64((rv * 0xffff) / mx, (gv * 0xffff) / mx, (bv * 0xffff) / mx, 0xffff).toArgb32();
+}
+
static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, QImage *outImage)
{
int nbits, y;
@@ -148,9 +154,6 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
}
raw = type >= '4';
- int maxc = mcc;
- if (maxc > 255)
- maxc = 255;
if (outImage->size() != QSize(w, h) || outImage->format() != format) {
*outImage = QImage(w, h, format);
if (outImage->isNull())
@@ -175,22 +178,50 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
b = buf24;
while (p < end) {
if (mcc < 256) {
- *p++ = qRgb(b[0],b[1],b[2]);
+ if (mcc == 255)
+ *p++ = qRgb(b[0],b[1],b[2]);
+ else
+ *p++ = scale_pbm_color(mcc, b[0], b[1], b[2]);
b += 3;
} else {
- *p++ = qRgb(((int(b[0]) * 256 + int(b[1]) + 1) * 256) / (mcc + 1) - 1,
- ((int(b[2]) * 256 + int(b[3]) + 1) * 256) / (mcc + 1) - 1,
- ((int(b[4]) * 256 + int(b[5]) + 1) * 256) / (mcc + 1) - 1);
+ quint16 rv = b[0] << 8 | b[1];
+ quint16 gv = b[2] << 8 | b[3];
+ quint16 bv = b[4] << 8 | b[5];
+ if (mcc == 0xffff)
+ *p++ = QRgba64::fromRgba64(rv, gv, bv, 0xffff).toArgb32();
+ else
+ *p++ = scale_pbm_color(mcc, rv, gv, bv);
b += 6;
}
}
}
delete[] buf24;
+ } else if (nbits == 8 && mcc > 255) { // type 5 16bit
+ pbm_bpl = 2*w;
+ uchar *buf16 = new uchar[pbm_bpl];
+ for (y=0; y<h; y++) {
+ if (device->read((char *)buf16, pbm_bpl) != pbm_bpl) {
+ delete[] buf16;
+ return false;
+ }
+ uchar *p = outImage->scanLine(y);
+ uchar *end = p + w;
+ uchar *b = buf16;
+ while (p < end) {
+ *p++ = (b[0] << 8 | b[1]) * 255 / mcc;
+ b += 2;
+ }
+ }
+ delete[] buf16;
} else { // type 4,5
for (y=0; y<h; y++) {
- if (device->read((char *)outImage->scanLine(y), pbm_bpl)
- != pbm_bpl)
+ uchar *p = outImage->scanLine(y);
+ if (device->read((char *)p, pbm_bpl) != pbm_bpl)
return false;
+ if (nbits == 8 && mcc < 255) {
+ for (int i = 0; i < pbm_bpl; i++)
+ p[i] = (p[i] * 255) / mcc;
+ }
}
}
} else { // read ascii data
@@ -227,7 +258,7 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
} else { // 32 bits
n /= 4;
int r, g, b;
- if (mcc == maxc) {
+ if (mcc == 255) {
while (n--) {
r = read_pbm_int(device);
g = read_pbm_int(device);
@@ -237,10 +268,10 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
}
} else {
while (n--) {
- r = read_pbm_int(device) * maxc / mcc;
- g = read_pbm_int(device) * maxc / mcc;
- b = read_pbm_int(device) * maxc / mcc;
- *((QRgb*)p) = qRgb(r, g, b);
+ r = read_pbm_int(device);
+ g = read_pbm_int(device);
+ b = read_pbm_int(device);
+ *((QRgb*)p) = scale_pbm_color(mcc, r, g, b);
p += 4;
}
}
diff --git a/src/gui/image/qxbmhandler.cpp b/src/gui/image/qxbmhandler.cpp
index 19015c5dcd..155a4f88b4 100644
--- a/src/gui/image/qxbmhandler.cpp
+++ b/src/gui/image/qxbmhandler.cpp
@@ -143,6 +143,8 @@ static bool read_xbm_body(QIODevice *device, int w, int h, QImage *outImage)
return false;
}
+ outImage->fill(Qt::color0); // in case the image data does not cover the full image
+
outImage->setColorCount(2);
outImage->setColor(0, qRgb(255,255,255)); // white
outImage->setColor(1, qRgb(0,0,0)); // black
diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp
index 1f1f6b388f..ce7f7b8a0f 100644
--- a/src/gui/image/qxpmhandler.cpp
+++ b/src/gui/image/qxpmhandler.cpp
@@ -852,6 +852,9 @@ static bool read_xpm_header(
#endif
return false; // < 4 numbers parsed
+ if (*w <= 0 || *w > 32767 || *h <= 0 || *h > 32767 || *ncols <= 0 || *ncols > (64 * 64 * 64 * 64) || *cpp <= 0 || *cpp > 15)
+ return false; // failed sanity check
+
return true;
}
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 219f782737..ac9edc8eb0 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -2939,6 +2939,7 @@ QDragMoveEvent::~QDragMoveEvent()
type information.
*/
+// ### pos is in which coordinate system?
/*!
Constructs a drop event of a certain \a type corresponding to a
drop at the point specified by \a pos in the destination widget's
@@ -2949,7 +2950,7 @@ QDragMoveEvent::~QDragMoveEvent()
The states of the mouse buttons and keyboard modifiers at the time of
the drop are specified by \a buttons and \a modifiers.
-*/ // ### pos is in which coordinate system?
+*/
QDropEvent::QDropEvent(const QPointF& pos, Qt::DropActions actions, const QMimeData *data,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Type type)
: QEvent(type), p(pos), mouseState(buttons),
@@ -3888,12 +3889,15 @@ QDebug operator<<(QDebug dbg, const QTouchEvent::TouchPoint &tp)
{
QDebugStateSaver saver(dbg);
dbg.nospace();
- dbg << "TouchPoint(" << tp.id() << " (";
- QtDebugUtils::formatQRect(dbg, tp.rect());
+ dbg << "TouchPoint(" << hex << tp.id() << dec << " (";
+ QtDebugUtils::formatQPoint(dbg, tp.pos());
dbg << ") ";
QtDebugUtils::formatQEnum(dbg, tp.state());
- dbg << " press " << tp.pressure() << " vel " << tp.velocity()
- << " start (";
+ dbg << " pressure " << tp.pressure() << " ellipse ("
+ << tp.ellipseDiameters().width() << " x " << tp.ellipseDiameters().height()
+ << " angle " << tp.rotation() << ") vel (";
+ QtDebugUtils::formatQPoint(dbg, tp.velocity().toPointF());
+ dbg << ") start (";
QtDebugUtils::formatQPoint(dbg, tp.startPos());
dbg << ") last (";
QtDebugUtils::formatQPoint(dbg, tp.lastPos());
@@ -4418,6 +4422,8 @@ QTouchEvent::~QTouchEvent()
\brief The TouchPoint class provides information about a touch point in a QTouchEvent.
\since 4.6
\inmodule QtGui
+
+ \image touchpoint-metrics.png
*/
/*! \enum TouchPoint::InfoFlag
@@ -4503,7 +4509,7 @@ Qt::TouchPointState QTouchEvent::TouchPoint::state() const
*/
QPointF QTouchEvent::TouchPoint::pos() const
{
- return d->rect.center();
+ return d->pos;
}
/*!
@@ -4518,7 +4524,7 @@ QPointF QTouchEvent::TouchPoint::pos() const
*/
QPointF QTouchEvent::TouchPoint::scenePos() const
{
- return d->sceneRect.center();
+ return d->scenePos;
}
/*!
@@ -4528,7 +4534,7 @@ QPointF QTouchEvent::TouchPoint::scenePos() const
*/
QPointF QTouchEvent::TouchPoint::screenPos() const
{
- return d->screenRect.center();
+ return d->screenPos;
}
/*!
@@ -4651,10 +4657,19 @@ QPointF QTouchEvent::TouchPoint::lastNormalizedPos() const
around the point returned by pos().
\note This function returns an empty rect if the device does not report touch point sizes.
+
+ \obsolete This function is deprecated in 5.9 because it returns the outer bounds
+ of the touchpoint regardless of rotation, whereas a touchpoint is more correctly
+ modeled as an ellipse at position pos() with ellipseDiameters()
+ which are independent of rotation().
+
+ \sa scenePos(), ellipseDiameters()
*/
QRectF QTouchEvent::TouchPoint::rect() const
{
- return d->rect;
+ QRectF ret(QPointF(), d->ellipseDiameters);
+ ret.moveCenter(d->pos);
+ return ret;
}
/*!
@@ -4662,11 +4677,18 @@ QRectF QTouchEvent::TouchPoint::rect() const
\note This function returns an empty rect if the device does not report touch point sizes.
- \sa scenePos(), rect()
+ \obsolete This function is deprecated in 5.9 because it returns the outer bounds
+ of the touchpoint regardless of rotation, whereas a touchpoint is more correctly
+ modeled as an ellipse at position scenePos() with ellipseDiameters()
+ which are independent of rotation().
+
+ \sa scenePos(), ellipseDiameters()
*/
QRectF QTouchEvent::TouchPoint::sceneRect() const
{
- return d->sceneRect;
+ QRectF ret(QPointF(), d->ellipseDiameters);
+ ret.moveCenter(d->scenePos);
+ return ret;
}
/*!
@@ -4674,11 +4696,18 @@ QRectF QTouchEvent::TouchPoint::sceneRect() const
\note This function returns an empty rect if the device does not report touch point sizes.
- \sa screenPos(), rect()
+ \obsolete This function is deprecated because it returns the outer bounds of the
+ touchpoint regardless of rotation, whereas a touchpoint is more correctly
+ modeled as an ellipse at position screenPos() with ellipseDiameters()
+ which are independent of rotation().
+
+ \sa screenPos(), ellipseDiameters()
*/
QRectF QTouchEvent::TouchPoint::screenRect() const
{
- return d->screenRect;
+ QRectF ret(QPointF(), d->ellipseDiameters);
+ ret.moveCenter(d->screenPos);
+ return ret;
}
/*!
@@ -4704,6 +4733,19 @@ qreal QTouchEvent::TouchPoint::rotation() const
}
/*!
+ \since 5.9
+ Returns the width and height of the bounding ellipse of this touch point.
+ The return value is in logical pixels. Most touchscreens do not detect the
+ shape of the contact point, so a null size is the most common value.
+ In other cases the diameters may be nonzero and equal (the ellipse is
+ approximated as a circle).
+*/
+QSizeF QTouchEvent::TouchPoint::ellipseDiameters() const
+{
+ return d->ellipseDiameters;
+}
+
+/*!
Returns a velocity vector for this touch point.
The vector is in the screen's coordinate system, using pixels per seconds for the magnitude.
@@ -4774,7 +4816,7 @@ void QTouchEvent::TouchPoint::setPos(const QPointF &pos)
{
if (d->ref.load() != 1)
d = d->detach();
- d->rect.moveCenter(pos);
+ d->pos = pos;
}
/*! \internal */
@@ -4782,7 +4824,7 @@ void QTouchEvent::TouchPoint::setScenePos(const QPointF &scenePos)
{
if (d->ref.load() != 1)
d = d->detach();
- d->sceneRect.moveCenter(scenePos);
+ d->scenePos = scenePos;
}
/*! \internal */
@@ -4790,7 +4832,7 @@ void QTouchEvent::TouchPoint::setScreenPos(const QPointF &screenPos)
{
if (d->ref.load() != 1)
d = d->detach();
- d->screenRect.moveCenter(screenPos);
+ d->screenPos = screenPos;
}
/*! \internal */
@@ -4865,28 +4907,32 @@ void QTouchEvent::TouchPoint::setLastNormalizedPos(const QPointF &lastNormalized
d->lastNormalizedPos = lastNormalizedPos;
}
-/*! \internal */
+// ### remove the following 3 setRect functions and their usages soon
+/*! \internal \obsolete */
void QTouchEvent::TouchPoint::setRect(const QRectF &rect)
{
if (d->ref.load() != 1)
d = d->detach();
- d->rect = rect;
+ d->pos = rect.center();
+ d->ellipseDiameters = rect.size();
}
-/*! \internal */
+/*! \internal \obsolete */
void QTouchEvent::TouchPoint::setSceneRect(const QRectF &sceneRect)
{
if (d->ref.load() != 1)
d = d->detach();
- d->sceneRect = sceneRect;
+ d->scenePos = sceneRect.center();
+ d->ellipseDiameters = sceneRect.size();
}
-/*! \internal */
+/*! \internal \obsolete */
void QTouchEvent::TouchPoint::setScreenRect(const QRectF &screenRect)
{
if (d->ref.load() != 1)
d = d->detach();
- d->screenRect = screenRect;
+ d->screenPos = screenRect.center();
+ d->ellipseDiameters = screenRect.size();
}
/*! \internal */
@@ -4906,6 +4952,14 @@ void QTouchEvent::TouchPoint::setRotation(qreal angle)
}
/*! \internal */
+void QTouchEvent::TouchPoint::setEllipseDiameters(const QSizeF &dia)
+{
+ if (d->ref.load() != 1)
+ d = d->detach();
+ d->ellipseDiameters = dia;
+}
+
+/*! \internal */
void QTouchEvent::TouchPoint::setVelocity(const QVector2D &v)
{
if (d->ref.load() != 1)
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 7881df205a..cfc3b842d7 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -885,6 +885,8 @@ public:
qreal pressure() const;
qreal rotation() const;
+ QSizeF ellipseDiameters() const;
+
QVector2D velocity() const;
InfoFlags flags() const;
QVector<QPointF> rawScreenPositions() const;
@@ -905,11 +907,12 @@ public:
void setLastScenePos(const QPointF &lastScenePos);
void setLastScreenPos(const QPointF &lastScreenPos);
void setLastNormalizedPos(const QPointF &lastNormalizedPos);
- void setRect(const QRectF &rect);
- void setSceneRect(const QRectF &sceneRect);
- void setScreenRect(const QRectF &screenRect);
+ void setRect(const QRectF &rect); // deprecated
+ void setSceneRect(const QRectF &sceneRect); // deprecated
+ void setScreenRect(const QRectF &screenRect); // deprecated
void setPressure(qreal pressure);
void setRotation(qreal angle);
+ void setEllipseDiameters(const QSizeF &dia);
void setVelocity(const QVector2D &v);
void setFlags(InfoFlags flags);
void setRawScreenPositions(const QVector<QPointF> &positions);
diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h
index 898ad16cf6..1eccfaea78 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -65,8 +65,9 @@ public:
: ref(1),
id(id),
state(Qt::TouchPointReleased),
- pressure(qreal(-1.)),
- rotation(qreal(0.))
+ pressure(-1),
+ rotation(0),
+ ellipseDiameters(0, 0)
{ }
inline QTouchEventTouchPointPrivate *detach()
@@ -82,12 +83,12 @@ public:
int id;
QPointingDeviceUniqueId uniqueId;
Qt::TouchPointStates state;
- QRectF rect, sceneRect, screenRect;
- QPointF normalizedPos,
+ QPointF pos, scenePos, screenPos, normalizedPos,
startPos, startScenePos, startScreenPos, startNormalizedPos,
lastPos, lastScenePos, lastScreenPos, lastNormalizedPos;
qreal pressure;
qreal rotation;
+ QSizeF ellipseDiameters;
QVector2D velocity;
QTouchEvent::TouchPoint::InfoFlags flags;
QVector<QPointF> rawScreenPositions;
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 46e5f6be70..56f112c36c 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -68,8 +68,8 @@
#include <qpalette.h>
#include <qscreen.h>
#include "qsessionmanager.h"
+#include <private/qcolorprofile_p.h>
#include <private/qscreen_p.h>
-#include <private/qdrawhelper_p.h>
#include <QtGui/qgenericpluginfactory.h>
#include <QtGui/qstylehints.h>
@@ -84,6 +84,7 @@
#include "private/qcursor_p.h"
#include "private/qopenglcontext_p.h"
#include "private/qinputdevicemanager_p.h"
+#include "private/qtouchdevice_p.h"
#include "private/qdnd_p.h"
#include <qpa/qplatformthemefactory_p.h>
@@ -107,9 +108,6 @@
#elif defined(Q_OS_WIN)
# include <QtCore/qt_windows.h>
# include <QtCore/QLibraryInfo>
-# if defined(Q_OS_WINPHONE)
-# include <Objbase.h>
-# endif
#endif // Q_OS_WIN
#include <ctype.h>
@@ -672,7 +670,7 @@ void QGuiApplication::setApplicationDisplayName(const QString &name)
disconnect(qGuiApp, &QGuiApplication::applicationNameChanged,
qGuiApp, &QGuiApplication::applicationDisplayNameChanged);
- if (QGuiApplicationPrivate::displayName != applicationName())
+ if (*QGuiApplicationPrivate::displayName != applicationName())
emit qGuiApp->applicationDisplayNameChanged();
}
} else if (name != *QGuiApplicationPrivate::displayName) {
@@ -821,19 +819,11 @@ bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blocking
for (int i = 0; i < modalWindowList.count(); ++i) {
QWindow *modalWindow = modalWindowList.at(i);
- {
- // check if the modal window is our window or a (transient) parent of our window
- QWindow *w = window;
- while (w) {
- if (w == modalWindow) {
- *blockingWindow = 0;
- return false;
- }
- QWindow *p = w->parent();
- if (!p)
- p = w->transientParent();
- w = p;
- }
+ // A window is not blocked by another modal window if the two are
+ // the same, or if the window is a child of the modal window.
+ if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients)) {
+ *blockingWindow = 0;
+ return false;
}
Qt::WindowModality windowModality = modalWindow->modality();
@@ -940,15 +930,25 @@ QWindowList QGuiApplication::topLevelWindows()
{
const QWindowList &list = QGuiApplicationPrivate::window_list;
QWindowList topLevelWindows;
- for (int i = 0; i < list.size(); i++) {
- if (!list.at(i)->parent() && list.at(i)->type() != Qt::Desktop) {
- // Top windows of embedded QAxServers do not have QWindow parents,
- // but they are not true top level windows, so do not include them.
- const bool embedded = list.at(i)->handle() && list.at(i)->handle()->isEmbedded();
- if (!embedded)
- topLevelWindows.prepend(list.at(i));
- }
+ for (int i = 0; i < list.size(); ++i) {
+ QWindow *window = list.at(i);
+ if (!window->isTopLevel())
+ continue;
+
+ // Desktop windows are special, as each individual desktop window
+ // will report that it's a top level window, but we don't want to
+ // include them in the application wide list of top level windows.
+ if (window->type() == Qt::Desktop)
+ continue;
+
+ // Windows embedded in native windows do not have QWindow parents,
+ // but they are not true top level windows, so do not include them.
+ if (window->handle() && window->handle()->isEmbedded())
+ continue;
+
+ topLevelWindows.prepend(window);
}
+
return topLevelWindows;
}
@@ -1124,7 +1124,7 @@ static void init_platform(const QString &pluginArgument, const QString &platform
= QStringLiteral("This application failed to start because it could not find or load the Qt platform plugin \"%1\"\nin \"%2\".\n\n").arg(name, QDir::toNativeSeparators(platformPluginPath));
if (!keys.isEmpty()) {
fatalMessage += QStringLiteral("Available platform plugins are: %1.\n\n").arg(
- keys.join(QStringLiteral(", ")));
+ keys.join(QLatin1String(", ")));
}
fatalMessage += QStringLiteral("Reinstalling the application may fix this problem.");
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
@@ -1523,7 +1523,8 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
platform_theme = 0;
delete platform_integration;
platform_integration = 0;
- delete m_gammaTables.load();
+ delete m_a8ColorProfile.load();
+ delete m_a32ColorProfile.load();
window_list.clear();
}
@@ -1958,7 +1959,8 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
points << point;
QEvent::Type type;
- QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type);
+ QList<QTouchEvent::TouchPoint> touchPoints =
+ QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, QTouchDevicePrivate::get(m_fakeTouchDevice)->id, &type);
QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers);
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
@@ -2006,6 +2008,8 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh
buttons, e->modifiers, e->phase, e->source, e->inverted);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &ev);
+#else
+ Q_UNUSED(e);
#endif /* ifndef QT_NO_WHEELEVENT */
}
@@ -2023,13 +2027,23 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
window = QGuiApplication::focusWindow();
}
+#if defined(Q_OS_ANDROID)
+ static bool backKeyPressAccepted = false;
+ static bool menuKeyPressAccepted = false;
+#endif
+
#if !defined(Q_OS_OSX)
// FIXME: Include OS X in this code path by passing the key event through
// QPlatformInputContext::filterEvent().
if (e->keyType == QEvent::KeyPress && window) {
if (QWindowSystemInterface::handleShortcutEvent(window, e->timestamp, e->key, e->modifiers,
- e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, e->unicode, e->repeat, e->repeatCount))
+ e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, e->unicode, e->repeat, e->repeatCount)) {
+#if defined(Q_OS_ANDROID)
+ backKeyPressAccepted = e->key == Qt::Key_Back;
+ menuKeyPressAccepted = e->key == Qt::Key_Menu;
+#endif
return;
+ }
}
#endif
@@ -2046,8 +2060,6 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
else
ev.setAccepted(false);
- static bool backKeyPressAccepted = false;
- static bool menuKeyPressAccepted = false;
if (e->keyType == QEvent::KeyPress) {
backKeyPressAccepted = e->key == Qt::Key_Back && ev.isAccepted();
menuKeyPressAccepted = e->key == Qt::Key_Menu && ev.isAccepted();
@@ -2160,7 +2172,7 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *wse)
{
if (QWindow *window = wse->window.data()) {
- QWindowStateChangeEvent e(window->windowState());
+ QWindowStateChangeEvent e(wse->oldState);
window->d_func()->windowState = wse->newState;
QGuiApplication::sendSpontaneousEvent(window, &e);
}
@@ -2195,10 +2207,10 @@ void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::
void QGuiApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePrivate::GeometryChangeEvent *e)
{
- if (e->tlw.isNull())
+ if (e->window.isNull())
return;
- QWindow *window = e->tlw.data();
+ QWindow *window = e->window.data();
if (!window)
return;
@@ -2563,7 +2575,10 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
Q_ASSERT(w.data() != 0);
// make the *scene* functions return the same as the *screen* functions
- touchPoint.d->sceneRect = touchPoint.screenRect();
+ // Note: touchPoint is a reference to the one from activeTouchPoints,
+ // so we can modify it as long as we're careful NOT to call setters and
+ // otherwise NOT to cause the d-pointer to be detached.
+ touchPoint.d->scenePos = touchPoint.screenPos();
touchPoint.d->startScenePos = touchPoint.startScreenPos();
touchPoint.d->lastScenePos = touchPoint.lastScreenPos();
@@ -2618,8 +2633,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
QTouchEvent touchEvent(eventType,
e->device,
e->modifiers,
- it.value().first,
- it.value().second);
+ it.value().first, // state flags
+ it.value().second); // list of touchpoints
touchEvent.setTimestamp(e->timestamp);
touchEvent.setWindow(w);
@@ -2628,13 +2643,14 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
QTouchEvent::TouchPoint &touchPoint = touchEvent._touchPoints[i];
// preserve the sub-pixel resolution
- QRectF rect = touchPoint.screenRect();
- const QPointF screenPos = rect.center();
+ const QPointF screenPos = touchPoint.screenPos();
const QPointF delta = screenPos - screenPos.toPoint();
- rect.moveCenter(w->mapFromGlobal(screenPos.toPoint()) + delta);
- touchPoint.d->rect = rect;
+ touchPoint.d->pos = w->mapFromGlobal(screenPos.toPoint()) + delta;
if (touchPoint.state() == Qt::TouchPointPressed) {
+ // touchPoint is actually a reference to one that is stored in activeTouchPoints,
+ // and we are now going to store the startPos and lastPos there, for the benefit
+ // of future moves and releases. It's important that the d-pointer is NOT detached.
touchPoint.d->startPos = w->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta;
touchPoint.d->lastPos = w->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta;
}
@@ -3674,14 +3690,30 @@ void QGuiApplicationPrivate::notifyDragStarted(const QDrag *drag)
}
#endif
-const QDrawHelperGammaTables *QGuiApplicationPrivate::gammaTables()
+const QColorProfile *QGuiApplicationPrivate::colorProfileForA8Text()
+{
+#ifdef Q_OS_WIN
+ QColorProfile *result = m_a8ColorProfile.load();
+ if (!result){
+ QColorProfile *cs = QColorProfile::fromGamma(2.31); // This is a hard-coded thing for Windows text rendering
+ if (!m_a8ColorProfile.testAndSetRelease(0, cs))
+ delete cs;
+ result = m_a8ColorProfile.load();
+ }
+ return result;
+#else
+ return colorProfileForA32Text();
+#endif
+}
+
+const QColorProfile *QGuiApplicationPrivate::colorProfileForA32Text()
{
- QDrawHelperGammaTables *result = m_gammaTables.load();
+ QColorProfile *result = m_a32ColorProfile.load();
if (!result){
- QDrawHelperGammaTables *tables = new QDrawHelperGammaTables(fontSmoothingGamma);
- if (!m_gammaTables.testAndSetRelease(0, tables))
- delete tables;
- result = m_gammaTables.load();
+ QColorProfile *cs = QColorProfile::fromGamma(fontSmoothingGamma);
+ if (!m_a32ColorProfile.testAndSetRelease(0, cs))
+ delete cs;
+ result = m_a32ColorProfile.load();
}
return result;
}
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index 0d62490c75..3804667ef3 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -66,10 +66,10 @@
QT_BEGIN_NAMESPACE
+class QColorProfile;
class QPlatformIntegration;
class QPlatformTheme;
class QPlatformDragQtResponse;
-struct QDrawHelperGammaTables;
#ifndef QT_NO_DRAGANDDROP
class QDrag;
#endif // QT_NO_DRAGANDDROP
@@ -293,7 +293,8 @@ public:
static QInputDeviceManager *inputDeviceManager();
- const QDrawHelperGammaTables *gammaTables();
+ const QColorProfile *colorProfileForA8Text();
+ const QColorProfile *colorProfileForA32Text();
// hook reimplemented in QApplication to apply the QStyle function on the QIcon
virtual QPixmap applyQIconStyleHelper(QIcon::Mode, const QPixmap &basePixmap) const { return basePixmap; }
@@ -317,7 +318,8 @@ private:
static QGuiApplicationPrivate *self;
static QTouchDevice *m_fakeTouchDevice;
static int m_fakeMouseSourcePointId;
- QAtomicPointer<QDrawHelperGammaTables> m_gammaTables;
+ QAtomicPointer<QColorProfile> m_a8ColorProfile;
+ QAtomicPointer<QColorProfile> m_a32ColorProfile;
bool ownGlobalShareContext;
diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp
index a6bc7d4d9c..20eac2ed15 100644
--- a/src/gui/kernel/qkeysequence.cpp
+++ b/src/gui/kernel/qkeysequence.cpp
@@ -1183,7 +1183,7 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence
QString keyName(tran == 0
? QCoreApplication::translate("QShortcut", keyname[i].name)
: QString::fromLatin1(keyname[i].name));
- if (accelRef == keyName.toLower()) {
+ if (accelRef == std::move(keyName).toLower()) {
ret |= keyname[i].key;
found = true;
break;
diff --git a/src/gui/kernel/qoffscreensurface.cpp b/src/gui/kernel/qoffscreensurface.cpp
index a9535a6ad7..307bc5e62f 100644
--- a/src/gui/kernel/qoffscreensurface.cpp
+++ b/src/gui/kernel/qoffscreensurface.cpp
@@ -102,6 +102,7 @@ public:
, requestedFormat(QSurfaceFormat::defaultFormat())
, screen(0)
, size(1, 1)
+ , nativeHandle(nullptr)
{
}
@@ -115,6 +116,7 @@ public:
QSurfaceFormat requestedFormat;
QScreen *screen;
QSize size;
+ void *nativeHandle;
};
@@ -217,6 +219,8 @@ void QOffscreenSurface::destroy()
delete d->offscreenWindow;
d->offscreenWindow = 0;
}
+
+ d->nativeHandle = nullptr;
}
/*!
@@ -331,6 +335,26 @@ void QOffscreenSurface::setScreen(QScreen *newScreen)
}
/*!
+ Sets the native handle to which the offscreen surface is connected to \a handle.
+
+ The native handle will be resolved in the create() function. Calling
+ this function after create() will not re-create a native surface.
+
+ \note The interpretation of the native handle is platform specific. Only
+ some platforms will support adopting native handles of offscreen surfaces
+ and platforms that do not implement this support will ignore the handle.
+
+ \since 5.9
+ \sa nativeHandle()
+*/
+
+void QOffscreenSurface::setNativeHandle(void *handle)
+{
+ Q_D(QOffscreenSurface);
+ d->nativeHandle = handle;
+}
+
+/*!
Called when the offscreen surface's screen is destroyed.
\internal
@@ -362,6 +386,19 @@ QPlatformOffscreenSurface *QOffscreenSurface::handle() const
}
/*!
+ Returns an optional native handle to which the offscreen surface is connected.
+
+ \since 5.9
+ \sa setNativeHandle()
+*/
+
+void *QOffscreenSurface::nativeHandle() const
+{
+ Q_D(const QOffscreenSurface);
+ return d->nativeHandle;
+}
+
+/*!
Returns the platform surface corresponding to the offscreen surface.
\internal
diff --git a/src/gui/kernel/qoffscreensurface.h b/src/gui/kernel/qoffscreensurface.h
index bacc9c851a..35c498c89a 100644
--- a/src/gui/kernel/qoffscreensurface.h
+++ b/src/gui/kernel/qoffscreensurface.h
@@ -79,6 +79,9 @@ public:
QPlatformOffscreenSurface *handle() const;
+ void *nativeHandle() const;
+ void setNativeHandle(void *handle);
+
Q_SIGNALS:
void screenChanged(QScreen *screen);
diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp
index 5890eb4fb6..01cf98c7c9 100644
--- a/src/gui/kernel/qplatformdialoghelper.cpp
+++ b/src/gui/kernel/qplatformdialoghelper.cpp
@@ -451,6 +451,7 @@ public:
QString defaultSuffix;
QStringList history;
QUrl initialDirectory;
+ QString initiallySelectedMimeTypeFilter;
QString initiallySelectedNameFilter;
QList<QUrl> initiallySelectedFiles;
QStringList supportedSchemes;
@@ -668,6 +669,16 @@ void QFileDialogOptions::setInitialDirectory(const QUrl &directory)
d->initialDirectory = directory;
}
+QString QFileDialogOptions::initiallySelectedMimeTypeFilter() const
+{
+ return d->initiallySelectedMimeTypeFilter;
+}
+
+void QFileDialogOptions::setInitiallySelectedMimeTypeFilter(const QString &filter)
+{
+ d->initiallySelectedMimeTypeFilter = filter;
+}
+
QString QFileDialogOptions::initiallySelectedNameFilter() const
{
return d->initiallySelectedNameFilter;
@@ -699,6 +710,16 @@ QStringList QFileDialogOptions::supportedSchemes() const
return d->supportedSchemes;
}
+void QPlatformFileDialogHelper::selectMimeTypeFilter(const QString &filter)
+{
+ Q_UNUSED(filter)
+}
+
+QString QPlatformFileDialogHelper::selectedMimeTypeFilter() const
+{
+ return QString();
+}
+
// Return true if the URL is supported by the filedialog implementation *and* by the application.
bool QPlatformFileDialogHelper::isSupportedUrl(const QUrl &url) const
{
diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h
index 6caef070e2..ed88c19c84 100644
--- a/src/gui/kernel/qplatformdialoghelper.h
+++ b/src/gui/kernel/qplatformdialoghelper.h
@@ -372,6 +372,9 @@ public:
QUrl initialDirectory() const;
void setInitialDirectory(const QUrl &);
+ QString initiallySelectedMimeTypeFilter() const;
+ void setInitiallySelectedMimeTypeFilter(const QString &);
+
QString initiallySelectedNameFilter() const;
void setInitiallySelectedNameFilter(const QString &);
@@ -397,7 +400,9 @@ public:
virtual void selectFile(const QUrl &filename) = 0;
virtual QList<QUrl> selectedFiles() const = 0;
virtual void setFilter() = 0;
+ virtual void selectMimeTypeFilter(const QString &filter);
virtual void selectNameFilter(const QString &filter) = 0;
+ virtual QString selectedMimeTypeFilter() const;
virtual QString selectedNameFilter() const = 0;
virtual bool isSupportedUrl(const QUrl &url) const;
diff --git a/src/gui/kernel/qplatforminputcontextfactory.cpp b/src/gui/kernel/qplatforminputcontextfactory.cpp
index 5f4f8d88fa..c59d89fabe 100644
--- a/src/gui/kernel/qplatforminputcontextfactory.cpp
+++ b/src/gui/kernel/qplatforminputcontextfactory.cpp
@@ -82,6 +82,8 @@ QPlatformInputContext *QPlatformInputContextFactory::create(const QString& key)
delete ic;
}
+#else
+ Q_UNUSED(key);
#endif
return 0;
}
diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp
index 5bf0df67db..fe1861e08b 100644
--- a/src/gui/kernel/qplatformintegration.cpp
+++ b/src/gui/kernel/qplatformintegration.cpp
@@ -354,11 +354,16 @@ QPlatformInputContext *QPlatformIntegration::inputContext() const
/*!
Returns the platforms accessibility.
- The default implementation returns 0, implying no accessibility support.
+ The default implementation returns QPlatformAccessibility which
+ delegates handling of accessibility to accessiblebridge plugins.
*/
QPlatformAccessibility *QPlatformIntegration::accessibility() const
{
- return 0;
+ static QPlatformAccessibility *accessibility = 0;
+ if (Q_UNLIKELY(!accessibility)) {
+ accessibility = new QPlatformAccessibility;
+ }
+ return accessibility;
}
#endif
@@ -404,6 +409,8 @@ QVariant QPlatformIntegration::styleHint(StyleHint hint) const
return QPlatformTheme::defaultThemeHint(QPlatformTheme::ItemViewActivateItemOnSingleClick);
case UiEffects:
return QPlatformTheme::defaultThemeHint(QPlatformTheme::UiEffects);
+ case WheelScrollLines:
+ return QPlatformTheme::defaultThemeHint(QPlatformTheme::WheelScrollLines);
}
return 0;
diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h
index 22a834f0e1..0449e0b4c8 100644
--- a/src/gui/kernel/qplatformintegration.h
+++ b/src/gui/kernel/qplatformintegration.h
@@ -108,6 +108,7 @@ public:
virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const;
virtual QPlatformWindow *createPlatformWindow(QWindow *window) const = 0;
+ virtual QPlatformWindow *createForeignWindow(QWindow *, WId) const { return 0; }
virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const = 0;
#ifndef QT_NO_OPENGL
virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
@@ -157,7 +158,8 @@ public:
TabFocusBehavior,
ReplayMousePressOutsidePopup,
ItemViewActivateItemOnSingleClick,
- UiEffects
+ UiEffects,
+ WheelScrollLines,
};
virtual QVariant styleHint(StyleHint hint) const;
diff --git a/src/gui/kernel/qplatformmenu.cpp b/src/gui/kernel/qplatformmenu.cpp
index 2912416309..1eb146dd0f 100644
--- a/src/gui/kernel/qplatformmenu.cpp
+++ b/src/gui/kernel/qplatformmenu.cpp
@@ -55,4 +55,9 @@ QPlatformMenu *QPlatformMenu::createSubMenu() const
return QGuiApplicationPrivate::platformTheme()->createPlatformMenu();
}
+QPlatformMenu *QPlatformMenuBar::createMenu() const
+{
+ return QGuiApplicationPrivate::platformTheme()->createPlatformMenu();
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h
index f08f0ef494..f8561445b1 100644
--- a/src/gui/kernel/qplatformmenu.h
+++ b/src/gui/kernel/qplatformmenu.h
@@ -150,7 +150,7 @@ public:
virtual void handleReparent(QWindow *newParentWindow) = 0;
virtual QPlatformMenu *menuForTag(quintptr tag) const = 0;
- virtual QPlatformMenu *createMenu() const { return nullptr; }
+ virtual QPlatformMenu *createMenu() const;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp
index 1d519e84f9..e22037c1e9 100644
--- a/src/gui/kernel/qplatformscreen.cpp
+++ b/src/gui/kernel/qplatformscreen.cpp
@@ -280,6 +280,45 @@ QPlatformScreen * QPlatformScreen::platformScreenForWindow(const QWindow *window
}
/*!
+ Reimplement this function in subclass to return the manufacturer
+ of this screen.
+
+ The default implementation returns an empty string.
+
+ \since 5.9
+*/
+QString QPlatformScreen::manufacturer() const
+{
+ return QString();
+}
+
+/*!
+ Reimplement this function in subclass to return the model
+ of this screen.
+
+ The default implementation returns an empty string.
+
+ \since 5.9
+*/
+QString QPlatformScreen::model() const
+{
+ return QString();
+}
+
+/*!
+ Reimplement this function in subclass to return the serial number
+ of this screen.
+
+ The default implementation returns an empty string.
+
+ \since 5.9
+*/
+QString QPlatformScreen::serialNumber() const
+{
+ return QString();
+}
+
+/*!
\class QPlatformScreen
\since 4.8
\internal
@@ -494,4 +533,53 @@ void QPlatformScreen::setPowerState(PowerState state)
Q_UNUSED(state);
}
+/*!
+ Reimplement this function in subclass to return the list
+ of modes for this screen.
+
+ The default implementation returns a list with
+ only one mode from the current screen size and refresh rate.
+
+ \sa QPlatformScreen::geometry
+ \sa QPlatformScreen::refreshRate
+
+ \since 5.9
+*/
+QVector<QPlatformScreen::Mode> QPlatformScreen::modes() const
+{
+ QVector<QPlatformScreen::Mode> list;
+ list.append({geometry().size(), refreshRate()});
+ return list;
+}
+
+/*!
+ Reimplement this function in subclass to return the
+ index of the current mode from the modes list.
+
+ The default implementation returns 0.
+
+ \sa QPlatformScreen::modes
+
+ \since 5.9
+*/
+int QPlatformScreen::currentMode() const
+{
+ return 0;
+}
+
+/*!
+ Reimplement this function in subclass to return the preferred
+ mode index from the modes list.
+
+ The default implementation returns 0.
+
+ \sa QPlatformScreen::modes
+
+ \since 5.9
+*/
+int QPlatformScreen::preferredMode() const
+{
+ return 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h
index 030edea880..97fe3fed03 100644
--- a/src/gui/kernel/qplatformscreen.h
+++ b/src/gui/kernel/qplatformscreen.h
@@ -66,7 +66,6 @@ QT_BEGIN_NAMESPACE
class QPlatformBackingStore;
-class QPlatformOpenGLContext;
class QPlatformScreenPrivate;
class QPlatformWindow;
class QPlatformCursor;
@@ -96,6 +95,11 @@ public:
PowerStateOff
};
+ struct Mode {
+ QSize size;
+ qreal refreshRate;
+ };
+
QPlatformScreen();
virtual ~QPlatformScreen();
@@ -130,12 +134,21 @@ public:
virtual QString name() const { return QString(); }
+ virtual QString manufacturer() const;
+ virtual QString model() const;
+ virtual QString serialNumber() const;
+
virtual QPlatformCursor *cursor() const;
virtual SubpixelAntialiasingType subpixelAntialiasingTypeHint() const;
virtual PowerState powerState() const;
virtual void setPowerState(PowerState state);
+ virtual QVector<Mode> modes() const;
+
+ virtual int currentMode() const;
+ virtual int preferredMode() const;
+
static int angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b);
static QTransform transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target);
static QRect mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect);
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp
index fc1b607563..878f656f2e 100644
--- a/src/gui/kernel/qplatformtheme.cpp
+++ b/src/gui/kernel/qplatformtheme.cpp
@@ -156,6 +156,11 @@ QT_BEGIN_NAMESPACE
\value ContextMenuOnMouseRelease (bool) Whether the context menu should be shown on mouse release.
+ \value TouchDoubleTapDistance (int) The maximum distance in logical pixels which a touchpoint can travel
+ between taps in order for the tap sequence to be handled as a double tap.
+ The default value is double the MouseDoubleClickDistance, or 10 logical pixels
+ if that is not specified.
+
\sa themeHint(), QStyle::pixelMetric()
*/
@@ -540,6 +545,14 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint)
}
case WheelScrollLines:
return QVariant(3);
+ case TouchDoubleTapDistance:
+ {
+ bool ok = false;
+ int dist = qEnvironmentVariableIntValue("QT_DBL_TAP_DIST", &ok);
+ if (!ok)
+ dist = defaultThemeHint(MouseDoubleClickDistance).toInt(&ok) * 2;
+ return QVariant(ok ? dist : 10);
+ }
}
return QVariant();
}
@@ -665,6 +678,19 @@ QString QPlatformTheme::standardButtonText(int button) const
return QPlatformTheme::defaultStandardButtonText(button);
}
+/*!
+ Returns the mnemonic that should be used for a standard \a button.
+
+ \since 5.9
+ \sa QPlatformDialogHelper::StandardButton
+ */
+
+QKeySequence QPlatformTheme::standardButtonShortcut(int button) const
+{
+ Q_UNUSED(button)
+ return QKeySequence();
+}
+
QString QPlatformTheme::defaultStandardButtonText(int button)
{
switch (button) {
diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h
index 686dbed4b1..2ba2f8669f 100644
--- a/src/gui/kernel/qplatformtheme.h
+++ b/src/gui/kernel/qplatformtheme.h
@@ -114,7 +114,8 @@ public:
ContextMenuOnMouseRelease,
MousePressAndHoldInterval,
MouseDoubleClickDistance,
- WheelScrollLines
+ WheelScrollLines,
+ TouchDoubleTapDistance
};
enum DialogType {
@@ -311,6 +312,7 @@ public:
#endif
virtual QString standardButtonText(int button) const;
+ virtual QKeySequence standardButtonShortcut(int button) const;
static QVariant defaultThemeHint(ThemeHint hint);
static QString defaultStandardButtonText(int button);
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index 11432a4272..5062bd1e77 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -192,15 +192,30 @@ bool QPlatformWindow::isActive() const
}
/*!
- Returns \c true if the window is a descendant of an embedded non-Qt window.
- Example of an embedded non-Qt window is the parent window of an in-process QAxServer.
+ Returns \c true if the window is an ancestor of the given \a child.
- If \a parentWindow is nonzero, only check if the window is embedded in the
- specified \a parentWindow.
+ Platform overrides should iterate the native window hierarchy of the child,
+ to ensure that ancestary is reflected even with native windows in the window
+ hierarchy.
*/
-bool QPlatformWindow::isEmbedded(const QPlatformWindow *parentWindow) const
+bool QPlatformWindow::isAncestorOf(const QPlatformWindow *child) const
+{
+ for (const QPlatformWindow *parent = child->parent(); parent; parent = child->parent()) {
+ if (parent == this)
+ return true;
+ }
+
+ return false;
+}
+
+/*!
+ Returns \c true if the window is a child of a non-Qt window.
+
+ A embedded window has no parent platform window as reflected
+ though parent(), but will have a native parent window.
+*/
+bool QPlatformWindow::isEmbedded() const
{
- Q_UNUSED(parentWindow);
return false;
}
@@ -262,13 +277,13 @@ WId QPlatformWindow::winId() const
return WId(1);
}
+//jl: It would be useful to have a property on the platform window which indicated if the sub-class
+// supported the setParent. If not, then geometry would be in screen coordinates.
/*!
This function is called to enable native child window in QPA. It is common not to support this
feature in Window systems, but can be faked. When this function is called all geometry of this
platform window will be relative to the parent.
*/
-//jl: It would be useful to have a property on the platform window which indicated if the sub-class
-// supported the setParent. If not, then geometry would be in screen coordinates.
void QPlatformWindow::setParent(const QPlatformWindow *parent)
{
Q_UNUSED(parent);
@@ -493,7 +508,7 @@ QPlatformScreen *QPlatformWindow::screenForGeometry(const QRect &newGeometry) co
// QRect::center can return a value outside the rectangle if it's empty.
// Apply mapToGlobal() in case it is a foreign/embedded window.
QPoint center = newGeometry.isEmpty() ? newGeometry.topLeft() : newGeometry.center();
- if (window()->type() == Qt::ForeignWindow)
+ if (isForeignWindow())
center = mapToGlobal(center - newGeometry.topLeft());
if (!parent() && currentScreen && !currentScreen->geometry().contains(center)) {
@@ -546,7 +561,8 @@ bool QPlatformWindow::isAlertState() const
// Return the effective screen for the initial geometry of a window. In a
// multimonitor-setup, try to find the right screen by checking the transient
// parent or the mouse cursor for parentless windows (cf QTBUG-34204,
-// QDialog::adjustPosition()).
+// QDialog::adjustPosition()), unless a non-primary screen has been set,
+// in which case we try to respect that.
static inline const QScreen *effectiveScreen(const QWindow *window)
{
if (!window)
@@ -554,6 +570,8 @@ static inline const QScreen *effectiveScreen(const QWindow *window)
const QScreen *screen = window->screen();
if (!screen)
return QGuiApplication::primaryScreen();
+ if (screen != QGuiApplication::primaryScreen())
+ return screen;
#ifndef QT_NO_CURSOR
const QList<QScreen *> siblings = screen->virtualSiblings();
if (siblings.size() > 1) {
diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h
index dcee4d2d84..8af8791bb4 100644
--- a/src/gui/kernel/qplatformwindow.h
+++ b/src/gui/kernel/qplatformwindow.h
@@ -102,7 +102,9 @@ public:
virtual bool isExposed() const;
virtual bool isActive() const;
- virtual bool isEmbedded(const QPlatformWindow *parentWindow = 0) const;
+ virtual bool isAncestorOf(const QPlatformWindow *child) const;
+ virtual bool isEmbedded() const;
+ virtual bool isForeignWindow() const { return window()->type() == Qt::ForeignWindow; };
virtual QPoint mapToGlobal(const QPoint &pos) const;
virtual QPoint mapFromGlobal(const QPoint &pos) const;
diff --git a/src/gui/kernel/qrasterwindow.cpp b/src/gui/kernel/qrasterwindow.cpp
index d8d448249e..73871e0f39 100644
--- a/src/gui/kernel/qrasterwindow.cpp
+++ b/src/gui/kernel/qrasterwindow.cpp
@@ -105,6 +105,14 @@ QRasterWindow::QRasterWindow(QWindow *parent)
d_func()->backingstore.reset(new QBackingStore(this));
}
+QRasterWindow::~QRasterWindow()
+{
+ Q_D(QRasterWindow);
+ // Delete backingstore while window is still alive, as it
+ // might need to reference the window in the process
+ d->backingstore.reset(nullptr);
+}
+
/*!
\internal
*/
diff --git a/src/gui/kernel/qrasterwindow.h b/src/gui/kernel/qrasterwindow.h
index 76312bcda2..9b29183ad6 100644
--- a/src/gui/kernel/qrasterwindow.h
+++ b/src/gui/kernel/qrasterwindow.h
@@ -54,6 +54,7 @@ class Q_GUI_EXPORT QRasterWindow : public QPaintDeviceWindow
public:
explicit QRasterWindow(QWindow *parent = Q_NULLPTR);
+ ~QRasterWindow();
protected:
int metric(PaintDeviceMetric metric) const Q_DECL_OVERRIDE;
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index 1dd8fb5e67..96f75f37eb 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -161,6 +161,42 @@ QString QScreen::name() const
}
/*!
+ \property QScreen::manufacturer
+ \brief the manufacturer of the screen
+
+ \since 5.9
+*/
+QString QScreen::manufacturer() const
+{
+ Q_D(const QScreen);
+ return d->platformScreen->manufacturer();
+}
+
+/*!
+ \property QScreen::model
+ \brief the model of the screen
+
+ \since 5.9
+*/
+QString QScreen::model() const
+{
+ Q_D(const QScreen);
+ return d->platformScreen->model();
+}
+
+/*!
+ \property QScreen::serialNumber
+ \brief the serial number of the screen
+
+ \since 5.9
+*/
+QString QScreen::serialNumber() const
+{
+ Q_D(const QScreen);
+ return d->platformScreen->serialNumber();
+}
+
+/*!
\property QScreen::depth
\brief the color depth of the screen
*/
diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h
index 98e35aff43..8c9b16e08e 100644
--- a/src/gui/kernel/qscreen.h
+++ b/src/gui/kernel/qscreen.h
@@ -69,6 +69,9 @@ class Q_GUI_EXPORT QScreen : public QObject
Q_DECLARE_PRIVATE(QScreen)
Q_PROPERTY(QString name READ name CONSTANT)
+ Q_PROPERTY(QString manufacturer READ manufacturer CONSTANT)
+ Q_PROPERTY(QString model READ model CONSTANT)
+ Q_PROPERTY(QString serialNumber READ serialNumber CONSTANT)
Q_PROPERTY(int depth READ depth CONSTANT)
Q_PROPERTY(QSize size READ size NOTIFY geometryChanged)
Q_PROPERTY(QSize availableSize READ availableSize NOTIFY availableGeometryChanged)
@@ -97,6 +100,10 @@ public:
QString name() const;
+ QString manufacturer() const;
+ QString model() const;
+ QString serialNumber() const;
+
int depth() const;
QSize size() const;
diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp
index 7ccf1d86b0..85c0768e35 100644
--- a/src/gui/kernel/qstylehints.cpp
+++ b/src/gui/kernel/qstylehints.cpp
@@ -78,6 +78,7 @@ public:
, m_cursorFlashTime(-1)
, m_tabFocusBehavior(-1)
, m_uiEffects(-1)
+ , m_wheelScrollLines(-1)
{}
int m_mouseDoubleClickInterval;
@@ -88,6 +89,7 @@ public:
int m_cursorFlashTime;
int m_tabFocusBehavior;
int m_uiEffects;
+ int m_wheelScrollLines;
};
/*!
@@ -329,7 +331,9 @@ int QStyleHints::cursorFlashTime() const
/*!
\property QStyleHints::showIsFullScreen
- \brief \c true if the platform defaults to windows being fullscreen,
+ \brief whether the platform defaults to fullscreen windows.
+
+ This property is \c true if the platform defaults to windows being fullscreen,
otherwise \c false.
\note The platform may still choose to show certain windows non-fullscreen,
@@ -344,7 +348,9 @@ bool QStyleHints::showIsFullScreen() const
/*!
\property QStyleHints::showIsMaximized
- \brief \c true if the platform defaults to windows being maximized,
+ \brief whether the platform defaults to maximized windows.
+
+ This property is \c true if the platform defaults to windows being maximized,
otherwise \c false.
\note The platform may still choose to show certain windows non-maximized,
@@ -389,7 +395,9 @@ qreal QStyleHints::fontSmoothingGamma() const
/*!
\property QStyleHints::useRtlExtensions
- \brief \c true if right-to-left writing direction is enabled,
+ \brief the writing direction.
+
+ This property is \c true if right-to-left writing direction is enabled,
otherwise \c false.
*/
bool QStyleHints::useRtlExtensions() const
@@ -399,7 +407,9 @@ bool QStyleHints::useRtlExtensions() const
/*!
\property QStyleHints::setFocusOnTouchRelease
- \brief \c true if focus objects (line edits etc) should receive
+ \brief the event that should set input focus on focus objects.
+
+ This property is \c true if focus objects (line edits etc) should receive
input focus after a touch/mouse release. This is normal behavior on
touch platforms. On desktop platforms, the standard is to set
focus already on touch/mouse press.
@@ -443,7 +453,9 @@ void QStyleHints::setTabFocusBehavior(Qt::TabFocusBehavior tabFocusBehavior)
/*!
\property QStyleHints::singleClickActivation
- \brief \c true if items should be activated by single click, \b false
+ \brief whether items are activated by single or double click.
+
+ This property is \c true if items should be activated by single click, \c false
if they should be activated by double click instead.
\since 5.5
@@ -455,7 +467,9 @@ bool QStyleHints::singleClickActivation() const
/*!
\property QStyleHints::useHoverEffects
- \brief \c true if UI elements should use hover effects. This is the
+ \brief whether UI elements use hover effects.
+
+ This property is \c true if UI elements should use hover effects. This is the
standard behavior on desktop platforms with a mouse pointer, whereas
on touch platforms the overhead of hover event delivery can be avoided.
@@ -483,4 +497,33 @@ void QStyleHints::setUseHoverEffects(bool useHoverEffects)
emit useHoverEffectsChanged(useHoverEffects);
}
+/*!
+ \property QStyleHints::wheelScrollLines
+ \brief Number of lines to scroll by default for each wheel click.
+
+ \since 5.9
+*/
+int QStyleHints::wheelScrollLines() const
+{
+ Q_D(const QStyleHints);
+ if (d->m_wheelScrollLines > 0)
+ return d->m_wheelScrollLines;
+ return themeableHint(QPlatformTheme::WheelScrollLines, QPlatformIntegration::WheelScrollLines).toInt();
+}
+
+/*!
+ Sets the \a wheelScrollLines.
+ \internal
+ \sa wheelScrollLines()
+ \since 5.9
+*/
+void QStyleHints::setWheelScrollLines(int scrollLines)
+{
+ Q_D(QStyleHints);
+ if (d->m_wheelScrollLines == scrollLines)
+ return;
+ d->m_wheelScrollLines = scrollLines;
+ emit wheelScrollLinesChanged(scrollLines);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qstylehints.h b/src/gui/kernel/qstylehints.h
index fb55cc7ed6..b9bf428edd 100644
--- a/src/gui/kernel/qstylehints.h
+++ b/src/gui/kernel/qstylehints.h
@@ -71,6 +71,7 @@ class Q_GUI_EXPORT QStyleHints : public QObject
Q_PROPERTY(Qt::TabFocusBehavior tabFocusBehavior READ tabFocusBehavior NOTIFY tabFocusBehaviorChanged FINAL)
Q_PROPERTY(bool singleClickActivation READ singleClickActivation STORED false CONSTANT FINAL)
Q_PROPERTY(bool useHoverEffects READ useHoverEffects WRITE setUseHoverEffects NOTIFY useHoverEffectsChanged FINAL)
+ Q_PROPERTY(int wheelScrollLines READ wheelScrollLines NOTIFY wheelScrollLinesChanged FINAL)
public:
void setMouseDoubleClickInterval(int mouseDoubleClickInterval);
@@ -99,6 +100,8 @@ public:
bool singleClickActivation() const;
bool useHoverEffects() const;
void setUseHoverEffects(bool useHoverEffects);
+ int wheelScrollLines() const;
+ void setWheelScrollLines(int scrollLines);
Q_SIGNALS:
void cursorFlashTimeChanged(int cursorFlashTime);
@@ -109,6 +112,7 @@ Q_SIGNALS:
void startDragTimeChanged(int startDragTime);
void tabFocusBehaviorChanged(Qt::TabFocusBehavior tabFocusBehavior);
void useHoverEffectsChanged(bool useHoverEffects);
+ void wheelScrollLinesChanged(int scrollLines);
private:
friend class QGuiApplication;
diff --git a/src/gui/kernel/qsurface.cpp b/src/gui/kernel/qsurface.cpp
index afe4cf93e1..3cdd11de8c 100644
--- a/src/gui/kernel/qsurface.cpp
+++ b/src/gui/kernel/qsurface.cpp
@@ -76,6 +76,8 @@ QT_BEGIN_NAMESPACE
\value RasterGLSurface The surface can be rendered to using a software rasterizer,
and also supports OpenGL. This surface type is intended for internal Qt use, and
requires the use of private API.
+ \value OpenVGSurface The surface is an OpenVG compatible surface and can be used
+ in conjunction with OpenVG contexts.
*/
diff --git a/src/gui/kernel/qsurface.h b/src/gui/kernel/qsurface.h
index d9ccdc096d..a96b7a6422 100644
--- a/src/gui/kernel/qsurface.h
+++ b/src/gui/kernel/qsurface.h
@@ -64,7 +64,8 @@ public:
enum SurfaceType {
RasterSurface,
OpenGLSurface,
- RasterGLSurface
+ RasterGLSurface,
+ OpenVGSurface,
};
virtual ~QSurface();
diff --git a/src/gui/kernel/qtouchdevice.h b/src/gui/kernel/qtouchdevice.h
index 0fb24e47bf..c98aa69236 100644
--- a/src/gui/kernel/qtouchdevice.h
+++ b/src/gui/kernel/qtouchdevice.h
@@ -87,6 +87,7 @@ public:
private:
QTouchDevicePrivate *d;
+ friend class QTouchDevicePrivate;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QTouchDevice::Capabilities)
diff --git a/src/gui/kernel/qtouchdevice_p.h b/src/gui/kernel/qtouchdevice_p.h
index 203d9fca74..18d2af46a7 100644
--- a/src/gui/kernel/qtouchdevice_p.h
+++ b/src/gui/kernel/qtouchdevice_p.h
@@ -64,16 +64,21 @@ public:
: type(QTouchDevice::TouchScreen),
caps(QTouchDevice::Position),
maxTouchPoints(1)
- { }
+ {
+ static quint8 nextId = 2; // device 0 is not used, device 1 is for mouse device
+ id = nextId++;
+ }
QTouchDevice::DeviceType type;
QTouchDevice::Capabilities caps;
QString name;
int maxTouchPoints;
+ quint8 id;
static void registerDevice(const QTouchDevice *dev);
static void unregisterDevice(const QTouchDevice *dev);
static bool isRegistered(const QTouchDevice *dev);
+ static QTouchDevicePrivate *get(QTouchDevice *q) { return q->d; }
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 7ab2d31b86..c7afcce874 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -155,8 +155,17 @@ QWindow::QWindow(QScreen *targetScreen)
, QSurface(QSurface::Window)
{
Q_D(QWindow);
- d->connectToScreen(targetScreen ? targetScreen : QGuiApplication::primaryScreen());
- d->init();
+ d->init(targetScreen);
+}
+
+static QWindow *nonDesktopParent(QWindow *parent)
+{
+ if (parent && parent->type() == Qt::Desktop) {
+ qWarning("QWindows can not be reparented into desktop windows");
+ return nullptr;
+ }
+
+ return parent;
}
/*!
@@ -170,14 +179,8 @@ QWindow::QWindow(QScreen *targetScreen)
\sa setParent()
*/
QWindow::QWindow(QWindow *parent)
- : QObject(*new QWindowPrivate(), parent)
- , QSurface(QSurface::Window)
+ : QWindow(*new QWindowPrivate(), parent)
{
- Q_D(QWindow);
- d->parentWindow = parent;
- if (!parent)
- d->connectToScreen(QGuiApplication::primaryScreen());
- d->init();
}
/*!
@@ -193,13 +196,10 @@ QWindow::QWindow(QWindow *parent)
\sa setParent()
*/
QWindow::QWindow(QWindowPrivate &dd, QWindow *parent)
- : QObject(dd, parent)
+ : QObject(dd, nonDesktopParent(parent))
, QSurface(QSurface::Window)
{
Q_D(QWindow);
- d->parentWindow = parent;
- if (!parent)
- d->connectToScreen(QGuiApplication::primaryScreen());
d->init();
}
@@ -208,16 +208,22 @@ QWindow::QWindow(QWindowPrivate &dd, QWindow *parent)
*/
QWindow::~QWindow()
{
- destroy();
+ Q_D(QWindow);
+ d->destroy();
QGuiApplicationPrivate::window_list.removeAll(this);
if (!QGuiApplicationPrivate::is_app_closing)
QGuiApplicationPrivate::instance()->modalWindowList.removeOne(this);
}
-void QWindowPrivate::init()
+void QWindowPrivate::init(QScreen *targetScreen)
{
Q_Q(QWindow);
+ parentWindow = static_cast<QWindow *>(q->QObject::parent());
+
+ if (!parentWindow)
+ connectToScreen(targetScreen ? targetScreen : QGuiApplication::primaryScreen());
+
// If your application aborts here, you are probably creating a QWindow
// before the screen list is populated.
if (Q_UNLIKELY(!parentWindow && !topLevelScreen)) {
@@ -343,6 +349,30 @@ void QWindowPrivate::updateVisibility()
emit q->visibilityChanged(visibility);
}
+void QWindowPrivate::updateSiblingPosition(SiblingPosition position)
+{
+ Q_Q(QWindow);
+
+ if (!q->parent())
+ return;
+
+ QObjectList &siblings = q->parent()->d_ptr->children;
+
+ const int siblingCount = siblings.size() - 1;
+ if (siblingCount == 0)
+ return;
+
+ const int currentPosition = siblings.indexOf(q);
+ Q_ASSERT(currentPosition >= 0);
+
+ const int targetPosition = position == PositionTop ? siblingCount : 0;
+
+ if (currentPosition == targetPosition)
+ return;
+
+ siblings.move(currentPosition, targetPosition);
+}
+
inline bool QWindowPrivate::windowRecreationRequired(QScreen *newScreen) const
{
Q_Q(const QWindow);
@@ -394,7 +424,7 @@ void QWindowPrivate::setTopLevelScreen(QScreen *newScreen, bool recreate)
}
}
-void QWindowPrivate::create(bool recursive)
+void QWindowPrivate::create(bool recursive, WId nativeHandle)
{
Q_Q(QWindow);
if (platformWindow)
@@ -403,8 +433,10 @@ void QWindowPrivate::create(bool recursive)
if (q->parent())
q->parent()->create();
- platformWindow = QGuiApplicationPrivate::platformIntegration()->createPlatformWindow(q);
- Q_ASSERT(platformWindow || q->type() == Qt::ForeignWindow);
+ QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ platformWindow = nativeHandle ? platformIntegration->createForeignWindow(q, nativeHandle)
+ : platformIntegration->createPlatformWindow(q);
+ Q_ASSERT(platformWindow);
if (!platformWindow) {
qWarning() << "Failed to create platform window for" << q << "with flags" << q->flags();
@@ -507,7 +539,9 @@ void QWindow::setVisible(bool visible)
// can defer creation until the parent is created or we're re-parented.
if (parent() && !parent()->handle())
return;
- else
+
+ // We only need to create the window if it's being shown
+ if (visible)
create();
}
@@ -549,7 +583,8 @@ void QWindow::setVisible(bool visible)
d->applyCursor();
#endif
- d->platformWindow->setVisible(visible);
+ if (d->platformWindow)
+ d->platformWindow->setVisible(visible);
if (!visible) {
QHideEvent hideEvent;
@@ -596,15 +631,28 @@ WId QWindow::winId() const
{
Q_D(const QWindow);
- if (type() == Qt::ForeignWindow)
- return WId(property("_q_foreignWinId").value<WId>());
-
if(!d->platformWindow)
const_cast<QWindow *>(this)->create();
return d->platformWindow->winId();
}
+ /*!
+ Returns the parent window, if any.
+
+ If \a mode is IncludeTransients, then the transient parent is returned
+ if there is no parent.
+
+ A window without a parent is known as a top level window.
+
+ \since 5.9
+*/
+QWindow *QWindow::parent(AncestorMode mode) const
+{
+ Q_D(const QWindow);
+ return d->parentWindow ? d->parentWindow : (mode == IncludeTransients ? transientParent() : nullptr);
+}
+
/*!
Returns the parent window, if any.
@@ -627,6 +675,8 @@ QWindow *QWindow::parent() const
*/
void QWindow::setParent(QWindow *parent)
{
+ parent = nonDesktopParent(parent);
+
Q_D(QWindow);
if (d->parentWindow == parent)
return;
@@ -797,10 +847,15 @@ QSurfaceFormat QWindow::format() const
The actual window flags might differ from the flags set with setFlags()
if the requested flags could not be fulfilled.
+
+ \sa setFlag()
*/
void QWindow::setFlags(Qt::WindowFlags flags)
{
Q_D(QWindow);
+ if (d->windowFlags == flags)
+ return;
+
if (d->platformWindow)
d->platformWindow->setWindowFlags(flags);
d->windowFlags = flags;
@@ -809,7 +864,29 @@ void QWindow::setFlags(Qt::WindowFlags flags)
Qt::WindowFlags QWindow::flags() const
{
Q_D(const QWindow);
- return d->windowFlags;
+ Qt::WindowFlags flags = d->windowFlags;
+
+ if (d->platformWindow && d->platformWindow->isForeignWindow())
+ flags |= Qt::ForeignWindow;
+
+ return flags;
+}
+
+/*!
+ \since 5.9
+
+ Sets the window flag \a flag on this window if \a on is true;
+ otherwise clears the flag.
+
+ \sa setFlags(), flags(), type()
+*/
+void QWindow::setFlag(Qt::WindowType flag, bool on)
+{
+ Q_D(QWindow);
+ if (on)
+ setFlags(d->windowFlags | flag);
+ else
+ setFlags(d->windowFlags & ~flag);
}
/*!
@@ -920,6 +997,9 @@ QIcon QWindow::icon() const
void QWindow::raise()
{
Q_D(QWindow);
+
+ d->updateSiblingPosition(QWindowPrivate::PositionTop);
+
if (d->platformWindow)
d->platformWindow->raise();
}
@@ -932,6 +1012,9 @@ void QWindow::raise()
void QWindow::lower()
{
Q_D(QWindow);
+
+ d->updateSiblingPosition(QWindowPrivate::PositionBottom);
+
if (d->platformWindow)
d->platformWindow->lower();
}
@@ -1065,11 +1148,10 @@ bool QWindow::isActive() const
if (focus == this)
return true;
- if (!parent() && !transientParent()) {
+ if (QWindow *p = parent(IncludeTransients))
+ return p->isActive();
+ else
return isAncestorOf(focus);
- } else {
- return (parent() && parent()->isActive()) || (transientParent() && transientParent()->isActive());
- }
}
/*!
@@ -1197,6 +1279,10 @@ void QWindow::setTransientParent(QWindow *parent)
qWarning() << parent << "must be a top level window.";
return;
}
+ if (parent == this) {
+ qWarning() << "transient parent" << parent << "can not be same as window";
+ return;
+ }
d->transientParent = parent;
@@ -1233,8 +1319,15 @@ bool QWindow::isAncestorOf(const QWindow *child, AncestorMode mode) const
if (child->parent() == this || (mode == IncludeTransients && child->transientParent() == this))
return true;
- return (child->parent() && isAncestorOf(child->parent(), mode))
- || (mode == IncludeTransients && child->transientParent() && isAncestorOf(child->transientParent(), mode));
+ if (QWindow *parent = child->parent(mode)) {
+ if (isAncestorOf(parent, mode))
+ return true;
+ } else if (handle() && child->handle()) {
+ if (handle()->isAncestorOf(child->handle()))
+ return true;
+ }
+
+ return false;
}
/*!
@@ -1455,6 +1548,8 @@ void QWindow::setSizeIncrement(const QSize &size)
Sets the geometry of the window, excluding its window frame, to a
rectangle constructed from \a posx, \a posy, \a w and \a h.
+ The geometry is in relation to the virtualGeometry() of its screen.
+
\sa geometry()
*/
void QWindow::setGeometry(int posx, int posy, int w, int h)
@@ -1465,6 +1560,8 @@ void QWindow::setGeometry(int posx, int posy, int w, int h)
/*!
\brief Sets the geometry of the window, excluding its window frame, to \a rect.
+ The geometry is in relation to the virtualGeometry() of its screen.
+
\sa geometry()
*/
void QWindow::setGeometry(const QRect &rect)
@@ -1526,6 +1623,8 @@ QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry)
/*!
Returns the geometry of the window, excluding its window frame.
+ The geometry is in relation to the virtualGeometry() of its screen.
+
\sa frameMargins(), frameGeometry()
*/
QRect QWindow::geometry() const
@@ -1552,6 +1651,8 @@ QMargins QWindow::frameMargins() const
/*!
Returns the geometry of the window, including its window frame.
+ The geometry is in relation to the virtualGeometry() of its screen.
+
\sa geometry(), frameMargins()
*/
QRect QWindow::frameGeometry() const
@@ -1584,6 +1685,8 @@ QPoint QWindow::framePosition() const
/*!
Sets the upper left position of the window (\a point) including its window frame.
+ The position is in relation to the virtualGeometry() of its screen.
+
\sa setGeometry(), frameGeometry()
*/
void QWindow::setFramePosition(const QPoint &point)
@@ -1601,6 +1704,8 @@ void QWindow::setFramePosition(const QPoint &point)
/*!
\brief set the position of the window on the desktop to \a pt
+ The position is in relation to the virtualGeometry() of its screen.
+
\sa position()
*/
void QWindow::setPosition(const QPoint &pt)
@@ -1611,6 +1716,8 @@ void QWindow::setPosition(const QPoint &pt)
/*!
\brief set the position of the window on the desktop to \a posx, \a posy
+ The position is in relation to the virtualGeometry() of its screen.
+
\sa position()
*/
void QWindow::setPosition(int posx, int posy)
@@ -1674,42 +1781,63 @@ void QWindow::destroy()
if (!d->platformWindow)
return;
- QObjectList childrenWindows = children();
+ if (d->platformWindow->isForeignWindow())
+ return;
+
+ d->destroy();
+}
+
+void QWindowPrivate::destroy()
+{
+ if (!platformWindow)
+ return;
+
+ Q_Q(QWindow);
+ QObjectList childrenWindows = q->children();
for (int i = 0; i < childrenWindows.size(); i++) {
QObject *object = childrenWindows.at(i);
if (object->isWindowType()) {
QWindow *w = static_cast<QWindow*>(object);
- w->destroy();
+ qt_window_private(w)->destroy();
}
}
- if (QGuiApplicationPrivate::focus_window == this)
- QGuiApplicationPrivate::focus_window = parent();
- if (QGuiApplicationPrivate::currentMouseWindow == this)
- QGuiApplicationPrivate::currentMouseWindow = parent();
- if (QGuiApplicationPrivate::currentMousePressWindow == this)
- QGuiApplicationPrivate::currentMousePressWindow = parent();
+ if (QGuiApplicationPrivate::focus_window == q)
+ QGuiApplicationPrivate::focus_window = q->parent();
+ if (QGuiApplicationPrivate::currentMouseWindow == q)
+ QGuiApplicationPrivate::currentMouseWindow = q->parent();
+ if (QGuiApplicationPrivate::currentMousePressWindow == q)
+ QGuiApplicationPrivate::currentMousePressWindow = q->parent();
for (int i = 0; i < QGuiApplicationPrivate::tabletDevicePoints.size(); ++i)
- if (QGuiApplicationPrivate::tabletDevicePoints.at(i).target == this)
- QGuiApplicationPrivate::tabletDevicePoints[i].target = parent();
+ if (QGuiApplicationPrivate::tabletDevicePoints.at(i).target == q)
+ QGuiApplicationPrivate::tabletDevicePoints[i].target = q->parent();
- bool wasVisible = isVisible();
- d->visibilityOnDestroy = wasVisible && d->platformWindow;
+ bool wasVisible = q->isVisible();
+ visibilityOnDestroy = wasVisible && platformWindow;
- setVisible(false);
+ q->setVisible(false);
+
+ // Let subclasses act, typically by doing graphics resource cleaup, when
+ // the window, to which graphics resource may be tied, is going away.
+ //
+ // NB! This is disfunctional when destroy() is invoked from the dtor since
+ // a reimplemented event() will not get called in the subclasses at that
+ // stage. However, the typical QWindow cleanup involves either close() or
+ // going through QWindowContainer, both of which will do an explicit, early
+ // destroy(), which is good here.
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
- QGuiApplication::sendEvent(this, &e);
+ QGuiApplication::sendEvent(q, &e);
- delete d->platformWindow;
- d->resizeEventPending = true;
- d->receivedExpose = false;
- d->exposed = false;
- d->platformWindow = 0;
+ delete platformWindow;
+ resizeEventPending = true;
+ receivedExpose = false;
+ exposed = false;
+ platformWindow = 0;
if (wasVisible)
- d->maybeQuitOnLastWindowClosed();
+ maybeQuitOnLastWindowClosed();
}
/*!
@@ -1787,8 +1915,9 @@ QScreen *QWindow::screen() const
If the window has been created, it will be recreated on the \a newScreen.
- Note that if the screen is part of a virtual desktop of multiple screens,
- the window can appear on any of the screens returned by QScreen::virtualSiblings().
+ \note If the screen is part of a virtual desktop of multiple screens,
+ the window will not move automatically to \a newScreen. To place the
+ window relative to the screen, use the screen's topLeft() position.
This function only works for top level windows.
@@ -2351,7 +2480,7 @@ QPoint QWindow::mapToGlobal(const QPoint &pos) const
Q_D(const QWindow);
// QTBUG-43252, prefer platform implementation for foreign windows.
if (d->platformWindow
- && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded())) {
+ && (d->platformWindow->isForeignWindow() || d->platformWindow->isEmbedded())) {
return QHighDpi::fromNativeLocalPosition(d->platformWindow->mapToGlobal(QHighDpi::toNativeLocalPosition(pos, this)), this);
}
return pos + d->globalPosition();
@@ -2371,12 +2500,28 @@ QPoint QWindow::mapFromGlobal(const QPoint &pos) const
Q_D(const QWindow);
// QTBUG-43252, prefer platform implementation for foreign windows.
if (d->platformWindow
- && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded())) {
+ && (d->platformWindow->isForeignWindow() || d->platformWindow->isEmbedded())) {
return QHighDpi::fromNativeLocalPosition(d->platformWindow->mapFromGlobal(QHighDpi::toNativeLocalPosition(pos, this)), this);
}
return pos - d->globalPosition();
}
+QPoint QWindowPrivate::globalPosition() const
+{
+ Q_Q(const QWindow);
+ QPoint offset = q->position();
+ for (const QWindow *p = q->parent(); p; p = p->parent()) {
+ QPlatformWindow *pw = p->handle();
+ if (pw && pw->isForeignWindow()) {
+ // Use mapToGlobal() for foreign windows
+ offset += p->mapToGlobal(QPoint(0, 0));
+ break;
+ } else {
+ offset += p->position();
+ }
+ }
+ return offset;
+}
Q_GUI_EXPORT QWindowPrivate *qt_window_private(QWindow *window)
{
@@ -2416,10 +2561,7 @@ QWindow *QWindowPrivate::topLevelWindow() const
QWindow *window = const_cast<QWindow *>(q);
while (window) {
- QWindow *parent = window->parent();
- if (!parent)
- parent = window->transientParent();
-
+ QWindow *parent = window->parent(QWindow::IncludeTransients);
if (!parent)
break;
@@ -2459,13 +2601,13 @@ QWindow *QWindow::fromWinId(WId id)
}
QWindow *window = new QWindow;
- window->setFlags(Qt::ForeignWindow);
- window->setProperty("_q_foreignWinId", QVariant::fromValue(id));
- window->create();
+ qt_window_private(window)->create(false, id);
+
if (!window->handle()) {
delete window;
return nullptr;
}
+
return window;
}
diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h
index bf25cf64c9..2883749d2e 100644
--- a/src/gui/kernel/qwindow.h
+++ b/src/gui/kernel/qwindow.h
@@ -132,6 +132,12 @@ public:
};
Q_ENUM(Visibility)
+ enum AncestorMode {
+ ExcludeTransients,
+ IncludeTransients
+ };
+ Q_ENUM(AncestorMode)
+
explicit QWindow(QScreen *screen = Q_NULLPTR);
explicit QWindow(QWindow *parent);
virtual ~QWindow();
@@ -148,7 +154,8 @@ public:
WId winId() const;
- QWindow *parent() const;
+ QWindow *parent(AncestorMode mode) const;
+ QWindow *parent() const; // ### Qt6: Merge with above
void setParent(QWindow *parent);
bool isTopLevel() const;
@@ -163,6 +170,7 @@ public:
void setFlags(Qt::WindowFlags flags);
Qt::WindowFlags flags() const;
+ void setFlag(Qt::WindowType, bool on = true);
Qt::WindowType type() const;
QString title() const;
@@ -186,11 +194,6 @@ public:
void setTransientParent(QWindow *parent);
QWindow *transientParent() const;
- enum AncestorMode {
- ExcludeTransients,
- IncludeTransients
- };
-
bool isAncestorOf(const QWindow *child, AncestorMode mode = IncludeTransients) const;
bool isExposed() const;
diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h
index c1955be6b6..dd282a671d 100644
--- a/src/gui/kernel/qwindow_p.h
+++ b/src/gui/kernel/qwindow_p.h
@@ -113,7 +113,7 @@ public:
{
}
- void init();
+ void init(QScreen *targetScreen = nullptr);
void maybeQuitOnLastWindowClosed();
#ifndef QT_NO_CURSOR
@@ -123,19 +123,7 @@ public:
void deliverUpdateRequest();
- QPoint globalPosition() const {
- Q_Q(const QWindow);
- QPoint offset = q->position();
- for (const QWindow *p = q->parent(); p; p = p->parent()) {
- if (p->type() != Qt::ForeignWindow) {
- offset += p->position();
- } else { // QTBUG-43252, mapToGlobal() for foreign children.
- offset += p->mapToGlobal(QPoint(0, 0));
- break;
- }
- }
- return offset;
- }
+ QPoint globalPosition() const;
QWindow *topLevelWindow() const;
@@ -144,8 +132,12 @@ public:
void updateVisibility();
void _q_clearAlert();
+ enum SiblingPosition { PositionTop, PositionBottom };
+ void updateSiblingPosition(SiblingPosition);
+
bool windowRecreationRequired(QScreen *newScreen) const;
- void create(bool recursive);
+ void create(bool recursive, WId nativeHandle = 0);
+ void destroy();
void setTopLevelScreen(QScreen *newScreen, bool recreate);
void connectToScreen(QScreen *topLevelScreen);
void disconnectFromScreen();
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 8e86ce0b5c..7ad4f57198 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -59,41 +59,57 @@ QWaitCondition QWindowSystemInterfacePrivate::eventsFlushed;
QMutex QWindowSystemInterfacePrivate::flushEventMutex;
QAtomicInt QWindowSystemInterfacePrivate::eventAccepted;
QWindowSystemEventHandler *QWindowSystemInterfacePrivate::eventHandler;
-
-//------------------------------------------------------------
-//
-// Callback functions for plugins:
-//
-
QWindowSystemInterfacePrivate::WindowSystemEventList QWindowSystemInterfacePrivate::windowSystemEventQueue;
extern QPointer<QWindow> qt_last_mouse_receiver;
+
+// ------------------- QWindowSystemInterfacePrivate -------------------
+
/*!
Handles a window system event asynchronously by posting the event to Qt Gui.
- \sa postWindowSystemEvent()
+ This function posts the event on the window system event queue and wakes the
+ Gui event dispatcher. Qt Gui will then handle the event asynchonously at a
+ later point.
*/
template<>
bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterface::AsynchronousDelivery>(WindowSystemEvent *ev)
{
- QWindowSystemInterfacePrivate::postWindowSystemEvent(ev);
+ windowSystemEventQueue.append(ev);
+ if (QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher())
+ dispatcher->wakeUp();
return true;
}
/*!
Handles a window system event synchronously.
+ Qt Gui will process the event immediately. The return value indicates if Qt
+ accepted the event.
+
If the event is delivered from another thread than the Qt main thread the
window system event queue is flushed, which may deliver other events as
well.
-
- \sa processWindowSystemEvent()
*/
template<>
bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterface::SynchronousDelivery>(WindowSystemEvent *ev)
{
- return QWindowSystemInterfacePrivate::processWindowSystemEvent(ev);
+ bool accepted = true;
+ if (QThread::currentThread() == QGuiApplication::instance()->thread()) {
+ // Process the event immediately on the current thread and return the accepted state.
+ QGuiApplicationPrivate::processWindowSystemEvent(ev);
+ accepted = ev->eventAccepted;
+ delete ev;
+ } else {
+ // Post the event on the Qt main thread queue and flush the queue.
+ // This will wake up the Gui thread which will process the event.
+ // Return the accepted state for the last event on the queue,
+ // which is the event posted by this function.
+ handleWindowSystemEvent<QWindowSystemInterface::AsynchronousDelivery>(ev);
+ accepted = QWindowSystemInterface::flushWindowSystemEvents();
+ }
+ return accepted;
}
/*!
@@ -109,7 +125,7 @@ bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterfa
than the Qt main thread the window system event queue is flushed, which may deliver
other events as well.
- \sa flushWindowSystemEvents(), processWindowSystemEvent(), setSynchronousWindowSystemEvents()
+ \sa flushWindowSystemEvents(), setSynchronousWindowSystemEvents()
*/
template<>
bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterface::DefaultDelivery>(QWindowSystemInterfacePrivate::WindowSystemEvent *ev)
@@ -120,6 +136,59 @@ bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterfa
return handleWindowSystemEvent<QWindowSystemInterface::AsynchronousDelivery>(ev);
}
+int QWindowSystemInterfacePrivate::windowSystemEventsQueued()
+{
+ return windowSystemEventQueue.count();
+}
+
+QWindowSystemInterfacePrivate::WindowSystemEvent * QWindowSystemInterfacePrivate::getWindowSystemEvent()
+{
+ return windowSystemEventQueue.takeFirstOrReturnNull();
+}
+
+QWindowSystemInterfacePrivate::WindowSystemEvent *QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent()
+{
+ return windowSystemEventQueue.takeFirstNonUserInputOrReturnNull();
+}
+
+QWindowSystemInterfacePrivate::WindowSystemEvent *QWindowSystemInterfacePrivate::peekWindowSystemEvent(EventType t)
+{
+ return windowSystemEventQueue.peekAtFirstOfType(t);
+}
+
+void QWindowSystemInterfacePrivate::removeWindowSystemEvent(WindowSystemEvent *event)
+{
+ windowSystemEventQueue.remove(event);
+}
+
+void QWindowSystemInterfacePrivate::installWindowSystemEventHandler(QWindowSystemEventHandler *handler)
+{
+ if (!eventHandler)
+ eventHandler = handler;
+}
+
+void QWindowSystemInterfacePrivate::removeWindowSystemEventhandler(QWindowSystemEventHandler *handler)
+{
+ if (eventHandler == handler)
+ eventHandler = 0;
+}
+
+QWindowSystemEventHandler::~QWindowSystemEventHandler()
+{
+ QWindowSystemInterfacePrivate::removeWindowSystemEventhandler(this);
+}
+
+bool QWindowSystemEventHandler::sendEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
+{
+ QGuiApplicationPrivate::processWindowSystemEvent(e);
+ return true;
+}
+
+//------------------------------------------------------------
+//
+// Callback functions for plugins:
+//
+
#define QT_DEFINE_QPA_EVENT_HANDLER(ReturnType, HandlerName, ...) \
template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName<QWindowSystemInterface::DefaultDelivery>(__VA_ARGS__); \
template Q_GUI_EXPORT ReturnType QWindowSystemInterface::HandlerName<QWindowSystemInterface::SynchronousDelivery>(__VA_ARGS__); \
@@ -138,17 +207,17 @@ bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterfa
until sendWindowSystemEvents() is called by the event dispatcher.
*/
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleEnterEvent, QWindow *tlw, const QPointF &local, const QPointF &global)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleEnterEvent, QWindow *window, const QPointF &local, const QPointF &global)
{
- if (tlw) {
- QWindowSystemInterfacePrivate::EnterEvent *e = new QWindowSystemInterfacePrivate::EnterEvent(tlw, local, global);
+ if (window) {
+ QWindowSystemInterfacePrivate::EnterEvent *e = new QWindowSystemInterfacePrivate::EnterEvent(window, local, global);
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleLeaveEvent, QWindow *tlw)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleLeaveEvent, QWindow *window)
{
- QWindowSystemInterfacePrivate::LeaveEvent *e = new QWindowSystemInterfacePrivate::LeaveEvent(tlw);
+ QWindowSystemInterfacePrivate::LeaveEvent *e = new QWindowSystemInterfacePrivate::LeaveEvent(window);
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
@@ -165,24 +234,28 @@ void QWindowSystemInterface::handleEnterLeaveEvent(QWindow *enter, QWindow *leav
handleEnterEvent(enter, local, global);
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowActivated, QWindow *tlw, Qt::FocusReason r)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowActivated, QWindow *window, Qt::FocusReason r)
{
QWindowSystemInterfacePrivate::ActivatedWindowEvent *e =
- new QWindowSystemInterfacePrivate::ActivatedWindowEvent(tlw, r);
+ new QWindowSystemInterfacePrivate::ActivatedWindowEvent(window, r);
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-void QWindowSystemInterface::handleWindowStateChanged(QWindow *tlw, Qt::WindowState newState)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowStateChanged, QWindow *window, Qt::WindowState newState, int oldState)
{
+ Q_ASSERT(window);
+ if (oldState < Qt::WindowNoState)
+ oldState = window->windowState();
+
QWindowSystemInterfacePrivate::WindowStateChangedEvent *e =
- new QWindowSystemInterfacePrivate::WindowStateChangedEvent(tlw, newState);
- QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
+ new QWindowSystemInterfacePrivate::WindowStateChangedEvent(window, newState, Qt::WindowState(oldState));
+ QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-void QWindowSystemInterface::handleWindowScreenChanged(QWindow *tlw, QScreen *screen)
+void QWindowSystemInterface::handleWindowScreenChanged(QWindow *window, QScreen *screen)
{
QWindowSystemInterfacePrivate::WindowScreenChangedEvent *e =
- new QWindowSystemInterfacePrivate::WindowScreenChangedEvent(tlw, screen);
+ new QWindowSystemInterfacePrivate::WindowScreenChangedEvent(window, screen);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
@@ -197,9 +270,9 @@ void QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState
/*!
If \a oldRect is null, Qt will use the previously reported geometry instead.
*/
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *tlw, const QRect &newRect, const QRect &oldRect)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect, const QRect &oldRect)
{
- QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw, QHighDpi::fromNativePixels(newRect, tlw), QHighDpi::fromNativePixels(oldRect, tlw));
+ QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, QHighDpi::fromNativePixels(newRect, window), QHighDpi::fromNativePixels(oldRect, window));
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
@@ -211,18 +284,18 @@ QWindowSystemInterfacePrivate::ExposeEvent::ExposeEvent(QWindow *window, const Q
{
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleExposeEvent, QWindow *tlw, const QRegion &region)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleExposeEvent, QWindow *window, const QRegion &region)
{
QWindowSystemInterfacePrivate::ExposeEvent *e =
- new QWindowSystemInterfacePrivate::ExposeEvent(tlw, QHighDpi::fromNativeLocalExposedRegion(region, tlw));
+ new QWindowSystemInterfacePrivate::ExposeEvent(window, QHighDpi::fromNativeLocalExposedRegion(region, window));
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-void QWindowSystemInterface::handleCloseEvent(QWindow *tlw, bool *accepted)
+void QWindowSystemInterface::handleCloseEvent(QWindow *window, bool *accepted)
{
- if (tlw) {
+ if (window) {
QWindowSystemInterfacePrivate::CloseEvent *e =
- new QWindowSystemInterfacePrivate::CloseEvent(tlw, accepted);
+ new QWindowSystemInterfacePrivate::CloseEvent(window, accepted);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
}
@@ -232,35 +305,35 @@ void QWindowSystemInterface::handleCloseEvent(QWindow *tlw, bool *accepted)
\a w == 0 means that the event is in global coords only, \a local will be ignored in this case
*/
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b,
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b,
Qt::KeyboardModifiers mods, Qt::MouseEventSource source)
{
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- handleMouseEvent<Delivery>(w, time, local, global, b, mods, source);
+ handleMouseEvent<Delivery>(window, time, local, global, b, mods, source);
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b,
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b,
Qt::KeyboardModifiers mods, Qt::MouseEventSource source)
{
QWindowSystemInterfacePrivate::MouseEvent * e =
- new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source);
+ new QWindowSystemInterfacePrivate::MouseEvent(window, timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativePixels(global, window), b, mods, source);
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b,
+void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b,
Qt::KeyboardModifiers mods, Qt::MouseEventSource source)
{
const unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- handleFrameStrutMouseEvent(w, time, local, global, b, mods, source);
+ handleFrameStrutMouseEvent(window, time, local, global, b, mods, source);
}
-void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b,
+void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b,
Qt::KeyboardModifiers mods, Qt::MouseEventSource source)
{
QWindowSystemInterfacePrivate::MouseEvent * e =
- new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp,
+ new QWindowSystemInterfacePrivate::MouseEvent(window, timestamp,
QWindowSystemInterfacePrivate::FrameStrutMouse,
- QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source);
+ QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativePixels(global, window), b, mods, source);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
@@ -309,35 +382,35 @@ bool QWindowSystemInterface::handleShortcutEvent(QWindow *window, ulong timestam
#endif
}
-QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) {
+QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *window, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) {
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- return handleKeyEvent<Delivery>(w, time, t, k, mods, text, autorep, count);
+ return handleKeyEvent<Delivery>(window, time, t, k, mods, text, autorep, count);
}
-QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *tlw, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count)
+QT_DEFINE_QPA_EVENT_HANDLER(bool, handleKeyEvent, QWindow *window, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count)
{
#if defined(Q_OS_OSX)
- if (t == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(tlw, timestamp, k, mods, 0, 0, 0, text, autorep, count))
+ if (t == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(window, timestamp, k, mods, 0, 0, 0, text, autorep, count))
return true;
#endif
QWindowSystemInterfacePrivate::KeyEvent * e =
- new QWindowSystemInterfacePrivate::KeyEvent(tlw, timestamp, t, k, mods, text, autorep, count);
+ new QWindowSystemInterfacePrivate::KeyEvent(window, timestamp, t, k, mods, text, autorep, count);
return QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
+bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *window, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
quint32 nativeScanCode, quint32 nativeVirtualKey,
quint32 nativeModifiers,
const QString& text, bool autorep,
ushort count, bool tryShortcutOverride)
{
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- return handleExtendedKeyEvent(w, time, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
+ return handleExtendedKeyEvent(window, time, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
text, autorep, count, tryShortcutOverride);
}
-bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *tlw, ulong timestamp, QEvent::Type type, int key,
+bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key,
Qt::KeyboardModifiers modifiers,
quint32 nativeScanCode, quint32 nativeVirtualKey,
quint32 nativeModifiers,
@@ -345,7 +418,7 @@ bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *tlw, ulong timestam
ushort count, bool tryShortcutOverride)
{
#if defined(Q_OS_OSX)
- if (tryShortcutOverride && type == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(tlw,
+ if (tryShortcutOverride && type == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(window,
timestamp, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count)) {
return true;
}
@@ -354,29 +427,36 @@ bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *tlw, ulong timestam
#endif
QWindowSystemInterfacePrivate::KeyEvent * e =
- new QWindowSystemInterfacePrivate::KeyEvent(tlw, timestamp, type, key, modifiers,
+ new QWindowSystemInterfacePrivate::KeyEvent(window, timestamp, type, key, modifiers,
nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
-void QWindowSystemInterface::handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods) {
+QWindowSystemInterfacePrivate::WheelEvent::WheelEvent(QWindow *window, ulong time, const QPointF &local, const QPointF &global, QPoint pixelD,
+ QPoint angleD, int qt4D, Qt::Orientation qt4O, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase, Qt::MouseEventSource src, bool inverted)
+ : InputEvent(window, time, Wheel, mods), pixelDelta(pixelD), angleDelta(angleD), qt4Delta(qt4D),
+ qt4Orientation(qt4O), localPos(local), globalPos(global), phase(phase), source(src), inverted(inverted)
+{
+}
+
+void QWindowSystemInterface::handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods) {
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- handleWheelEvent(w, time, local, global, d, o, mods);
+ handleWheelEvent(window, time, local, global, d, o, mods);
}
-void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods)
+void QWindowSystemInterface::handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods)
{
QPoint point = (o == Qt::Vertical) ? QPoint(0, d) : QPoint(d, 0);
- handleWheelEvent(tlw, timestamp, local, global, QPoint(), point, mods);
+ handleWheelEvent(window, timestamp, local, global, QPoint(), point, mods);
}
-void QWindowSystemInterface::handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase, Qt::MouseEventSource source)
+void QWindowSystemInterface::handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase, Qt::MouseEventSource source)
{
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- handleWheelEvent(w, time, local, global, pixelDelta, angleDelta, mods, phase, source);
+ handleWheelEvent(window, time, local, global, pixelDelta, angleDelta, mods, phase, source);
}
-void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, const QPointF & local, const QPointF & global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase,
+void QWindowSystemInterface::handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase,
Qt::MouseEventSource source, bool invertedScrolling)
{
// Qt 4 sends two separate wheel events for horizontal and vertical
@@ -395,7 +475,7 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con
// Simple case: vertical deltas only:
if (angleDelta.y() != 0 && angleDelta.x() == 0) {
- e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical,
+ e = new QWindowSystemInterfacePrivate::WheelEvent(window, timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativePixels(global, window), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical,
mods, phase, source, invertedScrolling);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
return;
@@ -403,7 +483,7 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con
// Simple case: horizontal deltas only:
if (angleDelta.y() == 0 && angleDelta.x() != 0) {
- e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling);
+ e = new QWindowSystemInterfacePrivate::WheelEvent(window, timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativePixels(global, window), pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
return;
}
@@ -411,106 +491,65 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con
// Both horizontal and vertical deltas: Send two wheel events.
// The first event contains the Qt 5 pixel and angle delta as points,
// and in addition the Qt 4 compatibility vertical angle delta.
- e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source, invertedScrolling);
+ e = new QWindowSystemInterfacePrivate::WheelEvent(window, timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativePixels(global, window), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source, invertedScrolling);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
// The second event contains null pixel and angle points and the
// Qt 4 compatibility horizontal angle delta.
- e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling);
+ e = new QWindowSystemInterfacePrivate::WheelEvent(window, timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativePixels(global, window), QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source, invertedScrolling);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
-int QWindowSystemInterfacePrivate::windowSystemEventsQueued()
+void QWindowSystemInterface::registerTouchDevice(const QTouchDevice *device)
{
- return windowSystemEventQueue.count();
+ QTouchDevicePrivate::registerDevice(device);
}
-QWindowSystemInterfacePrivate::WindowSystemEvent * QWindowSystemInterfacePrivate::getWindowSystemEvent()
+void QWindowSystemInterface::unregisterTouchDevice(const QTouchDevice *device)
{
- return windowSystemEventQueue.takeFirstOrReturnNull();
+ QTouchDevicePrivate::unregisterDevice(device);
}
-QWindowSystemInterfacePrivate::WindowSystemEvent *QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent()
+bool QWindowSystemInterface::isTouchDeviceRegistered(const QTouchDevice *device)
{
- return windowSystemEventQueue.takeFirstNonUserInputOrReturnNull();
+ return QTouchDevicePrivate::isRegistered(device);
}
-QWindowSystemInterfacePrivate::WindowSystemEvent *QWindowSystemInterfacePrivate::peekWindowSystemEvent(EventType t)
-{
- return windowSystemEventQueue.peekAtFirstOfType(t);
-}
+static int g_nextPointId = 1;
-void QWindowSystemInterfacePrivate::removeWindowSystemEvent(WindowSystemEvent *event)
-{
- windowSystemEventQueue.remove(event);
-}
+// map from device-independent point id (arbitrary) to "Qt point" ids
+typedef QMap<quint64, int> PointIdMap;
+Q_GLOBAL_STATIC(PointIdMap, g_pointIdMap)
/*!
- Posts a window system event to be handled asynchronously by Qt Gui.
-
- This function posts the event on the window system event queue and wakes the
- Gui event dispatcher. Qt Gui will then handle the event asynchonously at a
- later point.
-
- \sa flushWindowSystemEvents(), processWindowSystemEvent(), handleWindowSystemEvent()
-*/
-void QWindowSystemInterfacePrivate::postWindowSystemEvent(WindowSystemEvent *ev)
-{
- windowSystemEventQueue.append(ev);
- QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher();
- if (dispatcher)
- dispatcher->wakeUp();
-}
-
-/*!
- Processes a window system event synchronously.
-
- Qt Gui will process the event immediately. The return value indicates if Qt
- accepted the event.
-
- If the event is delivered from another thread than the Qt main thread the
- window system event queue is flushed, which may deliver other events as
- well.
-
- \sa flushWindowSystemEvents(), postWindowSystemEvent(), handleWindowSystemEvent()
+ \internal
+ This function maps potentially arbitrary point ids \a pointId in the 32 bit
+ value space to start from 1 and increase incrementally for each touch point
+ held down. If all touch points are released it will reset the id back to 1
+ for the following touch point.
+
+ We can then assume that the touch points ids will never become too large,
+ and it will then put the device identifier \a deviceId in the upper 8 bits.
+ This leaves us with max 255 devices, and 16.7M taps without full release
+ before we run out of value space.
*/
-bool QWindowSystemInterfacePrivate::processWindowSystemEvent(WindowSystemEvent *ev)
-{
- bool accepted = true;
- if (QThread::currentThread() == QGuiApplication::instance()->thread()) {
- // Process the event immediately on the current thread and return the accepted state.
- QGuiApplicationPrivate::processWindowSystemEvent(ev);
- accepted = ev->eventAccepted;
- delete ev;
+static int acquireCombinedPointId(quint8 deviceId, int pointId)
+{
+ quint64 combinedId64 = (quint64(deviceId) << 32) + pointId;
+ auto it = g_pointIdMap->constFind(combinedId64);
+ int uid;
+ if (it == g_pointIdMap->constEnd()) {
+ uid = g_nextPointId++;
+ g_pointIdMap->insert(combinedId64, uid);
} else {
- // Post the event on the Qt main thread queue and flush the queue.
- // This will wake up the Gui thread which will process the event.
- // Return the accepted state for the last event on the queue,
- // which is the event posted by this function.
- postWindowSystemEvent(ev);
- accepted = QWindowSystemInterface::flushWindowSystemEvents();
+ uid = *it;
}
- return accepted;
-}
-
-void QWindowSystemInterface::registerTouchDevice(const QTouchDevice *device)
-{
- QTouchDevicePrivate::registerDevice(device);
-}
-
-void QWindowSystemInterface::unregisterTouchDevice(const QTouchDevice *device)
-{
- QTouchDevicePrivate::unregisterDevice(device);
-}
-
-bool QWindowSystemInterface::isTouchDeviceRegistered(const QTouchDevice *device)
-{
- return QTouchDevicePrivate::isRegistered(device);
+ return (deviceId << 24) + uid;
}
QList<QTouchEvent::TouchPoint>
QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points,
- const QWindow *window,
+ const QWindow *window, quint8 deviceId,
QEvent::Type *type)
{
QList<QTouchEvent::TouchPoint> touchPoints;
@@ -521,7 +560,7 @@ QList<QTouchEvent::TouchPoint>
QList<QWindowSystemInterface::TouchPoint>::const_iterator point = points.constBegin();
QList<QWindowSystemInterface::TouchPoint>::const_iterator end = points.constEnd();
while (point != end) {
- p.setId(point->id);
+ p.setId(acquireCombinedPointId(deviceId, point->id));
if (point->uniqueId >= 0)
p.setUniqueId(point->uniqueId);
p.setPressure(point->pressure);
@@ -554,6 +593,11 @@ QList<QTouchEvent::TouchPoint>
*type = QEvent::TouchEnd;
}
+ if (states == Qt::TouchPointReleased) {
+ g_nextPointId = 1;
+ g_pointIdMap->clear();
+ }
+
return touchPoints;
}
@@ -578,14 +622,14 @@ QList<QWindowSystemInterface::TouchPoint>
return newList;
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchEvent, QWindow *w, QTouchDevice *device,
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchEvent, QWindow *window, QTouchDevice *device,
const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
{
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- handleTouchEvent<Delivery>(w, time, device, points, mods);
+ handleTouchEvent<Delivery>(window, time, device, points, mods);
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchEvent, QWindow *tlw, ulong timestamp, QTouchDevice *device,
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchEvent, QWindow *window, ulong timestamp, QTouchDevice *device,
const QList<TouchPoint> &points, Qt::KeyboardModifiers mods)
{
if (!points.size()) // Touch events must have at least one point
@@ -595,25 +639,26 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchEvent, QWindow *tlw, ulong timestam
return;
QEvent::Type type;
- QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, tlw, &type);
+ QList<QTouchEvent::TouchPoint> touchPoints =
+ QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, QTouchDevicePrivate::get(device)->id, &type);
QWindowSystemInterfacePrivate::TouchEvent *e =
- new QWindowSystemInterfacePrivate::TouchEvent(tlw, timestamp, type, device, touchPoints, mods);
+ new QWindowSystemInterfacePrivate::TouchEvent(window, timestamp, type, device, touchPoints, mods);
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchCancelEvent, QWindow *w, QTouchDevice *device,
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchCancelEvent, QWindow *window, QTouchDevice *device,
Qt::KeyboardModifiers mods)
{
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- handleTouchCancelEvent<Delivery>(w, time, device, mods);
+ handleTouchCancelEvent<Delivery>(window, time, device, mods);
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchCancelEvent, QWindow *w, ulong timestamp, QTouchDevice *device,
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleTouchCancelEvent, QWindow *window, ulong timestamp, QTouchDevice *device,
Qt::KeyboardModifiers mods)
{
QWindowSystemInterfacePrivate::TouchEvent *e =
- new QWindowSystemInterfacePrivate::TouchEvent(w, timestamp, QEvent::TouchCancel, device,
+ new QWindowSystemInterfacePrivate::TouchEvent(window, timestamp, QEvent::TouchCancel, device,
QList<QTouchEvent::TouchPoint>(), mods);
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
@@ -646,113 +691,21 @@ void QWindowSystemInterface::handleScreenRefreshRateChange(QScreen *screen, qrea
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
-void QWindowSystemInterface::handleThemeChange(QWindow *tlw)
+void QWindowSystemInterface::handleThemeChange(QWindow *window)
{
- QWindowSystemInterfacePrivate::ThemeChangeEvent *e = new QWindowSystemInterfacePrivate::ThemeChangeEvent(tlw);
+ QWindowSystemInterfacePrivate::ThemeChangeEvent *e = new QWindowSystemInterfacePrivate::ThemeChangeEvent(window);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
-void QWindowSystemInterface::deferredFlushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
-{
- Q_ASSERT(QThread::currentThread() == QGuiApplication::instance()->thread());
-
- QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
- sendWindowSystemEvents(flags);
- QWindowSystemInterfacePrivate::eventsFlushed.wakeOne();
-}
-
-/*!
- Make Qt Gui process all events on the event queue immediately. Return the
- accepted state for the last event on the queue.
-*/
-bool QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
-{
- const int count = QWindowSystemInterfacePrivate::windowSystemEventQueue.count();
- if (!count)
- return false;
- if (!QGuiApplication::instance()) {
- qWarning().nospace()
- << "QWindowSystemInterface::flushWindowSystemEvents() invoked after "
- "QGuiApplication destruction, discarding " << count << " events.";
- QWindowSystemInterfacePrivate::windowSystemEventQueue.clear();
- return false;
- }
- if (QThread::currentThread() != QGuiApplication::instance()->thread()) {
- // Post a FlushEvents event which will trigger a call back to
- // deferredFlushWindowSystemEvents from the Gui thread.
- QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
- QWindowSystemInterfacePrivate::FlushEventsEvent *e = new QWindowSystemInterfacePrivate::FlushEventsEvent(flags);
- QWindowSystemInterfacePrivate::handleWindowSystemEvent<AsynchronousDelivery>(e);
- QWindowSystemInterfacePrivate::eventsFlushed.wait(&QWindowSystemInterfacePrivate::flushEventMutex);
- } else {
- sendWindowSystemEvents(flags);
- }
- return QWindowSystemInterfacePrivate::eventAccepted.load() > 0;
-}
-
-bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
-{
- int nevents = 0;
-
- while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
- QWindowSystemInterfacePrivate::WindowSystemEvent *event =
- (flags & QEventLoop::ExcludeUserInputEvents) ?
- QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
- QWindowSystemInterfacePrivate::getWindowSystemEvent();
- if (!event)
- break;
-
- if (QWindowSystemInterfacePrivate::eventHandler) {
- if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event))
- nevents++;
- } else {
- nevents++;
- QGuiApplicationPrivate::processWindowSystemEvent(event);
- }
-
- // Record the accepted state for the processed event
- // (excluding flush events). This state can then be
- // returned by flushWindowSystemEvents().
- if (event->type != QWindowSystemInterfacePrivate::FlushEvents)
- QWindowSystemInterfacePrivate::eventAccepted.store(event->eventAccepted);
-
- delete event;
- }
-
- return (nevents > 0);
-}
-
-void QWindowSystemInterfacePrivate::installWindowSystemEventHandler(QWindowSystemEventHandler *handler)
-{
- if (!eventHandler)
- eventHandler = handler;
-}
-
-void QWindowSystemInterfacePrivate::removeWindowSystemEventhandler(QWindowSystemEventHandler *handler)
-{
- if (eventHandler == handler)
- eventHandler = 0;
-}
-
-void QWindowSystemInterface::setSynchronousWindowSystemEvents(bool enable)
-{
- QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = enable;
-}
-
-int QWindowSystemInterface::windowSystemEventsQueued()
-{
- return QWindowSystemInterfacePrivate::windowSystemEventsQueued();
-}
-
#ifndef QT_NO_DRAGANDDROP
-QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
+QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *window, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
{
- return QGuiApplicationPrivate::processDrag(w, dropData, QHighDpi::fromNativeLocalPosition(p, w) ,supportedActions);
+ return QGuiApplicationPrivate::processDrag(window, dropData, QHighDpi::fromNativeLocalPosition(p, window) ,supportedActions);
}
-QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
+QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *window, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
{
- return QGuiApplicationPrivate::processDrop(w, dropData, QHighDpi::fromNativeLocalPosition(p, w),supportedActions);
+ return QGuiApplicationPrivate::processDrop(window, dropData, QHighDpi::fromNativeLocalPosition(p, window),supportedActions);
}
#endif // QT_NO_DRAGANDDROP
@@ -780,45 +733,50 @@ void QWindowSystemInterface::handleFileOpenEvent(const QUrl &url)
QGuiApplicationPrivate::processWindowSystemEvent(&e);
}
-void QWindowSystemInterface::handleTabletEvent(QWindow *w, ulong timestamp, const QPointF &local, const QPointF &global,
+void QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(bool v)
+{
+ platformSynthesizesMouse = v;
+}
+
+void QWindowSystemInterface::handleTabletEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global,
int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers)
{
QWindowSystemInterfacePrivate::TabletEvent *e =
- new QWindowSystemInterfacePrivate::TabletEvent(w,timestamp,
- QHighDpi::fromNativeLocalPosition(local, w),
- QHighDpi::fromNativePixels(global, w),
+ new QWindowSystemInterfacePrivate::TabletEvent(window, timestamp,
+ QHighDpi::fromNativeLocalPosition(local, window),
+ QHighDpi::fromNativePixels(global, window),
device, pointerType, buttons, pressure,
xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
-void QWindowSystemInterface::handleTabletEvent(QWindow *w, const QPointF &local, const QPointF &global,
+void QWindowSystemInterface::handleTabletEvent(QWindow *window, const QPointF &local, const QPointF &global,
int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers)
{
ulong time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- handleTabletEvent(w, time, local, global, device, pointerType, buttons, pressure,
+ handleTabletEvent(window, time, local, global, device, pointerType, buttons, pressure,
xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
}
-void QWindowSystemInterface::handleTabletEvent(QWindow *w, ulong timestamp, bool down, const QPointF &local, const QPointF &global,
+void QWindowSystemInterface::handleTabletEvent(QWindow *window, ulong timestamp, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers)
{
- handleTabletEvent(w, timestamp, local, global, device, pointerType, (down ? Qt::LeftButton : Qt::NoButton), pressure,
+ handleTabletEvent(window, timestamp, local, global, device, pointerType, (down ? Qt::LeftButton : Qt::NoButton), pressure,
xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
}
-void QWindowSystemInterface::handleTabletEvent(QWindow *w, bool down, const QPointF &local, const QPointF &global,
+void QWindowSystemInterface::handleTabletEvent(QWindow *window, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers)
{
- handleTabletEvent(w, local, global, device, pointerType, (down ? Qt::LeftButton : Qt::NoButton), pressure,
+ handleTabletEvent(window, local, global, device, pointerType, (down ? Qt::LeftButton : Qt::NoButton), pressure,
xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
}
@@ -885,12 +843,12 @@ void QWindowSystemInterface::handlePlatformPanelEvent(QWindow *w)
}
#ifndef QT_NO_CONTEXTMENU
-void QWindowSystemInterface::handleContextMenuEvent(QWindow *w, bool mouseTriggered,
+void QWindowSystemInterface::handleContextMenuEvent(QWindow *window, bool mouseTriggered,
const QPoint &pos, const QPoint &globalPos,
Qt::KeyboardModifiers modifiers)
{
QWindowSystemInterfacePrivate::ContextMenuEvent *e =
- new QWindowSystemInterfacePrivate::ContextMenuEvent(w, mouseTriggered, pos,
+ new QWindowSystemInterfacePrivate::ContextMenuEvent(window, mouseTriggered, pos,
globalPos, modifiers);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
@@ -915,13 +873,97 @@ Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPo
}
#endif
+// ------------------ Event dispatcher functionality ------------------
+
+/*!
+ Make Qt Gui process all events on the event queue immediately. Return the
+ accepted state for the last event on the queue.
+*/
+bool QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ const int count = QWindowSystemInterfacePrivate::windowSystemEventQueue.count();
+ if (!count)
+ return false;
+ if (!QGuiApplication::instance()) {
+ qWarning().nospace()
+ << "QWindowSystemInterface::flushWindowSystemEvents() invoked after "
+ "QGuiApplication destruction, discarding " << count << " events.";
+ QWindowSystemInterfacePrivate::windowSystemEventQueue.clear();
+ return false;
+ }
+ if (QThread::currentThread() != QGuiApplication::instance()->thread()) {
+ // Post a FlushEvents event which will trigger a call back to
+ // deferredFlushWindowSystemEvents from the Gui thread.
+ QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
+ QWindowSystemInterfacePrivate::FlushEventsEvent *e = new QWindowSystemInterfacePrivate::FlushEventsEvent(flags);
+ QWindowSystemInterfacePrivate::handleWindowSystemEvent<AsynchronousDelivery>(e);
+ QWindowSystemInterfacePrivate::eventsFlushed.wait(&QWindowSystemInterfacePrivate::flushEventMutex);
+ } else {
+ sendWindowSystemEvents(flags);
+ }
+ return QWindowSystemInterfacePrivate::eventAccepted.load() > 0;
+}
+
+void QWindowSystemInterface::deferredFlushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ Q_ASSERT(QThread::currentThread() == QGuiApplication::instance()->thread());
+
+ QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex);
+ sendWindowSystemEvents(flags);
+ QWindowSystemInterfacePrivate::eventsFlushed.wakeOne();
+}
+
+bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ int nevents = 0;
+
+ while (QWindowSystemInterfacePrivate::windowSystemEventsQueued()) {
+ QWindowSystemInterfacePrivate::WindowSystemEvent *event =
+ (flags & QEventLoop::ExcludeUserInputEvents) ?
+ QWindowSystemInterfacePrivate::getNonUserInputWindowSystemEvent() :
+ QWindowSystemInterfacePrivate::getWindowSystemEvent();
+ if (!event)
+ break;
+
+ if (QWindowSystemInterfacePrivate::eventHandler) {
+ if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event))
+ nevents++;
+ } else {
+ nevents++;
+ QGuiApplicationPrivate::processWindowSystemEvent(event);
+ }
+
+ // Record the accepted state for the processed event
+ // (excluding flush events). This state can then be
+ // returned by flushWindowSystemEvents().
+ if (event->type != QWindowSystemInterfacePrivate::FlushEvents)
+ QWindowSystemInterfacePrivate::eventAccepted.store(event->eventAccepted);
+
+ delete event;
+ }
+
+ return (nevents > 0);
+}
+
+void QWindowSystemInterface::setSynchronousWindowSystemEvents(bool enable)
+{
+ QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = enable;
+}
+
+int QWindowSystemInterface::windowSystemEventsQueued()
+{
+ return QWindowSystemInterfacePrivate::windowSystemEventsQueued();
+}
+
+// --------------------- QtTestLib support ---------------------
+
// The following functions are used by testlib, and need to be synchronous to avoid
// race conditions with plugins delivering native events from secondary threads.
-Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp)
+Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp)
{
- const qreal factor = QHighDpiScaling::factor(w);
- QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(w, timestamp, local * factor, global * factor, b, mods);
+ const qreal factor = QHighDpiScaling::factor(window);
+ QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(window, timestamp, local * factor, global * factor, b, mods);
}
// Wrapper for compatibility with Qt < 5.6
@@ -931,9 +973,9 @@ Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF &local, const QP
qt_handleMouseEvent(w, local, global, b, mods, QWindowSystemInterfacePrivate::eventTime.elapsed());
}
-Q_GUI_EXPORT void qt_handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1)
+Q_GUI_EXPORT void qt_handleKeyEvent(QWindow *window, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1)
{
- QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(w, t, k, mods, text, autorep, count);
+ QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(window, t, k, mods, text, autorep, count);
}
Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1)
@@ -984,35 +1026,13 @@ namespace QTest
}
}
-Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *w, QTouchDevice *device,
+Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *window, QTouchDevice *device,
const QList<QTouchEvent::TouchPoint> &points,
Qt::KeyboardModifiers mods = Qt::NoModifier)
{
- QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(w, device,
- QWindowSystemInterfacePrivate::toNativeTouchPoints(points, w), mods);
-}
-
-QWindowSystemEventHandler::~QWindowSystemEventHandler()
-{
- QWindowSystemInterfacePrivate::removeWindowSystemEventhandler(this);
-}
-
-bool QWindowSystemEventHandler::sendEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
-{
- QGuiApplicationPrivate::processWindowSystemEvent(e);
- return true;
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(window, device,
+ QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window), mods);
}
-QWindowSystemInterfacePrivate::WheelEvent::WheelEvent(QWindow *w, ulong time, const QPointF &local, const QPointF &global, QPoint pixelD,
- QPoint angleD, int qt4D, Qt::Orientation qt4O, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase, Qt::MouseEventSource src, bool inverted)
- : InputEvent(w, time, Wheel, mods), pixelDelta(pixelD), angleDelta(angleD), qt4Delta(qt4D),
- qt4Orientation(qt4O), localPos(local), globalPos(global), phase(phase), source(src), inverted(inverted)
-{
-}
-
-void QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(bool v)
-{
- platformSynthesizesMouse = v;
-}
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h
index a28d1c93df..253584314c 100644
--- a/src/gui/kernel/qwindowsysteminterface.h
+++ b/src/gui/kernel/qwindowsysteminterface.h
@@ -77,44 +77,44 @@ public:
struct DefaultDelivery {};
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b,
+ static void handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b,
Qt::KeyboardModifiers mods = Qt::NoModifier,
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b,
+ static void handleMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b,
Qt::KeyboardModifiers mods = Qt::NoModifier,
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
- static void handleFrameStrutMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b,
+ static void handleFrameStrutMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b,
Qt::KeyboardModifiers mods = Qt::NoModifier,
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
- static void handleFrameStrutMouseEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, Qt::MouseButtons b,
+ static void handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b,
Qt::KeyboardModifiers mods = Qt::NoModifier,
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
- static bool handleShortcutEvent(QWindow *w, ulong timestamp, int k, Qt::KeyboardModifiers mods, quint32 nativeScanCode,
+ static bool handleShortcutEvent(QWindow *window, ulong timestamp, int k, Qt::KeyboardModifiers mods, quint32 nativeScanCode,
quint32 nativeVirtualKey, quint32 nativeModifiers, const QString & text = QString(), bool autorep = false, ushort count = 1);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static bool handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1);
+ static bool handleKeyEvent(QWindow *window, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static bool handleKeyEvent(QWindow *w, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1);
+ static bool handleKeyEvent(QWindow *window, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1);
- static bool handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
+ static bool handleExtendedKeyEvent(QWindow *window, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
quint32 nativeScanCode, quint32 nativeVirtualKey,
quint32 nativeModifiers,
const QString& text = QString(), bool autorep = false,
ushort count = 1, bool tryShortcutOverride = true);
- static bool handleExtendedKeyEvent(QWindow *w, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
+ static bool handleExtendedKeyEvent(QWindow *window, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
quint32 nativeScanCode, quint32 nativeVirtualKey,
quint32 nativeModifiers,
const QString& text = QString(), bool autorep = false,
ushort count = 1, bool tryShortcutOverride = true);
- static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global,
+ static void handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global,
QPoint pixelDelta, QPoint angleDelta,
Qt::KeyboardModifiers mods = Qt::NoModifier,
Qt::ScrollPhase phase = Qt::NoScrollPhase,
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
- static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global,
+ static void handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global,
QPoint pixelDelta, QPoint angleDelta,
Qt::KeyboardModifiers mods = Qt::NoModifier,
Qt::ScrollPhase phase = Qt::NoScrollPhase,
@@ -122,8 +122,8 @@ public:
bool inverted = false);
// Wheel event compatibility functions. Will be removed: do not use.
- static void handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);
- static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);
+ static void handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);
+ static void handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);
struct TouchPoint {
TouchPoint() : id(0), uniqueId(-1), pressure(0), rotation(0), state(Qt::TouchPointStationary) { }
@@ -131,9 +131,11 @@ public:
qint64 uniqueId; // for TUIO: object/token ID; otherwise empty
// TODO for TUIO 2.0: add registerPointerUniqueID(QPointingDeviceUniqueId)
QPointF normalPosition; // touch device coordinates, (0 to 1, 0 to 1)
- QRectF area; // the touched area, centered at position in screen coordinates
+ QRectF area; // dimensions of the elliptical contact patch, unrotated, and centered at position in screen coordinates
+ // width is the horizontal diameter, height is the vertical diameter
qreal pressure; // 0 to 1
- qreal rotation; // 0 means pointing straight up; 0 if unknown (like QTabletEvent::rotation)
+ qreal rotation; // rotation applied to the elliptical contact patch
+ // 0 means pointing straight up; 0 if unknown (like QTabletEvent::rotation)
Qt::TouchPointState state; //Qt::TouchPoint{Pressed|Moved|Stationary|Released}
QVector2D velocity; // in screen coordinate system, pixels / seconds
QTouchEvent::TouchPoint::InfoFlags flags;
@@ -145,43 +147,44 @@ public:
static bool isTouchDeviceRegistered(const QTouchDevice *device);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleTouchEvent(QWindow *w, QTouchDevice *device,
+ static void handleTouchEvent(QWindow *window, QTouchDevice *device,
const QList<struct TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleTouchEvent(QWindow *w, ulong timestamp, QTouchDevice *device,
+ static void handleTouchEvent(QWindow *window, ulong timestamp, QTouchDevice *device,
const QList<struct TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleTouchCancelEvent(QWindow *w, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier);
+ static void handleTouchCancelEvent(QWindow *window, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleTouchCancelEvent(QWindow *w, ulong timestamp, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier);
+ static void handleTouchCancelEvent(QWindow *window, ulong timestamp, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier);
// rect is relative to parent
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleGeometryChange(QWindow *w, const QRect &newRect, const QRect &oldRect = QRect());
+ static void handleGeometryChange(QWindow *window, const QRect &newRect, const QRect &oldRect = QRect());
// region is in local coordinates, do not confuse with geometry which is parent-relative
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleExposeEvent(QWindow *tlw, const QRegion &region);
+ static void handleExposeEvent(QWindow *window, const QRegion &region);
- static void handleCloseEvent(QWindow *w, bool *accepted = Q_NULLPTR);
+ static void handleCloseEvent(QWindow *window, bool *accepted = Q_NULLPTR);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleEnterEvent(QWindow *w, const QPointF &local = QPointF(), const QPointF& global = QPointF());
+ static void handleEnterEvent(QWindow *window, const QPointF &local = QPointF(), const QPointF& global = QPointF());
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleLeaveEvent(QWindow *w);
+ static void handleLeaveEvent(QWindow *window);
static void handleEnterLeaveEvent(QWindow *enter, QWindow *leave, const QPointF &local = QPointF(), const QPointF& global = QPointF());
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleWindowActivated(QWindow *w, Qt::FocusReason r = Qt::OtherFocusReason);
+ static void handleWindowActivated(QWindow *window, Qt::FocusReason r = Qt::OtherFocusReason);
- static void handleWindowStateChanged(QWindow *w, Qt::WindowState newState);
- static void handleWindowScreenChanged(QWindow *w, QScreen *newScreen);
+ template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
+ static void handleWindowStateChanged(QWindow *window, Qt::WindowState newState, int oldState = -1);
+ static void handleWindowScreenChanged(QWindow *window, QScreen *newScreen);
static void handleApplicationStateChanged(Qt::ApplicationState newState, bool forcePropagate = false);
#ifndef QT_NO_DRAGANDDROP
// Drag and drop. These events are sent immediately.
- static QPlatformDragQtResponse handleDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
- static QPlatformDropQtResponse handleDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
+ static QPlatformDragQtResponse handleDrag(QWindow *window, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
+ static QPlatformDropQtResponse handleDrop(QWindow *window, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
#endif
static bool handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result);
@@ -192,24 +195,24 @@ public:
static void handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal newDpiX, qreal newDpiY);
static void handleScreenRefreshRateChange(QScreen *screen, qreal newRefreshRate);
- static void handleThemeChange(QWindow *tlw);
+ static void handleThemeChange(QWindow *window);
static void handleFileOpenEvent(const QString& fileName);
static void handleFileOpenEvent(const QUrl &url);
- static void handleTabletEvent(QWindow *w, ulong timestamp, const QPointF &local, const QPointF &global,
+ static void handleTabletEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global,
int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers = Qt::NoModifier);
- static void handleTabletEvent(QWindow *w, const QPointF &local, const QPointF &global,
+ static void handleTabletEvent(QWindow *window, const QPointF &local, const QPointF &global,
int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers = Qt::NoModifier);
- static void handleTabletEvent(QWindow *w, ulong timestamp, bool down, const QPointF &local, const QPointF &global,
+ static void handleTabletEvent(QWindow *window, ulong timestamp, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers = Qt::NoModifier); // ### remove in Qt 6
- static void handleTabletEvent(QWindow *w, bool down, const QPointF &local, const QPointF &global,
+ static void handleTabletEvent(QWindow *window, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers = Qt::NoModifier); // ### remove in Qt 6
@@ -227,9 +230,9 @@ public:
ulong sequenceId, quint64 value, QPointF &local, QPointF &global);
#endif // QT_NO_GESTURES
- static void handlePlatformPanelEvent(QWindow *w);
+ static void handlePlatformPanelEvent(QWindow *window);
#ifndef QT_NO_CONTEXTMENU
- static void handleContextMenuEvent(QWindow *w, bool mouseTriggered,
+ static void handleContextMenuEvent(QWindow *window, bool mouseTriggered,
const QPoint &pos, const QPoint &globalPos,
Qt::KeyboardModifiers modifiers);
#endif
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index 7c9b1f2852..1bcc79552d 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -131,10 +131,10 @@ public:
class GeometryChangeEvent : public WindowSystemEvent {
public:
- GeometryChangeEvent(QWindow *tlw, const QRect &newGeometry, const QRect &oldGeometry)
- : WindowSystemEvent(GeometryChange), tlw(tlw), newGeometry(newGeometry), oldGeometry(oldGeometry)
+ GeometryChangeEvent(QWindow *window, const QRect &newGeometry, const QRect &oldGeometry)
+ : WindowSystemEvent(GeometryChange), window(window), newGeometry(newGeometry), oldGeometry(oldGeometry)
{ }
- QPointer<QWindow> tlw;
+ QPointer<QWindow> window;
QRect newGeometry;
QRect oldGeometry;
};
@@ -168,12 +168,13 @@ public:
class WindowStateChangedEvent : public WindowSystemEvent {
public:
- WindowStateChangedEvent(QWindow *_window, Qt::WindowState _newState)
- : WindowSystemEvent(WindowStateChanged), window(_window), newState(_newState)
+ WindowStateChangedEvent(QWindow *_window, Qt::WindowState _newState, Qt::WindowState _oldState)
+ : WindowSystemEvent(WindowStateChanged), window(_window), newState(_newState), oldState(_oldState)
{ }
QPointer<QWindow> window;
Qt::WindowState newState;
+ Qt::WindowState oldState;
};
class WindowScreenChangedEvent : public WindowSystemEvent {
@@ -226,11 +227,11 @@ public:
class MouseEvent : public InputEvent {
public:
- MouseEvent(QWindow * w, ulong time, const QPointF & local, const QPointF & global,
+ MouseEvent(QWindow * w, ulong time, const QPointF &local, const QPointF &global,
Qt::MouseButtons b, Qt::KeyboardModifiers mods,
Qt::MouseEventSource src = Qt::MouseEventNotSynthesized)
: InputEvent(w, time, Mouse, mods), localPos(local), globalPos(global), buttons(b), source(src) { }
- MouseEvent(QWindow * w, ulong time, EventType t, const QPointF & local, const QPointF & global,
+ MouseEvent(QWindow * w, ulong time, EventType t, const QPointF &local, const QPointF &global,
Qt::MouseButtons b, Qt::KeyboardModifiers mods,
Qt::MouseEventSource src = Qt::MouseEventNotSynthesized)
: InputEvent(w, time, t, mods), localPos(local), globalPos(global), buttons(b), source(src) { }
@@ -242,7 +243,7 @@ public:
class WheelEvent : public InputEvent {
public:
- WheelEvent(QWindow *w, ulong time, const QPointF & local, const QPointF & global, QPoint pixelD, QPoint angleD, int qt4D, Qt::Orientation qt4O,
+ WheelEvent(QWindow *w, ulong time, const QPointF &local, const QPointF &global, QPoint pixelD, QPoint angleD, int qt4D, Qt::Orientation qt4O,
Qt::KeyboardModifiers mods, Qt::ScrollPhase phase = Qt::NoScrollPhase, Qt::MouseEventSource src = Qt::MouseEventNotSynthesized, bool inverted = false);
QPoint pixelDelta;
QPoint angleDelta;
@@ -494,10 +495,6 @@ public:
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static bool handleWindowSystemEvent(WindowSystemEvent *ev);
-private:
- static void postWindowSystemEvent(WindowSystemEvent *ev);
- static bool processWindowSystemEvent(WindowSystemEvent *ev);
-
public:
static QElapsedTimer eventTime;
static bool synchronousWindowSystemEvents;
@@ -508,7 +505,7 @@ public:
static QList<QTouchEvent::TouchPoint>
fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points,
- const QWindow *window, QEvent::Type *type = Q_NULLPTR);
+ const QWindow *window, quint8 deviceId, QEvent::Type *type = Q_NULLPTR);
static QList<QWindowSystemInterface::TouchPoint>
toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList,
const QWindow *window);
diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri
index 1a1022b3a7..4c778b184e 100644
--- a/src/gui/opengl/opengl.pri
+++ b/src/gui/opengl/opengl.pri
@@ -33,7 +33,8 @@ qtConfig(opengl) {
opengl/qopengltexture_p.h \
opengl/qopengltexturehelper_p.h \
opengl/qopenglpixeltransferoptions.h \
- opengl/qopenglextrafunctions.h
+ opengl/qopenglextrafunctions.h \
+ opengl/qopenglprogrambinarycache_p.h
SOURCES += opengl/qopengl.cpp \
opengl/qopenglfunctions.cpp \
@@ -55,7 +56,8 @@ qtConfig(opengl) {
opengl/qopengltextureblitter.cpp \
opengl/qopengltexture.cpp \
opengl/qopengltexturehelper.cpp \
- opengl/qopenglpixeltransferoptions.cpp
+ opengl/qopenglpixeltransferoptions.cpp \
+ opengl/qopenglprogrambinarycache.cpp
!qtConfig(opengles2) {
HEADERS += opengl/qopenglfunctions_1_0.h \
diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp
index 384cd0bd13..7e663d48bb 100644
--- a/src/gui/opengl/qopengl.cpp
+++ b/src/gui/opengl/qopengl.cpp
@@ -42,6 +42,7 @@
#include "qopenglcontext.h"
#include "qopenglfunctions.h"
+#include "qoperatingsystemversion.h"
#include "qoffscreensurface.h"
#include <QtCore/QDebug>
@@ -223,29 +224,25 @@ struct OsTypeTerm
static QString hostOsRelease() {
QString ver;
#ifdef Q_OS_WIN
- switch (QSysInfo::windowsVersion()) {
- case QSysInfo::WV_XP:
- case QSysInfo::WV_2003:
- ver = QStringLiteral("xp");
- break;
- case QSysInfo::WV_VISTA:
- ver = QStringLiteral("vista");
- break;
- case QSysInfo::WV_WINDOWS7:
+ const auto osver = QOperatingSystemVersion::current();
+#define Q_WINVER(major, minor) (major << 8 | minor)
+ switch (Q_WINVER(osver.majorVersion(), osver.minorVersion())) {
+ case Q_WINVER(6, 1):
ver = QStringLiteral("7");
break;
- case QSysInfo::WV_WINDOWS8:
+ case Q_WINVER(6, 2):
ver = QStringLiteral("8");
break;
- case QSysInfo::WV_WINDOWS8_1:
+ case Q_WINVER(6, 3):
ver = QStringLiteral("8.1");
break;
- case QSysInfo::WV_WINDOWS10:
+ case Q_WINVER(10, 0):
ver = QStringLiteral("10");
break;
default:
break;
}
+#undef Q_WINVER
#endif
return ver;
}
diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h
index cd44ddfe4d..a76da20910 100644
--- a/src/gui/opengl/qopengl.h
+++ b/src/gui/opengl/qopengl.h
@@ -83,17 +83,16 @@ typedef void* GLeglImageOES;
# else // "uncontrolled" ES2 platforms
-// In "es2" builds (QT_OPENGL_ES_2) additional defines indicate if ES
-// 3.0 or higher is available. In this case include the corresponding
-// header. These are backwards compatible and it should be safe to
-// include headers on top of each other, meaning that applications can
-// include gl2.h even if gl31.h gets included here.
-
-// NB! This file contains the only usages of the ES_3 and ES_3_1
-// macros. They are useless for pretty much anything else. The fact
-// that Qt was built against an SDK with f.ex. ES 2 only does not mean
-// applications cannot target ES 3. Therefore QOpenGLFunctions and
-// friends do everything dynamically and never rely on these macros.
+// In "es2" builds (QT_OPENGL_ES_2) additional defines indicate GLES 3.0 or
+// higher is available *at build time*. In this case include the corresponding
+// header. These are backwards compatible and it should be safe to include
+// headers on top of each other, meaning that applications can include gl2.h
+// even if gl31.h gets included here.
+
+// NB! The fact that Qt was built against an SDK with GLES 2 only does not mean
+// applications cannot be deployed on a GLES 3 system. Therefore
+// QOpenGLFunctions and friends must do everything dynamically and must not rely
+// on these macros, except in special cases for controlled build/run environments.
// Some Khronos headers use the ext proto guard in the standard headers as well,
// which is bad. Work it around, but avoid spilling over to the ext header.
diff --git a/src/gui/opengl/qopengldebug.h b/src/gui/opengl/qopengldebug.h
index 74b2731f7e..6b10c36291 100644
--- a/src/gui/opengl/qopengldebug.h
+++ b/src/gui/opengl/qopengldebug.h
@@ -52,6 +52,11 @@
#include <QtCore/qdebug.h>
#include <QtGui/qopenglcontext.h>
+#if defined(Q_CLANG_QDOC)
+#undef GLuint
+typedef unsigned int GLuint;
+#endif
+
QT_BEGIN_NAMESPACE
class QOpenGLDebugLogger;
diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp
index 1d3e47f93b..3a94fa8805 100644
--- a/src/gui/opengl/qopenglengineshadermanager.cpp
+++ b/src/gui/opengl/qopenglengineshadermanager.cpp
@@ -126,11 +126,65 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
around without having to change the order of the glsl strings. It is hoped this will
make future hard-to-find runtime bugs more obvious and generally give more solid code.
*/
- static bool snippetsPopulated = false;
- if (!snippetsPopulated) {
- const char** code = qShaderSnippets; // shortcut
+ // Check if the user has requested an OpenGL 3.2 Core Profile or higher
+ // and if so use GLSL 1.50 core shaders instead of legacy ones.
+ const QSurfaceFormat &fmt = context->format();
+ const bool isCoreProfile = fmt.profile() == QSurfaceFormat::CoreProfile && fmt.version() >= qMakePair(3,2);
+
+ const char** code = qShaderSnippets; // shortcut
+
+ if (isCoreProfile) {
+ code[MainVertexShader] = qopenglslMainVertexShader_core;
+ code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader_core;
+ code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader_core;
+
+ code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader_core;
+ code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader_core;
+ code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader_core;
+ code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader_core;
+ code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader_core;
+ code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader_core;
+ code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader_core;
+ code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader_core;
+ code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader_core;
+ code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader_core;
+ code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader_core;
+ code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader_core;
+ code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader_core;
+
+ code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO_core;
+ code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM_core;
+ code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO_core;
+ code[MainFragmentShader_M] = qopenglslMainFragmentShader_M_core;
+ code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO_core;
+ code[MainFragmentShader_C] = qopenglslMainFragmentShader_C_core;
+ code[MainFragmentShader_O] = qopenglslMainFragmentShader_O_core;
+ code[MainFragmentShader] = qopenglslMainFragmentShader_core;
+ code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays_core;
+
+ code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader_core;
+ code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader_core;
+ code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader_core;
+ code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader_core;
+ code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader_core;
+ code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader_core; // Calls "customShader", which must be appended
+ code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader_core;
+
+ code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_desktop_core;
+ code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader_core;
+ code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader_core;
+ code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader_core;
+ code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader_core;
+ code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader_core;
+ code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader_core;
+ code[NoMaskFragmentShader] = "";
+ code[MaskFragmentShader] = qopenglslMaskFragmentShader_core;
+ code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1_core;
+ code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2_core;
+ code[RgbMaskWithGammaFragmentShader] = ""; //###
+ } else {
code[MainVertexShader] = qopenglslMainVertexShader;
code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader;
code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader;
@@ -182,34 +236,34 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1;
code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2;
code[RgbMaskWithGammaFragmentShader] = ""; //###
+ }
- code[NoCompositionModeFragmentShader] = "";
- code[MultiplyCompositionModeFragmentShader] = ""; //###
- code[ScreenCompositionModeFragmentShader] = ""; //###
- code[OverlayCompositionModeFragmentShader] = ""; //###
- code[DarkenCompositionModeFragmentShader] = ""; //###
- code[LightenCompositionModeFragmentShader] = ""; //###
- code[ColorDodgeCompositionModeFragmentShader] = ""; //###
- code[ColorBurnCompositionModeFragmentShader] = ""; //###
- code[HardLightCompositionModeFragmentShader] = ""; //###
- code[SoftLightCompositionModeFragmentShader] = ""; //###
- code[DifferenceCompositionModeFragmentShader] = ""; //###
- code[ExclusionCompositionModeFragmentShader] = ""; //###
+ // These shaders are not implemented yet and therefore are the same
+ // for all profiles. Implementations should make a version for both
+ // profiles and put the appropriate lines in the if-statement above.
+ code[NoCompositionModeFragmentShader] = "";
+ code[MultiplyCompositionModeFragmentShader] = ""; //###
+ code[ScreenCompositionModeFragmentShader] = ""; //###
+ code[OverlayCompositionModeFragmentShader] = ""; //###
+ code[DarkenCompositionModeFragmentShader] = ""; //###
+ code[LightenCompositionModeFragmentShader] = ""; //###
+ code[ColorDodgeCompositionModeFragmentShader] = ""; //###
+ code[ColorBurnCompositionModeFragmentShader] = ""; //###
+ code[HardLightCompositionModeFragmentShader] = ""; //###
+ code[SoftLightCompositionModeFragmentShader] = ""; //###
+ code[DifferenceCompositionModeFragmentShader] = ""; //###
+ code[ExclusionCompositionModeFragmentShader] = ""; //###
#if defined(QT_DEBUG)
- // Check that all the elements have been filled:
- for (int i = 0; i < TotalSnippetCount; ++i) {
- if (Q_UNLIKELY(!qShaderSnippets[i])) {
- qFatal("Shader snippet for %s (#%d) is missing!",
- snippetNameStr(SnippetName(i)).constData(), i);
- }
+ // Check that all the elements have been filled:
+ for (int i = 0; i < TotalSnippetCount; ++i) {
+ if (Q_UNLIKELY(!qShaderSnippets[i])) {
+ qFatal("Shader snippet for %s (#%d) is missing!",
+ snippetNameStr(SnippetName(i)).constData(), i);
}
-#endif
- snippetsPopulated = true;
}
+#endif
- QOpenGLShader* fragShader;
- QOpenGLShader* vertexShader;
QByteArray vertexSource;
QByteArray fragSource;
@@ -227,19 +281,11 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
bool inCache = simpleShaderCache.load(simpleShaderProg, context);
if (!inCache) {
- vertexShader = new QOpenGLShader(QOpenGLShader::Vertex);
- shaders.append(vertexShader);
- if (!vertexShader->compileSourceCode(vertexSource))
+ if (!simpleShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource))
qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");
-
- fragShader = new QOpenGLShader(QOpenGLShader::Fragment);
- shaders.append(fragShader);
- if (!fragShader->compileSourceCode(fragSource))
+ if (!simpleShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource))
qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile");
- simpleShaderProg->addShader(vertexShader);
- simpleShaderProg->addShader(fragShader);
-
simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR);
simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR);
@@ -271,19 +317,11 @@ QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context)
inCache = blitShaderCache.load(blitShaderProg, context);
if (!inCache) {
- vertexShader = new QOpenGLShader(QOpenGLShader::Vertex);
- shaders.append(vertexShader);
- if (!vertexShader->compileSourceCode(vertexSource))
+ if (!blitShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource))
qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");
-
- fragShader = new QOpenGLShader(QOpenGLShader::Fragment);
- shaders.append(fragShader);
- if (!fragShader->compileSourceCode(fragSource))
+ if (!blitShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource))
qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile");
- blitShaderProg->addShader(vertexShader);
- blitShaderProg->addShader(fragShader);
-
blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
}
@@ -306,9 +344,6 @@ QOpenGLEngineSharedShaders::~QOpenGLEngineSharedShaders()
#ifdef QT_GL_SHARED_SHADER_DEBUG
qDebug(" -> ~QOpenGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread());
#endif
- qDeleteAll(shaders);
- shaders.clear();
-
qDeleteAll(cachedPrograms);
cachedPrograms.clear();
@@ -370,50 +405,37 @@ QOpenGLEngineShaderProg *QOpenGLEngineSharedShaders::findProgramInCache(const QO
bool inCache = shaderCache.load(shaderProgram.data(), QOpenGLContext::currentContext());
if (!inCache) {
-
- QScopedPointer<QOpenGLShader> fragShader(new QOpenGLShader(QOpenGLShader::Fragment));
- QByteArray description;
+ if (!shaderProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource)) {
+ QByteArray description;
#if defined(QT_DEBUG)
- // Name the shader for easier debugging
- description.append("Fragment shader: main=");
- description.append(snippetNameStr(prog.mainFragShader));
- description.append(", srcPixel=");
- description.append(snippetNameStr(prog.srcPixelFragShader));
- if (prog.compositionFragShader) {
- description.append(", composition=");
- description.append(snippetNameStr(prog.compositionFragShader));
- }
- if (prog.maskFragShader) {
- description.append(", mask=");
- description.append(snippetNameStr(prog.maskFragShader));
- }
- fragShader->setObjectName(QString::fromLatin1(description));
+ description.append("Vertex shader: main=");
+ description.append(snippetNameStr(prog.mainVertexShader));
+ description.append(", position=");
+ description.append(snippetNameStr(prog.positionVertexShader));
#endif
- if (!fragShader->compileSourceCode(fragSource)) {
qWarning("Warning: \"%s\" failed to compile!", description.constData());
break;
}
-
- QScopedPointer<QOpenGLShader> vertexShader(new QOpenGLShader(QOpenGLShader::Vertex));
+ if (!shaderProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) {
+ QByteArray description;
#if defined(QT_DEBUG)
- // Name the shader for easier debugging
- description.clear();
- description.append("Vertex shader: main=");
- description.append(snippetNameStr(prog.mainVertexShader));
- description.append(", position=");
- description.append(snippetNameStr(prog.positionVertexShader));
- vertexShader->setObjectName(QString::fromLatin1(description));
+ description.append("Fragment shader: main=");
+ description.append(snippetNameStr(prog.mainFragShader));
+ description.append(", srcPixel=");
+ description.append(snippetNameStr(prog.srcPixelFragShader));
+ if (prog.compositionFragShader) {
+ description.append(", composition=");
+ description.append(snippetNameStr(prog.compositionFragShader));
+ }
+ if (prog.maskFragShader) {
+ description.append(", mask=");
+ description.append(snippetNameStr(prog.maskFragShader));
+ }
#endif
- if (!vertexShader->compileSourceCode(vertexSource)) {
qWarning("Warning: \"%s\" failed to compile!", description.constData());
break;
}
- shaders.append(vertexShader.data());
- shaders.append(fragShader.data());
- shaderProgram->addShader(vertexShader.take());
- shaderProgram->addShader(fragShader.take());
-
// We have to bind the vertex attribute names before the program is linked:
shaderProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
if (prog.useTextureCoords)
@@ -436,18 +458,9 @@ QOpenGLEngineShaderProg *QOpenGLEngineSharedShaders::findProgramInCache(const QO
shaderCache.store(newProg->program, QOpenGLContext::currentContext());
} else {
QString error;
- error = QLatin1String("Shader program failed to link,");
-#if defined(QT_DEBUG)
- QLatin1String br("\n");
- error += QLatin1String("\n Shaders Used:\n");
- for (int i = 0; i < newProg->program->shaders().count(); ++i) {
- QOpenGLShader *shader = newProg->program->shaders().at(i);
- error += QLatin1String(" ") + shader->objectName() + QLatin1String(": \n")
- + QLatin1String(shader->sourceCode()) + br;
- }
-#endif
- error += QLatin1String(" Error Log:\n")
- + QLatin1String(" ") + newProg->program->log();
+ error = QLatin1String("Shader program failed to link")
+ + QLatin1String(" Error Log:\n")
+ + QLatin1String(" ") + newProg->program->log();
qWarning() << error;
break;
}
@@ -519,7 +532,7 @@ GLuint QOpenGLEngineShaderManager::getUniformLocation(Uniform id)
if (uniformLocations.isEmpty())
uniformLocations.fill(GLuint(-1), NumUniforms);
- static const char *const uniformNames[] = {
+ const char uniformNames[][26] = {
"imageTexture",
"patternColor",
"globalOpacity",
diff --git a/src/gui/opengl/qopenglengineshadermanager_p.h b/src/gui/opengl/qopenglengineshadermanager_p.h
index 23b2ccf486..377501457d 100644
--- a/src/gui/opengl/qopenglengineshadermanager_p.h
+++ b/src/gui/opengl/qopenglengineshadermanager_p.h
@@ -366,7 +366,6 @@ private:
QOpenGLShaderProgram *blitShaderProg;
QOpenGLShaderProgram *simpleShaderProg;
QList<QOpenGLEngineShaderProg*> cachedPrograms;
- QList<QOpenGLShader *> shaders;
static const char* qShaderSnippets[TotalSnippetCount];
};
diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h
index 1e88ac63b5..a165643839 100644
--- a/src/gui/opengl/qopenglengineshadersource_p.h
+++ b/src/gui/opengl/qopenglengineshadersource_p.h
@@ -58,7 +58,6 @@
QT_BEGIN_NAMESPACE
-
static const char* const qopenglslMainVertexShader = "\n\
void setPosition(); \n\
void main(void) \n\
@@ -532,40 +531,498 @@ static const char* const qopenglslRgbMaskFragmentShaderPass2 = "\n\
ExclusionCompositionModeFragmentShader,
*/
-// OpenGL 3.2 core profile versions of shaders that are used by QOpenGLTextureGlyphCache
+/*
+ OpenGL 3.2+ Core Profile shaders
+ The following shader snippets are copies of the snippets above
+ but use the modern GLSL 1.5 keywords. New shaders should make
+ a snippet for both profiles and add them appropriately in the
+ shader manager.
+*/
+static const char* const qopenglslMainVertexShader_core =
+ "#version 150 core\n\
+ void setPosition(); \n\
+ void main(void) \n\
+ { \n\
+ setPosition(); \n\
+ }\n";
+
+static const char* const qopenglslMainWithTexCoordsVertexShader_core =
+ "#version 150 core\n\
+ in vec2 textureCoordArray; \n\
+ out vec2 textureCoords; \n\
+ void setPosition(); \n\
+ void main(void) \n\
+ { \n\
+ setPosition(); \n\
+ textureCoords = textureCoordArray; \n\
+ }\n";
+
+static const char* const qopenglslMainWithTexCoordsAndOpacityVertexShader_core =
+ "#version 150 core\n\
+ in vec2 textureCoordArray; \n\
+ in float opacityArray; \n\
+ out vec2 textureCoords; \n\
+ out float opacity; \n\
+ void setPosition(); \n\
+ void main(void) \n\
+ { \n\
+ setPosition(); \n\
+ textureCoords = textureCoordArray; \n\
+ opacity = opacityArray; \n\
+ }\n";
+
+// NOTE: We let GL do the perspective correction so texture lookups in the fragment
+// shader are also perspective corrected.
+static const char* const qopenglslPositionOnlyVertexShader_core = "\n\
+ in vec2 vertexCoordsArray; \n\
+ in vec3 pmvMatrix1; \n\
+ in vec3 pmvMatrix2; \n\
+ in vec3 pmvMatrix3; \n\
+ void setPosition(void) \n\
+ { \n\
+ mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position = vec4(transformedPos.xy, 0.0, transformedPos.z); \n\
+ }\n";
-static const char* const qopenglslMainWithTexCoordsVertexShader_core = "#version 150 core \n\
- in vec2 textureCoordArray; \n\
- out vec2 textureCoords; \n\
- void setPosition(); \n\
- void main(void) \n\
- { \n\
- setPosition(); \n\
- textureCoords = textureCoordArray; \n\
- }\n";
+static const char* const qopenglslComplexGeometryPositionOnlyVertexShader_core = "\n\
+ in vec2 vertexCoordsArray; \n\
+ uniform mat3 matrix; \n\
+ void setPosition(void) \n\
+ { \n\
+ gl_Position = vec4(matrix * vec3(vertexCoordsArray, 1), 1);\n\
+ } \n";
static const char* const qopenglslUntransformedPositionVertexShader_core = "\n\
- in vec4 vertexCoordsArray; \n\
- void setPosition(void) \n\
- { \n\
- gl_Position = vertexCoordsArray; \n\
- }\n";
-
-static const char* const qopenglslMainFragmentShader_core = "#version 150 core \n\
- vec4 srcPixel(); \n\
- out vec4 fragColor; \n\
- void main() \n\
- { \n\
- fragColor = srcPixel(); \n\
- }\n";
+ in vec4 vertexCoordsArray; \n\
+ void setPosition(void) \n\
+ { \n\
+ gl_Position = vertexCoordsArray; \n\
+ }\n";
+
+// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125
+static const char* const qopenglslPositionWithPatternBrushVertexShader_core = "\n\
+ in vec2 vertexCoordsArray; \n\
+ in vec3 pmvMatrix1; \n\
+ in vec3 pmvMatrix2; \n\
+ in vec3 pmvMatrix3; \n\
+ out vec2 patternTexCoords; \n\
+ uniform vec2 halfViewportSize; \n\
+ uniform vec2 invertedTextureSize; \n\
+ uniform mat3 brushTransform; \n\
+ void setPosition(void) \n\
+ { \n\
+ mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1.0); \n\
+ float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithPatternBrushVertexShader_core
+ = qopenglslPositionWithPatternBrushVertexShader_core;
+
+static const char* const qopenglslPatternBrushSrcFragmentShader_core = "\n\
+ in vec2 patternTexCoords;\n\
+ uniform sampler2D brushTexture; \n\
+ uniform vec4 patternColor; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ return patternColor * (1.0 - texture(brushTexture, patternTexCoords).r); \n\
+ }\n";
+
+
+// Linear Gradient Brush
+static const char* const qopenglslPositionWithLinearGradientBrushVertexShader_core = "\n\
+ in vec2 vertexCoordsArray; \n\
+ in vec3 pmvMatrix1; \n\
+ in vec3 pmvMatrix2; \n\
+ in vec3 pmvMatrix3; \n\
+ out float index; \n\
+ uniform vec2 halfViewportSize; \n\
+ uniform vec3 linearData; \n\
+ uniform mat3 brushTransform; \n\
+ void setPosition() \n\
+ { \n\
+ mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
+ float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithLinearGradientBrushVertexShader_core
+ = qopenglslPositionWithLinearGradientBrushVertexShader_core;
+
+static const char* const qopenglslLinearGradientBrushSrcFragmentShader_core = "\n\
+ uniform sampler2D brushTexture; \n\
+ in float index; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ vec2 val = vec2(index, 0.5); \n\
+ return texture(brushTexture, val); \n\
+ }\n";
+
+
+// Conical Gradient Brush
+static const char* const qopenglslPositionWithConicalGradientBrushVertexShader_core = "\n\
+ in vec2 vertexCoordsArray; \n\
+ in vec3 pmvMatrix1; \n\
+ in vec3 pmvMatrix2; \n\
+ in vec3 pmvMatrix3; \n\
+ out vec2 A; \n\
+ uniform vec2 halfViewportSize; \n\
+ uniform mat3 brushTransform; \n\
+ void setPosition(void) \n\
+ { \n\
+ mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
+ float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ A = hTexCoords.xy * invertedHTexCoordsZ; \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithConicalGradientBrushVertexShader_core
+ = qopenglslPositionWithConicalGradientBrushVertexShader_core;
+
+static const char* const qopenglslConicalGradientBrushSrcFragmentShader_core = "\n\
+ #define INVERSE_2PI 0.1591549430918953358 \n\
+ in vec2 A; \n\
+ uniform sampler2D brushTexture; \n\
+ uniform float angle; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ float t; \n\
+ if (abs(A.y) == abs(A.x)) \n\
+ t = (atan(-A.y + 0.002, A.x) + angle) * INVERSE_2PI; \n\
+ else \n\
+ t = (atan(-A.y, A.x) + angle) * INVERSE_2PI; \n\
+ return texture(brushTexture, vec2(t - floor(t), 0.5)); \n\
+ }\n";
+
+
+// Radial Gradient Brush
+static const char* const qopenglslPositionWithRadialGradientBrushVertexShader_core = "\n\
+ in vec2 vertexCoordsArray;\n\
+ in vec3 pmvMatrix1; \n\
+ in vec3 pmvMatrix2; \n\
+ in vec3 pmvMatrix3; \n\
+ out float b; \n\
+ out vec2 A; \n\
+ uniform vec2 halfViewportSize; \n\
+ uniform mat3 brushTransform; \n\
+ uniform vec2 fmp; \n\
+ uniform vec3 bradius; \n\
+ void setPosition(void) \n\
+ {\n\
+ mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
+ float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ A = hTexCoords.xy * invertedHTexCoordsZ; \n\
+ b = bradius.x + 2.0 * dot(A, fmp); \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithRadialGradientBrushVertexShader_core
+ = qopenglslPositionWithRadialGradientBrushVertexShader_core;
+
+static const char* const qopenglslRadialGradientBrushSrcFragmentShader_core = "\n\
+ in float b; \n\
+ in vec2 A; \n\
+ uniform sampler2D brushTexture; \n\
+ uniform float fmp2_m_radius2; \n\
+ uniform float inverse_2_fmp2_m_radius2; \n\
+ uniform float sqrfr; \n\
+ uniform vec3 bradius; \n\
+ \n\
+ vec4 srcPixel() \n\
+ { \n\
+ float c = sqrfr-dot(A, A); \n\
+ float det = b*b - 4.0*fmp2_m_radius2*c; \n\
+ vec4 result = vec4(0.0); \n\
+ if (det >= 0.0) { \n\
+ float detSqrt = sqrt(det); \n\
+ float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); \n\
+ if (bradius.y + w * bradius.z >= 0.0) \n\
+ result = texture(brushTexture, vec2(w, 0.5)); \n\
+ } \n\
+ return result; \n\
+ }\n";
+
+
+// Texture Brush
+static const char* const qopenglslPositionWithTextureBrushVertexShader_core = "\n\
+ in vec2 vertexCoordsArray; \n\
+ in vec3 pmvMatrix1; \n\
+ in vec3 pmvMatrix2; \n\
+ in vec3 pmvMatrix3; \n\
+ out vec2 brushTextureCoords; \n\
+ uniform vec2 halfViewportSize; \n\
+ uniform vec2 invertedTextureSize; \n\
+ uniform mat3 brushTransform; \n\
+ \n\
+ void setPosition(void) \n\
+ { \n\
+ mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\
+ vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\
+ gl_Position.xy = transformedPos.xy / transformedPos.z; \n\
+ vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\
+ vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\
+ float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
+ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
+ brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\
+ }\n";
+
+static const char* const qopenglslAffinePositionWithTextureBrushVertexShader_core
+ = qopenglslPositionWithTextureBrushVertexShader_core;
+
+static const char* const qopenglslTextureBrushSrcFragmentShader_desktop_core = "\n\
+ in vec2 brushTextureCoords; \n\
+ uniform sampler2D brushTexture; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ return texture(brushTexture, brushTextureCoords); \n\
+ }\n";
+
+static const char* const qopenglslTextureBrushSrcWithPatternFragmentShader_core = "\n\
+ in vec2 brushTextureCoords; \n\
+ uniform vec4 patternColor; \n\
+ uniform sampler2D brushTexture; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ return patternColor * (1.0 - texture(brushTexture, brushTextureCoords).r); \n\
+ }\n";
+
+// Solid Fill Brush
+static const char* const qopenglslSolidBrushSrcFragmentShader_core = "\n\
+ uniform vec4 fragmentColor; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ return fragmentColor; \n\
+ }\n";
static const char* const qopenglslImageSrcFragmentShader_core = "\n\
- in vec2 textureCoords; \n\
- uniform sampler2D imageTexture; \n\
- vec4 srcPixel() \n\
- { \n"
- "return texture(imageTexture, textureCoords); \n"
- "}\n";
+ in vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ return texture(imageTexture, textureCoords); \n\
+ }\n";
+
+static const char* const qopenglslCustomSrcFragmentShader_core = "\n\
+ in vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ return customShader(imageTexture, textureCoords); \n\
+ }\n";
+
+static const char* const qopenglslImageSrcWithPatternFragmentShader_core = "\n\
+ in vec2 textureCoords; \n\
+ uniform vec4 patternColor; \n\
+ uniform sampler2D imageTexture; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ return patternColor * (1.0 - texture(imageTexture, textureCoords).r); \n\
+ }\n";
+
+static const char* const qopenglslNonPremultipliedImageSrcFragmentShader_core = "\n\
+ in vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ vec4 sample = texture(imageTexture, textureCoords); \n\
+ sample.rgb = sample.rgb * sample.a; \n\
+ return sample; \n\
+ }\n";
+
+static const char* const qopenglslGrayscaleImageSrcFragmentShader_core = "\n\
+ in vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ return texture(imageTexture, textureCoords).rrra; \n\
+ }\n";
+
+static const char* const qopenglslAlphaImageSrcFragmentShader_core = "\n\
+ in vec2 textureCoords; \n\
+ uniform sampler2D imageTexture; \n\
+ vec4 srcPixel() \n\
+ { \n\
+ return vec4(0, 0, 0, texture(imageTexture, textureCoords).r); \n\
+ }\n";
+
+static const char* const qopenglslShockingPinkSrcFragmentShader_core = "\n\
+ vec4 srcPixel() \n\
+ { \n\
+ return vec4(0.98, 0.06, 0.75, 1.0); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_ImageArrays_core =
+ "#version 150 core\n\
+ in float opacity; \n\
+ out vec4 fragColor; \n\
+ vec4 srcPixel(); \n\
+ void main() \n\
+ { \n\
+ fragColor = srcPixel() * opacity; \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_CMO_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ uniform float globalOpacity; \n\
+ vec4 srcPixel(); \n\
+ vec4 applyMask(vec4); \n\
+ vec4 compose(vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_CM_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ vec4 srcPixel(); \n\
+ vec4 applyMask(vec4); \n\
+ vec4 compose(vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = applyMask(compose(srcPixel())); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_MO_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ uniform float globalOpacity; \n\
+ vec4 srcPixel(); \n\
+ vec4 applyMask(vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = applyMask(srcPixel()*globalOpacity); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_M_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ vec4 srcPixel(); \n\
+ vec4 applyMask(vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = applyMask(srcPixel()); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_CO_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ uniform float globalOpacity; \n\
+ vec4 srcPixel(); \n\
+ vec4 compose(vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = compose(srcPixel()*globalOpacity); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_C_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ vec4 srcPixel(); \n\
+ vec4 compose(vec4); \n\
+ void main() \n\
+ { \n\
+ fragColor = compose(srcPixel()); \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_O_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ uniform float globalOpacity; \n\
+ vec4 srcPixel(); \n\
+ void main() \n\
+ { \n\
+ fragColor = srcPixel()*globalOpacity; \n\
+ }\n";
+
+static const char* const qopenglslMainFragmentShader_core =
+ "#version 150 core\n\
+ out vec4 fragColor; \n\
+ vec4 srcPixel(); \n\
+ void main() \n\
+ { \n\
+ fragColor = srcPixel(); \n\
+ }\n";
+
+static const char* const qopenglslMaskFragmentShader_core = "\n\
+ in vec2 textureCoords;\n\
+ uniform sampler2D maskTexture;\n\
+ vec4 applyMask(vec4 src) \n\
+ {\n\
+ vec4 mask = texture(maskTexture, textureCoords); \n\
+ return src * mask.r; \n\
+ }\n";
+
+// For source over with subpixel antialiasing, the final color is calculated per component as follows
+// (.a is alpha component, .c is red, green or blue component):
+// alpha = src.a * mask.c * opacity
+// dest.c = dest.c * (1 - alpha) + src.c * alpha
+//
+// In the first pass, calculate: dest.c = dest.c * (1 - alpha) with blend funcs: zero, 1 - source color
+// In the second pass, calculate: dest.c = dest.c + src.c * alpha with blend funcs: one, one
+//
+// If source is a solid color (src is constant), only the first pass is needed, with blend funcs: constant, 1 - source color
+
+// For source composition with subpixel antialiasing, the final color is calculated per component as follows:
+// alpha = src.a * mask.c * opacity
+// dest.c = dest.c * (1 - mask.c) + src.c * alpha
+//
+
+static const char* const qopenglslRgbMaskFragmentShaderPass1_core = "\n\
+ in vec2 textureCoords;\n\
+ uniform sampler2D maskTexture;\n\
+ vec4 applyMask(vec4 src) \n\
+ { \n\
+ vec4 mask = texture(maskTexture, textureCoords); \n\
+ return src.a * mask; \n\
+ }\n";
+
+static const char* const qopenglslRgbMaskFragmentShaderPass2_core = "\n\
+ in vec2 textureCoords;\n\
+ uniform sampler2D maskTexture;\n\
+ vec4 applyMask(vec4 src) \n\
+ { \n\
+ vec4 mask = texture(maskTexture, textureCoords); \n\
+ return src * mask; \n\
+ }\n";
+
+/*
+ Left to implement:
+ RgbMaskFragmentShader_core,
+ RgbMaskWithGammaFragmentShader_core,
+
+ MultiplyCompositionModeFragmentShader_core,
+ ScreenCompositionModeFragmentShader_core,
+ OverlayCompositionModeFragmentShader_core,
+ DarkenCompositionModeFragmentShader_core,
+ LightenCompositionModeFragmentShader_core,
+ ColorDodgeCompositionModeFragmentShader_core,
+ ColorBurnCompositionModeFragmentShader_core,
+ HardLightCompositionModeFragmentShader_core,
+ SoftLightCompositionModeFragmentShader_core,
+ DifferenceCompositionModeFragmentShader_core,
+ ExclusionCompositionModeFragmentShader_core,
+*/
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index 98ff49ea31..b56bcd0866 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -1282,35 +1282,11 @@ static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool includ
return img;
}
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- // Without GL_UNSIGNED_INT_8_8_8_8_REV, GL_BGRA only makes sense on little endian.
- const bool has_bgra_ext = context->isOpenGLES()
- ? context->hasExtension(QByteArrayLiteral("GL_EXT_read_format_bgra"))
- : context->hasExtension(QByteArrayLiteral("GL_EXT_bgra"));
-
-#ifndef Q_OS_IOS
- const char *renderer = reinterpret_cast<const char *>(funcs->glGetString(GL_RENDERER));
- const char *ver = reinterpret_cast<const char *>(funcs->glGetString(GL_VERSION));
-
- // Blacklist GPU chipsets that have problems with their BGRA support.
- const bool blackListed = (qstrcmp(renderer, "PowerVR Rogue G6200") == 0
- && ::strstr(ver, "1.3") != 0) ||
- (qstrcmp(renderer, "Mali-T760") == 0
- && ::strstr(ver, "3.1") != 0) ||
- (qstrcmp(renderer, "Mali-T720") == 0
- && ::strstr(ver, "3.1") != 0) ||
- qstrcmp(renderer, "PowerVR SGX 554") == 0;
-#else
- const bool blackListed = true;
-#endif
- const bool supports_bgra = has_bgra_ext && !blackListed;
+ // For OpenGL ES stick with the byte ordered format / RGBA readback format
+ // since that is the only spec mandated way. (also, skip the
+ // GL_IMPLEMENTATION_COLOR_READ_FORMAT mess since there is nothing saying a
+ // BGRA capable impl would return BGRA from there)
- if (supports_bgra) {
- QImage img(size, include_alpha ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
- funcs->glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_BYTE, img.bits());
- return img;
- }
-#endif
QImage rgbaImage(size, include_alpha ? QImage::Format_RGBA8888_Premultiplied : QImage::Format_RGBX8888);
funcs->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaImage.bits());
return rgbaImage;
@@ -1362,8 +1338,11 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
If used together with QOpenGLPaintDevice, \a flipped should be the opposite of the value
of QOpenGLPaintDevice::paintFlipped().
- The returned image has a format of premultiplied ARGB32 or RGB32. The latter is used
- only when internalTextureFormat() is set to \c GL_RGB.
+ The returned image has a format of premultiplied ARGB32 or RGB32. The latter
+ is used only when internalTextureFormat() is set to \c GL_RGB. Since Qt 5.2
+ the function will fall back to premultiplied RGBA8888 or RGBx8888 when
+ reading to (A)RGB32 is not supported, and this includes OpenGL ES. Since Qt
+ 5.4 an A2BGR30 image is returned if the internal format is RGB10_A2.
If the rendering in the framebuffer was not done with premultiplied alpha in mind,
create a wrapper QImage with a non-premultiplied format. This is necessary before
@@ -1376,10 +1355,6 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32);
\endcode
- Since Qt 5.2 the function will fall back to premultiplied RGBA8888 or RGBx8888 when
- reading to (A)RGB32 is not supported. Since 5.4 an A2BGR30 image is returned if the
- internal format is RGB10_A2.
-
For multisampled framebuffer objects the samples are resolved using the
\c{GL_EXT_framebuffer_blit} extension. If the extension is not available, the contents
of the returned image is undefined.
diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h
index aad48571b3..f1a717f659 100644
--- a/src/gui/opengl/qopenglfunctions.h
+++ b/src/gui/opengl/qopenglfunctions.h
@@ -591,499 +591,319 @@ struct QOpenGLFunctionsPrivate
inline void QOpenGLFunctions::glBindTexture(GLenum target, GLuint texture)
{
-#ifdef QT_OPENGL_ES_2
- ::glBindTexture(target, texture);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BindTexture(target, texture);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBlendFunc(GLenum sfactor, GLenum dfactor)
{
-#ifdef QT_OPENGL_ES_2
- ::glBlendFunc(sfactor, dfactor);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BlendFunc(sfactor, dfactor);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glClear(GLbitfield mask)
{
-#ifdef QT_OPENGL_ES_2
- ::glClear(mask);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Clear(mask);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
{
-#ifdef QT_OPENGL_ES_2
- ::glClearColor(red, green, blue, alpha);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ClearColor(red, green, blue, alpha);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glClearStencil(GLint s)
{
-#ifdef QT_OPENGL_ES_2
- ::glClearStencil(s);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ClearStencil(s);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
{
-#ifdef QT_OPENGL_ES_2
- ::glColorMask(red, green, blue, alpha);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ColorMask(red, green, blue, alpha);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
{
-#ifdef QT_OPENGL_ES_2
- ::glCopyTexImage2D(target, level, internalformat, x, y, width,height, border);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.CopyTexImage2D(target, level, internalformat, x, y, width,height, border);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
{
-#ifdef QT_OPENGL_ES_2
- ::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glCullFace(GLenum mode)
{
-#ifdef QT_OPENGL_ES_2
- ::glCullFace(mode);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.CullFace(mode);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDeleteTextures(GLsizei n, const GLuint* textures)
{
-#ifdef QT_OPENGL_ES_2
- ::glDeleteTextures(n, textures);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DeleteTextures(n, textures);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDepthFunc(GLenum func)
{
-#ifdef QT_OPENGL_ES_2
- ::glDepthFunc(func);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DepthFunc(func);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDepthMask(GLboolean flag)
{
-#ifdef QT_OPENGL_ES_2
- ::glDepthMask(flag);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DepthMask(flag);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDisable(GLenum cap)
{
-#ifdef QT_OPENGL_ES_2
- ::glDisable(cap);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Disable(cap);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDrawArrays(GLenum mode, GLint first, GLsizei count)
{
-#ifdef QT_OPENGL_ES_2
- ::glDrawArrays(mode, first, count);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DrawArrays(mode, first, count);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
{
-#ifdef QT_OPENGL_ES_2
- ::glDrawElements(mode, count, type, indices);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DrawElements(mode, count, type, indices);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glEnable(GLenum cap)
{
-#ifdef QT_OPENGL_ES_2
- ::glEnable(cap);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Enable(cap);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glFinish()
{
-#ifdef QT_OPENGL_ES_2
- ::glFinish();
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Finish();
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glFlush()
{
-#ifdef QT_OPENGL_ES_2
- ::glFlush();
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Flush();
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glFrontFace(GLenum mode)
{
-#ifdef QT_OPENGL_ES_2
- ::glFrontFace(mode);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.FrontFace(mode);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGenTextures(GLsizei n, GLuint* textures)
{
-#ifdef QT_OPENGL_ES_2
- ::glGenTextures(n, textures);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GenTextures(n, textures);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetBooleanv(GLenum pname, GLboolean* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetBooleanv(pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetBooleanv(pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline GLenum QOpenGLFunctions::glGetError()
{
-#ifdef QT_OPENGL_ES_2
- GLenum result = ::glGetError();
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLenum result = d_ptr->f.GetError();
-#endif
return result;
}
inline void QOpenGLFunctions::glGetFloatv(GLenum pname, GLfloat* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetFloatv(pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetFloatv(pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetIntegerv(GLenum pname, GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetIntegerv(pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetIntegerv(pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline const GLubyte *QOpenGLFunctions::glGetString(GLenum name)
{
-#ifdef QT_OPENGL_ES_2
- const GLubyte *result = ::glGetString(name);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
const GLubyte *result = d_ptr->f.GetString(name);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline void QOpenGLFunctions::glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetTexParameterfv(target, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetTexParameterfv(target, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetTexParameteriv(target, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetTexParameteriv(target, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glHint(GLenum target, GLenum mode)
{
-#ifdef QT_OPENGL_ES_2
- ::glHint(target, mode);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Hint(target, mode);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline GLboolean QOpenGLFunctions::glIsEnabled(GLenum cap)
{
-#ifdef QT_OPENGL_ES_2
- GLboolean result = ::glIsEnabled(cap);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLboolean result = d_ptr->f.IsEnabled(cap);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline GLboolean QOpenGLFunctions::glIsTexture(GLuint texture)
{
-#ifdef QT_OPENGL_ES_2
- GLboolean result = ::glIsTexture(texture);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLboolean result = d_ptr->f.IsTexture(texture);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline void QOpenGLFunctions::glLineWidth(GLfloat width)
{
-#ifdef QT_OPENGL_ES_2
- ::glLineWidth(width);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.LineWidth(width);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glPixelStorei(GLenum pname, GLint param)
{
-#ifdef QT_OPENGL_ES_2
- ::glPixelStorei(pname, param);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.PixelStorei(pname, param);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glPolygonOffset(GLfloat factor, GLfloat units)
{
-#ifdef QT_OPENGL_ES_2
- ::glPolygonOffset(factor, units);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.PolygonOffset(factor, units);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
{
-#ifdef QT_OPENGL_ES_2
- ::glReadPixels(x, y, width, height, format, type, pixels);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ReadPixels(x, y, width, height, format, type, pixels);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
{
-#ifdef QT_OPENGL_ES_2
- ::glScissor(x, y, width, height);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Scissor(x, y, width, height);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glStencilFunc(GLenum func, GLint ref, GLuint mask)
{
-#ifdef QT_OPENGL_ES_2
- ::glStencilFunc(func, ref, mask);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.StencilFunc(func, ref, mask);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glStencilMask(GLuint mask)
{
-#ifdef QT_OPENGL_ES_2
- ::glStencilMask(mask);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.StencilMask(mask);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
{
-#ifdef QT_OPENGL_ES_2
- ::glStencilOp(fail, zfail, zpass);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.StencilOp(fail, zfail, zpass);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
{
-#ifdef QT_OPENGL_ES_2
- ::glTexImage2D(target, level, internalformat, width,height, border, format, type, pixels);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.TexImage2D(target, level, internalformat, width,height, border, format, type, pixels);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glTexParameterf(GLenum target, GLenum pname, GLfloat param)
{
-#ifdef QT_OPENGL_ES_2
- ::glTexParameterf(target, pname, param);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.TexParameterf(target, pname, param);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glTexParameterfv(target, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.TexParameterfv(target, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glTexParameteri(GLenum target, GLenum pname, GLint param)
{
-#ifdef QT_OPENGL_ES_2
- ::glTexParameteri(target, pname, param);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.TexParameteri(target, pname, param);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glTexParameteriv(target, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.TexParameteriv(target, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
{
-#ifdef QT_OPENGL_ES_2
- ::glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.TexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
{
-#ifdef QT_OPENGL_ES_2
- ::glViewport(x, y, width, height);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Viewport(x, y, width, height);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
@@ -1091,45 +911,29 @@ inline void QOpenGLFunctions::glViewport(GLint x, GLint y, GLsizei width, GLsize
inline void QOpenGLFunctions::glActiveTexture(GLenum texture)
{
-#ifdef QT_OPENGL_ES_2
- ::glActiveTexture(texture);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ActiveTexture(texture);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glAttachShader(GLuint program, GLuint shader)
{
-#ifdef QT_OPENGL_ES_2
- ::glAttachShader(program, shader);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.AttachShader(program, shader);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBindAttribLocation(GLuint program, GLuint index, const char* name)
{
-#ifdef QT_OPENGL_ES_2
- ::glBindAttribLocation(program, index, name);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BindAttribLocation(program, index, name);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBindBuffer(GLenum target, GLuint buffer)
{
-#ifdef QT_OPENGL_ES_2
- ::glBindBuffer(target, buffer);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BindBuffer(target, buffer);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
@@ -1137,1034 +941,662 @@ inline void QOpenGLFunctions::glBindFramebuffer(GLenum target, GLuint framebuffe
{
if (framebuffer == 0)
framebuffer = QOpenGLContext::currentContext()->defaultFramebufferObject();
-#ifdef QT_OPENGL_ES_2
- ::glBindFramebuffer(target, framebuffer);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BindFramebuffer(target, framebuffer);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBindRenderbuffer(GLenum target, GLuint renderbuffer)
{
-#ifdef QT_OPENGL_ES_2
- ::glBindRenderbuffer(target, renderbuffer);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BindRenderbuffer(target, renderbuffer);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
{
-#ifdef QT_OPENGL_ES_2
- ::glBlendColor(red, green, blue, alpha);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BlendColor(red, green, blue, alpha);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBlendEquation(GLenum mode)
{
-#ifdef QT_OPENGL_ES_2
- ::glBlendEquation(mode);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BlendEquation(mode);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
{
-#ifdef QT_OPENGL_ES_2
- ::glBlendEquationSeparate(modeRGB, modeAlpha);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BlendEquationSeparate(modeRGB, modeAlpha);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
{
-#ifdef QT_OPENGL_ES_2
- ::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBufferData(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage)
{
-#ifdef QT_OPENGL_ES_2
- ::glBufferData(target, size, data, usage);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BufferData(target, size, data, usage);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glBufferSubData(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data)
{
-#ifdef QT_OPENGL_ES_2
- ::glBufferSubData(target, offset, size, data);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.BufferSubData(target, offset, size, data);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline GLenum QOpenGLFunctions::glCheckFramebufferStatus(GLenum target)
{
-#ifdef QT_OPENGL_ES_2
- GLenum result = ::glCheckFramebufferStatus(target);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLenum result = d_ptr->f.CheckFramebufferStatus(target);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline void QOpenGLFunctions::glClearDepthf(GLclampf depth)
{
-#ifndef QT_OPENGL_ES
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ClearDepthf(depth);
-#else
- ::glClearDepthf(depth);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glCompileShader(GLuint shader)
{
-#ifdef QT_OPENGL_ES_2
- ::glCompileShader(shader);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.CompileShader(shader);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
{
-#ifdef QT_OPENGL_ES_2
- ::glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
{
-#ifdef QT_OPENGL_ES_2
- ::glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline GLuint QOpenGLFunctions::glCreateProgram()
{
-#ifdef QT_OPENGL_ES_2
- GLuint result = ::glCreateProgram();
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLuint result = d_ptr->f.CreateProgram();
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline GLuint QOpenGLFunctions::glCreateShader(GLenum type)
{
-#ifdef QT_OPENGL_ES_2
- GLuint result = ::glCreateShader(type);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLuint result = d_ptr->f.CreateShader(type);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline void QOpenGLFunctions::glDeleteBuffers(GLsizei n, const GLuint* buffers)
{
-#ifdef QT_OPENGL_ES_2
- ::glDeleteBuffers(n, buffers);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DeleteBuffers(n, buffers);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
{
-#ifdef QT_OPENGL_ES_2
- ::glDeleteFramebuffers(n, framebuffers);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DeleteFramebuffers(n, framebuffers);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDeleteProgram(GLuint program)
{
-#ifdef QT_OPENGL_ES_2
- ::glDeleteProgram(program);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DeleteProgram(program);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
{
-#ifdef QT_OPENGL_ES_2
- ::glDeleteRenderbuffers(n, renderbuffers);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DeleteRenderbuffers(n, renderbuffers);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDeleteShader(GLuint shader)
{
-#ifdef QT_OPENGL_ES_2
- ::glDeleteShader(shader);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DeleteShader(shader);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDepthRangef(GLclampf zNear, GLclampf zFar)
{
-#ifndef QT_OPENGL_ES
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DepthRangef(zNear, zFar);
-#else
- ::glDepthRangef(zNear, zFar);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDetachShader(GLuint program, GLuint shader)
{
-#ifdef QT_OPENGL_ES_2
- ::glDetachShader(program, shader);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DetachShader(program, shader);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glDisableVertexAttribArray(GLuint index)
{
-#ifdef QT_OPENGL_ES_2
- ::glDisableVertexAttribArray(index);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.DisableVertexAttribArray(index);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glEnableVertexAttribArray(GLuint index)
{
-#ifdef QT_OPENGL_ES_2
- ::glEnableVertexAttribArray(index);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.EnableVertexAttribArray(index);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
{
-#ifdef QT_OPENGL_ES_2
- ::glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
{
-#ifdef QT_OPENGL_ES_2
- ::glFramebufferTexture2D(target, attachment, textarget, texture, level);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.FramebufferTexture2D(target, attachment, textarget, texture, level);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGenBuffers(GLsizei n, GLuint* buffers)
{
-#ifdef QT_OPENGL_ES_2
- ::glGenBuffers(n, buffers);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GenBuffers(n, buffers);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGenerateMipmap(GLenum target)
{
-#ifdef QT_OPENGL_ES_2
- ::glGenerateMipmap(target);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GenerateMipmap(target);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGenFramebuffers(GLsizei n, GLuint* framebuffers)
{
-#ifdef QT_OPENGL_ES_2
- ::glGenFramebuffers(n, framebuffers);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GenFramebuffers(n, framebuffers);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
{
-#ifdef QT_OPENGL_ES_2
- ::glGenRenderbuffers(n, renderbuffers);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GenRenderbuffers(n, renderbuffers);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetActiveAttrib(program, index, bufsize, length, size, type, name);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetActiveAttrib(program, index, bufsize, length, size, type, name);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetActiveUniform(program, index, bufsize, length, size, type, name);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetActiveUniform(program, index, bufsize, length, size, type, name);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetAttachedShaders(program, maxcount, count, shaders);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetAttachedShaders(program, maxcount, count, shaders);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline GLint QOpenGLFunctions::glGetAttribLocation(GLuint program, const char* name)
{
-#ifdef QT_OPENGL_ES_2
- GLint result = ::glGetAttribLocation(program, name);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLint result = d_ptr->f.GetAttribLocation(program, name);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline void QOpenGLFunctions::glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetBufferParameteriv(target, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetBufferParameteriv(target, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetFramebufferAttachmentParameteriv(target, attachment, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetProgramiv(GLuint program, GLenum pname, GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetProgramiv(program, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetProgramiv(program, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetProgramInfoLog(program, bufsize, length, infolog);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetProgramInfoLog(program, bufsize, length, infolog);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetRenderbufferParameteriv(target, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetRenderbufferParameteriv(target, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetShaderiv(shader, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetShaderiv(shader, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetShaderInfoLog(shader, bufsize, length, infolog);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetShaderInfoLog(shader, bufsize, length, infolog);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetShaderSource(shader, bufsize, length, source);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetShaderSource(shader, bufsize, length, source);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetUniformfv(GLuint program, GLint location, GLfloat* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetUniformfv(program, location, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetUniformfv(program, location, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetUniformiv(GLuint program, GLint location, GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetUniformiv(program, location, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetUniformiv(program, location, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline GLint QOpenGLFunctions::glGetUniformLocation(GLuint program, const char* name)
{
-#ifdef QT_OPENGL_ES_2
- GLint result = ::glGetUniformLocation(program, name);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLint result = d_ptr->f.GetUniformLocation(program, name);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline void QOpenGLFunctions::glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetVertexAttribfv(index, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetVertexAttribfv(index, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetVertexAttribiv(index, pname, params);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetVertexAttribiv(index, pname, params);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer)
{
-#ifdef QT_OPENGL_ES_2
- ::glGetVertexAttribPointerv(index, pname, pointer);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.GetVertexAttribPointerv(index, pname, pointer);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline GLboolean QOpenGLFunctions::glIsBuffer(GLuint buffer)
{
-#ifdef QT_OPENGL_ES_2
- GLboolean result = ::glIsBuffer(buffer);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLboolean result = d_ptr->f.IsBuffer(buffer);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline GLboolean QOpenGLFunctions::glIsFramebuffer(GLuint framebuffer)
{
-#ifdef QT_OPENGL_ES_2
- GLboolean result = ::glIsFramebuffer(framebuffer);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLboolean result = d_ptr->f.IsFramebuffer(framebuffer);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline GLboolean QOpenGLFunctions::glIsProgram(GLuint program)
{
-#ifdef QT_OPENGL_ES_2
- GLboolean result = ::glIsProgram(program);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLboolean result = d_ptr->f.IsProgram(program);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline GLboolean QOpenGLFunctions::glIsRenderbuffer(GLuint renderbuffer)
{
-#ifdef QT_OPENGL_ES_2
- GLboolean result = ::glIsRenderbuffer(renderbuffer);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLboolean result = d_ptr->f.IsRenderbuffer(renderbuffer);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline GLboolean QOpenGLFunctions::glIsShader(GLuint shader)
{
-#ifdef QT_OPENGL_ES_2
- GLboolean result = ::glIsShader(shader);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
GLboolean result = d_ptr->f.IsShader(shader);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
return result;
}
inline void QOpenGLFunctions::glLinkProgram(GLuint program)
{
-#ifdef QT_OPENGL_ES_2
- ::glLinkProgram(program);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.LinkProgram(program);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glReleaseShaderCompiler()
{
-#ifdef QT_OPENGL_ES_2
- ::glReleaseShaderCompiler();
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ReleaseShaderCompiler();
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
{
-#ifdef QT_OPENGL_ES_2
- ::glRenderbufferStorage(target, internalformat, width, height);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.RenderbufferStorage(target, internalformat, width, height);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glSampleCoverage(GLclampf value, GLboolean invert)
{
-#ifdef QT_OPENGL_ES_2
- ::glSampleCoverage(value, invert);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.SampleCoverage(value, invert);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length)
{
-#ifdef QT_OPENGL_ES_2
- ::glShaderBinary(n, shaders, binaryformat, binary, length);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ShaderBinary(n, shaders, binaryformat, binary, length);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length)
{
-#ifdef QT_OPENGL_ES_2
- ::glShaderSource(shader, count, string, length);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ShaderSource(shader, count, string, length);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
{
-#ifdef QT_OPENGL_ES_2
- ::glStencilFuncSeparate(face, func, ref, mask);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.StencilFuncSeparate(face, func, ref, mask);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glStencilMaskSeparate(GLenum face, GLuint mask)
{
-#ifdef QT_OPENGL_ES_2
- ::glStencilMaskSeparate(face, mask);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.StencilMaskSeparate(face, mask);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
{
-#ifdef QT_OPENGL_ES_2
- ::glStencilOpSeparate(face, fail, zfail, zpass);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.StencilOpSeparate(face, fail, zfail, zpass);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform1f(GLint location, GLfloat x)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform1f(location, x);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform1f(location, x);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform1fv(location, count, v);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform1fv(location, count, v);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform1i(GLint location, GLint x)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform1i(location, x);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform1i(location, x);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform1iv(GLint location, GLsizei count, const GLint* v)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform1iv(location, count, v);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform1iv(location, count, v);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform2f(GLint location, GLfloat x, GLfloat y)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform2f(location, x, y);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform2f(location, x, y);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform2fv(location, count, v);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform2fv(location, count, v);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform2i(GLint location, GLint x, GLint y)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform2i(location, x, y);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform2i(location, x, y);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform2iv(GLint location, GLsizei count, const GLint* v)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform2iv(location, count, v);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform2iv(location, count, v);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform3f(location, x, y, z);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform3f(location, x, y, z);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform3fv(location, count, v);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform3fv(location, count, v);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform3i(GLint location, GLint x, GLint y, GLint z)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform3i(location, x, y, z);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform3i(location, x, y, z);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform3iv(GLint location, GLsizei count, const GLint* v)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform3iv(location, count, v);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform3iv(location, count, v);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform4f(location, x, y, z, w);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform4f(location, x, y, z, w);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform4fv(location, count, v);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform4fv(location, count, v);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform4i(location, x, y, z, w);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform4i(location, x, y, z, w);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniform4iv(GLint location, GLsizei count, const GLint* v)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniform4iv(location, count, v);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.Uniform4iv(location, count, v);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniformMatrix2fv(location, count, transpose, value);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.UniformMatrix2fv(location, count, transpose, value);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniformMatrix3fv(location, count, transpose, value);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.UniformMatrix3fv(location, count, transpose, value);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
{
-#ifdef QT_OPENGL_ES_2
- ::glUniformMatrix4fv(location, count, transpose, value);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.UniformMatrix4fv(location, count, transpose, value);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glUseProgram(GLuint program)
{
-#ifdef QT_OPENGL_ES_2
- ::glUseProgram(program);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.UseProgram(program);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glValidateProgram(GLuint program)
{
-#ifdef QT_OPENGL_ES_2
- ::glValidateProgram(program);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.ValidateProgram(program);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glVertexAttrib1f(GLuint indx, GLfloat x)
{
-#ifdef QT_OPENGL_ES_2
- ::glVertexAttrib1f(indx, x);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.VertexAttrib1f(indx, x);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glVertexAttrib1fv(GLuint indx, const GLfloat* values)
{
-#ifdef QT_OPENGL_ES_2
- ::glVertexAttrib1fv(indx, values);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.VertexAttrib1fv(indx, values);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
{
-#ifdef QT_OPENGL_ES_2
- ::glVertexAttrib2f(indx, x, y);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.VertexAttrib2f(indx, x, y);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glVertexAttrib2fv(GLuint indx, const GLfloat* values)
{
-#ifdef QT_OPENGL_ES_2
- ::glVertexAttrib2fv(indx, values);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.VertexAttrib2fv(indx, values);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
{
-#ifdef QT_OPENGL_ES_2
- ::glVertexAttrib3f(indx, x, y, z);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.VertexAttrib3f(indx, x, y, z);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glVertexAttrib3fv(GLuint indx, const GLfloat* values)
{
-#ifdef QT_OPENGL_ES_2
- ::glVertexAttrib3fv(indx, values);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.VertexAttrib3fv(indx, values);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
-#ifdef QT_OPENGL_ES_2
- ::glVertexAttrib4f(indx, x, y, z, w);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.VertexAttrib4f(indx, x, y, z, w);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glVertexAttrib4fv(GLuint indx, const GLfloat* values)
{
-#ifdef QT_OPENGL_ES_2
- ::glVertexAttrib4fv(indx, values);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.VertexAttrib4fv(indx, values);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
inline void QOpenGLFunctions::glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
{
-#ifdef QT_OPENGL_ES_2
- ::glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
-#else
Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr));
d_ptr->f.VertexAttribPointer(indx, size, type, normalized, stride, ptr);
-#endif
Q_OPENGL_FUNCTIONS_DEBUG
}
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index 90652a5ab8..aeb4fc0b7a 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -99,6 +99,12 @@ QOpenGL2PaintEngineExPrivate::~QOpenGL2PaintEngineExPrivate()
{
delete shaderManager;
+ vertexBuffer.destroy();
+ texCoordBuffer.destroy();
+ opacityBuffer.destroy();
+ indexBuffer.destroy();
+ vao.destroy();
+
if (elementIndicesVBOId != 0) {
funcs.glDeleteBuffers(1, &elementIndicesVBOId);
elementIndicesVBOId = 0;
@@ -578,6 +584,12 @@ void QOpenGL2PaintEngineExPrivate::drawTexture(const QOpenGLRect& dest, const QO
setCoords(staticVertexCoordinateArray, dest);
setCoords(staticTextureCoordinateArray, srcTextureRect);
+ setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
+ setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true);
+
+ uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8);
+ uploadData(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray, 8);
+
funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
@@ -664,6 +676,11 @@ void QOpenGL2PaintEngineExPrivate::resetGLState()
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
funcs.glVertexAttrib4fv(3, color);
}
+ if (vao.isCreated()) {
+ vao.release();
+ funcs.glBindBuffer(GL_ARRAY_BUFFER, 0);
+ funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
}
void QOpenGL2PaintEngineEx::endNativePainting()
@@ -696,16 +713,16 @@ void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
}
if (newMode == ImageDrawingMode) {
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
- setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray);
+ uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8);
+ uploadData(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray, 8);
}
if (newMode == ImageArrayDrawingMode || newMode == ImageOpacityArrayDrawingMode) {
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
- setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
+ uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data(), vertexCoordinateArray.vertexCount() * 2);
+ uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data(), textureCoordinateArray.vertexCount() * 2);
if (newMode == ImageOpacityArrayDrawingMode)
- setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data());
+ uploadData(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data(), opacityArray.size());
}
// This needs to change when we implement high-quality anti-aliasing...
@@ -761,6 +778,8 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
if (matrixDirty)
updateMatrix();
+ const bool supportsElementIndexUint = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint);
+
const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
// Check to see if there's any hints
@@ -824,9 +843,10 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
prepareForDraw(currentBrush.isOpaque());
#ifdef QT_OPENGL_CACHE_AS_VBOS
funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
+ uploadData(QT_VERTEX_COORD_ATTR, 0, cache->vertexCount);
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
#else
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
+ uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2);
#endif
funcs.glDrawArrays(cache->primitiveType, 0, cache->vertexCount);
@@ -881,7 +901,7 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
// Flatten the path at the current scale factor and fill it into the cache struct.
if (updateCache) {
- QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale));
+ QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint);
cache->vertexCount = polys.vertices.size() / 2;
cache->indexCount = polys.indices.size();
cache->primitiveType = GL_TRIANGLES;
@@ -920,6 +940,7 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
#ifdef QT_OPENGL_CACHE_AS_VBOS
funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo);
+ uploadData(QT_VERTEX_COORDS_ATTR, 0, cache->vertexCount);
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0);
if (cache->indexType == QVertexIndexVector::UnsignedInt)
funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0);
@@ -928,11 +949,10 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
funcs.glBindBuffer(GL_ARRAY_BUFFER, 0);
#else
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices);
- if (cache->indexType == QVertexIndexVector::UnsignedInt)
- funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, (qint32 *)cache->indices);
- else
- funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, (qint16 *)cache->indices);
+ uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2);
+ const GLenum indexValueType = cache->indexType == QVertexIndexVector::UnsignedInt ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
+ const bool useIndexVbo = uploadIndexData(cache->indices, indexValueType, cache->indexCount);
+ funcs.glDrawElements(cache->primitiveType, cache->indexCount, indexValueType, useIndexVbo ? nullptr : cache->indices);
#endif
} else {
@@ -950,18 +970,17 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
&& (bbox.top() > -0x8000 * inverseScale)
&& (bbox.bottom() < 0x8000 * inverseScale);
if (withinLimits) {
- QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale));
+ QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint);
QVarLengthArray<float> vertices(polys.vertices.size());
for (int i = 0; i < polys.vertices.size(); ++i)
vertices[i] = float(inverseScale * polys.vertices.at(i));
prepareForDraw(currentBrush.isOpaque());
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData());
- if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint))
- funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.data());
- else
- funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_SHORT, polys.indices.data());
+ uploadData(QT_VERTEX_COORDS_ATTR, vertices.constData(), vertices.size());
+ const GLenum indexValueType = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
+ const bool useIndexVbo = uploadIndexData(polys.indices.data(), indexValueType, polys.indices.size());
+ funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), indexValueType, useIndexVbo ? nullptr : polys.indices.data());
} else {
// We can't handle big, concave painter paths with OpenGL without stencil buffer.
qWarning("Painter path exceeds +/-32767 pixels.");
@@ -1083,7 +1102,8 @@ void QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
} else {
funcs.glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
}
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
+
+ uploadData(QT_VERTEX_COORDS_ATTR, data, count * 2);
funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
#endif
}
@@ -1213,7 +1233,8 @@ bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
void QOpenGL2PaintEngineExPrivate::composite(const QOpenGLRect& boundingRect)
{
setCoords(staticVertexCoordinateArray, boundingRect);
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray);
+
+ uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8);
funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
@@ -1222,16 +1243,12 @@ void QOpenGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stop
GLenum primitive)
{
// Now setup the pointer to the vertex array:
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data);
+ uploadData(QT_VERTEX_COORDS_ATTR, data, stops[stopCount-1] * 2);
int previousStop = 0;
for (int i=0; i<stopCount; ++i) {
int stop = stops[i];
-/*
- qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1);
- for (int i=previousStop; i<stop; ++i)
- qDebug(" %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
-*/
+
funcs.glDrawArrays(primitive, previousStop, stop - previousStop);
previousStop = stop;
}
@@ -1323,14 +1340,9 @@ void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &p
if (opaque) {
prepareForDraw(opaque);
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices());
- funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
-
-// QBrush b(Qt::green);
-// d->setBrush(&b);
-// d->prepareForDraw(true);
-// glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
+ uploadData(QT_VERTEX_COORDS_ATTR, stroker.vertices(), stroker.vertexCount());
+ funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
} else {
qreal width = qpen_widthf(pen) / 2;
if (width == 0)
@@ -1839,8 +1851,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
}
if (glyphFormat != QFontEngine::Format_ARGB || recreateVertexArrays) {
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data());
- setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data());
+ uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data(), vertexCoordinates->vertexCount() * 2);
+ uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data(), textureCoordinates->vertexCount() * 2);
}
if (!snapToPixelGrid) {
@@ -1904,7 +1916,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO)
funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0);
#else
- funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
+ const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs);
+ funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ? nullptr : elementIndices.data());
#endif
shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass2);
@@ -1955,7 +1968,8 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0);
funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#else
- funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data());
+ const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs);
+ funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ? nullptr : elementIndices.data());
#endif
}
@@ -2074,6 +2088,15 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
return false;
}
+ if (d->ctx != QOpenGLContext::currentContext()
+ || (d->ctx && QOpenGLContext::currentContext() && d->ctx->format() != QOpenGLContext::currentContext()->format())) {
+ d->vertexBuffer.destroy();
+ d->texCoordBuffer.destroy();
+ d->opacityBuffer.destroy();
+ d->indexBuffer.destroy();
+ d->vao.destroy();
+ }
+
d->ctx = QOpenGLContext::currentContext();
d->ctx->d_func()->active_engine = this;
@@ -2081,6 +2104,42 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev)
d->funcs.initializeOpenGLFunctions();
+ // Generate a new Vertex Array Object if we don't have one already. We can
+ // only hit the VAO-based path when using a core profile context. This is
+ // because while non-core contexts can support VAOs via extensions, legacy
+ // components like the QtOpenGL module do not know about VAOs. There are
+ // still tests for QGL-QOpenGL paint engine interoperability, so keep the
+ // status quo for now, and avoid introducing a VAO in non-core contexts.
+ const bool needsVAO = d->ctx->format().profile() == QSurfaceFormat::CoreProfile
+ && d->ctx->format().version() >= qMakePair(3, 2);
+ if (needsVAO && !d->vao.isCreated()) {
+ bool created = d->vao.create();
+
+ // If we managed to create it then we have a profile that supports VAOs
+ if (created) {
+ d->vao.bind();
+
+ // Generate a new Vertex Buffer Object if we don't have one already
+ if (!d->vertexBuffer.isCreated()) {
+ d->vertexBuffer.create();
+ // Set its usage to StreamDraw, we will use this buffer only a few times before refilling it
+ d->vertexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
+ }
+ if (!d->texCoordBuffer.isCreated()) {
+ d->texCoordBuffer.create();
+ d->texCoordBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
+ }
+ if (!d->opacityBuffer.isCreated()) {
+ d->opacityBuffer.create();
+ d->opacityBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
+ }
+ if (!d->indexBuffer.isCreated()) {
+ d->indexBuffer.create();
+ d->indexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
+ }
+ }
+ }
+
for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
d->vertexAttributeArraysEnabledState[i] = false;
@@ -2162,6 +2221,9 @@ void QOpenGL2PaintEngineEx::ensureActive()
Q_D(QOpenGL2PaintEngineEx);
QOpenGLContext *ctx = d->ctx;
+ if (d->vao.isCreated())
+ d->vao.bind();
+
if (isActive() && ctx->d_func()->active_engine != this) {
ctx->d_func()->active_engine = this;
d->needsSync = true;
diff --git a/src/gui/opengl/qopenglpaintengine_p.h b/src/gui/opengl/qopenglpaintengine_p.h
index 807efb1ec2..679b3c0557 100644
--- a/src/gui/opengl/qopenglpaintengine_p.h
+++ b/src/gui/opengl/qopenglpaintengine_p.h
@@ -65,6 +65,9 @@
#include <private/qopenglextensions_p.h>
+#include <QOpenGLVertexArrayObject>
+#include <QOpenGLBuffer>
+
enum EngineMode {
ImageDrawingMode,
TextDrawingMode,
@@ -193,7 +196,11 @@ public:
snapToPixelGrid(false),
nativePaintingActive(false),
inverseScale(1),
- lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT)
+ lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT),
+ vertexBuffer(QOpenGLBuffer::VertexBuffer),
+ texCoordBuffer(QOpenGLBuffer::VertexBuffer),
+ opacityBuffer(QOpenGLBuffer::VertexBuffer),
+ indexBuffer(QOpenGLBuffer::IndexBuffer)
{ }
~QOpenGL2PaintEngineExPrivate();
@@ -222,7 +229,8 @@ public:
void drawCachedGlyphs(QFontEngine::GlyphFormat glyphFormat, QStaticTextItem *staticTextItem);
// Calls glVertexAttributePointer if the pointer has changed
- inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer);
+ inline void uploadData(unsigned int arrayIndex, const GLfloat *data, GLuint count);
+ inline bool uploadIndexData(const void *data, GLenum indexValueType, GLuint count);
// draws whatever is in the vertex array:
void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive);
@@ -313,6 +321,12 @@ public:
GLenum lastTextureUnitUsed;
GLuint lastTextureUsed;
+ QOpenGLVertexArrayObject vao;
+ QOpenGLBuffer vertexBuffer;
+ QOpenGLBuffer texCoordBuffer;
+ QOpenGLBuffer opacityBuffer;
+ QOpenGLBuffer indexBuffer;
+
bool needsSync;
bool multisamplingAlwaysEnabled;
@@ -326,17 +340,55 @@ public:
};
-void QOpenGL2PaintEngineExPrivate::setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer)
+void QOpenGL2PaintEngineExPrivate::uploadData(unsigned int arrayIndex, const GLfloat *data, GLuint count)
{
Q_ASSERT(arrayIndex < 3);
- if (pointer == vertexAttribPointers[arrayIndex])
- return;
-
- vertexAttribPointers[arrayIndex] = pointer;
- if (arrayIndex == QT_OPACITY_ATTR)
- funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, pointer);
- else
- funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, pointer);
+
+ // If a vertex array object is created we have a profile that supports them
+ // and we will upload the data via a QOpenGLBuffer. Otherwise we will use
+ // the legacy way of uploading the data via glVertexAttribPointer.
+ if (vao.isCreated()) {
+ if (arrayIndex == QT_VERTEX_COORDS_ATTR) {
+ vertexBuffer.bind();
+ vertexBuffer.allocate(data, count * sizeof(float));
+ }
+ if (arrayIndex == QT_TEXTURE_COORDS_ATTR) {
+ texCoordBuffer.bind();
+ texCoordBuffer.allocate(data, count * sizeof(float));
+ }
+ if (arrayIndex == QT_OPACITY_ATTR) {
+ opacityBuffer.bind();
+ opacityBuffer.allocate(data, count * sizeof(float));
+ }
+ if (arrayIndex == QT_OPACITY_ATTR)
+ funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, 0);
+ else
+ funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, 0);
+ } else {
+ // If we already uploaded the data we don't have to do it again
+ if (data == vertexAttribPointers[arrayIndex])
+ return;
+
+ // Store the data in cache and upload it to the graphics card.
+ vertexAttribPointers[arrayIndex] = data;
+ if (arrayIndex == QT_OPACITY_ATTR)
+ funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, data);
+ else
+ funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, data);
+ }
+}
+
+bool QOpenGL2PaintEngineExPrivate::uploadIndexData(const void *data, GLenum indexValueType, GLuint count)
+{
+ // Follow the uploadData() logic: VBOs are used only when VAO support is available.
+ // Otherwise the legacy client-side pointer path is used.
+ if (vao.isCreated()) {
+ Q_ASSERT(indexValueType == GL_UNSIGNED_SHORT || indexValueType == GL_UNSIGNED_INT);
+ indexBuffer.bind();
+ indexBuffer.allocate(data, count * (indexValueType == GL_UNSIGNED_SHORT ? sizeof(quint16) : sizeof(quint32)));
+ return true;
+ }
+ return false;
}
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp
new file mode 100644
index 0000000000..06373e1113
--- /dev/null
+++ b/src/gui/opengl/qopenglprogrambinarycache.cpp
@@ -0,0 +1,376 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopenglprogrambinarycache_p.h"
+#include <QOpenGLContext>
+#include <QOpenGLExtraFunctions>
+#include <QStandardPaths>
+#include <QDir>
+#include <QSaveFile>
+#include <QLoggingCategory>
+
+#ifdef Q_OS_UNIX
+#include <sys/mman.h>
+#include <private/qcore_unix_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
+
+#ifndef GL_PROGRAM_BINARY_LENGTH
+#define GL_PROGRAM_BINARY_LENGTH 0x8741
+#endif
+
+const quint32 BINSHADER_MAGIC = 0x5174;
+const quint32 BINSHADER_VERSION = 0x2;
+const quint32 BINSHADER_QTVERSION = QT_VERSION;
+
+struct GLEnvInfo
+{
+ GLEnvInfo();
+
+ QByteArray glvendor;
+ QByteArray glrenderer;
+ QByteArray glversion;
+};
+
+GLEnvInfo::GLEnvInfo()
+{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ Q_ASSERT(ctx);
+ QOpenGLFunctions *f = ctx->functions();
+ const char *vendor = reinterpret_cast<const char *>(f->glGetString(GL_VENDOR));
+ const char *renderer = reinterpret_cast<const char *>(f->glGetString(GL_RENDERER));
+ const char *version = reinterpret_cast<const char *>(f->glGetString(GL_VERSION));
+ if (vendor)
+ glvendor = QByteArray(vendor);
+ if (renderer)
+ glrenderer = QByteArray(renderer);
+ if (version)
+ glversion = QByteArray(version);
+}
+
+static inline bool qt_ensureWritableDir(const QString &name)
+{
+ QDir::root().mkpath(name);
+ return QFileInfo(name).isWritable();
+}
+
+QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache()
+ : m_cacheWritable(false)
+{
+ const QString subPath = QLatin1String("/qtshadercache/");
+ const QString sharedCachePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
+ if (!sharedCachePath.isEmpty()) {
+ m_cacheDir = sharedCachePath + subPath;
+ m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
+ }
+ if (!m_cacheWritable) {
+ m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
+ m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
+ }
+ qCDebug(DBG_SHADER_CACHE, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
+}
+
+QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) const
+{
+ return m_cacheDir + QString::fromUtf8(cacheKey);
+}
+
+#define BASE_HEADER_SIZE (int(3 * sizeof(quint32)))
+#define FULL_HEADER_SIZE(stringsSize) (BASE_HEADER_SIZE + 12 + stringsSize + 8)
+#define PADDING_SIZE(fullHeaderSize) (((fullHeaderSize + 3) & ~3) - fullHeaderSize)
+
+static inline quint32 readUInt(const uchar **p)
+{
+ quint32 v;
+ memcpy(&v, *p, sizeof(quint32));
+ *p += sizeof(quint32);
+ return v;
+}
+
+static inline QByteArray readStr(const uchar **p)
+{
+ quint32 len = readUInt(p);
+ QByteArray ba = QByteArray::fromRawData(reinterpret_cast<const char *>(*p), len);
+ *p += len;
+ return ba;
+}
+
+bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const
+{
+ if (buf.size() < BASE_HEADER_SIZE) {
+ qCDebug(DBG_SHADER_CACHE, "Cached size too small");
+ return false;
+ }
+ const uchar *p = reinterpret_cast<const uchar *>(buf.constData());
+ if (readUInt(&p) != BINSHADER_MAGIC) {
+ qCDebug(DBG_SHADER_CACHE, "Magic does not match");
+ return false;
+ }
+ if (readUInt(&p) != BINSHADER_VERSION) {
+ qCDebug(DBG_SHADER_CACHE, "Version does not match");
+ return false;
+ }
+ if (readUInt(&p) != BINSHADER_QTVERSION) {
+ qCDebug(DBG_SHADER_CACHE, "Qt version does not match");
+ return false;
+ }
+ return true;
+}
+
+bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat, const void *p, uint blobSize)
+{
+ QOpenGLExtraFunctions *funcs = QOpenGLContext::currentContext()->extraFunctions();
+ while (funcs->glGetError() != GL_NO_ERROR) { }
+ funcs->glProgramBinary(programId, blobFormat, p, blobSize);
+ int err = funcs->glGetError();
+ qCDebug(DBG_SHADER_CACHE, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
+ programId, blobSize, blobFormat, err);
+ return err == 0;
+}
+
+#ifdef Q_OS_UNIX
+class FdWrapper
+{
+public:
+ FdWrapper(const QString &fn)
+ : ptr(MAP_FAILED)
+ {
+ fd = qt_safe_open(QFile::encodeName(fn).constData(), O_RDONLY);
+ }
+ ~FdWrapper()
+ {
+ if (ptr != MAP_FAILED)
+ munmap(ptr, mapSize);
+ if (fd != -1)
+ qt_safe_close(fd);
+ }
+ bool map()
+ {
+ off_t offs = lseek(fd, 0, SEEK_END);
+ if (offs == (off_t) -1) {
+ qErrnoWarning(errno, "lseek failed for program binary");
+ return false;
+ }
+ mapSize = static_cast<size_t>(offs);
+ ptr = mmap(nullptr, mapSize, PROT_READ, MAP_SHARED, fd, 0);
+ return ptr != MAP_FAILED;
+ }
+
+ int fd;
+ void *ptr;
+ size_t mapSize;
+};
+#endif
+
+class DeferredFileRemove
+{
+public:
+ DeferredFileRemove(const QString &fn)
+ : fn(fn),
+ active(false)
+ {
+ }
+ ~DeferredFileRemove()
+ {
+ if (active)
+ QFile(fn).remove();
+ }
+ void setActive()
+ {
+ active = true;
+ }
+
+ QString fn;
+ bool active;
+};
+
+bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId)
+{
+ if (m_memCache.contains(cacheKey)) {
+ const MemCacheEntry *e = m_memCache[cacheKey];
+ return setProgramBinary(programId, e->format, e->blob.constData(), e->blob.size());
+ }
+
+ QByteArray buf;
+ const QString fn = cacheFileName(cacheKey);
+ DeferredFileRemove undertaker(fn);
+#ifdef Q_OS_UNIX
+ FdWrapper fdw(fn);
+ if (fdw.fd == -1)
+ return false;
+ char header[BASE_HEADER_SIZE];
+ qint64 bytesRead = qt_safe_read(fdw.fd, header, BASE_HEADER_SIZE);
+ if (bytesRead == BASE_HEADER_SIZE)
+ buf = QByteArray::fromRawData(header, BASE_HEADER_SIZE);
+#else
+ QFile f(fn);
+ if (!f.open(QIODevice::ReadOnly))
+ return false;
+ buf = f.read(BASE_HEADER_SIZE);
+#endif
+
+ if (!verifyHeader(buf)) {
+ undertaker.setActive();
+ return false;
+ }
+
+ const uchar *p;
+#ifdef Q_OS_UNIX
+ if (!fdw.map()) {
+ undertaker.setActive();
+ return false;
+ }
+ p = static_cast<const uchar *>(fdw.ptr) + BASE_HEADER_SIZE;
+#else
+ buf = f.readAll();
+ p = reinterpret_cast<const uchar *>(buf.constData());
+#endif
+
+ GLEnvInfo info;
+
+ QByteArray vendor = readStr(&p);
+ if (vendor != info.glvendor) {
+ // readStr returns non-null terminated strings just pointing to inside
+ // 'p' so must print these via the stream qCDebug and not constData().
+ qCDebug(DBG_SHADER_CACHE) << "GL_VENDOR does not match" << vendor << info.glvendor;
+ undertaker.setActive();
+ return false;
+ }
+ QByteArray renderer = readStr(&p);
+ if (renderer != info.glrenderer) {
+ qCDebug(DBG_SHADER_CACHE) << "GL_RENDERER does not match" << renderer << info.glrenderer;
+ undertaker.setActive();
+ return false;
+ }
+ QByteArray version = readStr(&p);
+ if (version != info.glversion) {
+ qCDebug(DBG_SHADER_CACHE) << "GL_VERSION does not match" << version << info.glversion;
+ undertaker.setActive();
+ return false;
+ }
+
+ quint32 blobFormat = readUInt(&p);
+ quint32 blobSize = readUInt(&p);
+
+ p += PADDING_SIZE(FULL_HEADER_SIZE(vendor.size() + renderer.size() + version.size()));
+
+ return setProgramBinary(programId, blobFormat, p, blobSize)
+ && m_memCache.insert(cacheKey, new MemCacheEntry(p, blobSize, blobFormat));
+}
+
+static inline void writeUInt(uchar **p, quint32 value)
+{
+ memcpy(*p, &value, sizeof(quint32));
+ *p += sizeof(quint32);
+}
+
+static inline void writeStr(uchar **p, const QByteArray &str)
+{
+ writeUInt(p, str.size());
+ memcpy(*p, str.constData(), str.size());
+ *p += str.size();
+}
+
+void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
+{
+ if (!m_cacheWritable)
+ return;
+
+ GLEnvInfo info;
+
+ QOpenGLExtraFunctions *funcs = QOpenGLContext::currentContext()->extraFunctions();
+ GLint blobSize = 0;
+ while (funcs->glGetError() != GL_NO_ERROR) { }
+ funcs->glGetProgramiv(programId, GL_PROGRAM_BINARY_LENGTH, &blobSize);
+
+ const int headerSize = FULL_HEADER_SIZE(info.glvendor.size() + info.glrenderer.size() + info.glversion.size());
+
+ // Add padding to make the blob start 4-byte aligned in order to support
+ // OpenGL implementations on ARM that choke on non-aligned pointers passed
+ // to glProgramBinary.
+ const int paddingSize = PADDING_SIZE(headerSize);
+
+ const int totalSize = headerSize + paddingSize + blobSize;
+
+ qCDebug(DBG_SHADER_CACHE, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
+ if (!blobSize)
+ return;
+
+ QByteArray blob(totalSize, Qt::Uninitialized);
+ uchar *p = reinterpret_cast<uchar *>(blob.data());
+
+ writeUInt(&p, BINSHADER_MAGIC);
+ writeUInt(&p, BINSHADER_VERSION);
+ writeUInt(&p, BINSHADER_QTVERSION);
+
+ writeStr(&p, info.glvendor);
+ writeStr(&p, info.glrenderer);
+ writeStr(&p, info.glversion);
+
+ quint32 blobFormat = 0;
+ uchar *blobFormatPtr = p;
+ writeUInt(&p, blobFormat);
+ writeUInt(&p, blobSize);
+
+ for (int i = 0; i < paddingSize; ++i)
+ *p++ = 0;
+
+ GLint outSize = 0;
+ funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p);
+ if (blobSize != outSize) {
+ qCDebug(DBG_SHADER_CACHE, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
+ return;
+ }
+
+ writeUInt(&blobFormatPtr, blobFormat);
+
+ QSaveFile f(cacheFileName(cacheKey));
+ if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ f.write(blob);
+ if (!f.commit())
+ qCDebug(DBG_SHADER_CACHE, "Failed to write %s to shader cache", qPrintable(f.fileName()));
+ } else {
+ qCDebug(DBG_SHADER_CACHE, "Failed to create %s in shader cache", qPrintable(f.fileName()));
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglprogrambinarycache_p.h b/src/gui/opengl/qopenglprogrambinarycache_p.h
new file mode 100644
index 0000000000..a0e1f91e25
--- /dev/null
+++ b/src/gui/opengl/qopenglprogrambinarycache_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPENGLPROGRAMBINARYCACHE_P_H
+#define QOPENGLPROGRAMBINARYCACHE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qtguiglobal.h>
+#include <QtGui/qopenglshaderprogram.h>
+#include <QtCore/qcache.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLProgramBinaryCache
+{
+public:
+ struct ShaderDesc {
+ ShaderDesc() { }
+ ShaderDesc(QOpenGLShader::ShaderType type, const QByteArray &source = QByteArray())
+ : type(type), source(source)
+ { }
+ QOpenGLShader::ShaderType type;
+ QByteArray source;
+ };
+ struct ProgramDesc {
+ QVector<ShaderDesc> shaders;
+ };
+
+ QOpenGLProgramBinaryCache();
+
+ bool load(const QByteArray &cacheKey, uint programId);
+ void save(const QByteArray &cacheKey, uint programId);
+
+private:
+ QString cacheFileName(const QByteArray &cacheKey) const;
+ bool verifyHeader(const QByteArray &buf) const;
+ bool setProgramBinary(uint programId, uint blobFormat, const void *p, uint blobSize);
+
+ QString m_cacheDir;
+ bool m_cacheWritable;
+ struct MemCacheEntry {
+ MemCacheEntry(const void *p, int size, uint format)
+ : blob(reinterpret_cast<const char *>(p), size),
+ format(format)
+ { }
+ QByteArray blob;
+ uint format;
+ };
+ QCache<QByteArray, MemCacheEntry> m_memCache;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp
index cd582c5285..cc8af16bfe 100644
--- a/src/gui/opengl/qopenglshaderprogram.cpp
+++ b/src/gui/opengl/qopenglshaderprogram.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qopenglshaderprogram.h"
+#include "qopenglprogrambinarycache_p.h"
#include "qopenglfunctions.h"
#include "private/qopenglcontext_p.h"
#include <QtCore/private/qobject_p.h>
@@ -46,6 +47,9 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
#include <QtCore/qregularexpression.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qcryptographichash.h>
+#include <QtCore/qcoreapplication.h>
#include <QtGui/qtransform.h>
#include <QtGui/QColor>
#include <QtGui/QSurfaceFormat>
@@ -127,6 +131,20 @@ QT_BEGIN_NAMESPACE
on the shader program. The shader program's id can be explicitly
created using the create() function.
+ \section2 Caching Program Binaries
+
+ As of Qt 5.9, support for caching program binaries on disk is built in. To
+ enable this, switch to using addCacheableShaderFromSourceCode() and
+ addCacheableShaderFromSourceFile(). With an OpenGL ES 3.x context or support
+ for \c{GL_ARB_get_program_binary}, this will transparently cache program
+ binaries under QStandardPaths::GenericCacheLocation or
+ QStandardPaths::CacheLocation. When support is not available, calling the
+ cacheable function variants is equivalent to the normal ones.
+
+ \note Some drivers do not have any binary formats available, even though
+ they advertise the extension or offer OpenGL ES 3.0. In this case program
+ binary support will be disabled.
+
\sa QOpenGLShader
*/
@@ -162,6 +180,86 @@ QT_BEGIN_NAMESPACE
based on the core feature (requires OpenGL >= 4.3).
*/
+Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
+
+// For GLES 3.1/3.2
+#ifndef GL_GEOMETRY_SHADER
+#define GL_GEOMETRY_SHADER 0x8DD9
+#endif
+#ifndef GL_TESS_CONTROL_SHADER
+#define GL_TESS_CONTROL_SHADER 0x8E88
+#endif
+#ifndef GL_TESS_EVALUATION_SHADER
+#define GL_TESS_EVALUATION_SHADER 0x8E87
+#endif
+#ifndef GL_COMPUTE_SHADER
+#define GL_COMPUTE_SHADER 0x91B9
+#endif
+#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
+#endif
+#ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
+#endif
+#ifndef GL_PATCH_VERTICES
+#define GL_PATCH_VERTICES 0x8E72
+#endif
+#ifndef GL_PATCH_DEFAULT_OUTER_LEVEL
+#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74
+#endif
+#ifndef GL_PATCH_DEFAULT_INNER_LEVEL
+#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
+#endif
+
+#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
+#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
+#endif
+
+#ifndef QT_OPENGL_ES_2
+static inline bool isFormatGLES(const QSurfaceFormat &f)
+{
+ return (f.renderableType() == QSurfaceFormat::OpenGLES);
+}
+#endif
+
+static inline bool supportsGeometry(const QSurfaceFormat &f)
+{
+#ifndef QT_OPENGL_ES_2
+ if (!isFormatGLES(f))
+ return (f.version() >= qMakePair<int, int>(3, 2));
+ else
+ return false;
+#else
+ Q_UNUSED(f);
+ return false;
+#endif
+}
+
+static inline bool supportsCompute(const QSurfaceFormat &f)
+{
+#ifndef QT_OPENGL_ES_2
+ if (!isFormatGLES(f))
+ return (f.version() >= qMakePair<int, int>(4, 3));
+ else
+ return (f.version() >= qMakePair<int, int>(3, 1));
+#else
+ return (f.version() >= qMakePair<int, int>(3, 1));
+#endif
+}
+
+static inline bool supportsTessellation(const QSurfaceFormat &f)
+{
+#ifndef QT_OPENGL_ES_2
+ if (!isFormatGLES(f))
+ return (f.version() >= qMakePair<int, int>(4, 0));
+ else
+ return false;
+#else
+ Q_UNUSED(f);
+ return false;
+#endif
+}
+
class QOpenGLShaderPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QOpenGLShader)
@@ -171,22 +269,16 @@ public:
, shaderType(type)
, compiled(false)
, glfuncs(new QOpenGLFunctions(ctx))
-#ifndef QT_OPENGL_ES_2
, supportsGeometryShaders(false)
, supportsTessellationShaders(false)
-#endif
+ , supportsComputeShaders(false)
{
-#ifndef QT_OPENGL_ES_2
- if (!ctx->isOpenGLES()) {
- QSurfaceFormat f = ctx->format();
-
- // Geometry shaders require OpenGL >= 3.2
- if (shaderType & QOpenGLShader::Geometry)
- supportsGeometryShaders = (f.version() >= qMakePair<int, int>(3, 2));
- else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation))
- supportsTessellationShaders = (f.version() >= qMakePair<int, int>(4, 0));
- }
-#endif
+ if (shaderType & QOpenGLShader::Geometry)
+ supportsGeometryShaders = supportsGeometry(ctx->format());
+ else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation))
+ supportsTessellationShaders = supportsTessellation(ctx->format());
+ else if (shaderType & QOpenGLShader::Compute)
+ supportsComputeShaders = supportsCompute(ctx->format());
}
~QOpenGLShaderPrivate();
@@ -197,13 +289,13 @@ public:
QOpenGLFunctions *glfuncs;
-#ifndef QT_OPENGL_ES_2
// Support for geometry shaders
bool supportsGeometryShaders;
-
// Support for tessellation shaders
bool supportsTessellationShaders;
-#endif
+ // Support for compute shaders
+ bool supportsComputeShaders;
+
bool create();
bool compile(QOpenGLShader *q);
@@ -229,24 +321,18 @@ bool QOpenGLShaderPrivate::create()
QOpenGLContext *context = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
if (!context)
return false;
- GLuint shader;
+ GLuint shader = 0;
if (shaderType == QOpenGLShader::Vertex) {
shader = glfuncs->glCreateShader(GL_VERTEX_SHADER);
-#if defined(QT_OPENGL_3_2)
} else if (shaderType == QOpenGLShader::Geometry && supportsGeometryShaders) {
shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER);
-#endif
-#if defined(QT_OPENGL_4)
} else if (shaderType == QOpenGLShader::TessellationControl && supportsTessellationShaders) {
shader = glfuncs->glCreateShader(GL_TESS_CONTROL_SHADER);
} else if (shaderType == QOpenGLShader::TessellationEvaluation && supportsTessellationShaders) {
shader = glfuncs->glCreateShader(GL_TESS_EVALUATION_SHADER);
-#endif
-#if defined(QT_OPENGL_4_3)
- } else if (shaderType == QOpenGLShader::Compute) {
+ } else if (shaderType == QOpenGLShader::Compute && supportsComputeShaders) {
shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER);
-#endif
- } else {
+ } else if (shaderType == QOpenGLShader::Fragment) {
shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER);
}
if (!shader) {
@@ -710,6 +796,7 @@ public:
#ifndef QT_OPENGL_ES_2
, tessellationFuncs(0)
#endif
+ , linkBinaryRecursion(false)
{
}
~QOpenGLShaderProgramPrivate();
@@ -731,6 +818,13 @@ public:
#endif
bool hasShader(QOpenGLShader::ShaderType type) const;
+
+ QOpenGLProgramBinaryCache::ProgramDesc binaryProgram;
+ bool isCacheDisabled() const;
+ bool compileCacheable();
+ bool linkBinary();
+
+ bool linkBinaryRecursion;
};
namespace {
@@ -962,6 +1056,139 @@ bool QOpenGLShaderProgram::addShaderFromSourceFile
}
/*!
+ Registers the shader of the specified \a type and \a source to this
+ program. Unlike addShaderFromSourceCode(), this function does not perform
+ compilation. Compilation is deferred to link(), and may not happen at all,
+ because link() may potentially use a program binary from Qt's shader disk
+ cache. This will typically lead to a significant increase in performance.
+
+ \return true if the shader has been registered or, in the non-cached case,
+ compiled successfully; false if there was an error. The compilation error
+ messages can be retrieved via log().
+
+ When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for
+ example, or the OpenGL context has no support for context binaries, calling
+ this function is equivalent to addShaderFromSourceCode().
+
+ \since 5.9
+ \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile()
+ */
+bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source)
+{
+ Q_D(QOpenGLShaderProgram);
+ if (!init())
+ return false;
+ if (d->isCacheDisabled())
+ return addShaderFromSourceCode(type, source);
+
+ return addCacheableShaderFromSourceCode(type, QByteArray(source));
+}
+
+/*!
+ \overload
+
+ Registers the shader of the specified \a type and \a source to this
+ program. Unlike addShaderFromSourceCode(), this function does not perform
+ compilation. Compilation is deferred to link(), and may not happen at all,
+ because link() may potentially use a program binary from Qt's shader disk
+ cache. This will typically lead to a significant increase in performance.
+
+ \return true if the shader has been registered or, in the non-cached case,
+ compiled successfully; false if there was an error. The compilation error
+ messages can be retrieved via log().
+
+ When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for
+ example, or the OpenGL context has no support for context binaries, calling
+ this function is equivalent to addShaderFromSourceCode().
+
+ \since 5.9
+ \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile()
+ */
+bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray &source)
+{
+ Q_D(QOpenGLShaderProgram);
+ if (!init())
+ return false;
+ if (d->isCacheDisabled())
+ return addShaderFromSourceCode(type, source);
+
+ d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(type, source));
+ return true;
+}
+
+/*!
+ \overload
+
+ Registers the shader of the specified \a type and \a source to this
+ program. Unlike addShaderFromSourceCode(), this function does not perform
+ compilation. Compilation is deferred to link(), and may not happen at all,
+ because link() may potentially use a program binary from Qt's shader disk
+ cache. This will typically lead to a significant increase in performance.
+
+ When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for
+ example, or the OpenGL context has no support for context binaries, calling
+ this function is equivalent to addShaderFromSourceCode().
+
+ \since 5.9
+ \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile()
+ */
+bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString &source)
+{
+ Q_D(QOpenGLShaderProgram);
+ if (!init())
+ return false;
+ if (d->isCacheDisabled())
+ return addShaderFromSourceCode(type, source);
+
+ return addCacheableShaderFromSourceCode(type, source.toUtf8().constData());
+}
+
+/*!
+ Registers the shader of the specified \a type and \a fileName to this
+ program. Unlike addShaderFromSourceFile(), this function does not perform
+ compilation. Compilation is deferred to link(), and may not happen at all,
+ because link() may potentially use a program binary from Qt's shader disk
+ cache. This will typically lead to a significant increase in performance.
+
+ \return true if the file has been read successfully, false if the file could
+ not be opened or the normal, non-cached compilation of the shader has
+ failed. The compilation error messages can be retrieved via log().
+
+ When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for
+ example, or the OpenGL context has no support for context binaries, calling
+ this function is equivalent to addShaderFromSourceFile().
+
+ \since 5.9
+ \sa addShaderFromSourceFile(), addCacheableShaderFromSourceCode()
+ */
+bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString &fileName)
+{
+ Q_D(QOpenGLShaderProgram);
+ if (!init())
+ return false;
+ if (d->isCacheDisabled())
+ return addShaderFromSourceFile(type, fileName);
+
+ QOpenGLProgramBinaryCache::ShaderDesc shader(type);
+ // NB! It could be tempting to defer reading the file contents and just
+ // hash the filename as the cache key, perhaps combined with last-modified
+ // timestamp checks. However, this would raise a number of issues (no
+ // timestamps for files in the resource system; preference for global, not
+ // per-application cache items (where filenames may clash); resource-based
+ // shaders from libraries like Qt Quick; etc.), so just avoid it.
+ QFile f(fileName);
+ if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ shader.source = f.readAll();
+ f.close();
+ } else {
+ qWarning("QOpenGLShaderProgram: Unable to open file %s", qPrintable(fileName));
+ return false;
+ }
+ d->binaryProgram.shaders.append(shader);
+ return true;
+}
+
+/*!
Removes \a shader from this shader program. The object is not deleted.
The shader program must be valid in the current QOpenGLContext.
@@ -1019,6 +1246,7 @@ void QOpenGLShaderProgram::removeAllShaders()
qDeleteAll(d->anonShaders);
d->shaders.clear();
d->anonShaders.clear();
+ d->binaryProgram = QOpenGLProgramBinaryCache::ProgramDesc();
d->linked = false; // Program needs to be relinked.
d->removingShaders = false;
}
@@ -1035,6 +1263,16 @@ void QOpenGLShaderProgram::removeAllShaders()
If the shader program was already linked, calling this
function again will force it to be re-linked.
+ When shaders were added to this program via
+ addCacheableShaderFromSourceCode() or addCacheableShaderFromSourceFile(),
+ program binaries are supported, and a cached binary is available on disk,
+ actual compilation and linking are skipped. Instead, link() will initialize
+ the program with the binary blob via glProgramBinary(). If there is no
+ cached version of the program or it was generated with a different driver
+ version, the shaders will be compiled from source and the program will get
+ linked normally. This allows seamless upgrading of the graphics drivers,
+ without having to worry about potentially incompatible binary formats.
+
\sa addShader(), log()
*/
bool QOpenGLShaderProgram::link()
@@ -1044,12 +1282,17 @@ bool QOpenGLShaderProgram::link()
if (!program)
return false;
+ if (!d->linkBinaryRecursion && d->shaders.isEmpty() && !d->binaryProgram.shaders.isEmpty())
+ return d->linkBinary();
+
GLint value;
if (d->shaders.isEmpty()) {
// If there are no explicit shaders, then it is possible that the
- // application added a program binary with glProgramBinaryOES(),
- // or otherwise populated the shaders itself. Check to see if the
- // program is already linked and bail out if so.
+ // application added a program binary with glProgramBinaryOES(), or
+ // otherwise populated the shaders itself. This is also the case when
+ // we are recursively called back from linkBinary() after a successful
+ // glProgramBinary(). Check to see if the program is already linked and
+ // bail out if so.
value = 0;
d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value);
d->linked = (value != 0);
@@ -1069,7 +1312,7 @@ bool QOpenGLShaderProgram::link()
GLint len;
d->glfuncs->glGetProgramInfoLog(program, value, &len, logbuf);
d->log = QString::fromLatin1(logbuf);
- if (!d->linked) {
+ if (!d->linked && !d->linkBinaryRecursion) {
QString name = objectName();
if (name.isEmpty())
qWarning("QOpenGLShader::link: %ls", qUtf16Printable(d->log));
@@ -3230,10 +3473,8 @@ void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4
int QOpenGLShaderProgram::maxGeometryOutputVertices() const
{
GLint n = 0;
-#if defined(QT_OPENGL_3_2)
Q_D(const QOpenGLShaderProgram);
d->glfuncs->glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n);
-#endif
return n;
}
@@ -3257,7 +3498,7 @@ int QOpenGLShaderProgram::maxGeometryOutputVertices() const
*/
void QOpenGLShaderProgram::setPatchVertexCount(int count)
{
-#if defined(QT_OPENGL_4)
+#ifndef QT_OPENGL_ES_2
Q_D(QOpenGLShaderProgram);
if (d->tessellationFuncs)
d->tessellationFuncs->glPatchParameteri(GL_PATCH_VERTICES, count);
@@ -3276,13 +3517,15 @@ void QOpenGLShaderProgram::setPatchVertexCount(int count)
*/
int QOpenGLShaderProgram::patchVertexCount() const
{
+#ifndef QT_OPENGL_ES_2
int patchVertices = 0;
-#if defined(QT_OPENGL_4)
Q_D(const QOpenGLShaderProgram);
if (d->tessellationFuncs)
d->tessellationFuncs->glGetIntegerv(GL_PATCH_VERTICES, &patchVertices);
-#endif
return patchVertices;
+#else
+ return 0;
+#endif
}
/*!
@@ -3304,21 +3547,21 @@ int QOpenGLShaderProgram::patchVertexCount() const
*/
void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float> &levels)
{
-#if defined(QT_OPENGL_4)
- QVector<float> tessLevels = levels;
-
- // Ensure we have the required 4 outer tessellation levels
- // Use default of 1 for missing entries (same as spec)
- const int argCount = 4;
- if (tessLevels.size() < argCount) {
- tessLevels.reserve(argCount);
- for (int i = tessLevels.size(); i < argCount; ++i)
- tessLevels.append(1.0f);
- }
-
+#ifndef QT_OPENGL_ES_2
Q_D(QOpenGLShaderProgram);
- if (d->tessellationFuncs)
+ if (d->tessellationFuncs) {
+ QVector<float> tessLevels = levels;
+
+ // Ensure we have the required 4 outer tessellation levels
+ // Use default of 1 for missing entries (same as spec)
+ const int argCount = 4;
+ if (tessLevels.size() < argCount) {
+ tessLevels.reserve(argCount);
+ for (int i = tessLevels.size(); i < argCount; ++i)
+ tessLevels.append(1.0f);
+ }
d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data());
+ }
#else
Q_UNUSED(levels);
#endif
@@ -3341,13 +3584,15 @@ void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float
*/
QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const
{
+#ifndef QT_OPENGL_ES_2
QVector<float> tessLevels(4, 1.0f);
-#if defined(QT_OPENGL_4)
Q_D(const QOpenGLShaderProgram);
if (d->tessellationFuncs)
d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data());
-#endif
return tessLevels;
+#else
+ return QVector<float>();
+#endif
}
/*!
@@ -3369,21 +3614,21 @@ QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const
*/
void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float> &levels)
{
-#if defined(QT_OPENGL_4)
- QVector<float> tessLevels = levels;
-
- // Ensure we have the required 2 inner tessellation levels
- // Use default of 1 for missing entries (same as spec)
- const int argCount = 2;
- if (tessLevels.size() < argCount) {
- tessLevels.reserve(argCount);
- for (int i = tessLevels.size(); i < argCount; ++i)
- tessLevels.append(1.0f);
- }
-
+#ifndef QT_OPENGL_ES_2
Q_D(QOpenGLShaderProgram);
- if (d->tessellationFuncs)
+ if (d->tessellationFuncs) {
+ QVector<float> tessLevels = levels;
+
+ // Ensure we have the required 2 inner tessellation levels
+ // Use default of 1 for missing entries (same as spec)
+ const int argCount = 2;
+ if (tessLevels.size() < argCount) {
+ tessLevels.reserve(argCount);
+ for (int i = tessLevels.size(); i < argCount; ++i)
+ tessLevels.append(1.0f);
+ }
d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data());
+ }
#else
Q_UNUSED(levels);
#endif
@@ -3406,13 +3651,15 @@ void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float
*/
QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const
{
+#ifndef QT_OPENGL_ES_2
QVector<float> tessLevels(2, 1.0f);
-#if defined(QT_OPENGL_4)
Q_D(const QOpenGLShaderProgram);
if (d->tessellationFuncs)
d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data());
-#endif
return tessLevels;
+#else
+ return QVector<float>();
+#endif
}
@@ -3425,16 +3672,11 @@ QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const
*/
bool QOpenGLShaderProgram::hasOpenGLShaderPrograms(QOpenGLContext *context)
{
-#if !defined(QT_OPENGL_ES_2)
if (!context)
context = QOpenGLContext::currentContext();
if (!context)
return false;
return QOpenGLFunctions(context).hasOpenGLFeature(QOpenGLFunctions::Shaders);
-#else
- Q_UNUSED(context);
- return true;
-#endif
}
/*!
@@ -3465,37 +3707,148 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context)
if ((type & ~(Geometry | Vertex | Fragment | TessellationControl | TessellationEvaluation | Compute)) || type == 0)
return false;
- QSurfaceFormat format = context->format();
- if (type == Geometry) {
-#ifndef QT_OPENGL_ES_2
- // Geometry shaders require OpenGL 3.2 or newer
- QSurfaceFormat format = context->format();
- return (!context->isOpenGLES())
- && (format.version() >= qMakePair<int, int>(3, 2));
-#else
- // No geometry shader support in OpenGL ES2
- return false;
-#endif
- } else if (type == TessellationControl || type == TessellationEvaluation) {
-#if !defined(QT_OPENGL_ES_2)
- return (!context->isOpenGLES())
- && (format.version() >= qMakePair<int, int>(4, 0));
-#else
- // No tessellation shader support in OpenGL ES2
- return false;
-#endif
- } else if (type == Compute) {
-#if defined(QT_OPENGL_4_3)
- return (format.version() >= qMakePair<int, int>(4, 3));
-#else
- // No compute shader support without OpenGL 4.3 or newer
- return false;
-#endif
- }
+ if (type & QOpenGLShader::Geometry)
+ return supportsGeometry(context->format());
+ else if (type & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation))
+ return supportsTessellation(context->format());
+ else if (type & QOpenGLShader::Compute)
+ return supportsCompute(context->format());
// Unconditional support of vertex and fragment shaders implicitly assumes
// a minimum OpenGL version of 2.0
return true;
}
+// While unlikely, one application can in theory use contexts with different versions
+// or profiles. Therefore any version- or extension-specific checks must be done on a
+// per-context basis, not just once per process. QOpenGLSharedResource enables this,
+// although it's once-per-sharing-context-group, not per-context. Still, this should
+// be good enough in practice.
+class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
+{
+public:
+ QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
+ void invalidateResource() override { }
+ void freeResource(QOpenGLContext *) override { }
+
+ bool isSupported() const { return m_supported; }
+
+private:
+ bool m_supported;
+};
+
+QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
+ : QOpenGLSharedResource(context->shareGroup()),
+ m_supported(false)
+{
+ if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
+ qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via app attribute");
+ return;
+ }
+ if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
+ qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via env var");
+ return;
+ }
+
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (ctx) {
+ if (ctx->isOpenGLES()) {
+ qCDebug(DBG_SHADER_CACHE, "OpenGL ES v%d context", ctx->format().majorVersion());
+ if (ctx->format().majorVersion() >= 3)
+ m_supported = true;
+ } else {
+ const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
+ qCDebug(DBG_SHADER_CACHE, "GL_ARB_get_program_binary support = %d", hasExt);
+ if (hasExt)
+ m_supported = true;
+ }
+ if (m_supported) {
+ GLint fmtCount = 0;
+ ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
+ qCDebug(DBG_SHADER_CACHE, "Supported binary format count = %d", fmtCount);
+ m_supported = fmtCount > 0;
+ }
+ }
+ qCDebug(DBG_SHADER_CACHE, "Shader cache supported = %d", m_supported);
+}
+
+class QOpenGLProgramBinarySupportCheckWrapper
+{
+public:
+ QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
+ {
+ return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
+ }
+
+private:
+ QOpenGLMultiGroupSharedResource m_resource;
+};
+
+bool QOpenGLShaderProgramPrivate::isCacheDisabled() const
+{
+ static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck;
+ return !binSupportCheck.get(QOpenGLContext::currentContext())->isSupported();
+}
+
+bool QOpenGLShaderProgramPrivate::compileCacheable()
+{
+ Q_Q(QOpenGLShaderProgram);
+ for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) {
+ QScopedPointer<QOpenGLShader> s(new QOpenGLShader(shader.type, q));
+ if (!s->compileSourceCode(shader.source)) {
+ log = s->log();
+ return false;
+ }
+ anonShaders.append(s.take());
+ if (!q->addShader(anonShaders.last()))
+ return false;
+ }
+ return true;
+}
+
+bool QOpenGLShaderProgramPrivate::linkBinary()
+{
+ static QOpenGLProgramBinaryCache binCache;
+
+ Q_Q(QOpenGLShaderProgram);
+
+ QCryptographicHash keyBuilder(QCryptographicHash::Sha1);
+ for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders))
+ keyBuilder.addData(shader.source);
+
+ const QByteArray cacheKey = keyBuilder.result().toHex();
+ if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg))
+ qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s",
+ binaryProgram.shaders.count(), cacheKey.constData());
+
+ bool needsCompile = true;
+ if (binCache.load(cacheKey, q->programId())) {
+ qCDebug(DBG_SHADER_CACHE, "Program binary received from cache");
+ linkBinaryRecursion = true;
+ bool ok = q->link();
+ linkBinaryRecursion = false;
+ if (ok)
+ needsCompile = false;
+ else
+ qCDebug(DBG_SHADER_CACHE, "Link failed after glProgramBinary");
+ }
+
+ bool needsSave = false;
+ if (needsCompile) {
+ qCDebug(DBG_SHADER_CACHE, "Program binary not in cache, compiling");
+ if (compileCacheable())
+ needsSave = true;
+ else
+ return false;
+ }
+
+ linkBinaryRecursion = true;
+ bool ok = q->link();
+ linkBinaryRecursion = false;
+ if (ok && needsSave)
+ binCache.save(cacheKey, q->programId());
+
+ return ok;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglshaderprogram.h b/src/gui/opengl/qopenglshaderprogram.h
index 2da359c535..fd4d82ecf9 100644
--- a/src/gui/opengl/qopenglshaderprogram.h
+++ b/src/gui/opengl/qopenglshaderprogram.h
@@ -50,6 +50,13 @@
#include <QtGui/qvector4d.h>
#include <QtGui/qmatrix4x4.h>
+#if defined(Q_CLANG_QDOC)
+#undef GLint
+typedef int GLint;
+#undef GLfloat
+typedef double GLfloat;
+#endif
+
QT_BEGIN_NAMESPACE
@@ -119,6 +126,11 @@ public:
bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source);
bool addShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString& fileName);
+ bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source);
+ bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray &source);
+ bool addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString &source);
+ bool addCacheableShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString &fileName);
+
void removeAllShaders();
virtual bool link();
diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp
index c9b08f60b1..0831bfe706 100644
--- a/src/gui/opengl/qopengltexture.cpp
+++ b/src/gui/opengl/qopengltexture.cpp
@@ -1351,7 +1351,7 @@ void QOpenGLTexturePrivate::allocateImmutableStorage()
storageAllocated = true;
}
-void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace,
+void QOpenGLTexturePrivate::setData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace,
QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType,
const void *data, const QOpenGLPixelTransferOptions * const options)
{
@@ -1359,6 +1359,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub
case QOpenGLTexture::Target1D:
Q_UNUSED(layer);
Q_UNUSED(cubeFace);
+ Q_UNUSED(layerCount);
texFuncs->glTextureSubImage1D(textureId, target, bindingTarget, mipLevel,
0, mipLevelSize( mipLevel, dimensions[0] ),
sourceFormat, sourceType, data, options);
@@ -1369,13 +1370,14 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub
texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel,
0, layer,
mipLevelSize(mipLevel, dimensions[0]),
- 1,
+ layerCount,
sourceFormat, sourceType, data, options);
break;
case QOpenGLTexture::Target2D:
Q_UNUSED(layer);
Q_UNUSED(cubeFace);
+ Q_UNUSED(layerCount);
texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel,
0, 0,
mipLevelSize(mipLevel, dimensions[0]),
@@ -1389,12 +1391,13 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub
0, 0, layer,
mipLevelSize(mipLevel, dimensions[0]),
mipLevelSize(mipLevel, dimensions[1]),
- 1,
+ layerCount,
sourceFormat, sourceType, data, options);
break;
case QOpenGLTexture::Target3D:
Q_UNUSED(cubeFace);
+ Q_UNUSED(layerCount);
texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel,
0, 0, layer,
mipLevelSize(mipLevel, dimensions[0]),
@@ -1405,6 +1408,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub
case QOpenGLTexture::TargetCubeMap:
Q_UNUSED(layer);
+ Q_UNUSED(layerCount);
texFuncs->glTextureSubImage2D(textureId, cubeFace, bindingTarget, mipLevel,
0, 0,
mipLevelSize(mipLevel, dimensions[0]),
@@ -1419,7 +1423,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub
0, 0, layerFace,
mipLevelSize(mipLevel, dimensions[0]),
mipLevelSize(mipLevel, dimensions[1]),
- 1,
+ layerCount,
sourceFormat, sourceType, data, options);
break;
}
@@ -1428,6 +1432,7 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub
Q_UNUSED(mipLevel);
Q_UNUSED(layer);
Q_UNUSED(cubeFace);
+ Q_UNUSED(layerCount);
texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, 0,
0, 0,
dimensions[0],
@@ -1450,7 +1455,8 @@ void QOpenGLTexturePrivate::setData(int mipLevel, int layer, QOpenGLTexture::Cub
}
}
-void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace,
+void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, int layerCount,
+ QOpenGLTexture::CubeMapFace cubeFace,
int dataSize, const void *data,
const QOpenGLPixelTransferOptions * const options)
{
@@ -1465,6 +1471,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe
case QOpenGLTexture::Target1D:
Q_UNUSED(layer);
Q_UNUSED(cubeFace);
+ Q_UNUSED(layerCount);
if (needsFullSpec) {
texFuncs->glCompressedTextureImage1D(textureId, target, bindingTarget, mipLevel,
format,
@@ -1483,7 +1490,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe
texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel,
0, layer,
mipLevelSize(mipLevel, dimensions[0]),
- 1,
+ layerCount,
format, dataSize, data, options);
}
break;
@@ -1491,6 +1498,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe
case QOpenGLTexture::Target2D:
Q_UNUSED(layer);
Q_UNUSED(cubeFace);
+ Q_UNUSED(layerCount);
if (needsFullSpec) {
texFuncs->glCompressedTextureImage2D(textureId, target, bindingTarget, mipLevel,
format,
@@ -1513,13 +1521,14 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe
0, 0, layer,
mipLevelSize(mipLevel, dimensions[0]),
mipLevelSize(mipLevel, dimensions[1]),
- 1,
+ layerCount,
format, dataSize, data, options);
}
break;
case QOpenGLTexture::Target3D:
Q_UNUSED(cubeFace);
+ Q_UNUSED(layerCount);
if (needsFullSpec) {
texFuncs->glCompressedTextureImage3D(textureId, target, bindingTarget, mipLevel,
format,
@@ -1539,6 +1548,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe
case QOpenGLTexture::TargetCubeMap:
Q_UNUSED(layer);
+ Q_UNUSED(layerCount);
if (needsFullSpec) {
texFuncs->glCompressedTextureImage2D(textureId, cubeFace, bindingTarget, mipLevel,
format,
@@ -1562,7 +1572,7 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe
0, 0, layerFace,
mipLevelSize(mipLevel, dimensions[0]),
mipLevelSize(mipLevel, dimensions[1]),
- 1,
+ layerCount,
format, dataSize, data, options);
}
break;
@@ -3286,7 +3296,23 @@ void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace,
"To do so call allocateStorage() before this function");
return;
}
- d->setData(mipLevel, layer, cubeFace, sourceFormat, sourceType, data, options);
+ d->setData(mipLevel, layer, 1, cubeFace, sourceFormat, sourceType, data, options);
+}
+
+/*!
+ \since 5.9
+ \overload
+*/
+void QOpenGLTexture::setData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, const void *data, const QOpenGLPixelTransferOptions * const options)
+{
+ Q_D(QOpenGLTexture);
+ Q_ASSERT(d->textureId);
+ if (!isStorageAllocated()) {
+ qWarning("Cannot set data on a texture that does not have storage allocated.\n"
+ "To do so call allocateStorage() before this function");
+ return;
+ }
+ d->setData(mipLevel, layer, layerCount, cubeFace, sourceFormat, sourceType, data, options);
}
/*!
@@ -3299,7 +3325,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer,
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
+ d->setData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
}
/*!
@@ -3312,7 +3338,7 @@ void QOpenGLTexture::setData(int mipLevel,
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
+ d->setData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
}
/*!
@@ -3324,7 +3350,7 @@ void QOpenGLTexture::setData(PixelFormat sourceFormat, PixelType sourceType,
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setData(0, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
+ d->setData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
}
#if QT_DEPRECATED_SINCE(5, 3)
@@ -3345,7 +3371,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace,
"To do so call allocateStorage() before this function");
return;
}
- d->setData(mipLevel, layer, cubeFace, sourceFormat, sourceType, data, options);
+ d->setData(mipLevel, layer, 1, cubeFace, sourceFormat, sourceType, data, options);
}
/*!
@@ -3358,7 +3384,7 @@ void QOpenGLTexture::setData(int mipLevel, int layer,
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
+ d->setData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
}
/*!
@@ -3371,7 +3397,7 @@ void QOpenGLTexture::setData(int mipLevel,
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
+ d->setData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
}
/*!
@@ -3383,7 +3409,7 @@ void QOpenGLTexture::setData(PixelFormat sourceFormat, PixelType sourceType,
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setData(0, 0, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
+ d->setData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options);
}
#endif
@@ -3444,7 +3470,23 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cube
"To do so call allocateStorage() before this function");
return;
}
- d->setCompressedData(mipLevel, layer, cubeFace, dataSize, data, options);
+ d->setCompressedData(mipLevel, layer, 1, cubeFace, dataSize, data, options);
+}
+
+/*!
+ \since 5.9
+ \overload
+*/
+void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options)
+{
+ Q_D(QOpenGLTexture);
+ Q_ASSERT(d->textureId);
+ if (!isStorageAllocated()) {
+ qWarning("Cannot set data on a texture that does not have storage allocated.\n"
+ "To do so call allocateStorage() before this function");
+ return;
+ }
+ d->setCompressedData(mipLevel, layer, layerCount, cubeFace, dataSize, data, options);
}
/*!
@@ -3455,7 +3497,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int dataSize, co
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setCompressedData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
+ d->setCompressedData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
}
/*!
@@ -3466,7 +3508,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int dataSize, const void *d
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setCompressedData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
+ d->setCompressedData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
}
/*!
@@ -3477,7 +3519,7 @@ void QOpenGLTexture::setCompressedData(int dataSize, const void *data,
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setCompressedData(0, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
+ d->setCompressedData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
}
#if QT_DEPRECATED_SINCE(5, 3)
@@ -3496,7 +3538,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cube
"To do so call allocateStorage() before this function");
return;
}
- d->setCompressedData(mipLevel, layer, cubeFace, dataSize, data, options);
+ d->setCompressedData(mipLevel, layer, 1, cubeFace, dataSize, data, options);
}
/*!
@@ -3508,7 +3550,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int dataSize, vo
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setCompressedData(mipLevel, layer, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
+ d->setCompressedData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
}
/*!
@@ -3520,7 +3562,7 @@ void QOpenGLTexture::setCompressedData(int mipLevel, int dataSize, void *data,
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setCompressedData(mipLevel, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
+ d->setCompressedData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
}
/*!
@@ -3532,7 +3574,7 @@ void QOpenGLTexture::setCompressedData(int dataSize, void *data,
{
Q_D(QOpenGLTexture);
Q_ASSERT(d->textureId);
- d->setCompressedData(0, 0, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
+ d->setCompressedData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options);
}
#endif
@@ -3643,7 +3685,7 @@ bool QOpenGLTexture::hasFeature(Feature feature)
const char *renderer = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_RENDERER));
switch (feature) {
case ImmutableStorage:
- supported = (f.version() >= qMakePair(3, 0) || ctx->hasExtension(QByteArrayLiteral("EXT_texture_storage")))
+ supported = (f.version() >= qMakePair(3, 0) || ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_storage")))
&& !(renderer && strstr(renderer, "Mali")); // do not use on Mali: QTBUG-45106
break;
diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h
index d0a3bfec8b..6e6f7ef1f2 100644
--- a/src/gui/opengl/qopengltexture.h
+++ b/src/gui/opengl/qopengltexture.h
@@ -472,6 +472,9 @@ public:
void setData(int mipLevel, int layer, CubeMapFace cubeFace,
PixelFormat sourceFormat, PixelType sourceType,
const void *data, const QOpenGLPixelTransferOptions * const options = Q_NULLPTR);
+ void setData(int mipLevel, int layer, int layerCount, CubeMapFace cubeFace,
+ PixelFormat sourceFormat, PixelType sourceType,
+ const void *data, const QOpenGLPixelTransferOptions * const options = Q_NULLPTR);
void setData(int mipLevel, int layer,
PixelFormat sourceFormat, PixelType sourceType,
const void *data, const QOpenGLPixelTransferOptions * const options = Q_NULLPTR);
@@ -499,6 +502,9 @@ public:
void setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace,
int dataSize, const void *data,
const QOpenGLPixelTransferOptions * const options = Q_NULLPTR);
+ void setCompressedData(int mipLevel, int layer, int layerCount, CubeMapFace cubeFace,
+ int dataSize, const void *data,
+ const QOpenGLPixelTransferOptions * const options = Q_NULLPTR);
void setCompressedData(int mipLevel, int layer,
int dataSize, const void *data,
const QOpenGLPixelTransferOptions * const options = Q_NULLPTR);
diff --git a/src/gui/opengl/qopengltexture_p.h b/src/gui/opengl/qopengltexture_p.h
index 9914316bb4..f7694f77bc 100644
--- a/src/gui/opengl/qopengltexture_p.h
+++ b/src/gui/opengl/qopengltexture_p.h
@@ -98,13 +98,14 @@ public:
void allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType);
void allocateMutableStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType);
void allocateImmutableStorage();
- void setData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace,
+ void setData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace,
QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType,
const void *data, const QOpenGLPixelTransferOptions * const options);
- void setCompressedData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace,
+ void setCompressedData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace,
int dataSize, const void *data,
const QOpenGLPixelTransferOptions * const options);
+
void setWrapMode(QOpenGLTexture::WrapMode mode);
void setWrapMode(QOpenGLTexture::CoordinateDirection direction, QOpenGLTexture::WrapMode mode);
QOpenGLTexture::WrapMode wrapMode(QOpenGLTexture::CoordinateDirection direction) const;
diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp
index 858fc0d857..b65df9dc82 100644
--- a/src/gui/opengl/qopengltextureblitter.cpp
+++ b/src/gui/opengl/qopengltextureblitter.cpp
@@ -330,8 +330,8 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs
p->glProgram.reset(new QOpenGLShaderProgram);
- p->glProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vs);
- p->glProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fs);
+ p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vs);
+ p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fs);
p->glProgram->link();
if (!p->glProgram->isLinked()) {
qWarning() << "Could not link shader program:\n" << p->glProgram->log();
diff --git a/src/gui/opengl/qopengltexturecache.cpp b/src/gui/opengl/qopengltexturecache.cpp
index 688226551d..27aa8db33a 100644
--- a/src/gui/opengl/qopengltexturecache.cpp
+++ b/src/gui/opengl/qopengltexturecache.cpp
@@ -371,7 +371,7 @@ static void freeTexture(QOpenGLFunctions *funcs, GLuint id)
funcs->glDeleteTextures(1, &id);
}
-QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, int options, QOpenGLContext *context) : m_options(options)
+QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLTextureCache::BindOptions options, QOpenGLContext *context) : m_options(options)
{
m_resource = new QOpenGLSharedResourceGuard(context, id, freeTexture);
}
diff --git a/src/gui/opengl/qopengltexturecache_p.h b/src/gui/opengl/qopengltexturecache_p.h
index c68b068739..4a438c8d95 100644
--- a/src/gui/opengl/qopengltexturecache_p.h
+++ b/src/gui/opengl/qopengltexturecache_p.h
@@ -60,19 +60,7 @@
QT_BEGIN_NAMESPACE
-class QOpenGLCachedTexture
-{
-public:
- QOpenGLCachedTexture(GLuint id, int options, QOpenGLContext *context);
- ~QOpenGLCachedTexture() { m_resource->free(); }
-
- GLuint id() const { return m_resource->id(); }
- int options() const { return m_options; }
-
-private:
- QOpenGLSharedResourceGuard *m_resource;
- int m_options;
-};
+class QOpenGLCachedTexture;
class Q_GUI_EXPORT QOpenGLTextureCache : public QOpenGLSharedResource
{
@@ -106,6 +94,20 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLTextureCache::BindOptions)
+class QOpenGLCachedTexture
+{
+public:
+ QOpenGLCachedTexture(GLuint id, QOpenGLTextureCache::BindOptions options, QOpenGLContext *context);
+ ~QOpenGLCachedTexture() { m_resource->free(); }
+
+ GLuint id() const { return m_resource->id(); }
+ QOpenGLTextureCache::BindOptions options() const { return m_options; }
+
+private:
+ QOpenGLSharedResourceGuard *m_resource;
+ QOpenGLTextureCache::BindOptions m_options;
+};
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp
index 9a7b1eb21d..556d52ef99 100644
--- a/src/gui/opengl/qopengltextureglyphcache.cpp
+++ b/src/gui/opengl/qopengltextureglyphcache.cpp
@@ -47,7 +47,11 @@
QT_BEGIN_NAMESPACE
-QBasicAtomicInt qopengltextureglyphcache_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
+static int next_qopengltextureglyphcache_serial_number()
+{
+ static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
+ return 1 + serial.fetchAndAddRelaxed(1);
+}
QOpenGLTextureGlyphCache::QOpenGLTextureGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix)
: QImageTextureGlyphCache(format, matrix)
@@ -55,7 +59,7 @@ QOpenGLTextureGlyphCache::QOpenGLTextureGlyphCache(QFontEngine::GlyphFormat form
, pex(0)
, m_blitProgram(0)
, m_filterMode(Nearest)
- , m_serialNumber(qopengltextureglyphcache_serial_number.fetchAndAddRelaxed(1))
+ , m_serialNumber(next_qopengltextureglyphcache_serial_number())
, m_buffer(QOpenGLBuffer::VertexBuffer)
{
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
@@ -342,22 +346,14 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height)
QString source;
source.append(QLatin1String(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader));
source.append(QLatin1String(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader));
-
- QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram);
- vertexShader->compileSourceCode(source);
-
- m_blitProgram->addShader(vertexShader);
+ m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, source);
}
{
QString source;
source.append(QLatin1String(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader));
source.append(QLatin1String(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader));
-
- QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram);
- fragmentShader->compileSourceCode(source);
-
- m_blitProgram->addShader(fragmentShader);
+ m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, source);
}
m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
@@ -380,8 +376,8 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height)
blitProgram = m_blitProgram;
} else {
- pex->setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, m_vertexCoordinateArray);
- pex->setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, m_textureCoordinateArray);
+ pex->uploadData(QT_VERTEX_COORDS_ATTR, m_vertexCoordinateArray, 8);
+ pex->uploadData(QT_TEXTURE_COORDS_ATTR, m_textureCoordinateArray, 8);
pex->shaderManager->useBlitProgram();
blitProgram = pex->shaderManager->blitProgram();
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index 86e35c39f8..63e345545c 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -8,6 +8,7 @@ HEADERS += \
painting/qbrush.h \
painting/qcolor.h \
painting/qcolor_p.h \
+ painting/qcolorprofile_p.h \
painting/qcosmeticstroker_p.h \
painting/qdatabuffer_p.h \
painting/qdrawhelper_p.h \
@@ -63,11 +64,11 @@ SOURCES += \
painting/qblittable.cpp \
painting/qbrush.cpp \
painting/qcolor.cpp \
+ painting/qcolorprofile.cpp \
painting/qcompositionfunctions.cpp \
painting/qcosmeticstroker.cpp \
painting/qdrawhelper.cpp \
painting/qemulationpaintengine.cpp \
- painting/qgammatables.cpp \
painting/qgrayraster.c \
painting/qimagescale.cpp \
painting/qmatrix.cpp \
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index ebb035a2c1..cc3ee76f0d 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -1006,7 +1006,7 @@ bool QBrush::operator==(const QBrush &b) const
*/
QDebug operator<<(QDebug dbg, const QBrush &b)
{
- static const char *const BRUSH_STYLES[] = {
+ static const char BRUSH_STYLES[][24] = {
"NoBrush",
"SolidPattern",
"Dense1Pattern",
@@ -1025,7 +1025,7 @@ QDebug operator<<(QDebug dbg, const QBrush &b)
"LinearGradientPattern",
"RadialGradientPattern",
"ConicalGradientPattern",
- 0, 0, 0, 0, 0, 0,
+ "", "", "", "", "", "",
"TexturePattern" // 24
};
@@ -1419,6 +1419,25 @@ void QGradient::setColorAt(qreal pos, const QColor &color)
m_stops.insert(index, QGradientStop(pos, color));
}
+static inline bool ok(QGradientStop stop)
+{
+ return stop.first >= 0 && stop.first <= 1; // rejects NaNs
+}
+
+static inline bool ok(const QGradientStops &stops)
+{
+ qreal lastPos = -1;
+ for (const QGradientStop &stop : stops) {
+ if (Q_UNLIKELY(!ok(stop)))
+ return false;
+ const bool sorted = stop.first > lastPos; // rejects duplicates
+ if (Q_UNLIKELY(!sorted))
+ return false;
+ lastPos = stop.first;
+ }
+ return true;
+}
+
/*!
\fn void QGradient::setStops(const QGradientStops &stopPoints)
@@ -1430,6 +1449,14 @@ void QGradient::setColorAt(qreal pos, const QColor &color)
*/
void QGradient::setStops(const QGradientStops &stops)
{
+ // ## Qt 6: consider taking \a stops by value, so we can move into m_stops
+ if (Q_LIKELY(ok(stops))) {
+ // fast path for the common case: if everything is ok with the stops, just copy them
+ m_stops = stops;
+ return;
+ }
+ // otherwise, to keep the pre-5.9 behavior, add them one after another,
+ // so each stop is checked, invalid ones are skipped, they are added in-order (which may be O(N^2)).
m_stops.clear();
for (int i=0; i<stops.size(); ++i)
setColorAt(stops.at(i).first, stops.at(i).second);
diff --git a/src/gui/painting/qcolorprofile.cpp b/src/gui/painting/qcolorprofile.cpp
new file mode 100644
index 0000000000..3b7b0a248b
--- /dev/null
+++ b/src/gui/painting/qcolorprofile.cpp
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcolorprofile_p.h"
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+QColorProfile *QColorProfile::fromGamma(qreal gamma)
+{
+ QColorProfile *cp = new QColorProfile;
+
+ for (int i = 0; i <= (255 * 16); ++i) {
+ cp->m_toLinear[i] = ushort(qRound(qPow(i / qreal(255 * 16), gamma) * (255 * 256)));
+ cp->m_fromLinear[i] = ushort(qRound(qPow(i / qreal(255 * 16), qreal(1) / gamma) * (255 * 256)));
+ }
+
+ return cp;
+}
+
+static qreal srgbToLinear(qreal v)
+{
+ const qreal a = 0.055;
+ if (v <= qreal(0.04045))
+ return v / qreal(12.92);
+ else
+ return qPow((v + a) / (qreal(1) + a), qreal(2.4));
+}
+
+static qreal linearToSrgb(qreal v)
+{
+ const qreal a = 0.055;
+ if (v <= qreal(0.0031308))
+ return v * qreal(12.92);
+ else
+ return (qreal(1) + a) * qPow(v, qreal(1.0 / 2.4)) - a;
+}
+
+QColorProfile *QColorProfile::fromSRgb()
+{
+ QColorProfile *cp = new QColorProfile;
+
+ for (int i = 0; i <= (255 * 16); ++i) {
+ cp->m_toLinear[i] = ushort(qRound(srgbToLinear(i / qreal(255 * 16)) * (255 * 256)));
+ cp->m_fromLinear[i] = ushort(qRound(linearToSrgb(i / qreal(255 * 16)) * (255 * 256)));
+ }
+
+ return cp;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qcolorprofile_p.h b/src/gui/painting/qcolorprofile_p.h
new file mode 100644
index 0000000000..ca1786ee6d
--- /dev/null
+++ b/src/gui/painting/qcolorprofile_p.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOLORPROFILE_P_H
+#define QCOLORPROFILE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtGui/qrgb.h>
+#include <QtGui/qrgba64.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QColorProfile
+{
+public:
+ static QColorProfile *fromGamma(qreal gamma);
+ static QColorProfile *fromSRgb();
+
+ // The following methods all convert opaque or unpremultiplied colors:
+
+ QRgba64 toLinear64(QRgb rgb32) const
+ {
+ ushort r = m_toLinear[qRed(rgb32) << 4];
+ ushort g = m_toLinear[qGreen(rgb32) << 4];
+ ushort b = m_toLinear[qBlue(rgb32) << 4];
+ r = r + (r >> 8);
+ g = g + (g >> 8);
+ b = b + (b >> 8);
+ return QRgba64::fromRgba64(r, g, b, qAlpha(rgb32) * 257);
+ }
+
+ QRgb toLinear(QRgb rgb32) const
+ {
+ uchar r = (m_toLinear[qRed(rgb32) << 4] + 0x80) >> 8;
+ uchar g = (m_toLinear[qGreen(rgb32) << 4] + 0x80) >> 8;
+ uchar b = (m_toLinear[qBlue(rgb32) << 4] + 0x80) >> 8;
+ return qRgba(r, g, b, qAlpha(rgb32));
+ }
+
+ QRgba64 toLinear(QRgba64 rgb64) const
+ {
+ ushort r = rgb64.red();
+ ushort g = rgb64.green();
+ ushort b = rgb64.blue();
+ r = r - (r >> 8);
+ g = g - (g >> 8);
+ b = b - (b >> 8);
+ r = m_toLinear[r >> 4];
+ g = m_toLinear[g >> 4];
+ b = m_toLinear[b >> 4];
+ r = r + (r >> 8);
+ g = g + (g >> 8);
+ b = b + (b >> 8);
+ return QRgba64::fromRgba64(r, g, b, rgb64.alpha());
+ }
+
+ QRgb fromLinear64(QRgba64 rgb64) const
+ {
+ ushort r = rgb64.red();
+ ushort g = rgb64.green();
+ ushort b = rgb64.blue();
+ r = r - (r >> 8);
+ g = g - (g >> 8);
+ b = b - (b >> 8);
+ r = (m_fromLinear[r >> 4] + 0x80) >> 8;
+ g = (m_fromLinear[g >> 4] + 0x80) >> 8;
+ b = (m_fromLinear[b >> 4] + 0x80) >> 8;
+ return qRgba(r, g, b, rgb64.alpha8());
+ }
+
+ QRgb fromLinear(QRgb rgb32) const
+ {
+ uchar r = (m_fromLinear[qRed(rgb32) << 4] + 0x80) >> 8;
+ uchar g = (m_fromLinear[qGreen(rgb32) << 4] + 0x80) >> 8;
+ uchar b = (m_fromLinear[qBlue(rgb32) << 4] + 0x80) >> 8;
+ return qRgba(r, g, b, qAlpha(rgb32));
+ }
+
+ QRgba64 fromLinear(QRgba64 rgb64) const
+ {
+ ushort r = rgb64.red();
+ ushort g = rgb64.green();
+ ushort b = rgb64.blue();
+ r = r - (r >> 8);
+ g = g - (g >> 8);
+ b = b - (b >> 8);
+ r = m_fromLinear[r >> 4];
+ g = m_fromLinear[g >> 4];
+ b = m_fromLinear[b >> 4];
+ r = r + (r >> 8);
+ g = g + (g >> 8);
+ b = b + (b >> 8);
+ return QRgba64::fromRgba64(r, g, b, rgb64.alpha());
+ }
+
+private:
+ QColorProfile() { }
+
+ // We translate to 0-65280 (255*256) instead to 0-65535 to make simple
+ // shifting an accurate conversion.
+ // We translate from 0-4080 (255*16) for the same speed up, and to keep
+ // the tables small enough to fit in most inner caches.
+ ushort m_toLinear[(255 * 16) + 1]; // [0-4080] -> [0-65280]
+ ushort m_fromLinear[(255 * 16) + 1]; // [0-4080] -> [0-65280]
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QCOLORPROFILE_P_H
diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm
index 3753fa4e88..98fdd7f35e 100644
--- a/src/gui/painting/qcoregraphics.mm
+++ b/src/gui/painting/qcoregraphics.mm
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -39,6 +45,7 @@
#include <QtGui/private/qpaintengine_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qoperatingsystemversion.h>
QT_BEGIN_NAMESPACE
@@ -106,29 +113,6 @@ QImage qt_mac_toQImage(CGImageRef image)
#ifdef Q_OS_MACOS
-QT_END_NAMESPACE
-
-@interface NSGraphicsContext (QtAdditions)
-
-+ (NSGraphicsContext *)qt_graphicsContextWithCGContext:(CGContextRef)graphicsPort flipped:(BOOL)initialFlippedState;
-
-@end
-
-@implementation NSGraphicsContext (QtAdditions)
-
-+ (NSGraphicsContext *)qt_graphicsContextWithCGContext:(CGContextRef)graphicsPort flipped:(BOOL)initialFlippedState
-{
-#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_NA)
- if (QT_PREPEND_NAMESPACE(QSysInfo::MacintoshVersion) >= QT_PREPEND_NAMESPACE(QSysInfo::MV_10_10))
- return [self graphicsContextWithCGContext:graphicsPort flipped:initialFlippedState];
-#endif
- return [self graphicsContextWithGraphicsPort:graphicsPort flipped:initialFlippedState];
-}
-
-@end
-
-QT_BEGIN_NAMESPACE
-
static NSImage *qt_mac_cgimage_to_nsimage(CGImageRef image)
{
NSImage *newImage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize];
@@ -155,7 +139,7 @@ NSImage *qt_mac_create_nsimage(const QIcon &icon, int defaultSize)
QList<QSize> availableSizes = icon.availableSizes();
if (availableSizes.isEmpty() && defaultSize > 0)
availableSizes << QSize(defaultSize, defaultSize);
- foreach (QSize size, availableSizes) {
+ for (QSize size : qAsConst(availableSizes)) {
QPixmap pm = icon.pixmap(size);
if (pm.isNull())
continue;
@@ -179,7 +163,7 @@ QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size)
QMacCGContext ctx(&pixmap);
if (!ctx)
return QPixmap();
- NSGraphicsContext *gc = [NSGraphicsContext qt_graphicsContextWithCGContext:ctx flipped:YES];
+ NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES];
if (!gc)
return QPixmap();
[NSGraphicsContext saveGraphicsState];
diff --git a/src/gui/painting/qcoregraphics_p.h b/src/gui/painting/qcoregraphics_p.h
index 065910222d..54de3f332e 100644
--- a/src/gui/painting/qcoregraphics_p.h
+++ b/src/gui/painting/qcoregraphics_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 23da42c8cf..0cd5ff1d0e 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -43,6 +43,7 @@
#include <qstylehints.h>
#include <qguiapplication.h>
#include <qatomic.h>
+#include <private/qcolorprofile_p.h>
#include <private/qdrawhelper_p.h>
#include <private/qpaintengine_raster_p.h>
#include <private/qpainter_p.h>
@@ -1143,6 +1144,11 @@ static QRgba64 *QT_FASTCALL destFetch64uint32(QRgba64 *buffer, QRasterBuffer *ra
return const_cast<QRgba64 *>(layout->convertToARGB64PM(buffer, src, length, 0, 0));
}
+static QRgba64 * QT_FASTCALL destFetch64Undefined(QRgba64 *buffer, QRasterBuffer *, int, int, int)
+{
+ return buffer;
+}
+
static DestFetchProc destFetchProc[QImage::NImageFormats] =
{
0, // Format_Invalid
@@ -1175,8 +1181,8 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] =
static DestFetchProc64 destFetchProc64[QImage::NImageFormats] =
{
0, // Format_Invalid
- destFetch64, // Format_Mono,
- destFetch64, // Format_MonoLSB
+ 0, // Format_Mono,
+ 0, // Format_MonoLSB
0, // Format_Indexed8
destFetch64uint32, // Format_RGB32
destFetch64uint32, // Format_ARGB32,
@@ -1320,7 +1326,7 @@ static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, con
static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length)
{
for (int i = 0; i < length; ++i) {
- dest[i] = src[i].toArgb32();
+ dest[i] = toArgb32(src[i]);
}
}
@@ -1411,7 +1417,7 @@ static void QT_FASTCALL destStore64ARGB32(QRasterBuffer *rasterBuffer, int x, in
{
uint *dest = (uint*)rasterBuffer->scanLine(y) + x;
for (int i = 0; i < length; ++i) {
- dest[i] = buffer[i].unpremultiplied().toArgb32();
+ dest[i] = toArgb32(buffer[i].unpremultiplied());
}
}
@@ -1419,7 +1425,7 @@ static void QT_FASTCALL destStore64RGBA8888(QRasterBuffer *rasterBuffer, int x,
{
uint *dest = (uint*)rasterBuffer->scanLine(y) + x;
for (int i = 0; i < length; ++i) {
- dest[i] = ARGB2RGBA(buffer[i].unpremultiplied().toArgb32());
+ dest[i] = toRgba8888(buffer[i].unpremultiplied());
}
}
@@ -1914,562 +1920,695 @@ inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(int,
Q_ASSERT(v2 >= l1 && v2 <= l2);
}
-template<TextureBlendType blendType> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
-static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, const Operator *,
- const QSpanData *data, int y, int x,
- int length)
-{
- int image_width = data->texture.width;
- int image_height = data->texture.height;
-
- int image_x1 = data->texture.x1;
- int image_y1 = data->texture.y1;
- int image_x2 = data->texture.x2 - 1;
- int image_y2 = data->texture.y2 - 1;
-
- const qreal cx = x + qreal(0.5);
- const qreal cy = y + qreal(0.5);
-
- uint *end = buffer + length;
- uint *b = buffer;
- if (data->fast_matrix) {
- // The increment pr x in the scanline
- int fdx = (int)(data->m11 * fixed_scale);
- int fdy = (int)(data->m12 * fixed_scale);
-
- int fx = int((data->m21 * cy
- + data->m11 * cx + data->dx) * fixed_scale);
- int fy = int((data->m22 * cy
- + data->m12 * cx + data->dy) * fixed_scale);
-
- fx -= half_point;
- fy -= half_point;
-
- if (fdy == 0) { //simple scale, no rotation
- int y1 = (fy >> 16);
- int y2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uint *s1 = (const uint *)data->texture.scanLine(y1);
- const uint *s2 = (const uint *)data->texture.scanLine(y2);
-
- if (fdx <= fixed_scale && fdx > 0) { // scale up on X
- int disty = (fy & 0x0000ffff) >> 8;
- int idisty = 256 - disty;
- int x = fx >> 16;
+enum FastTransformTypes {
+ SimpleUpscaleTransform,
+ UpscaleTransform,
+ DownscaleTransform,
+ RotateTransform,
+ FastRotateTransform,
+ NFastTransformTypes
+};
- // The idea is first to do the interpolation between the row s1 and the row s2
- // into an intermediate buffer, then we interpolate between two pixel of this buffer.
+typedef void (QT_FASTCALL *BilinearFastTransformHelper)(uint *b, uint *end, const QTextureData &image, int &fx, int &fy, int fdx, int fdy);
- // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
- // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
- // +1 for the last pixel to interpolate with, and +1 for rounding errors.
- quint32 intermediate_buffer[2][buffer_size + 2];
- // count is the size used in the intermediate_buffer.
- int count = (qint64(length) * fdx + fixed_scale - 1) / fixed_scale + 2;
- Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
- int f = 0;
- int lim = count;
- if (blendType == BlendTransformedBilinearTiled) {
- x %= image_width;
- if (x < 0) x += image_width;
- } else {
- lim = qMin(count, image_x2-x+1);
- if (x < image_x1) {
- Q_ASSERT(x <= image_x2);
- uint t = s1[image_x1];
- uint b = s2[image_x1];
- quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
- quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
- do {
- intermediate_buffer[0][f] = rb;
- intermediate_buffer[1][f] = ag;
- f++;
- x++;
- } while (x < image_x1 && f < lim);
- }
- }
+template<TextureBlendType blendType>
+static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/)
+{
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
+
+ int disty = (fy & 0x0000ffff) >> 8;
+ int idisty = 256 - disty;
+ int x = fx >> 16;
+ int length = end - b;
+
+ // The idea is first to do the interpolation between the row s1 and the row s2
+ // into an intermediate buffer, then we interpolate between two pixel of this buffer.
+
+ // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
+ // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
+ // +1 for the last pixel to interpolate with, and +1 for rounding errors.
+ quint32 intermediate_buffer[2][buffer_size + 2];
+ // count is the size used in the intermediate_buffer.
+ int count = (qint64(length) * fdx + fixed_scale - 1) / fixed_scale + 2;
+ Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
+ int f = 0;
+ int lim = count;
+ if (blendType == BlendTransformedBilinearTiled) {
+ x %= image.width;
+ if (x < 0) x += image.width;
+ } else {
+ lim = qMin(count, image.x2 - x);
+ if (x < image.x1) {
+ Q_ASSERT(x < image.x2);
+ uint t = s1[image.x1];
+ uint b = s2[image.x1];
+ quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ do {
+ intermediate_buffer[0][f] = rb;
+ intermediate_buffer[1][f] = ag;
+ f++;
+ x++;
+ } while (x < image.x1 && f < lim);
+ }
+ }
- if (blendType != BlendTransformedBilinearTiled) {
+ if (blendType != BlendTransformedBilinearTiled) {
#if defined(__SSE2__)
- const __m128i disty_ = _mm_set1_epi16(disty);
- const __m128i idisty_ = _mm_set1_epi16(idisty);
- const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
-
- lim -= 3;
- for (; f < lim; x += 4, f += 4) {
- // Load 4 pixels from s1, and split the alpha-green and red-blue component
- __m128i top = _mm_loadu_si128((const __m128i*)((const uint *)(s1)+x));
- __m128i topAG = _mm_srli_epi16(top, 8);
- __m128i topRB = _mm_and_si128(top, colorMask);
- // Multiplies each colour component by idisty
- topAG = _mm_mullo_epi16 (topAG, idisty_);
- topRB = _mm_mullo_epi16 (topRB, idisty_);
-
- // Same for the s2 vector
- __m128i bottom = _mm_loadu_si128((const __m128i*)((const uint *)(s2)+x));
- __m128i bottomAG = _mm_srli_epi16(bottom, 8);
- __m128i bottomRB = _mm_and_si128(bottom, colorMask);
- bottomAG = _mm_mullo_epi16 (bottomAG, disty_);
- bottomRB = _mm_mullo_epi16 (bottomRB, disty_);
-
- // Add the values, and shift to only keep 8 significant bits per colors
- __m128i rAG =_mm_add_epi16(topAG, bottomAG);
- rAG = _mm_srli_epi16(rAG, 8);
- _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG);
- __m128i rRB =_mm_add_epi16(topRB, bottomRB);
- rRB = _mm_srli_epi16(rRB, 8);
- _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB);
- }
+ const __m128i disty_ = _mm_set1_epi16(disty);
+ const __m128i idisty_ = _mm_set1_epi16(idisty);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+
+ lim -= 3;
+ for (; f < lim; x += 4, f += 4) {
+ // Load 4 pixels from s1, and split the alpha-green and red-blue component
+ __m128i top = _mm_loadu_si128((const __m128i*)((const uint *)(s1)+x));
+ __m128i topAG = _mm_srli_epi16(top, 8);
+ __m128i topRB = _mm_and_si128(top, colorMask);
+ // Multiplies each color component by idisty
+ topAG = _mm_mullo_epi16 (topAG, idisty_);
+ topRB = _mm_mullo_epi16 (topRB, idisty_);
+
+ // Same for the s2 vector
+ __m128i bottom = _mm_loadu_si128((const __m128i*)((const uint *)(s2)+x));
+ __m128i bottomAG = _mm_srli_epi16(bottom, 8);
+ __m128i bottomRB = _mm_and_si128(bottom, colorMask);
+ bottomAG = _mm_mullo_epi16 (bottomAG, disty_);
+ bottomRB = _mm_mullo_epi16 (bottomRB, disty_);
+
+ // Add the values, and shift to only keep 8 significant bits per colors
+ __m128i rAG =_mm_add_epi16(topAG, bottomAG);
+ rAG = _mm_srli_epi16(rAG, 8);
+ _mm_storeu_si128((__m128i*)(&intermediate_buffer[1][f]), rAG);
+ __m128i rRB =_mm_add_epi16(topRB, bottomRB);
+ rRB = _mm_srli_epi16(rRB, 8);
+ _mm_storeu_si128((__m128i*)(&intermediate_buffer[0][f]), rRB);
+ }
#elif defined(__ARM_NEON__)
- const int16x8_t disty_ = vdupq_n_s16(disty);
- const int16x8_t idisty_ = vdupq_n_s16(idisty);
- const int16x8_t colorMask = vdupq_n_s16(0x00ff);
-
- lim -= 3;
- for (; f < lim; x += 4, f += 4) {
- // Load 4 pixels from s1, and split the alpha-green and red-blue component
- int16x8_t top = vld1q_s16((int16_t*)((const uint *)(s1)+x));
- int16x8_t topAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(top), 8));
- int16x8_t topRB = vandq_s16(top, colorMask);
- // Multiplies each colour component by idisty
- topAG = vmulq_s16(topAG, idisty_);
- topRB = vmulq_s16(topRB, idisty_);
-
- // Same for the s2 vector
- int16x8_t bottom = vld1q_s16((int16_t*)((const uint *)(s2)+x));
- int16x8_t bottomAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bottom), 8));
- int16x8_t bottomRB = vandq_s16(bottom, colorMask);
- bottomAG = vmulq_s16(bottomAG, disty_);
- bottomRB = vmulq_s16(bottomRB, disty_);
-
- // Add the values, and shift to only keep 8 significant bits per colors
- int16x8_t rAG = vaddq_s16(topAG, bottomAG);
- rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
- vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG);
- int16x8_t rRB = vaddq_s16(topRB, bottomRB);
- rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
- vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB);
- }
+ const int16x8_t disty_ = vdupq_n_s16(disty);
+ const int16x8_t idisty_ = vdupq_n_s16(idisty);
+ const int16x8_t colorMask = vdupq_n_s16(0x00ff);
+
+ lim -= 3;
+ for (; f < lim; x += 4, f += 4) {
+ // Load 4 pixels from s1, and split the alpha-green and red-blue component
+ int16x8_t top = vld1q_s16((int16_t*)((const uint *)(s1)+x));
+ int16x8_t topAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(top), 8));
+ int16x8_t topRB = vandq_s16(top, colorMask);
+ // Multiplies each color component by idisty
+ topAG = vmulq_s16(topAG, idisty_);
+ topRB = vmulq_s16(topRB, idisty_);
+
+ // Same for the s2 vector
+ int16x8_t bottom = vld1q_s16((int16_t*)((const uint *)(s2)+x));
+ int16x8_t bottomAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(bottom), 8));
+ int16x8_t bottomRB = vandq_s16(bottom, colorMask);
+ bottomAG = vmulq_s16(bottomAG, disty_);
+ bottomRB = vmulq_s16(bottomRB, disty_);
+
+ // Add the values, and shift to only keep 8 significant bits per colors
+ int16x8_t rAG = vaddq_s16(topAG, bottomAG);
+ rAG = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rAG), 8));
+ vst1q_s16((int16_t*)(&intermediate_buffer[1][f]), rAG);
+ int16x8_t rRB = vaddq_s16(topRB, bottomRB);
+ rRB = vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(rRB), 8));
+ vst1q_s16((int16_t*)(&intermediate_buffer[0][f]), rRB);
+ }
#endif
- }
- for (; f < count; f++) { // Same as above but without sse2
- if (blendType == BlendTransformedBilinearTiled) {
- if (x >= image_width) x -= image_width;
- } else {
- x = qMin(x, image_x2);
- }
+ }
+ for (; f < count; f++) { // Same as above but without simd
+ if (blendType == BlendTransformedBilinearTiled) {
+ if (x >= image.width) x -= image.width;
+ } else {
+ x = qMin(x, image.x2 - 1);
+ }
- uint t = s1[x];
- uint b = s2[x];
+ uint t = s1[x];
+ uint b = s2[x];
- intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
- intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
- x++;
- }
- // Now interpolate the values from the intermediate_buffer to get the final result.
- fx &= fixed_scale - 1;
- Q_ASSERT((fx >> 16) == 0);
- while (b < end) {
- int x1 = (fx >> 16);
- int x2 = x1 + 1;
- Q_ASSERT(x1 >= 0);
- Q_ASSERT(x2 < count);
+ intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ x++;
+ }
+ // Now interpolate the values from the intermediate_buffer to get the final result.
+ fx &= fixed_scale - 1;
+ Q_ASSERT((fx >> 16) == 0);
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2 = x1 + 1;
+ Q_ASSERT(x1 >= 0);
+ Q_ASSERT(x2 < count);
+
+ int distx = (fx & 0x0000ffff) >> 8;
+ int idistx = 256 - distx;
+ int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff;
+ int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00;
+ *b = rb | ag;
+ b++;
+ fx += fdx;
+ }
+}
- int distx = (fx & 0x0000ffff) >> 8;
- int idistx = 256 - distx;
- int rb = ((intermediate_buffer[0][x1] * idistx + intermediate_buffer[0][x2] * distx) >> 8) & 0xff00ff;
- int ag = (intermediate_buffer[1][x1] * idistx + intermediate_buffer[1][x2] * distx) & 0xff00ff00;
- *b = rb | ag;
- b++;
- fx += fdx;
- }
- } else if ((fdx < 0 && fdx > -(fixed_scale / 8)) || std::abs(data->m22) < (1./8.)) { // scale up more than 8x
- int y1 = (fy >> 16);
- int y2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uint *s1 = (const uint *)data->texture.scanLine(y1);
- const uint *s2 = (const uint *)data->texture.scanLine(y2);
- int disty = (fy & 0x0000ffff) >> 8;
- while (b < end) {
- int x1 = (fx >> 16);
- int x2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- uint tl = s1[x1];
- uint tr = s1[x2];
- uint bl = s2[x1];
- uint br = s2[x2];
- int distx = (fx & 0x0000ffff) >> 8;
- *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
+template<TextureBlendType blendType>
+static void QT_FASTCALL fetchTransformedBilinearARGB32PM_upscale_helper(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/)
+{
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
+ const int disty = (fy & 0x0000ffff) >> 8;
+
+ if (blendType != BlendTransformedBilinearTiled) {
+ const qint64 min_fx = qint64(image.x1) * fixed_scale;
+ const qint64 max_fx = qint64(image.x2 - 1) * fixed_scale;
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ if (x1 != x2)
+ break;
+ uint top = s1[x1];
+ uint bot = s2[x1];
+ *b = INTERPOLATE_PIXEL_256(top, 256 - disty, bot, disty);
+ fx += fdx;
+ ++b;
+ }
+ uint *boundedEnd = end;
+ if (fdx > 0)
+ boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx);
+ else if (fdx < 0)
+ boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx);
+
+ // A fast middle part without boundary checks
+ while (b < boundedEnd) {
+ int x = (fx >> 16);
+ int distx = (fx & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(s1 + x, s2 + x, distx, disty);
+ fx += fdx;
+ ++b;
+ }
+ }
- fx += fdx;
- ++b;
- }
- } else { //scale down
- int y1 = (fy >> 16);
- int y2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uint *s1 = (const uint *)data->texture.scanLine(y1);
- const uint *s2 = (const uint *)data->texture.scanLine(y2);
- const int disty8 = (fy & 0x0000ffff) >> 8;
- const int disty4 = (disty8 + 0x08) >> 4;
-
- if (blendType != BlendTransformedBilinearTiled) {
-#define BILINEAR_DOWNSCALE_BOUNDS_PROLOG \
- const qint64 min_fx = qint64(image_x1) * fixed_scale; \
- const qint64 max_fx = qint64(image_x2) * fixed_scale; \
- while (b < end) { \
- int x1 = (fx >> 16); \
- int x2; \
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); \
- if (x1 != x2) \
- break; \
- uint top = s1[x1]; \
- uint bot = s2[x1]; \
- *b = INTERPOLATE_PIXEL_256(top, 256 - disty8, bot, disty8); \
- fx += fdx; \
- ++b; \
- } \
- uint *boundedEnd = end; \
- if (fdx > 0) \
- boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx); \
- else if (fdx < 0) \
- boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx); \
- boundedEnd -= 3;
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1 , x1, x2);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
+ int distx = (fx & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
+
+ fx += fdx;
+ ++b;
+ }
+}
+template<TextureBlendType blendType>
+static void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/)
+{
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
+ const int disty8 = (fy & 0x0000ffff) >> 8;
+ const int disty4 = (disty8 + 0x08) >> 4;
+
+ if (blendType != BlendTransformedBilinearTiled) {
+ const qint64 min_fx = qint64(image.x1) * fixed_scale;
+ const qint64 max_fx = qint64(image.x2 - 1) * fixed_scale;
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ if (x1 != x2)
+ break;
+ uint top = s1[x1];
+ uint bot = s2[x1];
+ *b = INTERPOLATE_PIXEL_256(top, 256 - disty8, bot, disty8);
+ fx += fdx;
+ ++b;
+ }
+ uint *boundedEnd = end;
+ if (fdx > 0)
+ boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx);
+ else if (fdx < 0)
+ boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx);
+ // A fast middle part without boundary checks
#if defined(__SSE2__)
- BILINEAR_DOWNSCALE_BOUNDS_PROLOG
-
- const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
- const __m128i v_256 = _mm_set1_epi16(256);
- const __m128i v_disty = _mm_set1_epi16(disty4);
- const __m128i v_fdx = _mm_set1_epi32(fdx*4);
- const __m128i v_fx_r = _mm_set1_epi32(0x8);
- __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx);
-
- while (b < boundedEnd) {
- __m128i offset = _mm_srli_epi32(v_fx, 16);
- const int offset0 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
- const int offset1 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
- const int offset2 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
- const int offset3 = _mm_cvtsi128_si32(offset);
- const __m128i tl = _mm_setr_epi32(s1[offset0], s1[offset1], s1[offset2], s1[offset3]);
- const __m128i tr = _mm_setr_epi32(s1[offset0 + 1], s1[offset1 + 1], s1[offset2 + 1], s1[offset3 + 1]);
- const __m128i bl = _mm_setr_epi32(s2[offset0], s2[offset1], s2[offset2], s2[offset3]);
- const __m128i br = _mm_setr_epi32(s2[offset0 + 1], s2[offset1 + 1], s2[offset2 + 1], s2[offset3 + 1]);
-
- __m128i v_distx = _mm_srli_epi16(v_fx, 8);
- v_distx = _mm_srli_epi16(_mm_add_epi32(v_distx, v_fx_r), 4);
- v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
- v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
-
- interpolate_4_pixels_16_sse2(tl, tr, bl, br, v_distx, v_disty, colorMask, v_256, b);
- b += 4;
- v_fx = _mm_add_epi32(v_fx, v_fdx);
- }
- fx = _mm_cvtsi128_si32(v_fx);
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+ const __m128i v_256 = _mm_set1_epi16(256);
+ const __m128i v_disty = _mm_set1_epi16(disty4);
+ const __m128i v_fdx = _mm_set1_epi32(fdx*4);
+ const __m128i v_fx_r = _mm_set1_epi32(0x8);
+ __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx);
+
+ while (b < boundedEnd - 3) {
+ __m128i offset = _mm_srli_epi32(v_fx, 16);
+ const int offset0 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
+ const int offset1 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
+ const int offset2 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
+ const int offset3 = _mm_cvtsi128_si32(offset);
+ const __m128i tl = _mm_setr_epi32(s1[offset0], s1[offset1], s1[offset2], s1[offset3]);
+ const __m128i tr = _mm_setr_epi32(s1[offset0 + 1], s1[offset1 + 1], s1[offset2 + 1], s1[offset3 + 1]);
+ const __m128i bl = _mm_setr_epi32(s2[offset0], s2[offset1], s2[offset2], s2[offset3]);
+ const __m128i br = _mm_setr_epi32(s2[offset0 + 1], s2[offset1 + 1], s2[offset2 + 1], s2[offset3 + 1]);
+
+ __m128i v_distx = _mm_srli_epi16(v_fx, 8);
+ v_distx = _mm_srli_epi16(_mm_add_epi32(v_distx, v_fx_r), 4);
+ v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
+ v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
+
+ interpolate_4_pixels_16_sse2(tl, tr, bl, br, v_distx, v_disty, colorMask, v_256, b);
+ b += 4;
+ v_fx = _mm_add_epi32(v_fx, v_fdx);
+ }
+ fx = _mm_cvtsi128_si32(v_fx);
#elif defined(__ARM_NEON__)
- BILINEAR_DOWNSCALE_BOUNDS_PROLOG
-
- const int16x8_t colorMask = vdupq_n_s16(0x00ff);
- const int16x8_t invColorMask = vmvnq_s16(colorMask);
- const int16x8_t v_256 = vdupq_n_s16(256);
- const int16x8_t v_disty = vdupq_n_s16(disty4);
- const int16x8_t v_disty_ = vshlq_n_s16(v_disty, 4);
- int32x4_t v_fdx = vdupq_n_s32(fdx*4);
+ const int16x8_t colorMask = vdupq_n_s16(0x00ff);
+ const int16x8_t invColorMask = vmvnq_s16(colorMask);
+ const int16x8_t v_256 = vdupq_n_s16(256);
+ const int16x8_t v_disty = vdupq_n_s16(disty4);
+ const int16x8_t v_disty_ = vshlq_n_s16(v_disty, 4);
+ int32x4_t v_fdx = vdupq_n_s32(fdx*4);
- int32x4_t v_fx = vmovq_n_s32(fx);
- v_fx = vsetq_lane_s32(fx + fdx, v_fx, 1);
- v_fx = vsetq_lane_s32(fx + fdx * 2, v_fx, 2);
- v_fx = vsetq_lane_s32(fx + fdx * 3, v_fx, 3);
+ int32x4_t v_fx = vmovq_n_s32(fx);
+ v_fx = vsetq_lane_s32(fx + fdx, v_fx, 1);
+ v_fx = vsetq_lane_s32(fx + fdx * 2, v_fx, 2);
+ v_fx = vsetq_lane_s32(fx + fdx * 3, v_fx, 3);
- const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
- const int32x4_t v_fx_r = vdupq_n_s32(0x0800);
+ const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
+ const int32x4_t v_fx_r = vdupq_n_s32(0x0800);
- while (b < boundedEnd) {
- uint32x4x2_t v_top, v_bot;
+ while (b < boundedEnd - 3) {
+ uint32x4x2_t v_top, v_bot;
- int x1 = (fx >> 16);
- fx += fdx;
- v_top = vld2q_lane_u32(s1 + x1, v_top, 0);
- v_bot = vld2q_lane_u32(s2 + x1, v_bot, 0);
- x1 = (fx >> 16);
- fx += fdx;
- v_top = vld2q_lane_u32(s1 + x1, v_top, 1);
- v_bot = vld2q_lane_u32(s2 + x1, v_bot, 1);
- x1 = (fx >> 16);
- fx += fdx;
- v_top = vld2q_lane_u32(s1 + x1, v_top, 2);
- v_bot = vld2q_lane_u32(s2 + x1, v_bot, 2);
- x1 = (fx >> 16);
- fx += fdx;
- v_top = vld2q_lane_u32(s1 + x1, v_top, 3);
- v_bot = vld2q_lane_u32(s2 + x1, v_bot, 3);
-
- int32x4_t v_distx = vshrq_n_s32(vaddq_s32(vandq_s32(v_fx, v_ffff_mask), v_fx_r), 12);
- v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
-
- interpolate_4_pixels_16_neon(
- vreinterpretq_s16_u32(v_top.val[0]), vreinterpretq_s16_u32(v_top.val[1]),
- vreinterpretq_s16_u32(v_bot.val[0]), vreinterpretq_s16_u32(v_bot.val[1]),
- vreinterpretq_s16_s32(v_distx), v_disty, v_disty_,
- colorMask, invColorMask, v_256, b);
- b+=4;
- v_fx = vaddq_s32(v_fx, v_fdx);
- }
+ int x1 = (fx >> 16);
+ fx += fdx;
+ v_top = vld2q_lane_u32(s1 + x1, v_top, 0);
+ v_bot = vld2q_lane_u32(s2 + x1, v_bot, 0);
+ x1 = (fx >> 16);
+ fx += fdx;
+ v_top = vld2q_lane_u32(s1 + x1, v_top, 1);
+ v_bot = vld2q_lane_u32(s2 + x1, v_bot, 1);
+ x1 = (fx >> 16);
+ fx += fdx;
+ v_top = vld2q_lane_u32(s1 + x1, v_top, 2);
+ v_bot = vld2q_lane_u32(s2 + x1, v_bot, 2);
+ x1 = (fx >> 16);
+ fx += fdx;
+ v_top = vld2q_lane_u32(s1 + x1, v_top, 3);
+ v_bot = vld2q_lane_u32(s2 + x1, v_bot, 3);
+
+ int32x4_t v_distx = vshrq_n_s32(vaddq_s32(vandq_s32(v_fx, v_ffff_mask), v_fx_r), 12);
+ v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
+
+ interpolate_4_pixels_16_neon(
+ vreinterpretq_s16_u32(v_top.val[0]), vreinterpretq_s16_u32(v_top.val[1]),
+ vreinterpretq_s16_u32(v_bot.val[0]), vreinterpretq_s16_u32(v_bot.val[1]),
+ vreinterpretq_s16_s32(v_distx), v_disty, v_disty_,
+ colorMask, invColorMask, v_256, b);
+ b+=4;
+ v_fx = vaddq_s32(v_fx, v_fdx);
+ }
#endif
- }
+ while (b < boundedEnd) {
+ int x = (fx >> 16);
+#if defined(__SSE2__) || defined(__ARM_NEON__)
+ int distx8 = (fx & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(s1 + x, s2 + x, distx8, disty8);
+#else
+ uint tl = s1[x];
+ uint tr = s1[x + 1];
+ uint bl = s2[x];
+ uint br = s2[x + 1];
+ int distx4 = ((fx & 0x0000ffff) + 0x0800) >> 12;
+ *b = interpolate_4_pixels_16(tl, tr, bl, br, distx4, disty4);
+#endif
+ fx += fdx;
+ ++b;
+ }
+ }
- while (b < end) {
- int x1 = (fx >> 16);
- int x2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- uint tl = s1[x1];
- uint tr = s1[x2];
- uint bl = s2[x1];
- uint br = s2[x2];
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
#if defined(__SSE2__) || defined(__ARM_NEON__)
- // The optimized interpolate_4_pixels are faster than interpolate_4_pixels_16.
- int distx8 = (fx & 0x0000ffff) >> 8;
- *b = interpolate_4_pixels(tl, tr, bl, br, distx8, disty8);
+ // The optimized interpolate_4_pixels are faster than interpolate_4_pixels_16.
+ int distx8 = (fx & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(tl, tr, bl, br, distx8, disty8);
#else
- int distx4 = ((fx & 0x0000ffff) + 0x0800) >> 12;
- *b = interpolate_4_pixels_16(tl, tr, bl, br, distx4, disty4);
+ int distx4 = ((fx & 0x0000ffff) + 0x0800) >> 12;
+ *b = interpolate_4_pixels_16(tl, tr, bl, br, distx4, disty4);
#endif
- fx += fdx;
- ++b;
- }
- }
- } else { //rotation
- if (std::abs(data->m11) < (1./8.) || std::abs(data->m22) < (1./8.)) {
- //if we are zooming more than 8 times, we use 8bit precision for the position.
- while (b < end) {
- int x1 = (fx >> 16);
- int x2;
- int y1 = (fy >> 16);
- int y2;
+ fx += fdx;
+ ++b;
+ }
+}
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
+template<TextureBlendType blendType>
+static void QT_FASTCALL fetchTransformedBilinearARGB32PM_rotate_helper(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int fdy)
+{
+ // if we are zooming more than 8 times, we use 8bit precision for the position.
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ int y1 = (fy >> 16);
+ int y2;
- const uint *s1 = (const uint *)data->texture.scanLine(y1);
- const uint *s2 = (const uint *)data->texture.scanLine(y2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
- uint tl = s1[x1];
- uint tr = s1[x2];
- uint bl = s2[x1];
- uint br = s2[x2];
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
- int distx = (fx & 0x0000ffff) >> 8;
- int disty = (fy & 0x0000ffff) >> 8;
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
- *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
+ int distx = (fx & 0x0000ffff) >> 8;
+ int disty = (fy & 0x0000ffff) >> 8;
- fx += fdx;
- fy += fdy;
- ++b;
- }
- } else {
- //we are zooming less than 8x, use 4bit precision
-
- if (blendType != BlendTransformedBilinearTiled) {
-#define BILINEAR_ROTATE_BOUNDS_PROLOG \
- const qint64 min_fx = qint64(image_x1) * fixed_scale; \
- const qint64 max_fx = qint64(image_x2) * fixed_scale; \
- const qint64 min_fy = qint64(image_y1) * fixed_scale; \
- const qint64 max_fy = qint64(image_y2) * fixed_scale; \
- while (b < end) { \
- int x1 = (fx >> 16); \
- int x2; \
- int y1 = (fy >> 16); \
- int y2; \
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); \
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2); \
- if (x1 != x2 && y1 != y2) \
- break; \
- const uint *s1 = (const uint *)data->texture.scanLine(y1); \
- const uint *s2 = (const uint *)data->texture.scanLine(y2); \
- uint tl = s1[x1]; \
- uint tr = s1[x2]; \
- uint bl = s2[x1]; \
- uint br = s2[x2]; \
- int distx = (fx & 0x0000ffff) >> 8; \
- int disty = (fy & 0x0000ffff) >> 8; \
- *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty); \
- fx += fdx; \
- fy += fdy; \
- ++b; \
- } \
- uint *boundedEnd = end; \
- if (fdx > 0) \
- boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx); \
- else if (fdx < 0) \
- boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx); \
- if (fdy > 0) \
- boundedEnd = qMin(boundedEnd, b + (max_fy - fy) / fdy); \
- else if (fdy < 0) \
- boundedEnd = qMin(boundedEnd, b + (min_fy - fy) / fdy); \
- boundedEnd -= 3;
+ *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
-#if defined(__SSE2__)
- BILINEAR_ROTATE_BOUNDS_PROLOG
+ fx += fdx;
+ fy += fdy;
+ ++b;
+ }
+}
- const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
- const __m128i v_256 = _mm_set1_epi16(256);
- const __m128i v_fdx = _mm_set1_epi32(fdx*4);
- const __m128i v_fdy = _mm_set1_epi32(fdy*4);
- const __m128i v_fxy_r = _mm_set1_epi32(0x8);
- __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx);
- __m128i v_fy = _mm_setr_epi32(fy, fy + fdy, fy + fdy + fdy, fy + fdy + fdy + fdy);
+template<TextureBlendType blendType>
+static void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int fdy)
+{
+ //we are zooming less than 8x, use 4bit precision
+ if (blendType != BlendTransformedBilinearTiled) {
+ const qint64 min_fx = qint64(image.x1) * fixed_scale;
+ const qint64 max_fx = qint64(image.x2 - 1) * fixed_scale;
+ const qint64 min_fy = qint64(image.y1) * fixed_scale;
+ const qint64 max_fy = qint64(image.y2 - 1) * fixed_scale;
+ // first handle the possibly bounded part in the beginning
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+ if (x1 != x2 && y1 != y2)
+ break;
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
+#if defined(__SSE2__) || defined(__ARM_NEON__)
+ int distx = (fx & 0x0000ffff) >> 8;
+ int disty = (fy & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
+#else
+ int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
+ int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
+ *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
+#endif
+ fx += fdx;
+ fy += fdy;
+ ++b;
+ }
+ uint *boundedEnd = end; \
+ if (fdx > 0) \
+ boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx); \
+ else if (fdx < 0) \
+ boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx); \
+ if (fdy > 0) \
+ boundedEnd = qMin(boundedEnd, b + (max_fy - fy) / fdy); \
+ else if (fdy < 0) \
+ boundedEnd = qMin(boundedEnd, b + (min_fy - fy) / fdy); \
+
+ // until boundedEnd we can now have a fast middle part without boundary checks
+#if defined(__SSE2__)
+ const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
+ const __m128i v_256 = _mm_set1_epi16(256);
+ const __m128i v_fdx = _mm_set1_epi32(fdx*4);
+ const __m128i v_fdy = _mm_set1_epi32(fdy*4);
+ const __m128i v_fxy_r = _mm_set1_epi32(0x8);
+ __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx);
+ __m128i v_fy = _mm_setr_epi32(fy, fy + fdy, fy + fdy + fdy, fy + fdy + fdy + fdy);
+
+ const uchar *textureData = image.imageData;
+ const int bytesPerLine = image.bytesPerLine;
+ const __m128i vbpl = _mm_shufflelo_epi16(_mm_cvtsi32_si128(bytesPerLine/4), _MM_SHUFFLE(0, 0, 0, 0));
+
+ while (b < boundedEnd - 3) {
+ const __m128i vy = _mm_packs_epi32(_mm_srli_epi32(v_fy, 16), _mm_setzero_si128());
+ // 4x16bit * 4x16bit -> 4x32bit
+ __m128i offset = _mm_unpacklo_epi16(_mm_mullo_epi16(vy, vbpl), _mm_mulhi_epi16(vy, vbpl));
+ offset = _mm_add_epi32(offset, _mm_srli_epi32(v_fx, 16));
+ const int offset0 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
+ const int offset1 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
+ const int offset2 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
+ const int offset3 = _mm_cvtsi128_si32(offset);
+ const uint *topData = (const uint *)(textureData);
+ const __m128i tl = _mm_setr_epi32(topData[offset0], topData[offset1], topData[offset2], topData[offset3]);
+ const __m128i tr = _mm_setr_epi32(topData[offset0 + 1], topData[offset1 + 1], topData[offset2 + 1], topData[offset3 + 1]);
+ const uint *bottomData = (const uint *)(textureData + bytesPerLine);
+ const __m128i bl = _mm_setr_epi32(bottomData[offset0], bottomData[offset1], bottomData[offset2], bottomData[offset3]);
+ const __m128i br = _mm_setr_epi32(bottomData[offset0 + 1], bottomData[offset1 + 1], bottomData[offset2 + 1], bottomData[offset3 + 1]);
+
+ __m128i v_distx = _mm_srli_epi16(v_fx, 8);
+ __m128i v_disty = _mm_srli_epi16(v_fy, 8);
+ v_distx = _mm_srli_epi16(_mm_add_epi32(v_distx, v_fxy_r), 4);
+ v_disty = _mm_srli_epi16(_mm_add_epi32(v_disty, v_fxy_r), 4);
+ v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
+ v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
+ v_disty = _mm_shufflehi_epi16(v_disty, _MM_SHUFFLE(2,2,0,0));
+ v_disty = _mm_shufflelo_epi16(v_disty, _MM_SHUFFLE(2,2,0,0));
+
+ interpolate_4_pixels_16_sse2(tl, tr, bl, br, v_distx, v_disty, colorMask, v_256, b);
+ b += 4;
+ v_fx = _mm_add_epi32(v_fx, v_fdx);
+ v_fy = _mm_add_epi32(v_fy, v_fdy);
+ }
+ fx = _mm_cvtsi128_si32(v_fx);
+ fy = _mm_cvtsi128_si32(v_fy);
+#elif defined(__ARM_NEON__)
+ const int16x8_t colorMask = vdupq_n_s16(0x00ff);
+ const int16x8_t invColorMask = vmvnq_s16(colorMask);
+ const int16x8_t v_256 = vdupq_n_s16(256);
+ int32x4_t v_fdx = vdupq_n_s32(fdx * 4);
+ int32x4_t v_fdy = vdupq_n_s32(fdy * 4);
+
+ const uchar *textureData = image.imageData;
+ const int bytesPerLine = image.bytesPerLine;
+
+ int32x4_t v_fx = vmovq_n_s32(fx);
+ int32x4_t v_fy = vmovq_n_s32(fy);
+ v_fx = vsetq_lane_s32(fx + fdx, v_fx, 1);
+ v_fy = vsetq_lane_s32(fy + fdy, v_fy, 1);
+ v_fx = vsetq_lane_s32(fx + fdx * 2, v_fx, 2);
+ v_fy = vsetq_lane_s32(fy + fdy * 2, v_fy, 2);
+ v_fx = vsetq_lane_s32(fx + fdx * 3, v_fx, 3);
+ v_fy = vsetq_lane_s32(fy + fdy * 3, v_fy, 3);
+
+ const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
+ const int32x4_t v_round = vdupq_n_s32(0x0800);
+
+ while (b < boundedEnd - 3) {
+ uint32x4x2_t v_top, v_bot;
+
+ int x1 = (fx >> 16);
+ int y1 = (fy >> 16);
+ fx += fdx; fy += fdy;
+ const uchar *sl = textureData + bytesPerLine * y1;
+ const uint *s1 = reinterpret_cast<const uint *>(sl);
+ const uint *s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
+ v_top = vld2q_lane_u32(s1 + x1, v_top, 0);
+ v_bot = vld2q_lane_u32(s2 + x1, v_bot, 0);
+ x1 = (fx >> 16);
+ y1 = (fy >> 16);
+ fx += fdx; fy += fdy;
+ sl = textureData + bytesPerLine * y1;
+ s1 = reinterpret_cast<const uint *>(sl);
+ s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
+ v_top = vld2q_lane_u32(s1 + x1, v_top, 1);
+ v_bot = vld2q_lane_u32(s2 + x1, v_bot, 1);
+ x1 = (fx >> 16);
+ y1 = (fy >> 16);
+ fx += fdx; fy += fdy;
+ sl = textureData + bytesPerLine * y1;
+ s1 = reinterpret_cast<const uint *>(sl);
+ s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
+ v_top = vld2q_lane_u32(s1 + x1, v_top, 2);
+ v_bot = vld2q_lane_u32(s2 + x1, v_bot, 2);
+ x1 = (fx >> 16);
+ y1 = (fy >> 16);
+ fx += fdx; fy += fdy;
+ sl = textureData + bytesPerLine * y1;
+ s1 = reinterpret_cast<const uint *>(sl);
+ s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
+ v_top = vld2q_lane_u32(s1 + x1, v_top, 3);
+ v_bot = vld2q_lane_u32(s2 + x1, v_bot, 3);
+
+ int32x4_t v_distx = vshrq_n_s32(vaddq_s32(vandq_s32(v_fx, v_ffff_mask), v_round), 12);
+ int32x4_t v_disty = vshrq_n_s32(vaddq_s32(vandq_s32(v_fy, v_ffff_mask), v_round), 12);
+ v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
+ v_disty = vorrq_s32(v_disty, vshlq_n_s32(v_disty, 16));
+ int16x8_t v_disty_ = vshlq_n_s16(vreinterpretq_s16_s32(v_disty), 4);
+
+ interpolate_4_pixels_16_neon(
+ vreinterpretq_s16_u32(v_top.val[0]), vreinterpretq_s16_u32(v_top.val[1]),
+ vreinterpretq_s16_u32(v_bot.val[0]), vreinterpretq_s16_u32(v_bot.val[1]),
+ vreinterpretq_s16_s32(v_distx), vreinterpretq_s16_s32(v_disty),
+ v_disty_, colorMask, invColorMask, v_256, b);
+ b += 4;
+ v_fx = vaddq_s32(v_fx, v_fdx);
+ v_fy = vaddq_s32(v_fy, v_fdy);
+ }
+#endif
+ while (b < boundedEnd) {
+ int x = (fx >> 16);
+ int y = (fy >> 16);
- const uchar *textureData = data->texture.imageData;
- const int bytesPerLine = data->texture.bytesPerLine;
- const __m128i vbpl = _mm_shufflelo_epi16(_mm_cvtsi32_si128(bytesPerLine/4), _MM_SHUFFLE(0, 0, 0, 0));
+ const uint *s1 = (const uint *)image.scanLine(y);
+ const uint *s2 = (const uint *)image.scanLine(y + 1);
- while (b < boundedEnd) {
- const __m128i vy = _mm_packs_epi32(_mm_srli_epi32(v_fy, 16), _mm_setzero_si128());
- // 4x16bit * 4x16bit -> 4x32bit
- __m128i offset = _mm_unpacklo_epi16(_mm_mullo_epi16(vy, vbpl), _mm_mulhi_epi16(vy, vbpl));
- offset = _mm_add_epi32(offset, _mm_srli_epi32(v_fx, 16));
- const int offset0 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
- const int offset1 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
- const int offset2 = _mm_cvtsi128_si32(offset); offset = _mm_srli_si128(offset, 4);
- const int offset3 = _mm_cvtsi128_si32(offset);
- const uint *topData = (const uint *)(textureData);
- const __m128i tl = _mm_setr_epi32(topData[offset0], topData[offset1], topData[offset2], topData[offset3]);
- const __m128i tr = _mm_setr_epi32(topData[offset0 + 1], topData[offset1 + 1], topData[offset2 + 1], topData[offset3 + 1]);
- const uint *bottomData = (const uint *)(textureData + bytesPerLine);
- const __m128i bl = _mm_setr_epi32(bottomData[offset0], bottomData[offset1], bottomData[offset2], bottomData[offset3]);
- const __m128i br = _mm_setr_epi32(bottomData[offset0 + 1], bottomData[offset1 + 1], bottomData[offset2 + 1], bottomData[offset3 + 1]);
-
- __m128i v_distx = _mm_srli_epi16(v_fx, 8);
- __m128i v_disty = _mm_srli_epi16(v_fy, 8);
- v_distx = _mm_srli_epi16(_mm_add_epi32(v_distx, v_fxy_r), 4);
- v_disty = _mm_srli_epi16(_mm_add_epi32(v_disty, v_fxy_r), 4);
- v_distx = _mm_shufflehi_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
- v_distx = _mm_shufflelo_epi16(v_distx, _MM_SHUFFLE(2,2,0,0));
- v_disty = _mm_shufflehi_epi16(v_disty, _MM_SHUFFLE(2,2,0,0));
- v_disty = _mm_shufflelo_epi16(v_disty, _MM_SHUFFLE(2,2,0,0));
-
- interpolate_4_pixels_16_sse2(tl, tr, bl, br, v_distx, v_disty, colorMask, v_256, b);
- b += 4;
- v_fx = _mm_add_epi32(v_fx, v_fdx);
- v_fy = _mm_add_epi32(v_fy, v_fdy);
- }
- fx = _mm_cvtsi128_si32(v_fx);
- fy = _mm_cvtsi128_si32(v_fy);
-#elif defined(__ARM_NEON__)
- BILINEAR_ROTATE_BOUNDS_PROLOG
+#if defined(__SSE2__) || defined(__ARM_NEON__)
+ int distx = (fx & 0x0000ffff) >> 8;
+ int disty = (fy & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(s1 + x, s2 + x, distx, disty);
+#else
+ uint tl = s1[x];
+ uint tr = s1[x + 1];
+ uint bl = s2[x];
+ uint br = s2[x + 1];
+ int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
+ int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
+ *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
+#endif
- const int16x8_t colorMask = vdupq_n_s16(0x00ff);
- const int16x8_t invColorMask = vmvnq_s16(colorMask);
- const int16x8_t v_256 = vdupq_n_s16(256);
- int32x4_t v_fdx = vdupq_n_s32(fdx * 4);
- int32x4_t v_fdy = vdupq_n_s32(fdy * 4);
+ fx += fdx;
+ fy += fdy;
+ ++b;
+ }
+ }
- const uchar *textureData = data->texture.imageData;
- const int bytesPerLine = data->texture.bytesPerLine;
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ int y1 = (fy >> 16);
+ int y2;
- int32x4_t v_fx = vmovq_n_s32(fx);
- int32x4_t v_fy = vmovq_n_s32(fy);
- v_fx = vsetq_lane_s32(fx + fdx, v_fx, 1);
- v_fy = vsetq_lane_s32(fy + fdy, v_fy, 1);
- v_fx = vsetq_lane_s32(fx + fdx * 2, v_fx, 2);
- v_fy = vsetq_lane_s32(fy + fdy * 2, v_fy, 2);
- v_fx = vsetq_lane_s32(fx + fdx * 3, v_fx, 3);
- v_fy = vsetq_lane_s32(fy + fdy * 3, v_fy, 3);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
- const int32x4_t v_ffff_mask = vdupq_n_s32(0x0000ffff);
- const int32x4_t v_round = vdupq_n_s32(0x0800);
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
- while (b < boundedEnd) {
- uint32x4x2_t v_top, v_bot;
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
- int x1 = (fx >> 16);
- int y1 = (fy >> 16);
- fx += fdx; fy += fdy;
- const uchar *sl = textureData + bytesPerLine * y1;
- const uint *s1 = reinterpret_cast<const uint *>(sl);
- const uint *s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
- v_top = vld2q_lane_u32(s1 + x1, v_top, 0);
- v_bot = vld2q_lane_u32(s2 + x1, v_bot, 0);
- x1 = (fx >> 16);
- y1 = (fy >> 16);
- fx += fdx; fy += fdy;
- sl = textureData + bytesPerLine * y1;
- s1 = reinterpret_cast<const uint *>(sl);
- s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
- v_top = vld2q_lane_u32(s1 + x1, v_top, 1);
- v_bot = vld2q_lane_u32(s2 + x1, v_bot, 1);
- x1 = (fx >> 16);
- y1 = (fy >> 16);
- fx += fdx; fy += fdy;
- sl = textureData + bytesPerLine * y1;
- s1 = reinterpret_cast<const uint *>(sl);
- s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
- v_top = vld2q_lane_u32(s1 + x1, v_top, 2);
- v_bot = vld2q_lane_u32(s2 + x1, v_bot, 2);
- x1 = (fx >> 16);
- y1 = (fy >> 16);
- fx += fdx; fy += fdy;
- sl = textureData + bytesPerLine * y1;
- s1 = reinterpret_cast<const uint *>(sl);
- s2 = reinterpret_cast<const uint *>(sl + bytesPerLine);
- v_top = vld2q_lane_u32(s1 + x1, v_top, 3);
- v_bot = vld2q_lane_u32(s2 + x1, v_bot, 3);
-
- int32x4_t v_distx = vshrq_n_s32(vaddq_s32(vandq_s32(v_fx, v_ffff_mask), v_round), 12);
- int32x4_t v_disty = vshrq_n_s32(vaddq_s32(vandq_s32(v_fy, v_ffff_mask), v_round), 12);
- v_distx = vorrq_s32(v_distx, vshlq_n_s32(v_distx, 16));
- v_disty = vorrq_s32(v_disty, vshlq_n_s32(v_disty, 16));
- int16x8_t v_disty_ = vshlq_n_s16(vreinterpretq_s16_s32(v_disty), 4);
-
- interpolate_4_pixels_16_neon(
- vreinterpretq_s16_u32(v_top.val[0]), vreinterpretq_s16_u32(v_top.val[1]),
- vreinterpretq_s16_u32(v_bot.val[0]), vreinterpretq_s16_u32(v_bot.val[1]),
- vreinterpretq_s16_s32(v_distx), vreinterpretq_s16_s32(v_disty),
- v_disty_, colorMask, invColorMask, v_256, b);
- b += 4;
- v_fx = vaddq_s32(v_fx, v_fdx);
- v_fy = vaddq_s32(v_fy, v_fdy);
- }
+#if defined(__SSE2__) || defined(__ARM_NEON__)
+ // The optimized interpolate_4_pixels are faster than interpolate_4_pixels_16.
+ int distx = (fx & 0x0000ffff) >> 8;
+ int disty = (fy & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
+#else
+ int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
+ int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
+ *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
#endif
- }
- while (b < end) {
- int x1 = (fx >> 16);
- int x2;
- int y1 = (fy >> 16);
- int y2;
+ fx += fdx;
+ fy += fdy;
+ ++b;
+ }
+}
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uint *s1 = (const uint *)data->texture.scanLine(y1);
- const uint *s2 = (const uint *)data->texture.scanLine(y2);
+static BilinearFastTransformHelper bilinearFastTransformHelperARGB32PM[2][NFastTransformTypes] = {
+ {
+ fetchTransformedBilinearARGB32PM_simple_upscale_helper<BlendTransformedBilinear>,
+ fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinear>,
+ fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinear>,
+ fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinear>,
+ fetchTransformedBilinearARGB32PM_fast_rotate_helper<BlendTransformedBilinear>
+ },
+ {
+ fetchTransformedBilinearARGB32PM_simple_upscale_helper<BlendTransformedBilinearTiled>,
+ fetchTransformedBilinearARGB32PM_upscale_helper<BlendTransformedBilinearTiled>,
+ fetchTransformedBilinearARGB32PM_downscale_helper<BlendTransformedBilinearTiled>,
+ fetchTransformedBilinearARGB32PM_rotate_helper<BlendTransformedBilinearTiled>,
+ fetchTransformedBilinearARGB32PM_fast_rotate_helper<BlendTransformedBilinearTiled>
+ }
+};
- uint tl = s1[x1];
- uint tr = s1[x2];
- uint bl = s2[x1];
- uint br = s2[x2];
+template<TextureBlendType blendType> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
+static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, const Operator *,
+ const QSpanData *data, int y, int x,
+ int length)
+{
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+ Q_CONSTEXPR int tiled = (blendType == BlendTransformedBilinearTiled) ? 1 : 0;
-#if defined(__SSE2__) || defined(__ARM_NEON__)
- // The optimized interpolate_4_pixels are faster than interpolate_4_pixels_16.
- int distx = (fx & 0x0000ffff) >> 8;
- int disty = (fy & 0x0000ffff) >> 8;
- *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
-#else
- int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
- int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
- *b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
-#endif
+ uint *end = buffer + length;
+ uint *b = buffer;
+ if (data->fast_matrix) {
+ // The increment pr x in the scanline
+ int fdx = (int)(data->m11 * fixed_scale);
+ int fdy = (int)(data->m12 * fixed_scale);
- fx += fdx;
- fy += fdy;
- ++b;
- }
+ int fx = int((data->m21 * cy
+ + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy
+ + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+
+ if (fdy == 0) { // simple scale, no rotation or shear
+ if (fdx <= fixed_scale && fdx > 0) {
+ // simple scale up on X without mirroring
+ bilinearFastTransformHelperARGB32PM[tiled][SimpleUpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
+ } else if ((fdx < 0 && fdx > -(fixed_scale / 8)) || qAbs(data->m22) < qreal(1./8.)) {
+ // scale up more than 8x (on either Y or on X mirrored)
+ bilinearFastTransformHelperARGB32PM[tiled][UpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
+ } else {
+ // scale down on X (or up on X mirrored less than 8x)
+ bilinearFastTransformHelperARGB32PM[tiled][DownscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
+ }
+ } else { // rotation or shear
+ if (qAbs(data->m11) < qreal(1./8.) || qAbs(data->m22) < qreal(1./8.) ) {
+ // if we are zooming more than 8 times, we use 8bit precision for the position.
+ bilinearFastTransformHelperARGB32PM[tiled][RotateTransform](b, end, data->texture, fx, fy, fdx, fdy);
+ } else {
+ // we are zooming less than 8x, use 4bit precision
+ bilinearFastTransformHelperARGB32PM[tiled][FastRotateTransform](b, end, data->texture, fx, fy, fdx, fdy);
}
}
} else {
+ const QTextureData &image = data->texture;
+
const qreal fdx = data->m11;
const qreal fdy = data->m12;
const qreal fdw = data->m13;
@@ -2491,8 +2630,8 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c
int distx = int((px - x1) * 256);
int disty = int((py - y1) * 256);
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
const uint *s1 = (const uint *)data->texture.scanLine(y1);
const uint *s2 = (const uint *)data->texture.scanLine(y2);
@@ -2674,7 +2813,7 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0);
layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0);
- if ((fdx < 0 && fdx > -(fixed_scale / 8)) || std::abs(data->m22) < (1./8.)) { // scale up more than 8x
+ if ((fdx < 0 && fdx > -(fixed_scale / 8)) || qAbs(data->m22) < qreal(1./8.)) { // scale up more than 8x
int disty = (fy & 0x0000ffff) >> 8;
for (int i = 0; i < len; ++i) {
int distx = (fracX & 0x0000ffff) >> 8;
@@ -2726,7 +2865,7 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0);
layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0);
- if (std::abs(data->m11) < (1./8.) || std::abs(data->m22) < (1./8.)) {
+ if (qAbs(data->m11) < qreal(1./8.) || qAbs(data->m22) < qreal(1./8.) ) {
//if we are zooming more than 8 times, we use 8bit precision for the position.
for (int i = 0; i < len; ++i) {
int distx = (fracX & 0x0000ffff) >> 8;
@@ -3603,27 +3742,23 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
op.destFetch = destFetchProc[data->rasterBuffer->format];
op.destFetch64 = destFetchProc64[data->rasterBuffer->format];
- if (op.mode == QPainter::CompositionMode_Source) {
- switch (data->rasterBuffer->format) {
- case QImage::Format_RGB32:
- case QImage::Format_ARGB32_Premultiplied:
- // don't clear destFetch as it sets up the pointer correctly to save one copy
- break;
- default: {
- if (data->type == QSpanData::Texture && data->texture.const_alpha != 256)
+ if (op.mode == QPainter::CompositionMode_Source &&
+ (data->type != QSpanData::Texture || data->texture.const_alpha == 256)) {
+ const QSpan *lastSpan = spans + spanCount;
+ bool alphaSpans = false;
+ while (spans < lastSpan) {
+ if (spans->coverage != 255) {
+ alphaSpans = true;
break;
- const QSpan *lastSpan = spans + spanCount;
- bool alphaSpans = false;
- while (spans < lastSpan) {
- if (spans->coverage != 255) {
- alphaSpans = true;
- break;
- }
- ++spans;
}
- if (!alphaSpans)
- op.destFetch = 0;
+ ++spans;
}
+ if (!alphaSpans) {
+ // If all spans are opaque we do not need to fetch dest.
+ // But don't clear passthrough destFetch as they are just as fast and save destStore.
+ if (op.destFetch != destFetchARGB32P)
+ op.destFetch = 0;
+ op.destFetch64 = destFetch64Undefined;
}
}
@@ -5191,6 +5326,8 @@ void qBlendTexture(int count, const QSpan *spans, void *userData)
case QImage::Format_RGB16:
proc = processTextureSpansRGB16[blendType];
break;
+ case QImage::Format_ARGB32:
+ case QImage::Format_RGBA8888:
case QImage::Format_BGR30:
case QImage::Format_A2BGR30_Premultiplied:
case QImage::Format_RGB30:
@@ -5403,134 +5540,200 @@ inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
map, mapWidth, mapHeight, mapStride);
}
-static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
+static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorProfile *colorProfile)
+{
+ if (coverage == 0) {
+ // nothing
+ } else if (coverage == 255) {
+ dest[x] = src;
+ } else {
+ QRgba64 dstColor = dest[x];
+ if (colorProfile) {
+ if (dstColor.isOpaque())
+ dstColor = colorProfile->toLinear(dstColor);
+ else if (!dstColor.isTransparent())
+ dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
+ }
+
+ dstColor = interpolate255(srcLinear, coverage, dstColor, 255 - coverage);
+ if (colorProfile) {
+ if (dstColor.isOpaque())
+ dstColor = colorProfile->fromLinear(dstColor);
+ else if (!dstColor.isTransparent())
+ dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
+ }
+ dest[x] = dstColor;
+ }
+}
+
+static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
const uchar *map,
int mapWidth, int mapHeight, int mapStride,
- const QClipData *)
+ const QClipData *clip, bool useGammaCorrection)
{
- const quint16 c = color.toRgb16();
- quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
- const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
+ if (color.isTransparent())
+ return;
- while (mapHeight--) {
- for (int i = 0; i < mapWidth; ++i) {
- const int coverage = map[i];
+ const QColorProfile *colorProfile = nullptr;
- if (coverage == 0) {
- // nothing
- } else if (coverage == 255) {
- dest[i] = c;
- } else {
- int ialpha = 255 - coverage;
- dest[i] = BYTE_MUL_RGB16(c, coverage)
- + BYTE_MUL_RGB16(dest[i], ialpha);
+ if (useGammaCorrection)
+ colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
+
+ QRgba64 srcColor = color;
+ if (colorProfile) {
+ if (color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
+ else
+ srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
+ }
+
+ quint64 buffer[buffer_size];
+ const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
+ const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format];
+
+ if (!clip) {
+ for (int ly = 0; ly < mapHeight; ++ly) {
+ int i = x;
+ int length = mapWidth;
+ while (length > 0) {
+ int l = qMin(buffer_size, length);
+ QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l);
+ for (int j=0; j < l; ++j) {
+ const int coverage = map[j + (i - x)];
+ alphamapblend_generic(coverage, dest, j, srcColor, color, colorProfile);
+ }
+ destStore64(rasterBuffer, i, y + ly, dest, l);
+ length -= l;
+ i += l;
}
+ map += mapStride;
}
- dest += destStride;
- map += mapStride;
- }
-}
+ } else {
+ int bottom = qMin(y + mapHeight, rasterBuffer->height());
-static inline void rgbBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb, const uchar *gamma, const uchar *invgamma)
-{
- // Do a gray alphablend...
- int da = qAlpha(*dst);
- int dr = qRed(*dst);
- int dg = qGreen(*dst);
- int db = qBlue(*dst);
+ int top = qMax(y, 0);
+ map += (top - y) * mapStride;
+
+ const_cast<QClipData *>(clip)->initialize();
+ for (int yp = top; yp<bottom; ++yp) {
+ const QClipData::ClipLine &line = clip->m_clipLines[yp];
- if (da != 255
- ) {
+ for (int i=0; i<line.count; ++i) {
+ const QSpan &clip = line.spans[i];
- int a = qGray(coverage);
- sr = qt_div_255(invgamma[sr] * a);
- sg = qt_div_255(invgamma[sg] * a);
- sb = qt_div_255(invgamma[sb] * a);
+ int start = qMax<int>(x, clip.x);
+ int end = qMin<int>(x + mapWidth, clip.x + clip.len);
+ Q_ASSERT(clip.len <= buffer_size);
+ QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, clip.len);
- int ia = 255 - a;
- dr = qt_div_255(dr * ia);
- dg = qt_div_255(dg * ia);
- db = qt_div_255(db * ia);
+ for (int xp=start; xp<end; ++xp) {
+ const int coverage = map[xp - x];
+ alphamapblend_generic(coverage, dest, xp - start, srcColor, color, colorProfile);
+ }
+ destStore64(rasterBuffer, start, clip.y, dest, clip.len);
+ } // for (i -> line.count)
+ map += mapStride;
+ } // for (yp -> bottom)
+ }
+}
- *dst = ((a + qt_div_255((255 - a) * da)) << 24)
- | ((sr + dr) << 16)
- | ((sg + dg) << 8)
- | ((sb + db));
+static inline void alphamapblend_quint16(int coverage, quint16 *dest, int x, const quint16 srcColor)
+{
+ if (coverage == 0) {
+ // nothing
+ } else if (coverage == 255) {
+ dest[x] = srcColor;
+ } else {
+ dest[x] = BYTE_MUL_RGB16(srcColor, coverage)
+ + BYTE_MUL_RGB16(dest[x], 255 - coverage);
+ }
+}
+
+void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
+ int x, int y, const QRgba64 &color,
+ const uchar *map,
+ int mapWidth, int mapHeight, int mapStride,
+ const QClipData *clip, bool useGammaCorrection)
+{
+ if (useGammaCorrection) {
+ qt_alphamapblit_generic(rasterBuffer, x, y, color, map, mapWidth, mapHeight, mapStride, clip, useGammaCorrection);
return;
}
- int mr = qRed(coverage);
- int mg = qGreen(coverage);
- int mb = qBlue(coverage);
+ const quint16 c = color.toRgb16();
- dr = gamma[dr];
- dg = gamma[dg];
- db = gamma[db];
+ if (!clip) {
+ quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
+ const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
+ while (mapHeight--) {
+ for (int i = 0; i < mapWidth; ++i)
+ alphamapblend_quint16(map[i], dest, i, c);
+ dest += destStride;
+ map += mapStride;
+ }
+ } else {
+ int top = qMax(y, 0);
+ int bottom = qMin(y + mapHeight, rasterBuffer->height());
+ map += (top - y) * mapStride;
- int nr = qt_div_255(sr * mr + dr * (255 - mr));
- int ng = qt_div_255(sg * mg + dg * (255 - mg));
- int nb = qt_div_255(sb * mb + db * (255 - mb));
+ const_cast<QClipData *>(clip)->initialize();
+ for (int yp = top; yp<bottom; ++yp) {
+ const QClipData::ClipLine &line = clip->m_clipLines[yp];
- nr = invgamma[nr];
- ng = invgamma[ng];
- nb = invgamma[nb];
+ quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(yp));
- *dst = qRgb(nr, ng, nb);
-}
+ for (int i=0; i<line.count; ++i) {
+ const QSpan &clip = line.spans[i];
+
+ int start = qMax<int>(x, clip.x);
+ int end = qMin<int>(x + mapWidth, clip.x + clip.len);
-#if defined(Q_OS_WIN)
-Q_GUI_EXPORT bool qt_needs_a8_gamma_correction = false;
+ for (int xp=start; xp<end; ++xp)
+ alphamapblend_quint16(map[xp - x], dest, xp, c);
+ } // for (i -> line.count)
+ map += mapStride;
+ } // for (yp -> bottom)
+ }
+}
-static inline void grayBlendPixel(quint32 *dst, int coverage, int sr, int sg, int sb, const uint *gamma, const uchar *invgamma)
+static inline void rgbBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorProfile *colorProfile, bool useGammaCorrection)
{
- // Do a gammacorrected gray alphablend...
- int dr = qRed(*dst);
- int dg = qGreen(*dst);
- int db = qBlue(*dst);
+ // Do a gammacorrected RGB alphablend...
+ const QRgba64 dlinear = useGammaCorrection ? colorProfile->toLinear64(*dst) : QRgba64::fromArgb32(*dst);
- dr = gamma[dr];
- dg = gamma[dg];
- db = gamma[db];
+ QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
- int alpha = coverage;
- int ialpha = 255 - alpha;
- int nr = qt_div_255(sr * alpha + dr * ialpha);
- int ng = qt_div_255(sg * alpha + dg * ialpha);
- int nb = qt_div_255(sb * alpha + db * ialpha);
+ *dst = useGammaCorrection ? colorProfile->fromLinear64(blend) : toArgb32(blend);
+}
+
+static inline void grayBlendPixel(quint32 *dst, int coverage, QRgba64 slinear, const QColorProfile *colorProfile)
+{
+ // Do a gammacorrected gray alphablend...
+ const QRgba64 dlinear = colorProfile->toLinear64(*dst);
- nr = invgamma[nr];
- ng = invgamma[ng];
- nb = invgamma[nb];
+ QRgba64 blend = interpolate255(slinear, coverage, dlinear, 255 - coverage);
- *dst = qRgb(nr, ng, nb);
+ *dst = colorProfile->fromLinear64(blend);
}
-#endif
static void qt_alphamapblit_uint32(QRasterBuffer *rasterBuffer,
int x, int y, quint32 color,
const uchar *map,
int mapWidth, int mapHeight, int mapStride,
- const QClipData *clip)
+ const QClipData *clip, bool useGammaCorrection)
{
const quint32 c = color;
const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
-#if defined(Q_OS_WIN)
- const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables();
- if (!tables)
+ const QColorProfile *colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
+ if (!colorProfile)
return;
- const uint *gamma = tables->qt_pow_gamma;
- const uchar *invgamma = tables->qt_pow_invgamma;
-
- int sr = gamma[qRed(color)];
- int sg = gamma[qGreen(color)];
- int sb = gamma[qBlue(color)];
+ const QRgba64 slinear = colorProfile->toLinear64(c);
bool opaque_src = (qAlpha(color) == 255);
- bool doGrayBlendPixel = opaque_src && qt_needs_a8_gamma_correction;
-#endif
+ bool doGrayBlendPixel = opaque_src && useGammaCorrection;
if (!clip) {
quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
@@ -5543,13 +5746,9 @@ static void qt_alphamapblit_uint32(QRasterBuffer *rasterBuffer,
} else if (coverage == 255) {
dest[i] = c;
} else {
-#if defined(Q_OS_WIN)
- if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && doGrayBlendPixel
- && qAlpha(dest[i]) == 255) {
- grayBlendPixel(dest+i, coverage, sr, sg, sb, gamma, invgamma);
- } else
-#endif
- {
+ if (doGrayBlendPixel && qAlpha(dest[i]) == 255) {
+ grayBlendPixel(dest+i, coverage, slinear, colorProfile);
+ } else {
int ialpha = 255 - coverage;
dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha);
}
@@ -5584,13 +5783,9 @@ static void qt_alphamapblit_uint32(QRasterBuffer *rasterBuffer,
} else if (coverage == 255) {
dest[xp] = c;
} else {
-#if defined(Q_OS_WIN)
- if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP && doGrayBlendPixel
- && qAlpha(dest[xp]) == 255) {
- grayBlendPixel(dest+xp, coverage, sr, sg, sb, gamma, invgamma);
- } else
-#endif
- {
+ if (doGrayBlendPixel && qAlpha(dest[xp]) == 255) {
+ grayBlendPixel(dest+xp, coverage, slinear, colorProfile);
+ } else {
int ialpha = 255 - coverage;
dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha);
}
@@ -5608,9 +5803,9 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
const uchar *map,
int mapWidth, int mapHeight, int mapStride,
- const QClipData *clip)
+ const QClipData *clip, bool useGammaCorrection)
{
- qt_alphamapblit_uint32(rasterBuffer, x, y, color.toArgb32(), map, mapWidth, mapHeight, mapStride, clip);
+ qt_alphamapblit_uint32(rasterBuffer, x, y, color.toArgb32(), map, mapWidth, mapHeight, mapStride, clip, useGammaCorrection);
}
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
@@ -5618,38 +5813,132 @@ static void qt_alphamapblit_rgba8888(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
const uchar *map,
int mapWidth, int mapHeight, int mapStride,
- const QClipData *clip)
+ const QClipData *clip, bool useGammaCorrection)
{
- qt_alphamapblit_uint32(rasterBuffer, x, y, ARGB2RGBA(color.toArgb32()), map, mapWidth, mapHeight, mapStride, clip);
+ qt_alphamapblit_uint32(rasterBuffer, x, y, ARGB2RGBA(color.toArgb32()), map, mapWidth, mapHeight, mapStride, clip, useGammaCorrection);
}
#endif
-static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
- int x, int y, const QRgba64 &color,
- const uint *src, int mapWidth, int mapHeight, int srcStride,
- const QClipData *clip)
+static inline int qRgbAvg(QRgb rgb)
{
- const quint32 c = color.toArgb32();
+ return (qRed(rgb) * 5 + qGreen(rgb) * 6 + qBlue(rgb) * 5) / 16;
+}
- int sr = qRed(c);
- int sg = qGreen(c);
- int sb = qBlue(c);
- int sa = qAlpha(c);
+static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorProfile *colorProfile)
+{
+ if (coverage == 0xff000000) {
+ // nothing
+ } else if (coverage == 0xffffffff) {
+ dest[x] = src;
+ } else {
+ QRgba64 dstColor = dest[x];
+ if (dstColor.isOpaque()) {
+ if (colorProfile)
+ dstColor = colorProfile->toLinear(dstColor);
+ dstColor = rgbBlend(dstColor, srcLinear, coverage);
+ if (colorProfile)
+ dstColor = colorProfile->fromLinear(dstColor);
+ dest[x] = dstColor;
+ } else {
+ // Give up and do a gray alphablend.
+ if (colorProfile && !dstColor.isTransparent())
+ dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
+ const int a = qRgbAvg(coverage);
+ dstColor = interpolate255(srcLinear, coverage, dstColor, 255 - a);
+ if (colorProfile && !dstColor.isTransparent())
+ dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
+ dest[x] = dstColor;
+ }
+ }
+}
- const QDrawHelperGammaTables *tables = QGuiApplicationPrivate::instance()->gammaTables();
- if (!tables)
+static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
+ int x, int y, const QRgba64 &color,
+ const uint *src, int mapWidth, int mapHeight, int srcStride,
+ const QClipData *clip, bool useGammaCorrection)
+{
+ if (color.isTransparent())
return;
- const uchar *gamma = tables->qt_pow_rgb_gamma;
- const uchar *invgamma = tables->qt_pow_rgb_invgamma;
+ const QColorProfile *colorProfile = nullptr;
+
+ if (useGammaCorrection)
+ colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
+
+ QRgba64 srcColor = color;
+ if (colorProfile) {
+ if (color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
+ else
+ srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
+ }
+
+ quint64 buffer[buffer_size];
+ const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
+ const DestStoreProc64 destStore64 = destStoreProc64[rasterBuffer->format];
+
+ if (!clip) {
+ for (int ly = 0; ly < mapHeight; ++ly) {
+ int i = x;
+ int length = mapWidth;
+ while (length > 0) {
+ int l = qMin(buffer_size, length);
+ QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, i, y + ly, l);
+ for (int j=0; j < l; ++j) {
+ const uint coverage = src[j + (i - x)];
+ alphargbblend_generic(coverage, dest, j, srcColor, color, colorProfile);
+ }
+ destStore64(rasterBuffer, i, y + ly, dest, l);
+ length -= l;
+ i += l;
+ }
+ src += srcStride;
+ }
+ } else {
+ int bottom = qMin(y + mapHeight, rasterBuffer->height());
+
+ int top = qMax(y, 0);
+ src += (top - y) * srcStride;
+
+ const_cast<QClipData *>(clip)->initialize();
+ for (int yp = top; yp<bottom; ++yp) {
+ const QClipData::ClipLine &line = clip->m_clipLines[yp];
+
+ for (int i=0; i<line.count; ++i) {
+ const QSpan &clip = line.spans[i];
+
+ int start = qMax<int>(x, clip.x);
+ int end = qMin<int>(x + mapWidth, clip.x + clip.len);
+ Q_ASSERT(clip.len <= buffer_size);
+ QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, clip.len);
+
+ for (int xp=start; xp<end; ++xp) {
+ const uint coverage = src[xp - x];
+ alphargbblend_generic(coverage, dest, xp - start, srcColor, color, colorProfile);
+ }
+ destStore64(rasterBuffer, start, clip.y, dest, clip.len);
+ } // for (i -> line.count)
+ src += srcStride;
+ } // for (yp -> bottom)
+ }
+}
+
+static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
+ int x, int y, const QRgba64 &color,
+ const uint *src, int mapWidth, int mapHeight, int srcStride,
+ const QClipData *clip, bool useGammaCorrection)
+{
+ if (color.isTransparent())
+ return;
- sr = gamma[sr];
- sg = gamma[sg];
- sb = gamma[sb];
+ const quint32 c = color.toArgb32();
- if (sa == 0)
+ const QColorProfile *colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
+ if (!colorProfile)
return;
+ const QRgba64 slinear = useGammaCorrection ? colorProfile->toLinear64(c) : color;
+
if (!clip) {
quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
@@ -5659,7 +5948,16 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
if (coverage == 0xffffffff) {
dst[i] = c;
} else if (coverage != 0xff000000) {
- rgbBlendPixel(dst+i, coverage, sr, sg, sb, gamma, invgamma);
+ if (dst[i] >= 0xff000000) {
+ rgbBlendPixel(dst+i, coverage, slinear, colorProfile, useGammaCorrection);
+ } else {
+ // Give up and do a gray blend.
+ const int a = qRgbAvg(coverage);
+ if (useGammaCorrection)
+ grayBlendPixel(dst+i, a, slinear, colorProfile);
+ else
+ dst[i] = INTERPOLATE_PIXEL_255(c, a, dst[i], 255 - a);
+ }
}
}
@@ -5689,7 +5987,16 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
if (coverage == 0xffffffff) {
dst[xp] = c;
} else if (coverage != 0xff000000) {
- rgbBlendPixel(dst+xp, coverage, sr, sg, sb, gamma, invgamma);
+ if (dst[xp] >= 0xff000000) {
+ rgbBlendPixel(dst+xp, coverage, slinear, colorProfile, useGammaCorrection);
+ } else {
+ // Give up and do a gray blend.
+ const int a = qRgbAvg(coverage);
+ if (useGammaCorrection)
+ grayBlendPixel(dst+xp, a, slinear, colorProfile);
+ else
+ dst[xp] = INTERPOLATE_PIXEL_255(c, a, dst[xp], 255 - coverage);
+ }
}
}
} // for (i -> line.count)
@@ -5822,56 +6129,80 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
qt_gradient_quint16,
qt_bitmapblit_quint16,
qt_alphamapblit_quint16,
- 0,
+ qt_alphargbblit_generic,
qt_rectfill_quint16
},
// Format_ARGB8565_Premultiplied
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0, 0
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ 0
},
// Format_RGB666
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0, 0
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ 0
},
// Format_ARGB6666_Premultiplied
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0, 0
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ 0
},
// Format_RGB555
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0, 0
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ 0
},
// Format_ARGB8555_Premultiplied
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0, 0
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ 0
},
// Format_RGB888
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0, 0
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ 0
},
// Format_RGB444
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0, 0
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ 0
},
// Format_ARGB4444_Premultiplied
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0, 0
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ 0
},
// Format_RGBX8888
{
@@ -5881,9 +6212,9 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
qt_alphamapblit_rgba8888,
#else
- 0,
+ qt_alphamapblit_generic,
#endif
- 0,
+ qt_alphargbblit_generic,
qt_rectfill_rgba
},
// Format_RGBA8888
@@ -5894,9 +6225,9 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
qt_alphamapblit_rgba8888,
#else
- 0,
+ qt_alphamapblit_generic,
#endif
- 0,
+ qt_alphargbblit_generic,
qt_rectfill_nonpremul_rgba
},
// Format_RGB8888_Premultiplied
@@ -5907,9 +6238,9 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
qt_alphamapblit_rgba8888,
#else
- 0,
+ qt_alphamapblit_generic,
#endif
- 0,
+ qt_alphargbblit_generic,
qt_rectfill_rgba
},
// Format_BGR30
@@ -5917,8 +6248,8 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
blend_color_generic_rgb64,
blend_src_generic_rgb64,
qt_bitmapblit_rgb30<PixelOrderBGR>,
- 0,
- 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
qt_rectfill_rgb30<PixelOrderBGR>
},
// Format_A2BGR30_Premultiplied
@@ -5926,8 +6257,8 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
blend_color_generic_rgb64,
blend_src_generic_rgb64,
qt_bitmapblit_rgb30<PixelOrderBGR>,
- 0,
- 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
qt_rectfill_rgb30<PixelOrderBGR>
},
// Format_RGB30
@@ -5935,8 +6266,8 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
blend_color_generic_rgb64,
blend_src_generic_rgb64,
qt_bitmapblit_rgb30<PixelOrderRGB>,
- 0,
- 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
qt_rectfill_rgb30<PixelOrderRGB>
},
// Format_A2RGB30_Premultiplied
@@ -5944,22 +6275,26 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
blend_color_generic_rgb64,
blend_src_generic_rgb64,
qt_bitmapblit_rgb30<PixelOrderRGB>,
- 0,
- 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
qt_rectfill_rgb30<PixelOrderRGB>
},
// Format_Alpha8
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0,
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
qt_rectfill_alpha
},
// Format_Grayscale8
{
blend_color_generic,
blend_src_generic,
- 0, 0, 0,
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
qt_rectfill_gray
},
};
@@ -6117,20 +6452,18 @@ static void qInitDrawhelperFunctions()
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
if (qCpuHasFeature(SSE4_1)) {
-#if !defined(__SSE4_1__)
extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, const uint *src, int count,
const QVector<QRgb> *, QDitherInfo *);
extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, const uint *src, int count,
const QVector<QRgb> *, QDitherInfo *);
- qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4;
- qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4;
-#endif
extern const uint *QT_FASTCALL convertARGB32FromARGB32PM_sse4(uint *buffer, const uint *src, int count,
const QVector<QRgb> *, QDitherInfo *);
extern const uint *QT_FASTCALL convertRGBA8888FromARGB32PM_sse4(uint *buffer, const uint *src, int count,
const QVector<QRgb> *, QDitherInfo *);
extern const uint *QT_FASTCALL convertRGBXFromARGB32PM_sse4(uint *buffer, const uint *src, int count,
const QVector<QRgb> *, QDitherInfo *);
+ qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4;
+ qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4;
qPixelLayouts[QImage::Format_ARGB32].convertFromARGB32PM = convertARGB32FromARGB32PM_sse4;
qPixelLayouts[QImage::Format_RGBA8888].convertFromARGB32PM = convertRGBA8888FromARGB32PM_sse4;
qPixelLayouts[QImage::Format_RGBX8888].convertFromARGB32PM = convertRGBXFromARGB32PM_sse4;
@@ -6141,14 +6474,6 @@ static void qInitDrawhelperFunctions()
#if defined(QT_COMPILER_SUPPORTS_AVX2)
if (qCpuHasFeature(AVX2)) {
-#if !defined(__AVX2__)
- extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *);
- extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *);
- qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_avx2;
- qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2;
-#endif
extern void qt_blend_rgb32_on_rgb32_avx2(uchar *destPixels, int dbpl,
const uchar *srcPixels, int sbpl,
int w, int h, int const_alpha);
@@ -6170,6 +6495,17 @@ static void qInitDrawhelperFunctions()
qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_avx2;
qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_avx2;
qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_avx2;
+
+ extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/);
+ extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/);
+ extern void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int fdy);
+
+ bilinearFastTransformHelperARGB32PM[0][SimpleUpscaleTransform] = fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2;
+ bilinearFastTransformHelperARGB32PM[0][DownscaleTransform] = fetchTransformedBilinearARGB32PM_downscale_helper_avx2;
+ bilinearFastTransformHelperARGB32PM[0][FastRotateTransform] = fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2;
}
#endif
@@ -6198,6 +6534,15 @@ static void qInitDrawhelperFunctions()
sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_neon;
+#if defined(Q_PROCESSOR_ARM_64) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, const uint *src, int count,
+ const QVector<QRgb> *, QDitherInfo *);
+ extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_neon(uint *buffer, const uint *src, int count,
+ const QVector<QRgb> *, QDitherInfo *);
+ qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_neon;
+ qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_neon;
+#endif
+
#if defined(ENABLE_PIXMAN_DRAWHELPERS)
// The RGB16 helpers are using Arm32 assemblythat has not been ported to AArch64
qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16_neon;
@@ -6215,8 +6560,8 @@ static void qInitDrawhelperFunctions()
destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon;
destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon;
- qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
- qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
+ qMemRotateFunctions[QPixelLayout::BPP16][0] = qt_memrotate90_16_neon;
+ qMemRotateFunctions[QPixelLayout::BPP16][2] = qt_memrotate270_16_neon;
#endif
#endif // defined(__ARM_NEON__)
diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp
index 9c1335298e..a7e03a7bb3 100644
--- a/src/gui/painting/qdrawhelper_avx2.cpp
+++ b/src/gui/painting/qdrawhelper_avx2.cpp
@@ -44,18 +44,12 @@
QT_BEGIN_NAMESPACE
-// Autovectorized premultiply functions:
-const uint *QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- return qt_convertARGB32ToARGB32PM(buffer, src, count);
-}
+static Q_CONSTEXPR int BufferSize = 2048;
-const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
-{
- return qt_convertRGBA8888ToARGB32PM(buffer, src, count);
-}
+enum {
+ FixedScale = 1 << 16,
+ HalfPoint = 1 << 15
+};
// Vectorized blend functions:
@@ -356,6 +350,413 @@ void QT_FASTCALL comp_func_solid_SourceOver_avx2(uint *destPixels, int length, u
}
}
+#define interpolate_4_pixels_16_avx2(tlr1, tlr2, blr1, blr2, distx, disty, colorMask, v_256, b) \
+{ \
+ /* Correct for later unpack */ \
+ const __m256i vdistx = _mm256_permute4x64_epi64(distx, _MM_SHUFFLE(3, 1, 2, 0)); \
+ const __m256i vdisty = _mm256_permute4x64_epi64(disty, _MM_SHUFFLE(3, 1, 2, 0)); \
+ \
+ __m256i dxdy = _mm256_mullo_epi16 (vdistx, vdisty); \
+ const __m256i distx_ = _mm256_slli_epi16(vdistx, 4); \
+ const __m256i disty_ = _mm256_slli_epi16(vdisty, 4); \
+ __m256i idxidy = _mm256_add_epi16(dxdy, _mm256_sub_epi16(v_256, _mm256_add_epi16(distx_, disty_))); \
+ __m256i dxidy = _mm256_sub_epi16(distx_, dxdy); \
+ __m256i idxdy = _mm256_sub_epi16(disty_, dxdy); \
+ \
+ __m256i tlr1AG = _mm256_srli_epi16(tlr1, 8); \
+ __m256i tlr1RB = _mm256_and_si256(tlr1, colorMask); \
+ __m256i tlr2AG = _mm256_srli_epi16(tlr2, 8); \
+ __m256i tlr2RB = _mm256_and_si256(tlr2, colorMask); \
+ __m256i blr1AG = _mm256_srli_epi16(blr1, 8); \
+ __m256i blr1RB = _mm256_and_si256(blr1, colorMask); \
+ __m256i blr2AG = _mm256_srli_epi16(blr2, 8); \
+ __m256i blr2RB = _mm256_and_si256(blr2, colorMask); \
+ \
+ __m256i odxidy1 = _mm256_unpacklo_epi32(idxidy, dxidy); \
+ __m256i odxidy2 = _mm256_unpackhi_epi32(idxidy, dxidy); \
+ tlr1AG = _mm256_mullo_epi16(tlr1AG, odxidy1); \
+ tlr1RB = _mm256_mullo_epi16(tlr1RB, odxidy1); \
+ tlr2AG = _mm256_mullo_epi16(tlr2AG, odxidy2); \
+ tlr2RB = _mm256_mullo_epi16(tlr2RB, odxidy2); \
+ __m256i odxdy1 = _mm256_unpacklo_epi32(idxdy, dxdy); \
+ __m256i odxdy2 = _mm256_unpackhi_epi32(idxdy, dxdy); \
+ blr1AG = _mm256_mullo_epi16(blr1AG, odxdy1); \
+ blr1RB = _mm256_mullo_epi16(blr1RB, odxdy1); \
+ blr2AG = _mm256_mullo_epi16(blr2AG, odxdy2); \
+ blr2RB = _mm256_mullo_epi16(blr2RB, odxdy2); \
+ \
+ /* Add the values, and shift to only keep 8 significant bits per colors */ \
+ __m256i topAG = _mm256_hadd_epi32(tlr1AG, tlr2AG); \
+ __m256i topRB = _mm256_hadd_epi32(tlr1RB, tlr2RB); \
+ __m256i botAG = _mm256_hadd_epi32(blr1AG, blr2AG); \
+ __m256i botRB = _mm256_hadd_epi32(blr1RB, blr2RB); \
+ __m256i rAG = _mm256_add_epi16(topAG, botAG); \
+ __m256i rRB = _mm256_add_epi16(topRB, botRB); \
+ rRB = _mm256_srli_epi16(rRB, 8); \
+ /* Correct for hadd */ \
+ rAG = _mm256_permute4x64_epi64(rAG, _MM_SHUFFLE(3, 1, 2, 0)); \
+ rRB = _mm256_permute4x64_epi64(rRB, _MM_SHUFFLE(3, 1, 2, 0)); \
+ _mm256_storeu_si256((__m256i*)(b), _mm256_blendv_epi8(rAG, rRB, colorMask)); \
+}
+
+inline void fetchTransformedBilinear_pixelBounds(int, int l1, int l2, int &v1, int &v2)
+{
+ if (v1 < l1)
+ v2 = v1 = l1;
+ else if (v1 >= l2)
+ v2 = v1 = l2;
+ else
+ v2 = v1 + 1;
+ Q_ASSERT(v1 >= l1 && v1 <= l2);
+ Q_ASSERT(v2 >= l1 && v2 <= l2);
+}
+
+void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/)
+{
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds(image.height, image.y1, image.y2 - 1, y1, y2);
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
+
+ int disty = (fy & 0x0000ffff) >> 8;
+ int idisty = 256 - disty;
+ int x = fx >> 16;
+ int length = end - b;
+
+ // The idea is first to do the interpolation between the row s1 and the row s2
+ // into an intermediate buffer, then we interpolate between two pixel of this buffer.
+
+ // intermediate_buffer[0] is a buffer of red-blue component of the pixel, in the form 0x00RR00BB
+ // intermediate_buffer[1] is the alpha-green component of the pixel, in the form 0x00AA00GG
+ // +1 for the last pixel to interpolate with, and +1 for rounding errors.
+ quint32 intermediate_buffer[2][BufferSize + 2];
+ // count is the size used in the intermediate_buffer.
+ int count = (qint64(length) * fdx + FixedScale - 1) / FixedScale + 2;
+ Q_ASSERT(count <= BufferSize + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
+ int f = 0;
+ int lim = qMin(count, image.x2 - x);
+ if (x < image.x1) {
+ Q_ASSERT(x < image.x2);
+ uint t = s1[image.x1];
+ uint b = s2[image.x1];
+ quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ do {
+ intermediate_buffer[0][f] = rb;
+ intermediate_buffer[1][f] = ag;
+ f++;
+ x++;
+ } while (x < image.x1 && f < lim);
+ }
+
+ const __m256i disty_ = _mm256_set1_epi16(disty);
+ const __m256i idisty_ = _mm256_set1_epi16(idisty);
+ const __m256i colorMask = _mm256_set1_epi32(0x00ff00ff);
+
+ lim -= 7;
+ for (; f < lim; x += 8, f += 8) {
+ // Load 8 pixels from s1, and split the alpha-green and red-blue component
+ __m256i top = _mm256_loadu_si256((const __m256i*)((const uint *)(s1)+x));
+ __m256i topAG = _mm256_srli_epi16(top, 8);
+ __m256i topRB = _mm256_and_si256(top, colorMask);
+ // Multiplies each color component by idisty
+ topAG = _mm256_mullo_epi16 (topAG, idisty_);
+ topRB = _mm256_mullo_epi16 (topRB, idisty_);
+
+ // Same for the s2 vector
+ __m256i bottom = _mm256_loadu_si256((const __m256i*)((const uint *)(s2)+x));
+ __m256i bottomAG = _mm256_srli_epi16(bottom, 8);
+ __m256i bottomRB = _mm256_and_si256(bottom, colorMask);
+ bottomAG = _mm256_mullo_epi16 (bottomAG, disty_);
+ bottomRB = _mm256_mullo_epi16 (bottomRB, disty_);
+
+ // Add the values, and shift to only keep 8 significant bits per colors
+ __m256i rAG =_mm256_add_epi16(topAG, bottomAG);
+ rAG = _mm256_srli_epi16(rAG, 8);
+ _mm256_storeu_si256((__m256i*)(&intermediate_buffer[1][f]), rAG);
+ __m256i rRB =_mm256_add_epi16(topRB, bottomRB);
+ rRB = _mm256_srli_epi16(rRB, 8);
+ _mm256_storeu_si256((__m256i*)(&intermediate_buffer[0][f]), rRB);
+ }
+
+ for (; f < count; f++) { // Same as above but without simd
+ x = qMin(x, image.x2 - 1);
+
+ uint t = s1[x];
+ uint b = s2[x];
+
+ intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ x++;
+ }
+ // Now interpolate the values from the intermediate_buffer to get the final result.
+ fx &= FixedScale - 1;
+ Q_ASSERT((fx >> 16) == 0);
+
+ const __m128i v_fdx = _mm_set1_epi32(fdx * 4);
+ const __m128i v_blend = _mm_set1_epi32(0x00800080);
+ __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx);
+
+ while (b < end - 3) {
+ const __m128i offset = _mm_srli_epi32(v_fx, 16);
+ __m256i vrb = _mm256_i32gather_epi64((const long long *)intermediate_buffer[0], offset, 4);
+ __m256i vag = _mm256_i32gather_epi64((const long long *)intermediate_buffer[1], offset, 4);
+
+ __m128i vdx = _mm_and_si128(v_fx, _mm_set1_epi32(0x0000ffff));
+ vdx = _mm_srli_epi16(vdx, 8);
+ __m128i vidx = _mm_sub_epi32(_mm_set1_epi32(256), vdx);
+ __m256i vmulx = _mm256_castsi128_si256(_mm_unpacklo_epi32(vidx, vdx));
+ vmulx = _mm256_inserti128_si256(vmulx, _mm_unpackhi_epi32(vidx, vdx), 1);
+
+ vrb = _mm256_mullo_epi32(vrb, vmulx);
+ vag = _mm256_mullo_epi32(vag, vmulx);
+
+ __m256i vrbag = _mm256_hadd_epi32(vrb, vag);
+ vrbag = _mm256_permute4x64_epi64(vrbag, _MM_SHUFFLE(3, 1, 2, 0));
+
+ __m128i rb = _mm256_castsi256_si128(vrbag);
+ __m128i ag = _mm256_extracti128_si256(vrbag, 1);
+ rb = _mm_srli_epi16(rb, 8);
+
+ _mm_storeu_si128((__m128i*)b, _mm_blendv_epi8(ag, rb, v_blend));
+
+ b += 4;
+ fx += 4 * fdx;
+ v_fx = _mm_add_epi32(v_fx, v_fdx);
+ }
+ while (b < end) {
+ int x = (fx >> 16);
+
+ uint distx = (fx & 0x0000ffff) >> 8;
+ uint idistx = 256 - distx;
+
+ uint rb = ((intermediate_buffer[0][x] * idistx + intermediate_buffer[0][x + 1] * distx) >> 8) & 0xff00ff;
+ uint ag = (intermediate_buffer[1][x] * idistx + intermediate_buffer[1][x + 1] * distx) & 0xff00ff00;
+ *b = rb | ag;
+ b++;
+ fx += fdx;
+ }
+}
+
+void QT_FASTCALL fetchTransformedBilinearARGB32PM_downscale_helper_avx2(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/)
+{
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds(image.height, image.y1, image.y2 - 1, y1, y2);
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
+ const int disty8 = (fy & 0x0000ffff) >> 8;
+ const int disty4 = (disty8 + 0x08) >> 4;
+
+ const qint64 min_fx = qint64(image.x1) * FixedScale;
+ const qint64 max_fx = qint64(image.x2 - 1) * FixedScale;
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ fetchTransformedBilinear_pixelBounds(image.width, image.x1, image.x2 - 1, x1, x2);
+ if (x1 != x2)
+ break;
+ uint top = s1[x1];
+ uint bot = s2[x1];
+ *b = INTERPOLATE_PIXEL_256(top, 256 - disty8, bot, disty8);
+ fx += fdx;
+ ++b;
+ }
+ uint *boundedEnd = end;
+ if (fdx > 0)
+ boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx);
+ else if (fdx < 0)
+ boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx);
+
+ // A fast middle part without boundary checks
+ const __m256i vdistShuffle =
+ _mm256_setr_epi8(0, char(0x80), 0, char(0x80), 4, char(0x80), 4, char(0x80), 8, char(0x80), 8, char(0x80), 12, char(0x80), 12, char(0x80),
+ 0, char(0x80), 0, char(0x80), 4, char(0x80), 4, char(0x80), 8, char(0x80), 8, char(0x80), 12, char(0x80), 12, char(0x80));
+ const __m256i colorMask = _mm256_set1_epi32(0x00ff00ff);
+ const __m256i v_256 = _mm256_set1_epi16(256);
+ const __m256i v_disty = _mm256_set1_epi16(disty4);
+ const __m256i v_fdx = _mm256_set1_epi32(fdx * 8);
+ const __m256i v_fx_r = _mm256_set1_epi32(0x08);
+ const __m256i v_index = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7);
+ __m256i v_fx = _mm256_set1_epi32(fx);
+ v_fx = _mm256_add_epi32(v_fx, _mm256_mullo_epi32(_mm256_set1_epi32(fdx), v_index));
+
+ while (b < boundedEnd - 7) {
+ const __m256i offset = _mm256_srli_epi32(v_fx, 16);
+ const __m128i offsetLo = _mm256_castsi256_si128(offset);
+ const __m128i offsetHi = _mm256_extracti128_si256(offset, 1);
+ const __m256i toplo = _mm256_i32gather_epi64((const long long *)s1, offsetLo, 4);
+ const __m256i tophi = _mm256_i32gather_epi64((const long long *)s1, offsetHi, 4);
+ const __m256i botlo = _mm256_i32gather_epi64((const long long *)s2, offsetLo, 4);
+ const __m256i bothi = _mm256_i32gather_epi64((const long long *)s2, offsetHi, 4);
+
+ __m256i v_distx = _mm256_srli_epi16(v_fx, 8);
+ v_distx = _mm256_srli_epi16(_mm256_add_epi32(v_distx, v_fx_r), 4);
+ v_distx = _mm256_shuffle_epi8(v_distx, vdistShuffle);
+
+ interpolate_4_pixels_16_avx2(toplo, tophi, botlo, bothi, v_distx, v_disty, colorMask, v_256, b);
+ b += 8;
+ v_fx = _mm256_add_epi32(v_fx, v_fdx);
+ }
+ fx = _mm_extract_epi32(_mm256_castsi256_si128(v_fx) , 0);
+
+ while (b < boundedEnd) {
+ int x = (fx >> 16);
+ int distx8 = (fx & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(s1 + x, s2 + x, distx8, disty8);
+ fx += fdx;
+ ++b;
+ }
+
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ fetchTransformedBilinear_pixelBounds(image.width, image.x1, image.x2 - 1, x1, x2);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
+ int distx8 = (fx & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(tl, tr, bl, br, distx8, disty8);
+ fx += fdx;
+ ++b;
+ }
+}
+
+void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int fdy)
+{
+ const qint64 min_fx = qint64(image.x1) * FixedScale;
+ const qint64 max_fx = qint64(image.x2 - 1) * FixedScale;
+ const qint64 min_fy = qint64(image.y1) * FixedScale;
+ const qint64 max_fy = qint64(image.y2 - 1) * FixedScale;
+ // first handle the possibly bounded part in the beginning
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds(image.height, image.y1, image.y2 - 1, y1, y2);
+ if (x1 != x2 && y1 != y2)
+ break;
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
+ int distx = (fx & 0x0000ffff) >> 8;
+ int disty = (fy & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
+ fx += fdx;
+ fy += fdy;
+ ++b;
+ }
+ uint *boundedEnd = end;
+ if (fdx > 0)
+ boundedEnd = qMin(boundedEnd, b + (max_fx - fx) / fdx);
+ else if (fdx < 0)
+ boundedEnd = qMin(boundedEnd, b + (min_fx - fx) / fdx);
+ if (fdy > 0)
+ boundedEnd = qMin(boundedEnd, b + (max_fy - fy) / fdy);
+ else if (fdy < 0)
+ boundedEnd = qMin(boundedEnd, b + (min_fy - fy) / fdy);
+
+ // until boundedEnd we can now have a fast middle part without boundary checks
+ const __m256i vdistShuffle =
+ _mm256_setr_epi8(0, char(0x80), 0, char(0x80), 4, char(0x80), 4, char(0x80), 8, char(0x80), 8, char(0x80), 12, char(0x80), 12, char(0x80),
+ 0, char(0x80), 0, char(0x80), 4, char(0x80), 4, char(0x80), 8, char(0x80), 8, char(0x80), 12, char(0x80), 12, char(0x80));
+ const __m256i colorMask = _mm256_set1_epi32(0x00ff00ff);
+ const __m256i v_256 = _mm256_set1_epi16(256);
+ const __m256i v_fdx = _mm256_set1_epi32(fdx * 8);
+ const __m256i v_fdy = _mm256_set1_epi32(fdy * 8);
+ const __m256i v_fxy_r = _mm256_set1_epi32(0x08);
+ const __m256i v_index = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7);
+ __m256i v_fx = _mm256_set1_epi32(fx);
+ __m256i v_fy = _mm256_set1_epi32(fy);
+ v_fx = _mm256_add_epi32(v_fx, _mm256_mullo_epi32(_mm256_set1_epi32(fdx), v_index));
+ v_fy = _mm256_add_epi32(v_fy, _mm256_mullo_epi32(_mm256_set1_epi32(fdy), v_index));
+
+ const uchar *textureData = image.imageData;
+ const int bytesPerLine = image.bytesPerLine;
+ const __m256i vbpl = _mm256_set1_epi16(bytesPerLine/4);
+
+ while (b < boundedEnd - 7) {
+ const __m256i vy = _mm256_packs_epi32(_mm256_srli_epi32(v_fy, 16), _mm256_setzero_si256());
+ // 8x16bit * 8x16bit -> 8x32bit
+ __m256i offset = _mm256_unpacklo_epi16(_mm256_mullo_epi16(vy, vbpl), _mm256_mulhi_epi16(vy, vbpl));
+ offset = _mm256_add_epi32(offset, _mm256_srli_epi32(v_fx, 16));
+ const __m128i offsetLo = _mm256_castsi256_si128(offset);
+ const __m128i offsetHi = _mm256_extracti128_si256(offset, 1);
+ const uint *topData = (const uint *)(textureData);
+ const uint *botData = (const uint *)(textureData + bytesPerLine);
+ const __m256i toplo = _mm256_i32gather_epi64((const long long *)topData, offsetLo, 4);
+ const __m256i tophi = _mm256_i32gather_epi64((const long long *)topData, offsetHi, 4);
+ const __m256i botlo = _mm256_i32gather_epi64((const long long *)botData, offsetLo, 4);
+ const __m256i bothi = _mm256_i32gather_epi64((const long long *)botData, offsetHi, 4);
+
+ __m256i v_distx = _mm256_srli_epi16(v_fx, 8);
+ __m256i v_disty = _mm256_srli_epi16(v_fy, 8);
+ v_distx = _mm256_srli_epi16(_mm256_add_epi32(v_distx, v_fxy_r), 4);
+ v_disty = _mm256_srli_epi16(_mm256_add_epi32(v_disty, v_fxy_r), 4);
+ v_distx = _mm256_shuffle_epi8(v_distx, vdistShuffle);
+ v_disty = _mm256_shuffle_epi8(v_disty, vdistShuffle);
+
+ interpolate_4_pixels_16_avx2(toplo, tophi, botlo, bothi, v_distx, v_disty, colorMask, v_256, b);
+ b += 8;
+ v_fx = _mm256_add_epi32(v_fx, v_fdx);
+ v_fy = _mm256_add_epi32(v_fy, v_fdy);
+ }
+ fx = _mm_extract_epi32(_mm256_castsi256_si128(v_fx) , 0);
+ fy = _mm_extract_epi32(_mm256_castsi256_si128(v_fy) , 0);
+
+ while (b < boundedEnd) {
+ int x = (fx >> 16);
+ int y = (fy >> 16);
+
+ const uint *s1 = (const uint *)image.scanLine(y);
+ const uint *s2 = (const uint *)image.scanLine(y + 1);
+
+ int distx = (fx & 0x0000ffff) >> 8;
+ int disty = (fy & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(s1 + x, s2 + x, distx, disty);
+
+ fx += fdx;
+ fy += fdy;
+ ++b;
+ }
+
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2;
+ int y1 = (fy >> 16);
+ int y2;
+
+ fetchTransformedBilinear_pixelBounds(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds(image.height, image.y1, image.y2 - 1, y1, y2);
+
+ const uint *s1 = (const uint *)image.scanLine(y1);
+ const uint *s2 = (const uint *)image.scanLine(y2);
+
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
+
+ int distx = (fx & 0x0000ffff) >> 8;
+ int disty = (fy & 0x0000ffff) >> 8;
+ *b = interpolate_4_pixels(tl, tr, bl, br, distx, disty);
+
+ fx += fdx;
+ fy += fdy;
+ ++b;
+ }
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index a833520b00..4cbac009d8 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -535,12 +535,23 @@ void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl,
}
#if defined(ENABLE_PIXMAN_DRAWHELPERS)
+extern void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
+ int x, int y, const QRgba64 &color,
+ const uchar *map,
+ int mapWidth, int mapHeight, int mapStride,
+ const QClipData *clip, bool useGammaCorrection);
+
void qt_alphamapblit_quint16_neon(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
const uchar *bitmap,
int mapWidth, int mapHeight, int mapStride,
- const QClipData *)
+ const QClipData *clip, bool useGammaCorrection)
{
+ if (clip || useGammaCorrection) {
+ qt_alphamapblit_quint16(rasterBuffer, x, y, color, bitmap, mapWidth, mapHeight, mapStride, clip, useGammaCorrection);
+ return;
+ }
+
quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
@@ -1069,6 +1080,67 @@ const uint * QT_FASTCALL qt_fetchUntransformed_888_neon(uint *buffer, const Oper
return buffer;
}
+#if defined(Q_PROCESSOR_ARM_64) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+template<bool RGBA>
+static inline void convertARGBToARGB32PM_neon(uint *buffer, const uint *src, int count)
+{
+ int i = 0;
+ const uint8x16_t rgbaMask = { 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15};
+ const uint8x8_t shuffleMask = { 3, 3, 3, 3, 7, 7, 7, 7};
+ const uint32x4_t blendMask = vdupq_n_u32(0xff000000);
+
+ for (; i < count - 3; i += 4) {
+ uint32x4_t srcVector = vld1q_u32(src + i);
+ uint32x4_t alphaVector = vshrq_n_u32(srcVector, 24);
+ uint32_t alphaSum = vaddvq_u32(alphaVector);
+ if (alphaSum) {
+ if (alphaSum != 255 * 4) {
+ if (RGBA)
+ srcVector = vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(srcVector), rgbaMask));
+ const uint8x8_t s1 = vreinterpret_u8_u32(vget_low_u32(srcVector));
+ const uint8x8_t s2 = vreinterpret_u8_u32(vget_high_u32(srcVector));
+ const uint8x8_t alpha1 = vtbl1_u8(s1, shuffleMask);
+ const uint8x8_t alpha2 = vtbl1_u8(s2, shuffleMask);
+ uint16x8_t src1 = vmull_u8(s1, alpha1);
+ uint16x8_t src2 = vmull_u8(s2, alpha2);
+ src1 = vsraq_n_u16(src1, src1, 8);
+ src2 = vsraq_n_u16(src2, src2, 8);
+ const uint8x8_t d1 = vrshrn_n_u16(src1, 8);
+ const uint8x8_t d2 = vrshrn_n_u16(src2, 8);
+ const uint32x4_t d = vbslq_u32(blendMask, srcVector, vreinterpretq_u32_u8(vcombine_u8(d1, d2)));
+ vst1q_u32(buffer + i, d);
+ } else {
+ if (RGBA)
+ vst1q_u32(buffer + i, vreinterpretq_u32_u8(vqtbl1q_u8(vreinterpretq_u8_u32(srcVector), rgbaMask)));
+ else if (buffer != src)
+ vst1q_u32(buffer + i, srcVector);
+ }
+ } else {
+ vst1q_u32(buffer + i, vdupq_n_u32(0));
+ }
+ }
+
+ SIMD_EPILOGUE(i, count, 3) {
+ uint v = qPremultiply(src[i]);
+ buffer[i] = RGBA ? RGBA2ARGB(v) : v;
+ }
+}
+
+const uint *QT_FASTCALL convertARGB32ToARGB32PM_neon(uint *buffer, const uint *src, int count,
+ const QVector<QRgb> *, QDitherInfo *)
+{
+ convertARGBToARGB32PM_neon<false>(buffer, src, count);
+ return buffer;
+}
+
+const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_neon(uint *buffer, const uint *src, int count,
+ const QVector<QRgb> *, QDitherInfo *)
+{
+ convertARGBToARGB32PM_neon<true>(buffer, src, count);
+ return buffer;
+}
+#endif
+
QT_END_NAMESPACE
#endif // __ARM_NEON__
diff --git a/src/gui/painting/qdrawhelper_neon_p.h b/src/gui/painting/qdrawhelper_neon_p.h
index 3cf949fc32..40475a9bde 100644
--- a/src/gui/painting/qdrawhelper_neon_p.h
+++ b/src/gui/painting/qdrawhelper_neon_p.h
@@ -91,7 +91,7 @@ void qt_alphamapblit_quint16_neon(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
const uchar *bitmap,
int mapWidth, int mapHeight, int mapStride,
- const QClipData *clip);
+ const QClipData *clip, bool /*useGammaCorrection*/);
void qt_scale_image_argb32_on_rgb16_neon(uchar *destPixels, int dbpl,
const uchar *srcPixels, int sbpl, int srch,
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 694959909b..1f97621171 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -113,13 +113,13 @@ typedef void (*AlphamapBlitFunc)(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
const uchar *bitmap,
int mapWidth, int mapHeight, int mapStride,
- const QClipData *clip);
+ const QClipData *clip, bool useGammaCorrection);
typedef void (*AlphaRGBBlitFunc)(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
const uint *rgbmask,
int mapWidth, int mapHeight, int mapStride,
- const QClipData *clip);
+ const QClipData *clip, bool useGammaCorrection);
typedef void (*RectFillFunc)(QRasterBuffer *rasterBuffer,
int x, int y, int width, int height,
@@ -159,7 +159,6 @@ struct DrawHelper {
extern SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats];
extern SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats];
extern SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats];
-extern MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3];
extern DrawHelper qDrawHelper[QImage::NImageFormats];
@@ -351,18 +350,6 @@ struct QSpanData
void adjustSpanMethods();
};
-struct QDrawHelperGammaTables
-{
- explicit QDrawHelperGammaTables(qreal smoothing);
-
- void refresh(qreal smoothing);
-
- uchar qt_pow_rgb_gamma[256];
- uchar qt_pow_rgb_invgamma[256];
- uint qt_pow_gamma[256];
- uchar qt_pow_invgamma[2048];
-};
-
static inline uint qt_gradient_clamp(const QGradientData *data, int ipos)
{
if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
@@ -1244,6 +1231,7 @@ extern QPixelLayout qPixelLayouts[QImage::NImageFormats];
extern const FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount];
extern StorePixelsFunc qStorePixels[QPixelLayout::BPPCount];
+extern MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3];
QT_END_NAMESPACE
diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp
index 257bad9eca..14bfaabf09 100644
--- a/src/gui/painting/qdrawhelper_sse4.cpp
+++ b/src/gui/painting/qdrawhelper_sse4.cpp
@@ -44,16 +44,67 @@
QT_BEGIN_NAMESPACE
+template<bool RGBA>
+static inline void convertARGBToARGB32PM_sse4(uint *buffer, const uint *src, int count)
+{
+ int i = 0;
+ const __m128i alphaMask = _mm_set1_epi32(0xff000000);
+ const __m128i rgbaMask = _mm_setr_epi8(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15);
+ const __m128i shuffleMask = _mm_setr_epi8(6, 7, 6, 7, 6, 7, 6, 7, 14, 15, 14, 15, 14, 15, 14, 15);
+ const __m128i half = _mm_set1_epi16(0x0080);
+ const __m128i zero = _mm_setzero_si128();
+
+ for (; i < count - 3; i += 4) {
+ __m128i srcVector = _mm_loadu_si128((const __m128i *)&src[i]);
+ if (!_mm_testz_si128(srcVector, alphaMask)) {
+ if (!_mm_testc_si128(srcVector, alphaMask)) {
+ if (RGBA)
+ srcVector = _mm_shuffle_epi8(srcVector, rgbaMask);
+ __m128i src1 = _mm_unpacklo_epi8(srcVector, zero);
+ __m128i src2 = _mm_unpackhi_epi8(srcVector, zero);
+ __m128i alpha1 = _mm_shuffle_epi8(src1, shuffleMask);
+ __m128i alpha2 = _mm_shuffle_epi8(src2, shuffleMask);
+ src1 = _mm_mullo_epi16(src1, alpha1);
+ src2 = _mm_mullo_epi16(src2, alpha2);
+ src1 = _mm_add_epi16(src1, _mm_srli_epi16(src1, 8));
+ src2 = _mm_add_epi16(src2, _mm_srli_epi16(src2, 8));
+ src1 = _mm_add_epi16(src1, half);
+ src2 = _mm_add_epi16(src2, half);
+ src1 = _mm_srli_epi16(src1, 8);
+ src2 = _mm_srli_epi16(src2, 8);
+ src1 = _mm_blend_epi16(src1, alpha1, 0x88);
+ src2 = _mm_blend_epi16(src2, alpha2, 0x88);
+ srcVector = _mm_packus_epi16(src1, src2);
+ _mm_storeu_si128((__m128i *)&buffer[i], srcVector);
+ } else {
+ if (RGBA)
+ _mm_storeu_si128((__m128i *)&buffer[i], _mm_shuffle_epi8(srcVector, rgbaMask));
+ else if (buffer != src)
+ _mm_storeu_si128((__m128i *)&buffer[i], srcVector);
+ }
+ } else {
+ _mm_storeu_si128((__m128i *)&buffer[i], _mm_setzero_si128());
+ }
+ }
+
+ SIMD_EPILOGUE(i, count, 3) {
+ uint v = qPremultiply(src[i]);
+ buffer[i] = RGBA ? RGBA2ARGB(v) : v;
+ }
+}
+
const uint *QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, const uint *src, int count,
const QVector<QRgb> *, QDitherInfo *)
{
- return qt_convertARGB32ToARGB32PM(buffer, src, count);
+ convertARGBToARGB32PM_sse4<false>(buffer, src, count);
+ return buffer;
}
const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, const uint *src, int count,
const QVector<QRgb> *, QDitherInfo *)
{
- return qt_convertRGBA8888ToARGB32PM(buffer, src, count);
+ convertARGBToARGB32PM_sse4<true>(buffer, src, count);
+ return buffer;
}
const uint *QT_FASTCALL convertARGB32FromARGB32PM_sse4(uint *buffer, const uint *src, int count,
diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp
index 3fbae76de5..25aa6a3122 100644
--- a/src/gui/painting/qmemrotate.cpp
+++ b/src/gui/painting/qmemrotate.cpp
@@ -41,164 +41,10 @@
QT_BEGIN_NAMESPACE
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
static const int tileSize = 32;
-#endif
-
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_PACKED || QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
-#error Big endian version not implemented for the transformed driver!
-#endif
-#endif
-
-template <class T>
-Q_STATIC_TEMPLATE_FUNCTION
-inline void qt_memrotate90_cachedRead(const T *src, int w, int h, int sstride, T *dest,
- int dstride)
-{
- const char *s = reinterpret_cast<const char*>(src);
- char *d = reinterpret_cast<char*>(dest);
- for (int y = 0; y < h; ++y) {
- for (int x = w - 1; x >= 0; --x) {
- T *destline = reinterpret_cast<T *>(d + (w - x - 1) * dstride);
- destline[y] = src[x];
- }
- s += sstride;
- src = reinterpret_cast<const T*>(s);
- }
-}
template <class T>
Q_STATIC_TEMPLATE_FUNCTION
-inline void qt_memrotate270_cachedRead(const T *src, int w, int h, int sstride, T *dest,
- int dstride)
-{
- const char *s = reinterpret_cast<const char*>(src);
- char *d = reinterpret_cast<char*>(dest);
- s += (h - 1) * sstride;
- for (int y = h - 1; y >= 0; --y) {
- src = reinterpret_cast<const T*>(s);
- for (int x = 0; x < w; ++x) {
- T *destline = reinterpret_cast<T *>(d + x * dstride);
- destline[h - y - 1] = src[x];
- }
- s -= sstride;
- }
-}
-
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
-
-template <class T>
-Q_STATIC_TEMPLATE_FUNCTION
-inline void qt_memrotate90_cachedWrite(const T *src, int w, int h, int sstride, T *dest,
- int dstride)
-{
- for (int x = w - 1; x >= 0; --x) {
- T *d = dest + (w - x - 1) * dstride;
- for (int y = 0; y < h; ++y) {
- *d++ = src[y * sstride + x];
- }
- }
-
-}
-
-template <class T>
-Q_STATIC_TEMPLATE_FUNCTION
-inline void qt_memrotate270_cachedWrite(const T *src, int w, int h, int sstride, T *dest,
- int dstride)
-{
- for (int x = 0; x < w; ++x) {
- T *d = dest + x * dstride;
- for (int y = h - 1; y >= 0; --y) {
- *d++ = src[y * sstride + x];
- }
- }
-}
-
-#endif // QT_ROTATION_CACHEDWRITE
-
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
-
-// TODO: packing algorithms should probably be modified on 64-bit architectures
-
-template <class T>
-Q_STATIC_TEMPLATE_FUNCTION
-inline void qt_memrotate90_packing(const T *src, int w, int h, int sstride, T *dest, int dstride)
-{
- sstride /= sizeof(T);
- dstride /= sizeof(T);
-
- const int pack = sizeof(quint32) / sizeof(T);
- const int unaligned = int((long(dest) & (sizeof(quint32)-1))) / sizeof(T);
-
- for (int x = w - 1; x >= 0; --x) {
- int y = 0;
-
- for (int i = 0; i < unaligned; ++i) {
- dest[(w - x - 1) * dstride + y] = src[y * sstride + x];
- ++y;
- }
-
- quint32 *d = reinterpret_cast<quint32*>(dest + (w - x - 1) * dstride
- + unaligned);
- const int rest = (h - unaligned) % pack;
- while (y < h - rest) {
- quint32 c = src[y * sstride + x];
- for (int i = 1; i < pack; ++i) {
- c |= src[(y + i) * sstride + x] << (sizeof(int) * 8 / pack * i);
- }
- *d++ = c;
- y += pack;
- }
-
- while (y < h) {
- dest[(w - x - 1) * dstride + y] = src[y * sstride + x];
- ++y;
- }
- }
-}
-
-template <class T>
-Q_STATIC_TEMPLATE_FUNCTION
-inline void qt_memrotate270_packing(const T *src, int w, int h, int sstride, T *dest, int dstride)
-{
- sstride /= sizeof(T);
- dstride /= sizeof(T);
-
- const int pack = sizeof(quint32) / sizeof(T);
- const int unaligned = int((long(dest) & (sizeof(quint32)-1))) / sizeof(T);
-
- for (int x = 0; x < w; ++x) {
- int y = h - 1;
-
- for (int i = 0; i < unaligned; ++i) {
- dest[x * dstride + h - y - 1] = src[y * sstride + x];
- --y;
- }
-
- quint32 *d = reinterpret_cast<quint32*>(dest + x * dstride
- + unaligned);
- const int rest = (h - unaligned) % pack;
- while (y > rest) {
- quint32 c = src[y * sstride + x];
- for (int i = 1; i < pack; ++i) {
- c |= src[(y - i) * sstride + x] << (sizeof(int) * 8 / pack * i);
- }
- *d++ = c;
- y -= pack;
- }
- while (y >= 0) {
- dest[x * dstride + h - y - 1] = src[y * sstride + x];
- --y;
- }
- }
-}
-
-#endif // QT_ROTATION_PACKING
-
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
-template <class T>
-Q_STATIC_TEMPLATE_FUNCTION
inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
{
sstride /= sizeof(T);
@@ -235,7 +81,7 @@ inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *des
for (int y = starty; y < stopy; y += pack) {
quint32 c = src[y * sstride + x];
for (int i = 1; i < pack; ++i) {
- const int shift = (sizeof(int) * 8 / pack * i);
+ const int shift = (sizeof(T) * 8 * i);
const T color = src[(y + i) * sstride + x];
c |= color << shift;
}
@@ -293,7 +139,7 @@ inline void qt_memrotate270_tiled(const T *src, int w, int h, int sstride, T *de
const int pack = sizeof(quint32) / sizeof(T);
const int unaligned =
- qMin(uint((long(dest) & (sizeof(quint32)-1)) / sizeof(T)), uint(h));
+ qMin(uint((quintptr(dest) & (sizeof(quint32)-1)) / sizeof(T)), uint(h));
const int restX = w % tileSize;
const int restY = (h - unaligned) % tileSize;
const int unoptimizedY = restY % pack;
@@ -320,10 +166,10 @@ inline void qt_memrotate270_tiled(const T *src, int w, int h, int sstride, T *de
for (int x = startx; x < stopx; ++x) {
quint32 *d = reinterpret_cast<quint32*>(dest + x * dstride
+ h - 1 - starty);
- for (int y = starty; y > stopy; y -= pack) {
+ for (int y = starty; y >= stopy; y -= pack) {
quint32 c = src[y * sstride + x];
for (int i = 1; i < pack; ++i) {
- const int shift = (sizeof(int) * 8 / pack * i);
+ const int shift = (sizeof(T) * 8 * i);
const T color = src[(y - i) * sstride + x];
c |= color << shift;
}
@@ -371,22 +217,26 @@ inline void qt_memrotate270_tiled_unpacked(const T *src, int w, int h, int sstri
}
}
-#endif // QT_ROTATION_ALGORITHM
template <class T>
Q_STATIC_TEMPLATE_FUNCTION
inline void qt_memrotate90_template(const T *src, int srcWidth, int srcHeight, int srcStride,
T *dest, int dstStride)
{
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
- qt_memrotate90_cachedRead<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
- qt_memrotate90_cachedWrite<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
- qt_memrotate90_packing<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
- qt_memrotate90_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ // packed algorithm assumes little endian and that sizeof(quint32)/sizeof(T) is an integer
+ if (sizeof(quint32) % sizeof(T) == 0)
+ qt_memrotate90_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+ else
#endif
+ qt_memrotate90_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+}
+
+template <>
+inline void qt_memrotate90_template<quint32>(const quint32 *src, int w, int h, int sstride, quint32 *dest, int dstride)
+{
+ // packed algorithm doesn't have any benefit for quint32
+ qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
}
template <class T>
@@ -394,11 +244,11 @@ Q_STATIC_TEMPLATE_FUNCTION
inline void qt_memrotate180_template(const T *src, int w, int h, int sstride, T *dest, int dstride)
{
const char *s = (const char*)(src) + (h - 1) * sstride;
- for (int y = h - 1; y >= 0; --y) {
- T *d = reinterpret_cast<T*>((char *)(dest) + (h - y - 1) * dstride);
+ for (int dy = 0; dy < h; ++dy) {
+ T *d = reinterpret_cast<T*>((char *)(dest) + dy * dstride);
src = reinterpret_cast<const T*>(s);
- for (int x = w - 1; x >= 0; --x) {
- d[w - x - 1] = src[x];
+ for (int dx = 0; dx < w; ++dx) {
+ d[dx] = src[w - 1 - dx];
}
s -= sstride;
}
@@ -409,32 +259,20 @@ Q_STATIC_TEMPLATE_FUNCTION
inline void qt_memrotate270_template(const T *src, int srcWidth, int srcHeight, int srcStride,
T *dest, int dstStride)
{
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
- qt_memrotate270_cachedRead<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
- qt_memrotate270_cachedWrite<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
- qt_memrotate270_packing<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
- qt_memrotate270_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ // packed algorithm assumes little endian and that sizeof(quint32)/sizeof(T) is an integer
+ if (sizeof(quint32) % sizeof(T) == 0)
+ qt_memrotate270_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
+ else
#endif
+ qt_memrotate270_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
}
template <>
-inline void qt_memrotate90_template<quint24>(const quint24 *src, int srcWidth, int srcHeight,
- int srcStride, quint24 *dest, int dstStride)
+inline void qt_memrotate270_template<quint32>(const quint32 *src, int w, int h, int sstride, quint32 *dest, int dstride)
{
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
- qt_memrotate90_cachedRead<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
- qt_memrotate90_cachedWrite<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
- // packed algorithm not implemented
- qt_memrotate90_cachedRead<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
- // packed algorithm not implemented
- qt_memrotate90_tiled_unpacked<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
-#endif
+ // packed algorithm doesn't have any benefit for quint32
+ qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride);
}
#define QT_IMPL_MEMROTATE(type) \
@@ -458,7 +296,7 @@ Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
Q_GUI_EXPORT void qt_memrotate90(const type *src, int w, int h, int sstride, \
type *dest, int dstride) \
{ \
- qt_memrotate90_tiled_unpacked<type>(src, w, h, sstride, dest, dstride); \
+ qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride); \
} \
Q_GUI_EXPORT void qt_memrotate180(const type *src, int w, int h, int sstride, \
type *dest, int dstride) \
@@ -468,7 +306,7 @@ Q_GUI_EXPORT void qt_memrotate180(const type *src, int w, int h, int sstride, \
Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
type *dest, int dstride) \
{ \
- qt_memrotate270_tiled_unpacked<type>(src, w, h, sstride, dest, dstride); \
+ qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride); \
}
@@ -509,6 +347,21 @@ void qt_memrotate270_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *d
qt_memrotate270((const ushort *)srcPixels, w, h, sbpl, (ushort *)destPixels, dbpl);
}
+void qt_memrotate90_24(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate90((const quint24 *)srcPixels, w, h, sbpl, (quint24 *)destPixels, dbpl);
+}
+
+void qt_memrotate180_24(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate180((const quint24 *)srcPixels, w, h, sbpl, (quint24 *)destPixels, dbpl);
+}
+
+void qt_memrotate270_24(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
+{
+ qt_memrotate270((const quint24 *)srcPixels, w, h, sbpl, (quint24 *)destPixels, dbpl);
+}
+
void qt_memrotate90_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
{
qt_memrotate90((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
@@ -524,34 +377,16 @@ void qt_memrotate270_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *d
qt_memrotate270((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
}
-MemRotateFunc qMemRotateFunctions[QImage::NImageFormats][3] =
+MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3] =
// 90, 180, 270
{
- { 0, 0, 0 }, // Format_Invalid,
- { 0, 0, 0 }, // Format_Mono,
- { 0, 0, 0 }, // Format_MonoLSB,
- { 0, 0, 0 }, // Format_Indexed8,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGB32,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_ARGB32,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_ARGB32_Premultiplied,
- { qt_memrotate90_16, qt_memrotate180_16, qt_memrotate270_16 }, // Format_RGB16,
- { 0, 0, 0 }, // Format_ARGB8565_Premultiplied,
- { 0, 0, 0 }, // Format_RGB666,
- { 0, 0, 0 }, // Format_ARGB6666_Premultiplied,
- { 0, 0, 0 }, // Format_RGB555,
- { 0, 0, 0 }, // Format_ARGB8555_Premultiplied,
- { 0, 0, 0 }, // Format_RGB888,
- { 0, 0, 0 }, // Format_RGB444,
- { 0, 0, 0 }, // Format_ARGB4444_Premultiplied,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGBX8888,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGBA8888,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGBA8888_Premultiplied,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_BGB30,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_A2BGR30_Premultiplied,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_RGB30,
- { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // Format_A2RGB30_Premultiplied,
- { qt_memrotate90_8, qt_memrotate180_8, qt_memrotate270_8 }, // Format_Alpha8,
- { qt_memrotate90_8, qt_memrotate180_8, qt_memrotate270_8 }, // Format_Grayscale8,
+ { 0, 0, 0 }, // BPPNone,
+ { 0, 0, 0 }, // BPP1MSB,
+ { 0, 0, 0 }, // BPP1LSB,
+ { qt_memrotate90_8, qt_memrotate180_8, qt_memrotate270_8 }, // BPP8,
+ { qt_memrotate90_16, qt_memrotate180_16, qt_memrotate270_16 }, // BPP16,
+ { qt_memrotate90_24, qt_memrotate180_24, qt_memrotate270_24 }, // BPP24
+ { qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // BPP32
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qmemrotate_p.h b/src/gui/painting/qmemrotate_p.h
index 62613d301a..9bc3fd1010 100644
--- a/src/gui/painting/qmemrotate_p.h
+++ b/src/gui/painting/qmemrotate_p.h
@@ -56,19 +56,6 @@
QT_BEGIN_NAMESPACE
-#define QT_ROTATION_CACHEDREAD 1
-#define QT_ROTATION_CACHEDWRITE 2
-#define QT_ROTATION_PACKING 3
-#define QT_ROTATION_TILED 4
-
-#ifndef QT_ROTATION_ALGORITHM
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-#define QT_ROTATION_ALGORITHM QT_ROTATION_TILED
-#else
-#define QT_ROTATION_ALGORITHM QT_ROTATION_CACHEDREAD
-#endif
-#endif
-
#define QT_DECL_MEMROTATE(type) \
void Q_GUI_EXPORT qt_memrotate90(const type*, int, int, int, type*, int); \
void Q_GUI_EXPORT qt_memrotate180(const type*, int, int, int, type*, int); \
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 6d5eaf5aed..eb43453ddb 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -272,6 +272,35 @@ static void qt_debug_path(const QPainterPath &path)
}
#endif
+// QRect::normalized() will change the width/height of the rectangle due to
+// its incusive-integer definition of left/right vs width. This is not
+// something we want to change in QRect as that would potentially introduce
+// regressions all over the place, so we implement a straightforward
+// normalized here. QRectF already does this, so QRectF::normalized() is ok to
+// use.
+static QRect qrect_normalized(const QRect &rect)
+{
+ int x, y, w, h;
+ if (Q_UNLIKELY(rect.width() < 0)) {
+ x = rect.x() + rect.width();
+ w = -rect.width();
+ } else {
+ x = rect.x();
+ w = rect.width();
+ }
+
+ if (Q_UNLIKELY(rect.height() < 0)) {
+ y = rect.y() + rect.height();
+ h = -rect.height();
+ } else {
+ y = rect.y();
+ h = rect.height();
+ }
+
+ return QRect(x, y, w, h);
+}
+
+
QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
QPaintEngineExPrivate(),
cachedLines(0)
@@ -1236,7 +1265,9 @@ void QRasterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
bool QRasterPaintEngine::setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op)
{
Q_D(QRasterPaintEngine);
- QRect clipRect = r & d->deviceRect;
+ // normalize before using the & operator which uses QRect::normalize()
+ // internally which will give us the wrong values.
+ QRect clipRect = qrect_normalized(r) & d->deviceRect;
QRasterPaintEngineState *s = state();
if (op == Qt::ReplaceClip || s->clip == 0) {
@@ -1471,7 +1502,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
int offset_x = int(s->matrix.dx());
int offset_y = int(s->matrix.dy());
while (r < lastRect) {
- QRect rect = r->normalized();
+ QRect rect = qrect_normalized(*r);
QRect rr = rect.translated(offset_x, offset_y);
fillRect_normalized(rr, &s->brushData, d);
++r;
@@ -2266,8 +2297,9 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
&& d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
{
RotationType rotationType = qRotationType(s->matrix);
+ const QPixelLayout::BPP plBpp = qPixelLayouts[d->rasterBuffer->format].bpp;
- if (rotationType != NoRotation && qMemRotateFunctions[d->rasterBuffer->format][rotationType] && img.rect().contains(sr.toAlignedRect())) {
+ if (rotationType != NoRotation && qMemRotateFunctions[plBpp][rotationType] && img.rect().contains(sr.toAlignedRect())) {
QRectF transformedTargetRect = s->matrix.mapRect(r);
if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
@@ -2297,7 +2329,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
uint cw = clippedSourceRect.width();
uint ch = clippedSourceRect.height();
- qMemRotateFunctions[d->rasterBuffer->format][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
+ qMemRotateFunctions[plBpp][rotationType](srcBase, cw, ch, sbpl, dstBase, dbpl);
return;
}
@@ -2500,7 +2532,7 @@ void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap,
QRectF rr = r;
rr.translate(s->matrix.dx(), s->matrix.dy());
- fillRect_normalized(rr.toRect().normalized(), &d->image_filler, d);
+ fillRect_normalized(rr.normalized().toRect(), &d->image_filler, d);
}
}
@@ -2523,7 +2555,7 @@ QRasterBuffer *QRasterPaintEngine::rasterBuffer()
/*!
\internal
*/
-void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h)
+void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h, bool useGammaCorrection)
{
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
@@ -2578,18 +2610,18 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
} else if (depth == 8) {
if (s->penData.alphamapBlit) {
s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
- scanline, w, h, bpl, 0);
+ scanline, w, h, bpl, 0, useGammaCorrection);
return;
}
} else if (depth == 32) {
// (A)RGB Alpha mask where the alpha component is not used.
if (s->penData.alphaRGBBlit) {
s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
- (const uint *) scanline, w, h, bpl / 4, 0);
+ (const uint *) scanline, w, h, bpl / 4, 0, useGammaCorrection);
return;
}
}
- } else if (d->deviceDepth == 32 && ((depth == 8 && s->penData.alphamapBlit) || (depth == 32 && s->penData.alphaRGBBlit))) {
+ } else if ((depth == 8 && s->penData.alphamapBlit) || (depth == 32 && s->penData.alphaRGBBlit)) {
// (A)RGB Alpha mask where the alpha component is not used.
if (!clip) {
int nx = qMax(0, rx);
@@ -2614,10 +2646,10 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
}
if (depth == 8)
s->penData.alphamapBlit(rb, rx, ry, s->penData.solid.color,
- scanline, w, h, bpl, clip);
+ scanline, w, h, bpl, clip, useGammaCorrection);
else if (depth == 32)
s->penData.alphaRGBBlit(rb, rx, ry, s->penData.solid.color,
- (const uint *) scanline, w, h, bpl / 4, clip);
+ (const uint *) scanline, w, h, bpl / 4, clip, useGammaCorrection);
return;
}
}
@@ -2775,7 +2807,8 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
alphaPenBlt(alphaMap->constBits(), alphaMap->bytesPerLine(), alphaMap->depth(),
qFloor(positions[i].x) + offset.x(),
qRound(positions[i].y) + offset.y(),
- alphaMap->width(), alphaMap->height());
+ alphaMap->width(), alphaMap->height(),
+ fontEngine->expectsGammaCorrectedBlending());
fontEngine->unlockAlphaMapForGlyph();
}
@@ -2836,7 +2869,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
drawImage(QPoint(x, y), QImage(glyphBits, c.w, c.h, bpl, image.format()));
s->matrix = originalTransform;
} else {
- alphaPenBlt(glyphBits, bpl, depth, x, y, c.w, c.h);
+ alphaPenBlt(glyphBits, bpl, depth, x, y, c.w, c.h, fontEngine->expectsGammaCorrectedBlending());
}
}
}
@@ -2880,7 +2913,7 @@ bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
const QRasterPaintEngineState *s = q->state();
const QClipData *cl = clip();
if (!cl) {
- QRect r = rect.normalized();
+ QRect r = qrect_normalized(rect);
// inline contains() for performance (we know the rects are normalized)
const QRect &r1 = deviceRect;
return (r.left() >= r1.left() && r.right() <= r1.right()
@@ -2895,7 +2928,7 @@ bool QRasterPaintEnginePrivate::isUnclipped(const QRect &rect,
if (s->flags.antialiased)
++penWidth;
- QRect r = rect.normalized();
+ QRect r = qrect_normalized(rect);
if (penWidth > 0) {
r.setX(r.x() - penWidth);
r.setY(r.y() - penWidth);
@@ -4439,9 +4472,9 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
gradient.alphaColor = !brush.isOpaque() || alpha != 256;
auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
- cachedGradient = cacheInfo;
gradient.colorTable32 = cacheInfo->buffer32;
gradient.colorTable64 = cacheInfo->buffer64;
+ cachedGradient = std::move(cacheInfo);
gradient.spread = g->spread();
@@ -4461,9 +4494,9 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
gradient.alphaColor = !brush.isOpaque() || alpha != 256;
auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
- cachedGradient = cacheInfo;
gradient.colorTable32 = cacheInfo->buffer32;
gradient.colorTable64 = cacheInfo->buffer64;
+ cachedGradient = std::move(cacheInfo);
gradient.spread = g->spread();
@@ -4487,9 +4520,9 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
gradient.alphaColor = !brush.isOpaque() || alpha != 256;
auto cacheInfo = qt_gradient_cache()->getBuffer(*g, alpha);
- cachedGradient = cacheInfo;
gradient.colorTable32 = cacheInfo->buffer32;
gradient.colorTable64 = cacheInfo->buffer64;
+ cachedGradient = std::move(cacheInfo);
gradient.spread = QGradient::RepeatSpread;
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index 59213220a6..d0b82b3a93 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -225,7 +225,7 @@ public:
#endif
QRasterBuffer *rasterBuffer();
- void alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h);
+ void alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h, bool useGammaCorrection);
Type type() const Q_DECL_OVERRIDE { return Raster; }
diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h
index 46817b9c73..64d15d5296 100644
--- a/src/gui/painting/qpainter.h
+++ b/src/gui/painting/qpainter.h
@@ -83,7 +83,6 @@ class Q_GUI_EXPORT QPainter
{
Q_DECLARE_PRIVATE(QPainter)
Q_GADGET
- Q_FLAGS(RenderHint RenderHints)
public:
enum RenderHint {
@@ -94,8 +93,10 @@ public:
NonCosmeticDefaultPen = 0x10,
Qt4CompatiblePainting = 0x20
};
+ Q_FLAG(RenderHint)
Q_DECLARE_FLAGS(RenderHints, RenderHint)
+ Q_FLAG(RenderHints)
class PixmapFragment {
public:
diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp
index 644999e00a..afeb198953 100644
--- a/src/gui/painting/qpdf.cpp
+++ b/src/gui/painting/qpdf.cpp
@@ -1504,16 +1504,25 @@ void QPdfEnginePrivate::writeInfo()
printString(creator);
xprintf("\n/Producer ");
printString(QString::fromLatin1("Qt " QT_VERSION_STR));
- QDateTime now = QDateTime::currentDateTimeUtc();
+ QDateTime now = QDateTime::currentDateTime();
QTime t = now.time();
QDate d = now.date();
- xprintf("\n/CreationDate (D:%d%02d%02d%02d%02d%02d)\n",
+ xprintf("\n/CreationDate (D:%d%02d%02d%02d%02d%02d",
d.year(),
d.month(),
d.day(),
t.hour(),
t.minute(),
t.second());
+ int offset = now.offsetFromUtc();
+ int hours = (offset / 60) / 60;
+ int mins = (offset / 60) % 60;
+ if (offset < 0)
+ xprintf("-%02d'%02d')\n", -hours, -mins);
+ else if (offset > 0)
+ xprintf("+%02d'%02d')\n", hours , mins);
+ else
+ xprintf("Z)\n");
xprintf(">>\n"
"endobj\n");
}
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index 0571e1a328..3fb6f925b3 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -739,7 +739,7 @@ bool QRegion::intersects(const QRegion &region) const
*/
-#if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN)
+#if !defined (Q_OS_UNIX) && !defined (Q_OS_WIN) || defined(Q_CLANG_QDOC)
/*!
\overload
\since 4.4
diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h
index a3ae0c9b14..2c8f8fa8c4 100644
--- a/src/gui/painting/qrgba64.h
+++ b/src/gui/painting/qrgba64.h
@@ -64,26 +64,14 @@ class QRgba64 {
#endif
};
- // No constructors are allowed in C++98, since this needs to be usable in a union.
- // We however require one for constexprs in C++11/C++14
-#ifdef Q_COMPILER_CONSTEXPR
explicit Q_ALWAYS_INLINE Q_DECL_CONSTEXPR QRgba64(quint64 c) : rgba(c) { }
-#endif
public:
-#ifdef Q_COMPILER_CONSTEXPR
- Q_ALWAYS_INLINE Q_DECL_CONSTEXPR QRgba64() : rgba(0) { }
-#endif
+ QRgba64() = default;
Q_DECL_CONSTEXPR static
QRgba64 fromRgba64(quint64 c)
{
-#ifdef Q_COMPILER_CONSTEXPR
return QRgba64(c);
-#else
- QRgba64 rgba64;
- rgba64.rgba = c;
- return rgba64;
-#endif
}
Q_DECL_CONSTEXPR static
QRgba64 fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h
index 0dadc038fa..7776a5b08a 100644
--- a/src/gui/painting/qrgba64_p.h
+++ b/src/gui/painting/qrgba64_p.h
@@ -185,6 +185,60 @@ inline QRgba64 addWithSaturation(QRgba64 a, QRgba64 b)
qMin(a.alpha() + b.alpha(), 65535));
}
+#if defined __SSE2__
+Q_ALWAYS_INLINE uint toArgb32(__m128i v)
+{
+ v = _mm_unpacklo_epi16(v, _mm_setzero_si128());
+ v = _mm_add_epi32(v, _mm_set1_epi32(128));
+ v = _mm_sub_epi32(v, _mm_srli_epi32(v, 8));
+ v = _mm_srli_epi32(v, 8);
+ v = _mm_packs_epi32(v, v);
+ v = _mm_packus_epi16(v, v);
+ return _mm_cvtsi128_si32(v);
+}
+#elif defined __ARM_NEON__
+Q_ALWAYS_INLINE uint toArgb32(uint16x4_t v)
+{
+ v = vsub_u16(v, vrshr_n_u16(v, 8));
+ v = vrshr_n_u16(v, 8);
+ uint8x8_t v8 = vmovn_u16(vcombine_u16(v, v));
+ return vget_lane_u32(vreinterpret_u32_u8(v8), 0);
+}
+#endif
+
+inline uint toArgb32(QRgba64 rgba64)
+{
+#if defined __SSE2__
+ __m128i v = _mm_loadl_epi64((const __m128i *)&rgba64);
+ v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(3, 0, 1, 2));
+ return toArgb32(v);
+#elif defined __ARM_NEON__
+ uint16x4_t v = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&rgba64)));
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ const uint8x8_t shuffleMask = { 4, 5, 2, 3, 0, 1, 6, 7 };
+ v = vreinterpret_u16_u8(vtbl1_u8(vreinterpret_u8_u16(v), shuffleMask));
+#else
+ v = vext_u16(v, v, 3);
+#endif
+ return toArgb32(v);
+#else
+ return rgba64.toArgb32();
+#endif
+}
+
+inline uint toRgba8888(QRgba64 rgba64)
+{
+#if defined __SSE2__
+ __m128i v = _mm_loadl_epi64((const __m128i *)&rgba64);
+ return toArgb32(v);
+#elif defined __ARM_NEON__
+ uint16x4_t v = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&rgba64)));
+ return toArgb32(v);
+#else
+ return ARGB2RGBA(toArgb32(rgba64));
+#endif
+}
+
#if defined(__SSE2__)
Q_ALWAYS_INLINE __m128i addWithSaturation(__m128i a, __m128i b)
{
@@ -199,6 +253,53 @@ Q_ALWAYS_INLINE uint16x4_t addWithSaturation(uint16x4_t a, uint16x4_t b)
}
#endif
+inline QRgba64 rgbBlend(QRgba64 d, QRgba64 s, uint rgbAlpha)
+{
+ QRgba64 blend;
+#if defined(__SSE2__)
+ __m128i vd = _mm_loadl_epi64((const __m128i *)&d);
+ __m128i vs = _mm_loadl_epi64((const __m128i *)&s);
+ __m128i va = _mm_cvtsi32_si128(rgbAlpha);
+ va = _mm_unpacklo_epi8(va, va);
+ va = _mm_shufflelo_epi16(va, _MM_SHUFFLE(3, 0, 1, 2));
+ __m128i vb = _mm_xor_si128(_mm_set1_epi16(-1), va);
+
+ vs = _mm_unpacklo_epi16(_mm_mullo_epi16(vs, va), _mm_mulhi_epu16(vs, va));
+ vd = _mm_unpacklo_epi16(_mm_mullo_epi16(vd, vb), _mm_mulhi_epu16(vd, vb));
+ vd = _mm_add_epi32(vd, vs);
+ vd = _mm_add_epi32(vd, _mm_srli_epi32(vd, 16));
+ vd = _mm_add_epi32(vd, _mm_set1_epi32(0x8000));
+ vd = _mm_srai_epi32(vd, 16);
+ vd = _mm_packs_epi32(vd, _mm_setzero_si128());
+
+ _mm_storel_epi64((__m128i *)&blend, vd);
+#elif defined(__ARM_NEON__)
+ uint16x4_t vd = vreinterpret_u16_u64(vmov_n_u64(d));
+ uint16x4_t vs = vreinterpret_u16_u64(vmov_n_u64(s));
+ uint8x8_t va8 = vreinterpret_u8_u32(vmov_n_u32(ARGB2RGBA(rgbAlpha)));
+ uint16x4_t va = vreinterpret_u16_u8(vzip_u8(va8, va8).val[0]);
+ uint16x4_t vb = vdup_n_u16(0xffff);
+ vb = vsub_u16(vb, va);
+
+ uint32x4_t vs32 = vmull_u16(vs, va);
+ uint32x4_t vd32 = vmull_u16(vd, vb);
+ vd32 = vaddq_u32(vd32, vs32);
+ vd32 = vsraq_n_u32(vd32, vd32, 16);
+ vd = vrshrn_n_u32(vd32, 16);
+ vst1_u64(reinterpret_cast<uint64_t *>(&blend), vreinterpret_u64_u16(vd));
+#else
+ const int mr = qRed(rgbAlpha);
+ const int mg = qGreen(rgbAlpha);
+ const int mb = qBlue(rgbAlpha);
+ blend.setRed (qt_div_255(s.red() * mr + d.red() * (255 - mr)));
+ blend.setGreen(qt_div_255(s.green() * mg + d.green() * (255 - mg)));
+ blend.setBlue (qt_div_255(s.blue() * mb + d.blue() * (255 - mb)));
+ blend.setAlpha(s.alpha());
+#endif
+ return blend;
+}
+
+
QT_END_NAMESPACE
#endif // QRGBA64_P_H
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp
index 4e0489b352..7f06915444 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -1118,16 +1118,16 @@ QDataStream & operator>>(QDataStream &s, QTransform &t)
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QTransform &m)
{
- static const char *const typeStr[] =
+ static const char typeStr[][12] =
{
"TxNone",
"TxTranslate",
"TxScale",
- 0,
+ "",
"TxRotate",
- 0, 0, 0,
+ "", "", "",
"TxShear",
- 0, 0, 0, 0, 0, 0, 0,
+ "", "", "", "", "", "", "",
"TxProject"
};
diff --git a/src/gui/painting/qtriangulator.cpp b/src/gui/painting/qtriangulator.cpp
index 6604d407f0..6d57eba123 100644
--- a/src/gui/painting/qtriangulator.cpp
+++ b/src/gui/painting/qtriangulator.cpp
@@ -50,10 +50,6 @@
#include <QtCore/qglobal.h>
#include <QtCore/qpoint.h>
#include <QtCore/qalgorithms.h>
-#ifndef QT_NO_OPENGL
-# include <private/qopenglcontext_p.h>
-# include <private/qopenglextensions_p.h>
-#endif
#include <private/qrbtree_p.h>
QT_BEGIN_NAMESPACE
@@ -2266,23 +2262,12 @@ void QTriangulator<T>::MonotoneToTriangles::decompose()
// qTriangulate //
//============================================================================//
-static bool hasElementIndexUint()
-{
-#ifndef QT_NO_OPENGL
- QOpenGLContext *context = QOpenGLContext::currentContext();
- if (!context)
- return false;
- return static_cast<QOpenGLExtensions *>(context->functions())->hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint);
-#else
- return false;
-#endif
-}
-
Q_GUI_EXPORT QTriangleSet qTriangulate(const qreal *polygon,
- int count, uint hint, const QTransform &matrix)
+ int count, uint hint, const QTransform &matrix,
+ bool allowUintIndices)
{
QTriangleSet triangleSet;
- if (hasElementIndexUint()) {
+ if (allowUintIndices) {
QTriangulator<quint32> triangulator;
triangulator.initialize(polygon, count, hint, matrix);
QVertexSet<quint32> vertexSet = triangulator.triangulate();
@@ -2300,10 +2285,13 @@ Q_GUI_EXPORT QTriangleSet qTriangulate(const qreal *polygon,
}
Q_GUI_EXPORT QTriangleSet qTriangulate(const QVectorPath &path,
- const QTransform &matrix, qreal lod)
+ const QTransform &matrix, qreal lod, bool allowUintIndices)
{
QTriangleSet triangleSet;
- if (hasElementIndexUint()) {
+ // For now systems that support 32-bit index values will always get 32-bit
+ // index values. This is not necessary ideal since 16-bit would be enough in
+ // many cases. TODO revisit this at a later point.
+ if (allowUintIndices) {
QTriangulator<quint32> triangulator;
triangulator.initialize(path, matrix, lod);
QVertexSet<quint32> vertexSet = triangulator.triangulate();
@@ -2320,10 +2308,10 @@ Q_GUI_EXPORT QTriangleSet qTriangulate(const QVectorPath &path,
}
QTriangleSet qTriangulate(const QPainterPath &path,
- const QTransform &matrix, qreal lod)
+ const QTransform &matrix, qreal lod, bool allowUintIndices)
{
QTriangleSet triangleSet;
- if (hasElementIndexUint()) {
+ if (allowUintIndices) {
QTriangulator<quint32> triangulator;
triangulator.initialize(path, matrix, lod);
QVertexSet<quint32> vertexSet = triangulator.triangulate();
@@ -2340,10 +2328,10 @@ QTriangleSet qTriangulate(const QPainterPath &path,
}
QPolylineSet qPolyline(const QVectorPath &path,
- const QTransform &matrix, qreal lod)
+ const QTransform &matrix, qreal lod, bool allowUintIndices)
{
QPolylineSet polyLineSet;
- if (hasElementIndexUint()) {
+ if (allowUintIndices) {
QTriangulator<quint32> triangulator;
triangulator.initialize(path, matrix, lod);
QVertexSet<quint32> vertexSet = triangulator.polyline();
@@ -2360,10 +2348,10 @@ QPolylineSet qPolyline(const QVectorPath &path,
}
QPolylineSet qPolyline(const QPainterPath &path,
- const QTransform &matrix, qreal lod)
+ const QTransform &matrix, qreal lod, bool allowUintIndices)
{
QPolylineSet polyLineSet;
- if (hasElementIndexUint()) {
+ if (allowUintIndices) {
QTriangulator<quint32> triangulator;
triangulator.initialize(path, matrix, lod);
QVertexSet<quint32> vertexSet = triangulator.polyline();
diff --git a/src/gui/painting/qtriangulator_p.h b/src/gui/painting/qtriangulator_p.h
index 4d1aba099c..8f043fc925 100644
--- a/src/gui/painting/qtriangulator_p.h
+++ b/src/gui/painting/qtriangulator_p.h
@@ -137,11 +137,18 @@ struct Q_GUI_EXPORT QPolylineSet
// integers, the polygon is triangulated, and then scaled back by 1/32.
// 'hint' should be a combination of QVectorPath::Hints.
// 'lod' is the level of detail. Default is 1. Curves are split into more lines when 'lod' is higher.
-QTriangleSet Q_GUI_EXPORT qTriangulate(const qreal *polygon, int count, uint hint = QVectorPath::PolygonHint | QVectorPath::OddEvenFill, const QTransform &matrix = QTransform());
-QTriangleSet Q_GUI_EXPORT qTriangulate(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
-QTriangleSet Q_GUI_EXPORT qTriangulate(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
-QPolylineSet qPolyline(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
-QPolylineSet Q_GUI_EXPORT qPolyline(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
+QTriangleSet Q_GUI_EXPORT qTriangulate(const qreal *polygon, int count,
+ uint hint = QVectorPath::PolygonHint | QVectorPath::OddEvenFill,
+ const QTransform &matrix = QTransform(),
+ bool allowUintIndices = true);
+QTriangleSet Q_GUI_EXPORT qTriangulate(const QVectorPath &path, const QTransform &matrix = QTransform(),
+ qreal lod = 1, bool allowUintIndices = true);
+QTriangleSet Q_GUI_EXPORT qTriangulate(const QPainterPath &path, const QTransform &matrix = QTransform(),
+ qreal lod = 1, bool allowUintIndices = true);
+QPolylineSet qPolyline(const QVectorPath &path, const QTransform &matrix = QTransform(),
+ qreal lod = 1, bool allowUintIndices = true);
+QPolylineSet Q_GUI_EXPORT qPolyline(const QPainterPath &path, const QTransform &matrix = QTransform(),
+ qreal lod = 1, bool allowUintIndices = true);
QT_END_NAMESPACE
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index a0438bd458..64adeaa260 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -1822,7 +1822,7 @@ void StyleSheet::buildIndexes(Qt::CaseSensitivity nameCaseSensitivity)
nr.order = i;
QString name = sel.elementName;
if (nameCaseSensitivity == Qt::CaseInsensitive)
- name=name.toLower();
+ name = std::move(name).toLower();
nameIndex.insert(name, nr);
} else {
universalsSelectors += selector;
@@ -2027,7 +2027,7 @@ QVector<StyleRule> StyleSelector::styleRulesForNode(NodePtr node)
for (int i = 0; i < names.count(); i++) {
QString name = names.at(i);
if (nameCaseSensitivity == Qt::CaseInsensitive)
- name = name.toLower();
+ name = std::move(name).toLower();
QMultiHash<QString, StyleRule>::const_iterator it = styleSheet.nameIndex.constFind(name);
while (it != styleSheet.nameIndex.constEnd() && it.key() == name) {
matchRule(node, it.value(), styleSheet.origin, styleSheet.depth, &weightedRules);
@@ -2748,7 +2748,7 @@ bool Parser::testAndParseUri(QString *uri)
index = rewind;
return false;
}
- if (name.toLower() != QLatin1String("url")) {
+ if (name.compare(QLatin1String("url"), Qt::CaseInsensitive) != 0) {
index = rewind;
return false;
}
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 0b2972f189..596c79fd05 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -445,6 +445,11 @@ bool QFontEngine::supportsTransformation(const QTransform &transform) const
return transform.type() < QTransform::TxProject;
}
+bool QFontEngine::expectsGammaCorrectedBlending() const
+{
+ return true;
+}
+
void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags,
QVarLengthArray<glyph_t> &glyphs_out, QVarLengthArray<QFixedPoint> &positions)
{
@@ -1268,7 +1273,7 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))
return 0;
- quint16 platformSpecificId;
+ quint16 platformSpecificId = 0;
if (!qSafeFromBigEndian(maps + 8 * n + 2, endPtr, &platformSpecificId))
return 0;
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index c0e350f755..514e9424b2 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -254,6 +254,7 @@ public:
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily);
virtual bool hasUnreliableGlyphOutline() const;
+ virtual bool expectsGammaCorrectedBlending() const;
enum HintStyle {
HintNone,
diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp
index 55ef9f0d15..6aca660205 100644
--- a/src/gui/text/qharfbuzzng.cpp
+++ b/src/gui/text/qharfbuzzng.cpp
@@ -422,19 +422,53 @@ hb_unicode_funcs_t *hb_qt_get_unicode_funcs()
// Font routines
+#if HB_VERSION_ATLEAST(1, 1, 3)
static hb_bool_t
-_hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data,
- hb_codepoint_t unicode, hb_codepoint_t /*variation_selector*/,
- hb_codepoint_t *glyph,
- void * /*user_data*/)
+_hb_qt_get_font_h_extents(hb_font_t * /*font*/, void *font_data,
+ hb_font_extents_t *metrics,
+ void * /*user_data*/)
{
QFontEngine *fe = static_cast<QFontEngine *>(font_data);
Q_ASSERT(fe);
- *glyph = fe->glyphIndex(unicode);
+ metrics->ascender = fe->ascent().value();
+ metrics->descender = fe->descent().value();
+ metrics->line_gap = fe->leading().value();
return true;
}
+#endif
+
+#if HB_VERSION_ATLEAST(1, 2, 3)
+static hb_bool_t
+_hb_qt_font_get_nominal_glyph(hb_font_t * /*font*/, void *font_data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t *glyph,
+ void * /*user_data*/)
+{
+ QFontEngine *fe = static_cast<QFontEngine *>(font_data);
+ Q_ASSERT(fe);
+
+ *glyph = fe->glyphIndex(unicode);
+
+ return *glyph != 0;
+}
+#endif
+
+static hb_bool_t
+_hb_qt_font_get_variation_glyph(hb_font_t * /*font*/, void *font_data,
+ hb_codepoint_t unicode, hb_codepoint_t /*variation_selector*/,
+ hb_codepoint_t *glyph,
+ void * /*user_data*/)
+{
+ QFontEngine *fe = static_cast<QFontEngine *>(font_data);
+ Q_ASSERT(fe);
+
+ // ### TODO add support for variation selectors
+ *glyph = fe->glyphIndex(unicode);
+
+ return *glyph != 0;
+}
static hb_position_t
_hb_qt_font_get_glyph_h_advance(hb_font_t *font, void *font_data,
@@ -456,15 +490,7 @@ _hb_qt_font_get_glyph_h_advance(hb_font_t *font, void *font_data,
return advance.value();
}
-static hb_position_t
-_hb_qt_font_get_glyph_v_advance(hb_font_t * /*font*/, void * /*font_data*/,
- hb_codepoint_t /*glyph*/,
- void * /*user_data*/)
-{
- qCritical("hb_qt_font_get_glyph_v_advance: vertical writing isn't supported!");
- return 0;
-}
-
+#if !HB_VERSION_ATLEAST(1, 1, 2)
static hb_bool_t
_hb_qt_font_get_glyph_h_origin(hb_font_t * /*font*/, void * /*font_data*/,
hb_codepoint_t /*glyph*/,
@@ -473,16 +499,7 @@ _hb_qt_font_get_glyph_h_origin(hb_font_t * /*font*/, void * /*font_data*/,
{
return true; // we always work in the horizontal coordinates
}
-
-static hb_bool_t
-_hb_qt_font_get_glyph_v_origin(hb_font_t * /*font*/, void * /*font_data*/,
- hb_codepoint_t /*glyph*/,
- hb_position_t * /*x*/, hb_position_t * /*y*/,
- void * /*user_data*/)
-{
- qCritical("hb_qt_get_glyph_v_origin: vertical writing isn't supported!");
- return false;
-}
+#endif
static hb_position_t
_hb_qt_font_get_glyph_h_kerning(hb_font_t *font, void *font_data,
@@ -505,15 +522,6 @@ _hb_qt_font_get_glyph_h_kerning(hb_font_t *font, void *font_data,
return advance.value();
}
-static hb_position_t
-_hb_qt_font_get_glyph_v_kerning(hb_font_t * /*font*/, void * /*font_data*/,
- hb_codepoint_t /*first_glyph*/, hb_codepoint_t /*second_glyph*/,
- void * /*user_data*/)
-{
- qCritical("hb_qt_get_glyph_v_kerning: vertical writing isn't supported!");
- return 0;
-}
-
static hb_bool_t
_hb_qt_font_get_glyph_extents(hb_font_t * /*font*/, void *font_data,
hb_codepoint_t glyph,
@@ -554,29 +562,6 @@ _hb_qt_font_get_glyph_contour_point(hb_font_t * /*font*/, void *font_data,
return false;
}
-static hb_bool_t
-_hb_qt_font_get_glyph_name(hb_font_t * /*font*/, void * /*font_data*/,
- hb_codepoint_t /*glyph*/,
- char *name, unsigned int size,
- void * /*user_data*/)
-{
- qCritical("hb_qt_font_get_glyph_name: not implemented!");
- if (size)
- *name = '\0';
- return false;
-}
-
-static hb_bool_t
-_hb_qt_font_get_glyph_from_name(hb_font_t * /*font*/, void * /*font_data*/,
- const char * /*name*/, int /*len*/,
- hb_codepoint_t *glyph,
- void * /*user_data*/)
-{
- qCritical("hb_qt_font_get_glyph_from_name: not implemented!");
- *glyph = 0;
- return false;
-}
-
static hb_user_data_key_t _useDesignMetricsKey;
@@ -595,17 +580,25 @@ struct _hb_qt_font_funcs_t {
_hb_qt_font_funcs_t()
{
funcs = hb_font_funcs_create();
- hb_font_funcs_set_glyph_func(funcs, _hb_qt_font_get_glyph, NULL, NULL);
+
+#if HB_VERSION_ATLEAST(1, 1, 3)
+ hb_font_funcs_set_font_h_extents_func(funcs, _hb_qt_get_font_h_extents, NULL, NULL);
+#endif
+#if HB_VERSION_ATLEAST(1, 2, 3)
+ hb_font_funcs_set_nominal_glyph_func(funcs, _hb_qt_font_get_nominal_glyph, NULL, NULL);
+ hb_font_funcs_set_variation_glyph_func(funcs, _hb_qt_font_get_variation_glyph, NULL, NULL);
+#else
+ hb_font_funcs_set_glyph_func(funcs, _hb_qt_font_get_variation_glyph, NULL, NULL);
+#endif
hb_font_funcs_set_glyph_h_advance_func(funcs, _hb_qt_font_get_glyph_h_advance, NULL, NULL);
- hb_font_funcs_set_glyph_v_advance_func(funcs, _hb_qt_font_get_glyph_v_advance, NULL, NULL);
+#if !HB_VERSION_ATLEAST(1, 1, 2)
hb_font_funcs_set_glyph_h_origin_func(funcs, _hb_qt_font_get_glyph_h_origin, NULL, NULL);
- hb_font_funcs_set_glyph_v_origin_func(funcs, _hb_qt_font_get_glyph_v_origin, NULL, NULL);
+#endif
hb_font_funcs_set_glyph_h_kerning_func(funcs, _hb_qt_font_get_glyph_h_kerning, NULL, NULL);
- hb_font_funcs_set_glyph_v_kerning_func(funcs, _hb_qt_font_get_glyph_v_kerning, NULL, NULL);
hb_font_funcs_set_glyph_extents_func(funcs, _hb_qt_font_get_glyph_extents, NULL, NULL);
hb_font_funcs_set_glyph_contour_point_func(funcs, _hb_qt_font_get_glyph_contour_point, NULL, NULL);
- hb_font_funcs_set_glyph_name_func(funcs, _hb_qt_font_get_glyph_name, NULL, NULL);
- hb_font_funcs_set_glyph_from_name_func(funcs, _hb_qt_font_get_glyph_from_name, NULL, NULL);
+
+ hb_font_funcs_make_immutable(funcs);
}
~_hb_qt_font_funcs_t()
{
diff --git a/src/gui/text/qinputcontrol.cpp b/src/gui/text/qinputcontrol.cpp
index 2f7dcfcd2b..3381fdb673 100644
--- a/src/gui/text/qinputcontrol.cpp
+++ b/src/gui/text/qinputcontrol.cpp
@@ -85,4 +85,55 @@ bool QInputControl::isAcceptableInput(const QKeyEvent *event) const
return false;
}
+bool QInputControl::isCommonTextEditShortcut(const QKeyEvent *ke)
+{
+ if (ke->modifiers() == Qt::NoModifier
+ || ke->modifiers() == Qt::ShiftModifier
+ || ke->modifiers() == Qt::KeypadModifier) {
+ if (ke->key() < Qt::Key_Escape) {
+ return true;
+ } else {
+ switch (ke->key()) {
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ case Qt::Key_Delete:
+ case Qt::Key_Home:
+ case Qt::Key_End:
+ case Qt::Key_Backspace:
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Tab:
+ return true;
+ default:
+ break;
+ }
+ }
+#if QT_CONFIG(shortcut)
+ } else if (ke->matches(QKeySequence::Copy)
+ || ke->matches(QKeySequence::Paste)
+ || ke->matches(QKeySequence::Cut)
+ || ke->matches(QKeySequence::Redo)
+ || ke->matches(QKeySequence::Undo)
+ || ke->matches(QKeySequence::MoveToNextWord)
+ || ke->matches(QKeySequence::MoveToPreviousWord)
+ || ke->matches(QKeySequence::MoveToStartOfDocument)
+ || ke->matches(QKeySequence::MoveToEndOfDocument)
+ || ke->matches(QKeySequence::SelectNextWord)
+ || ke->matches(QKeySequence::SelectPreviousWord)
+ || ke->matches(QKeySequence::SelectStartOfLine)
+ || ke->matches(QKeySequence::SelectEndOfLine)
+ || ke->matches(QKeySequence::SelectStartOfBlock)
+ || ke->matches(QKeySequence::SelectEndOfBlock)
+ || ke->matches(QKeySequence::SelectStartOfDocument)
+ || ke->matches(QKeySequence::SelectEndOfDocument)
+ || ke->matches(QKeySequence::SelectAll)
+ ) {
+ return true;
+#endif
+ }
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/text/qinputcontrol_p.h b/src/gui/text/qinputcontrol_p.h
index e5709b5e54..b4c1ca8f8f 100644
--- a/src/gui/text/qinputcontrol_p.h
+++ b/src/gui/text/qinputcontrol_p.h
@@ -69,6 +69,7 @@ public:
explicit QInputControl(Type type, QObject *parent = nullptr);
bool isAcceptableInput(const QKeyEvent *event) const;
+ static bool isCommonTextEditShortcut(const QKeyEvent *ke);
protected:
explicit QInputControl(Type type, QObjectPrivate &dd, QObject *parent = nullptr);
diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp
index b83affecdc..599b18ac05 100644
--- a/src/gui/text/qplatformfontdatabase.cpp
+++ b/src/gui/text/qplatformfontdatabase.cpp
@@ -423,14 +423,14 @@ QFont QPlatformFontDatabase::defaultFont() const
return QFont(QLatin1String("Helvetica"));
}
+
+QString qt_resolveFontFamilyAlias(const QString &alias);
+
/*!
Resolve alias to actual font family names.
\since 5.0
*/
-
-QString qt_resolveFontFamilyAlias(const QString &alias);
-
QString QPlatformFontDatabase::resolveFontFamilyAlias(const QString &family) const
{
return qt_resolveFontFamilyAlias(family);
@@ -465,16 +465,6 @@ bool QPlatformFontDatabase::fontsAlwaysScalable() const
return ret;
}
-QFontEngine::SubpixelAntialiasingType QPlatformFontDatabase::subpixelAntialiasingTypeHint() const
-{
- static int type = -1;
- if (type == -1) {
- if (QScreen *screen = QGuiApplication::primaryScreen())
- type = screen->handle()->subpixelAntialiasingTypeHint();
- }
- return static_cast<QFontEngine::SubpixelAntialiasingType>(type);
-}
-
// ### copied to tools/makeqpf/qpf2.cpp
// see the Unicode subset bitfields in the MSDN docs
@@ -628,12 +618,13 @@ QSupportedWritingSystems QPlatformFontDatabase::writingSystemsFromTrueTypeBits(q
}
/*!
- Helper function that returns the Qt font weight matching a given opentype integer value.
+ Helper function that returns the Qt font weight matching
+ a given opentype integer value. Converts the integer
+ \a weight (0 ~ 1000) to QFont::Weight and returns it.
\since 5.5
*/
-// convert 0 ~ 1000 integer to QFont::Weight
QFont::Weight QPlatformFontDatabase::weightFromInteger(int weight)
{
if (weight < 150)
diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h
index 13d8cbde60..2d99183ca3 100644
--- a/src/gui/text/qplatformfontdatabase.h
+++ b/src/gui/text/qplatformfontdatabase.h
@@ -116,7 +116,6 @@ public:
virtual QString resolveFontFamilyAlias(const QString &family) const;
virtual bool fontsAlwaysScalable() const;
virtual QList<int> standardSizes() const;
- QFontEngine::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const;
// helper
static QSupportedWritingSystems writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]);
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index c006e7f427..f8215f92e9 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -133,7 +133,7 @@ bool Qt::mightBeRichText(const QString& text)
return false; // that's not a tag
}
#ifndef QT_NO_TEXTHTMLPARSER
- return QTextHtmlParser::lookupElement(tag.toLower()) != -1;
+ return QTextHtmlParser::lookupElement(std::move(tag).toLower()) != -1;
#else
return false;
#endif // QT_NO_TEXTHTMLPARSER
@@ -1145,13 +1145,30 @@ void QTextDocument::setMetaInformation(MetaInformation info, const QString &stri
}
/*!
+ Returns the raw text contained in the document without any
+ formatting information. If you want formatting information
+ use a QTextCursor instead.
+
+ \since 5.9
+ \sa toPlainText()
+*/
+QString QTextDocument::toRawText() const
+{
+ Q_D(const QTextDocument);
+ return d->plainText();
+}
+
+/*!
Returns the plain text contained in the document. If you want
formatting information use a QTextCursor instead.
- Some formatting characters are replaced by ASCII equivalents.
+ This function returns the same as toRawText(), but will replace
+ some unicode characters with ASCII alternatives.
In particular, no-break space (U+00A0) is replaced by a regular
space (U+0020), and both paragraph (U+2029) and line (U+2028)
separators are replaced by line feed (U+000A).
+ If you need the precise contents of the document, use toRawText()
+ instead.
\note Embedded objects, such as images, are represented by a
Unicode value U+FFFC (OBJECT REPLACEMENT CHARACTER).
diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h
index 1888088f0d..c2761a39b9 100644
--- a/src/gui/text/qtextdocument.h
+++ b/src/gui/text/qtextdocument.h
@@ -151,6 +151,7 @@ public:
void setHtml(const QString &html);
#endif
+ QString toRawText() const;
QString toPlainText() const;
void setPlainText(const QString &text);
diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp
index 079b2e01f7..ea37695f4e 100644
--- a/src/gui/text/qtextdocumentfragment.cpp
+++ b/src/gui/text/qtextdocumentfragment.cpp
@@ -408,6 +408,8 @@ QTextDocumentFragment QTextDocumentFragment::fromPlainText(const QString &plainT
return res;
}
+#ifndef QT_NO_TEXTHTMLPARSER
+
static QTextListFormat::Style nextListStyle(QTextListFormat::Style style)
{
if (style == QTextListFormat::ListDisc)
@@ -417,8 +419,6 @@ static QTextListFormat::Style nextListStyle(QTextListFormat::Style style)
return style;
}
-#ifndef QT_NO_TEXTHTMLPARSER
-
QTextHtmlImporter::QTextHtmlImporter(QTextDocument *_doc, const QString &_html, ImportMode mode, const QTextDocument *resourceProvider)
: indent(0), compressNextWhitespace(PreserveWhiteSpace), doc(_doc), importMode(mode)
{
@@ -825,9 +825,13 @@ bool QTextHtmlImporter::closeTag()
break;
case Html_div:
- if (closedNode->children.isEmpty())
- break;
- Q_FALLTHROUGH();
+ if (cursor.position() > 0) {
+ const QChar curChar = cursor.document()->characterAt(cursor.position() - 1);
+ if (!closedNode->children.isEmpty() && curChar != QChar::LineSeparator) {
+ blockTagClosed = true;
+ }
+ }
+ break;
default:
if (closedNode->isBlock())
blockTagClosed = true;
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index 8ad2d85e7c..e9194e73ff 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -834,6 +834,8 @@ void QTextDocumentLayoutPrivate::drawBorder(QPainter *painter, const QRectF &rec
#ifndef QT_NO_CSSPARSER
QCss::BorderStyle cssStyle = static_cast<QCss::BorderStyle>(style + 1);
+#else
+ Q_UNUSED(style);
#endif //QT_NO_CSSPARSER
bool turn_off_antialiasing = !(painter->renderHints() & QPainter::Antialiasing);
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 4f052dafd7..4d24fb50af 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -1170,6 +1170,20 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
hb_buffer_clear_contents(buffer);
hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16_t *>(string) + item_pos, item_length, 0, item_length);
+#if defined(Q_OS_DARWIN)
+ // ### temporary workaround for QTBUG-38113
+ // CoreText throws away the PDF token, while the OpenType backend will replace it with
+ // a zero-advance glyph. This becomes a real issue when PDF is the last character,
+ // since it gets treated like if it were a grapheme extender, so we
+ // temporarily replace it with some visible grapheme starter.
+ bool endsWithPDF = actualFontEngine->type() == QFontEngine::Mac && string[item_pos + item_length - 1] == 0x202c;
+ if (Q_UNLIKELY(endsWithPDF)) {
+ uint num_glyphs;
+ hb_glyph_info_t *infos = hb_buffer_get_glyph_infos(buffer, &num_glyphs);
+ infos[num_glyphs - 1].codepoint = '.';
+ }
+#endif
+
hb_buffer_set_segment_properties(buffer, &props);
hb_buffer_guess_segment_properties(buffer);
@@ -1291,6 +1305,20 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
while (str_pos < item_length)
log_clusters[str_pos++] = last_glyph_pos;
+#if defined(Q_OS_DARWIN)
+ if (Q_UNLIKELY(endsWithPDF)) {
+ int last_glyph_idx = num_glyphs - 1;
+ g.glyphs[last_glyph_idx] = 0xffff;
+ g.advances[last_glyph_idx] = QFixed();
+ g.offsets[last_glyph_idx].x = QFixed();
+ g.offsets[last_glyph_idx].y = QFixed();
+ g.attributes[last_glyph_idx].clusterStart = true;
+ g.attributes[last_glyph_idx].dontPrint = true;
+
+ log_clusters[item_length - 1] = glyphs_shaped + last_glyph_idx;
+ }
+#endif
+
if (Q_UNLIKELY(engineIdx != 0)) {
for (quint32 i = 0; i < num_glyphs; ++i)
g.glyphs[i] |= (engineIdx << 24);
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index d4c43b3069..da4e21728f 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -329,17 +329,17 @@ bool operator<(const QTextHtmlEntity &entity1, const QTextHtmlEntity &entity2)
}
#endif
-static bool operator<(const QString &entityStr, const QTextHtmlEntity &entity)
+static bool operator<(const QStringRef &entityStr, const QTextHtmlEntity &entity)
{
return entityStr < QLatin1String(entity.name);
}
-static bool operator<(const QTextHtmlEntity &entity, const QString &entityStr)
+static bool operator<(const QTextHtmlEntity &entity, const QStringRef &entityStr)
{
return QLatin1String(entity.name) < entityStr;
}
-static QChar resolveEntity(const QString &entity)
+static QChar resolveEntity(const QStringRef &entity)
{
const QTextHtmlEntity *start = &entities[0];
const QTextHtmlEntity *end = &entities[MAX_ENTITY];
@@ -706,8 +706,8 @@ void QTextHtmlParser::parseTag()
node = resolveParent();
resolveNode();
- const int nodeIndex = nodes.count() - 1; // this new node is always the last
#ifndef QT_NO_CSSPARSER
+ const int nodeIndex = nodes.count() - 1; // this new node is always the last
node->applyCssDeclarations(declarationsForNode(nodeIndex), resourceProvider);
#endif
applyAttributes(node->attributes);
@@ -801,8 +801,9 @@ void QTextHtmlParser::parseExclamationTag()
// parses an entity after "&", and returns it
QString QTextHtmlParser::parseEntity()
{
- int recover = pos;
- QString entity;
+ const int recover = pos;
+ int entityLen = 0;
+ QStringRef entity;
while (pos < len) {
QChar c = txt.at(pos++);
if (c.isSpace() || pos - recover > 9) {
@@ -810,36 +811,38 @@ QString QTextHtmlParser::parseEntity()
}
if (c == QLatin1Char(';'))
break;
- entity += c;
+ ++entityLen;
}
- {
+ if (entityLen) {
+ entity = QStringRef(&txt, recover, entityLen);
QChar resolved = resolveEntity(entity);
if (!resolved.isNull())
return QString(resolved);
- }
- if (entity.length() > 1 && entity.at(0) == QLatin1Char('#')) {
- entity.remove(0, 1); // removing leading #
- int base = 10;
- bool ok = false;
+ if (entityLen > 1 && entity.at(0) == QLatin1Char('#')) {
+ entity = entity.mid(1); // removing leading #
- if (entity.at(0).toLower() == QLatin1Char('x')) { // hex entity?
- entity.remove(0, 1);
- base = 16;
- }
+ int base = 10;
+ bool ok = false;
- uint uc = entity.toUInt(&ok, base);
- if (ok) {
- if (uc >= 0x80 && uc < 0x80 + (sizeof(windowsLatin1ExtendedCharacters)/sizeof(windowsLatin1ExtendedCharacters[0])))
- uc = windowsLatin1ExtendedCharacters[uc - 0x80];
- QString str;
- if (QChar::requiresSurrogates(uc)) {
- str += QChar(QChar::highSurrogate(uc));
- str += QChar(QChar::lowSurrogate(uc));
- } else {
- str = QChar(uc);
+ if (entity.at(0).toLower() == QLatin1Char('x')) { // hex entity?
+ entity = entity.mid(1);
+ base = 16;
+ }
+
+ uint uc = entity.toUInt(&ok, base);
+ if (ok) {
+ if (uc >= 0x80 && uc < 0x80 + (sizeof(windowsLatin1ExtendedCharacters)/sizeof(windowsLatin1ExtendedCharacters[0])))
+ uc = windowsLatin1ExtendedCharacters[uc - 0x80];
+ QString str;
+ if (QChar::requiresSurrogates(uc)) {
+ str += QChar(QChar::highSurrogate(uc));
+ str += QChar(QChar::lowSurrogate(uc));
+ } else {
+ str = QChar(uc);
+ }
+ return str;
}
- return str;
}
}
error:
@@ -1522,7 +1525,7 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
} else if (value == QLatin1String("I")) {
node->listStyle = QTextListFormat::ListUpperRoman;
} else {
- value = value.toLower();
+ value = std::move(value).toLower();
if (value == QLatin1String("square"))
node->listStyle = QTextListFormat::ListSquare;
else if (value == QLatin1String("disc"))
@@ -1633,7 +1636,7 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
node->parseStyleAttribute(value, resourceProvider);
#endif
} else if (key == QLatin1String("align")) {
- value = value.toLower();
+ value = std::move(value).toLower();
bool alignmentSet = true;
if (value == QLatin1String("left"))
@@ -1661,7 +1664,7 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
}
}
} else if (key == QLatin1String("valign")) {
- value = value.toLower();
+ value = std::move(value).toLower();
if (value == QLatin1String("top"))
node->charFormat.setVerticalAlignment(QTextCharFormat::AlignTop);
else if (value == QLatin1String("middle"))
@@ -1669,7 +1672,7 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
else if (value == QLatin1String("bottom"))
node->charFormat.setVerticalAlignment(QTextCharFormat::AlignBottom);
} else if (key == QLatin1String("dir")) {
- value = value.toLower();
+ value = std::move(value).toLower();
if (value == QLatin1String("ltr"))
node->blockFormat.setLayoutDirection(Qt::LeftToRight);
else if (value == QLatin1String("rtl"))
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 540bbf5d54..023a1b7f52 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -1653,6 +1653,7 @@ namespace {
int maxGlyphs;
int currentPosition;
glyph_t previousGlyph;
+ QFontEngine *previousGlyphFontEngine;
QFixed minw;
QFixed softHyphenWidth;
@@ -1686,13 +1687,14 @@ namespace {
if (currentPosition > 0 &&
logClusters[currentPosition - 1] < glyphs.numGlyphs) {
previousGlyph = currentGlyph(); // needed to calculate right bearing later
+ previousGlyphFontEngine = fontEngine;
}
}
- inline void calculateRightBearing(glyph_t glyph)
+ inline void calculateRightBearing(QFontEngine *engine, glyph_t glyph)
{
qreal rb;
- fontEngine->getGlyphBearings(glyph, 0, &rb);
+ engine->getGlyphBearings(glyph, 0, &rb);
// We only care about negative right bearings, so we limit the range
// of the bearing here so that we can assume it's negative in the rest
@@ -1705,13 +1707,13 @@ namespace {
{
if (currentPosition <= 0)
return;
- calculateRightBearing(currentGlyph());
+ calculateRightBearing(fontEngine, currentGlyph());
}
inline void calculateRightBearingForPreviousGlyph()
{
if (previousGlyph > 0)
- calculateRightBearing(previousGlyph);
+ calculateRightBearing(previousGlyphFontEngine, previousGlyph);
}
static const QFixed RightBearingNotCalculated;
diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp
index 085c073bb1..c9747877f7 100644
--- a/src/gui/util/qdesktopservices.cpp
+++ b/src/gui/util/qdesktopservices.cpp
@@ -198,8 +198,15 @@ bool QDesktopServices::openUrl(const QUrl &url)
return false;
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
- if (!platformIntegration)
+ if (Q_UNLIKELY(!platformIntegration)) {
+ QCoreApplication *application = QCoreApplication::instance();
+ if (Q_UNLIKELY(!application))
+ qWarning("QDesktopServices::openUrl: Please instantiate the QGuiApplication object "
+ "first");
+ else if (Q_UNLIKELY(!qobject_cast<QGuiApplication *>(application)))
+ qWarning("QDesktopServices::openUrl: Application is not a GUI application");
return false;
+ }
QPlatformServices *platformServices = platformIntegration->services();
if (!platformServices) {
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index 70ace3f55e..13d52ea44a 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -39,7 +39,9 @@ HEADERS += \
access/qhttpmultipart.h \
access/qhttpmultipart_p.h \
access/qnetworkfile_p.h \
- access/qhttp2protocolhandler_p.h
+ access/qhttp2protocolhandler_p.h \
+ access/qhsts_p.h \
+ access/qhstspolicy.h
SOURCES += \
access/qftp.cpp \
@@ -72,7 +74,9 @@ SOURCES += \
access/qhttpthreaddelegate.cpp \
access/qhttpmultipart.cpp \
access/qnetworkfile.cpp \
- access/qhttp2protocolhandler.cpp
+ access/qhttp2protocolhandler.cpp \
+ access/qhsts.cpp \
+ access/qhstspolicy.cpp
mac: LIBS_PRIVATE += -framework Security
diff --git a/src/network/access/qftp.cpp b/src/network/access/qftp.cpp
index 52b9dd9169..47579ba654 100644
--- a/src/network/access/qftp.cpp
+++ b/src/network/access/qftp.cpp
@@ -246,22 +246,25 @@ public:
} data;
bool is_ba;
- static QBasicAtomicInt idCounter;
};
-QBasicAtomicInt QFtpCommand::idCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
+static int nextId()
+{
+ static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
+ return 1 + counter.fetchAndAddRelaxed(1);
+}
QFtpCommand::QFtpCommand(QFtp::Command cmd, const QStringList &raw, const QByteArray &ba)
: command(cmd), rawCmds(raw), is_ba(true)
{
- id = idCounter.fetchAndAddRelaxed(1);
+ id = nextId();
data.ba = new QByteArray(ba);
}
QFtpCommand::QFtpCommand(QFtp::Command cmd, const QStringList &raw, QIODevice *dev)
: command(cmd), rawCmds(raw), is_ba(false)
{
- id = idCounter.fetchAndAddRelaxed(1);
+ id = nextId();
data.dev = dev;
}
@@ -571,7 +574,7 @@ static void _q_parseDosDir(const QStringList &tokens, const QString &userName, Q
QString name = tokens.at(3);
info->setName(name);
- info->setSymLink(name.toLower().endsWith(QLatin1String(".lnk")));
+ info->setSymLink(name.endsWith(QLatin1String(".lnk"), Qt::CaseInsensitive));
if (tokens.at(2) == QLatin1String("<DIR>")) {
info->setFile(false);
diff --git a/src/network/access/qhsts.cpp b/src/network/access/qhsts.cpp
new file mode 100644
index 0000000000..ca9f3b977b
--- /dev/null
+++ b/src/network/access/qhsts.cpp
@@ -0,0 +1,512 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhsts_p.h"
+
+#include "QtCore/private/qipaddress_p.h"
+#include "QtCore/qvector.h"
+#include "QtCore/qlist.h"
+
+QT_BEGIN_NAMESPACE
+
+static bool is_valid_domain_name(const QString &host)
+{
+ if (!host.size())
+ return false;
+
+ // RFC6797 8.1.1
+ // If the substring matching the host production from the Request-URI
+ // (of the message to which the host responded) syntactically matches
+ //the IP-literal or IPv4address productions from Section 3.2.2 of
+ //[RFC3986], then the UA MUST NOT note this host as a Known HSTS Host.
+ using namespace QIPAddressUtils;
+
+ IPv4Address ipv4Addr = {};
+ if (parseIp4(ipv4Addr, host.constBegin(), host.constEnd()))
+ return false;
+
+ IPv6Address ipv6Addr = {};
+ // Unlike parseIp4, parseIp6 returns nullptr if it managed to parse IPv6
+ // address successfully.
+ if (!parseIp6(ipv6Addr, host.constBegin(), host.constEnd()))
+ return false;
+
+ // TODO: for now we do not test IPvFuture address, it must be addressed
+ // by introducing parseIpFuture (actually, there is an implementation
+ // in QUrl that can be adopted/modified/moved to QIPAddressUtils).
+ return true;
+}
+
+void QHstsCache::updateFromHeaders(const QList<QPair<QByteArray, QByteArray>> &headers,
+ const QUrl &url)
+{
+ if (!url.isValid())
+ return;
+
+ QHstsHeaderParser parser;
+ if (parser.parse(headers))
+ updateKnownHost(url.host(), parser.expirationDate(), parser.includeSubDomains());
+}
+
+void QHstsCache::updateFromPolicies(const QVector<QHstsPolicy> &policies)
+{
+ for (const auto &policy : policies)
+ updateKnownHost(policy.host(), policy.expiry(), policy.includesSubDomains());
+}
+
+void QHstsCache::updateKnownHost(const QUrl &url, const QDateTime &expires,
+ bool includeSubDomains)
+{
+ if (!url.isValid())
+ return;
+
+ updateKnownHost(url.host(), expires, includeSubDomains);
+}
+
+void QHstsCache::updateKnownHost(const QString &host, const QDateTime &expires,
+ bool includeSubDomains)
+{
+ if (!is_valid_domain_name(host))
+ return;
+
+ // HSTS is a per-host policy, regardless of protocol, port or any of the other
+ // details in an URL; so we only want the host part. QUrl::host handles
+ // IDNA 2003 (RFC3490) for us, as required by HSTS (RFC6797, section 10).
+ const HostName hostName(host);
+ const auto pos = knownHosts.find(hostName);
+ QHstsPolicy::PolicyFlags flags;
+ if (includeSubDomains)
+ flags = QHstsPolicy::IncludeSubDomains;
+
+ const QHstsPolicy newPolicy(expires, flags, hostName.name);
+ if (pos == knownHosts.end()) {
+ // A new, previously unknown host.
+ if (newPolicy.isExpired()) {
+ // Nothing to do at all - we did not know this host previously,
+ // we do not have to - since its policy expired.
+ return;
+ }
+
+ knownHosts.insert(pos, hostName, newPolicy);
+ return;
+ }
+
+ if (newPolicy.isExpired())
+ knownHosts.erase(pos);
+ else
+ *pos = std::move(newPolicy);
+}
+
+bool QHstsCache::isKnownHost(const QUrl &url) const
+{
+ if (!url.isValid() || !is_valid_domain_name(url.host()))
+ return false;
+
+ /*
+ RFC6797, 8.2. Known HSTS Host Domain Name Matching
+
+ * Superdomain Match
+ If a label-for-label match between an entire Known HSTS Host's
+ domain name and a right-hand portion of the given domain name
+ is found, then this Known HSTS Host's domain name is a
+ superdomain match for the given domain name. There could be
+ multiple superdomain matches for a given domain name.
+ * Congruent Match
+ If a label-for-label match between a Known HSTS Host's domain
+ name and the given domain name is found -- i.e., there are no
+ further labels to compare -- then the given domain name
+ congruently matches this Known HSTS Host.
+
+ We start from the congruent match, and then chop labels and dots and
+ proceed with superdomain match. While RFC6797 recommends to start from
+ superdomain, the result is the same - some valid policy will make a host
+ known.
+ */
+
+ bool superDomainMatch = false;
+ const QString hostNameAsString(url.host());
+ HostName nameToTest(static_cast<QStringRef>(&hostNameAsString));
+ while (nameToTest.fragment.size()) {
+ auto const pos = knownHosts.find(nameToTest);
+ if (pos != knownHosts.end()) {
+ if (pos.value().isExpired())
+ knownHosts.erase(pos);
+ else if (!superDomainMatch || pos.value().includesSubDomains())
+ return true;
+ }
+
+ const int dot = nameToTest.fragment.indexOf(QLatin1Char('.'));
+ if (dot == -1)
+ break;
+
+ nameToTest.fragment = nameToTest.fragment.mid(dot + 1);
+ superDomainMatch = true;
+ }
+
+ return false;
+}
+
+void QHstsCache::clear()
+{
+ knownHosts.clear();
+}
+
+QVector<QHstsPolicy> QHstsCache::policies() const
+{
+ QVector<QHstsPolicy> values;
+ values.reserve(knownHosts.size());
+ for (const auto &host : knownHosts)
+ values << host;
+ return values;
+}
+
+// The parser is quite simple: 'nextToken' knowns exactly what kind of tokens
+// are valid and it will return false if something else was found; then
+// we immediately stop parsing. 'parseDirective' knows how these tokens can
+// be combined into a valid directive and if some weird combination of
+// valid tokens is found - we immediately stop.
+// And finally we call parseDirective again and again until some error found or
+// we have no more bytes in the header.
+
+// The following isXXX functions are based on RFC2616, 2.2 Basic Rules.
+
+static bool isCHAR(int c)
+{
+ // CHAR = <any US-ASCII character (octets 0 - 127)>
+ return c >= 0 && c <= 127;
+}
+
+static bool isCTL(int c)
+{
+ // CTL = <any US-ASCII control character
+ // (octets 0 - 31) and DEL (127)>
+ return (c >= 0 && c <= 31) || c == 127;
+}
+
+
+static bool isLWS(int c)
+{
+ // LWS = [CRLF] 1*( SP | HT )
+ //
+ // CRLF = CR LF
+ // CR = <US-ASCII CR, carriage return (13)>
+ // LF = <US-ASCII LF, linefeed (10)>
+ // SP = <US-ASCII SP, space (32)>
+ // HT = <US-ASCII HT, horizontal-tab (9)>
+ //
+ // CRLF is handled by the time we parse a header (they were replaced with
+ // spaces). We only have to deal with remaining SP|HT
+ return c == ' ' || c == '\t';
+}
+
+static bool isTEXT(char c)
+{
+ // TEXT = <any OCTET except CTLs,
+ // but including LWS>
+ return !isCTL(c) || isLWS(c);
+}
+
+static bool isSeparator(char c)
+{
+ // separators = "(" | ")" | "<" | ">" | "@"
+ // | "," | ";" | ":" | "\" | <">
+ // | "/" | "[" | "]" | "?" | "="
+ // | "{" | "}" | SP | HT
+ static const char separators[] = "()<>@,;:\\\"/[]?={}";
+ static const char *end = separators + sizeof separators - 1;
+ return isLWS(c) || std::find(separators, end, c) != end;
+}
+
+static QByteArray unescapeMaxAge(const QByteArray &value)
+{
+ if (value.size() < 2 || value[0] != '"')
+ return value;
+
+ Q_ASSERT(value[value.size() - 1] == '"');
+ return value.mid(1, value.size() - 2);
+}
+
+static bool isTOKEN(char c)
+{
+ // token = 1*<any CHAR except CTLs or separators>
+ return isCHAR(c) && !isCTL(c) && !isSeparator(c);
+}
+
+/*
+
+RFC6797, 6.1 Strict-Transport-Security HTTP Response Header Field.
+Syntax:
+
+Strict-Tranposrt-Security = "Strict-Transport-Security" ":"
+ [ directive ] *( ";" [ directive ] )
+
+directive = directive-name [ "=" directive-value ]
+directive-name = token
+directive-value = token | quoted-string
+
+RFC 2616, 2.2 Basic Rules.
+
+token = 1*<any CHAR except CTLs or separators>
+quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+
+
+qdtext = <any TEXT except <">>
+quoted-pair = "\" CHAR
+
+*/
+
+bool QHstsHeaderParser::parse(const QList<QPair<QByteArray, QByteArray>> &headers)
+{
+ for (const auto &h : headers) {
+ // We use '==' since header name was already 'trimmed' for us:
+ if (h.first == "Strict-Transport-Security") {
+ header = h.second;
+ // RFC6797, 8.1:
+ //
+ // The UA MUST ignore any STS header fields not conforming to the
+ // grammar specified in Section 6.1 ("Strict-Transport-Security HTTP
+ // Response Header Field").
+ //
+ // If a UA receives more than one STS header field in an HTTP
+ // response message over secure transport, then the UA MUST process
+ // only the first such header field.
+ //
+ // We read this as: ignore all invalid headers and take the first valid:
+ if (parseSTSHeader() && maxAgeFound) {
+ expiry = QDateTime::currentDateTimeUtc().addSecs(maxAge);
+ return true;
+ }
+ }
+ }
+
+ // In case it was set by a syntactically correct header (but without
+ // REQUIRED max-age directive):
+ subDomainsFound = false;
+
+ return false;
+}
+
+bool QHstsHeaderParser::parseSTSHeader()
+{
+ expiry = QDateTime();
+ maxAgeFound = false;
+ subDomainsFound = false;
+ maxAge = 0;
+ tokenPos = 0;
+ token.clear();
+
+ while (tokenPos < header.size()) {
+ if (!parseDirective())
+ return false;
+
+ if (token.size() && token != ";") {
+ // After a directive we can only have a ";" or no more tokens.
+ // Invalid syntax.
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool QHstsHeaderParser::parseDirective()
+{
+ // RFC 6797, 6.1:
+ //
+ // directive = directive-name [ "=" directive-value ]
+ // directive-name = token
+ // directive-value = token | quoted-string
+
+
+ // RFC 2616, 2.2:
+ //
+ // token = 1*<any CHAR except CTLs or separators>
+
+ if (!nextToken())
+ return false;
+
+ if (!token.size()) // No more data, but no error.
+ return true;
+
+ if (token == ";") // That's a weird grammar, but that's what it is.
+ return true;
+
+ if (!isTOKEN(token[0])) // Not a valid directive-name.
+ return false;
+
+ const QByteArray directiveName = token;
+ // 2. Try to read "=" or ";".
+ if (!nextToken())
+ return false;
+
+ QByteArray directiveValue;
+ if (token == ";") // No directive-value
+ return processDirective(directiveName, directiveValue);
+
+ if (token == "=") {
+ // We expect a directive-value now:
+ if (!nextToken() || !token.size())
+ return false;
+ directiveValue = token;
+ } else if (token.size()) {
+ // Invalid syntax:
+ return false;
+ }
+
+ if (!processDirective(directiveName, directiveValue))
+ return false;
+
+ // Read either ";", or 'end of header', or some invalid token.
+ return nextToken();
+}
+
+bool QHstsHeaderParser::processDirective(const QByteArray &name, const QByteArray &value)
+{
+ Q_ASSERT(name.size());
+ // RFC6797 6.1/3 Directive names are case-insensitive
+ const auto lcName = name.toLower();
+ if (lcName == "max-age") {
+ // RFC 6797, 6.1.1
+ // The syntax of the max-age directive's REQUIRED value (after
+ // quoted-string unescaping, if necessary) is defined as:
+ //
+ // max-age-value = delta-seconds
+ if (maxAgeFound) {
+ // RFC 6797, 6.1/2:
+ // All directives MUST appear only once in an STS header field.
+ return false;
+ }
+
+ const QByteArray unescapedValue = unescapeMaxAge(value);
+ if (!unescapedValue.size())
+ return false;
+
+ bool ok = false;
+ const qint64 age = unescapedValue.toLongLong(&ok);
+ if (!ok || age < 0)
+ return false;
+
+ maxAge = age;
+ maxAgeFound = true;
+ } else if (lcName == "includesubdomains") {
+ // RFC 6797, 6.1.2. The includeSubDomains Directive.
+ // The OPTIONAL "includeSubDomains" directive is a valueless directive.
+
+ if (subDomainsFound) {
+ // RFC 6797, 6.1/2:
+ // All directives MUST appear only once in an STS header field.
+ return false;
+ }
+
+ subDomainsFound = true;
+ } // else we do nothing, skip unknown directives (RFC 6797, 6.1/5)
+
+ return true;
+}
+
+bool QHstsHeaderParser::nextToken()
+{
+ // Returns true if we found a valid token or we have no more data (token is
+ // empty then).
+
+ token.clear();
+
+ // Fortunately enough, by this point qhttpnetworkreply already got rid of
+ // [CRLF] parts, but we can have 1*(SP|HT) yet.
+ while (tokenPos < header.size() && isLWS(header[tokenPos]))
+ ++tokenPos;
+
+ if (tokenPos == header.size())
+ return true;
+
+ const char ch = header[tokenPos];
+ if (ch == ';' || ch == '=') {
+ token.append(ch);
+ ++tokenPos;
+ return true;
+ }
+
+ // RFC 2616, 2.2.
+ //
+ // quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ // qdtext = <any TEXT except <">>
+ if (ch == '"') {
+ int last = tokenPos + 1;
+ while (last < header.size()) {
+ if (header[last] == '"') {
+ // The end of a quoted-string.
+ break;
+ } else if (header[last] == '\\') {
+ // quoted-pair = "\" CHAR
+ if (last + 1 < header.size() && isCHAR(header[last + 1]))
+ last += 2;
+ else
+ return false;
+ } else {
+ if (!isTEXT(header[last]))
+ return false;
+ ++last;
+ }
+ }
+
+ if (last >= header.size()) // no closing '"':
+ return false;
+
+ token = header.mid(tokenPos, last - tokenPos + 1);
+ tokenPos = last + 1;
+ return true;
+ }
+
+ // RFC 2616, 2.2:
+ //
+ // token = 1*<any CHAR except CTLs or separators>
+ if (!isTOKEN(ch))
+ return false;
+
+ int last = tokenPos + 1;
+ while (last < header.size() && isTOKEN(header[last]))
+ ++last;
+
+ token = header.mid(tokenPos, last - tokenPos);
+ tokenPos = last;
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhsts_p.h b/src/network/access/qhsts_p.h
new file mode 100644
index 0000000000..ab3ca536fb
--- /dev/null
+++ b/src/network/access/qhsts_p.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHSTS_P_H
+#define QHSTS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the Network Access API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/qhstspolicy.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qmap.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T> class QList;
+template <typename T> class QVector;
+
+class Q_AUTOTEST_EXPORT QHstsCache
+{
+public:
+
+ void updateFromHeaders(const QList<QPair<QByteArray, QByteArray>> &headers,
+ const QUrl &url);
+ void updateFromPolicies(const QVector<QHstsPolicy> &hosts);
+ void updateKnownHost(const QUrl &url, const QDateTime &expires,
+ bool includeSubDomains);
+ bool isKnownHost(const QUrl &url) const;
+ void clear();
+
+ QVector<QHstsPolicy> policies() const;
+
+private:
+
+ void updateKnownHost(const QString &hostName, const QDateTime &expires,
+ bool includeSubDomains);
+
+ struct HostName
+ {
+ explicit HostName(const QString &n) : name(n) { }
+ explicit HostName(const QStringRef &r) : fragment(r) { }
+
+ bool operator < (const HostName &rhs) const
+ {
+ if (fragment.size()) {
+ if (rhs.fragment.size())
+ return fragment < rhs.fragment;
+ return fragment < QStringRef(&rhs.name);
+ }
+
+ if (rhs.fragment.size())
+ return QStringRef(&name) < rhs.fragment;
+ return name < rhs.name;
+ }
+
+ // We use 'name' for a HostName object contained in our dictionary;
+ // we use 'fragment' only during lookup, when chopping the complete host
+ // name, removing subdomain names (such HostName object is 'transient', it
+ // must not outlive the original QString object.
+ QString name;
+ QStringRef fragment;
+ };
+
+ mutable QMap<HostName, QHstsPolicy> knownHosts;
+};
+
+class Q_AUTOTEST_EXPORT QHstsHeaderParser
+{
+public:
+
+ bool parse(const QList<QPair<QByteArray, QByteArray>> &headers);
+
+ QDateTime expirationDate() const { return expiry; }
+ bool includeSubDomains() const { return subDomainsFound; }
+
+private:
+
+ bool parseSTSHeader();
+ bool parseDirective();
+ bool processDirective(const QByteArray &name, const QByteArray &value);
+ bool nextToken();
+
+ QByteArray header;
+ QByteArray token;
+
+ QDateTime expiry;
+ int tokenPos = 0;
+ bool maxAgeFound = false;
+ qint64 maxAge = 0;
+ bool subDomainsFound = false;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/access/qhstspolicy.cpp b/src/network/access/qhstspolicy.cpp
new file mode 100644
index 0000000000..0ea9f3f046
--- /dev/null
+++ b/src/network/access/qhstspolicy.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhstspolicy.h"
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QHstsPolicy
+ \brief The QHstsPolicy class specifies that a host supports HTTP Strict Transport
+ Security policy (HSTS).
+ \since 5.9
+ \ingroup network
+ \inmodule QtNetwork
+
+ HSTS policy defines a period of time during which QNetworkAccessManager
+ should only access a host in a secure fashion. HSTS policy is defined by
+ RFC6797.
+
+ You can set expiry time and host name for this policy, and control whether it
+ applies to subdomains, either in the constructor or by calling setExpiry(),
+ setHost() and setIncludesSubdomains().
+
+ \sa QNetworkAccessManager::setStrictTransportSecurityEnabled()
+*/
+
+/*
+ \enum QHstsPolicy::PolicyFlag
+
+ Specifies attributes that a policy can have.
+
+ \value IncludeSubDomains HSTS policy also applies to subdomains.
+*/
+
+class QHstsPolicyPrivate : public QSharedData
+{
+public:
+ QUrl url;
+ QDateTime expiry;
+ bool includeSubDomains = false;
+
+ bool operator == (const QHstsPolicyPrivate &other) const
+ {
+ return url.host() == other.url.host() && expiry == other.expiry
+ && includeSubDomains == other.includeSubDomains;
+ }
+};
+
+/*!
+ Returns \c true if the two policies have the same host and expiration date
+ while agreeing on whether to include or exclude subdomains.
+*/
+bool operator==(const QHstsPolicy &lhs, const QHstsPolicy &rhs)
+{
+ return *lhs.d == *rhs.d;
+}
+
+/*!
+ Constructs an invalid (expired) policy with empty host name and subdomains
+ not included.
+*/
+QHstsPolicy::QHstsPolicy() : d(new QHstsPolicyPrivate)
+{
+}
+
+/*!
+ Constructs QHstsPolicy with \a expiry (in UTC); \a includeSubDomains parameter
+ defines if this policy must also include subdomains, \a host data is interpreted
+ according to \a mode.
+
+ \sa QUrl::setHost(), QUrl::ParsingMode
+*/
+QHstsPolicy::QHstsPolicy(const QDateTime &expiry, PolicyFlags flags,
+ const QString &host, QUrl::ParsingMode mode)
+ : d(new QHstsPolicyPrivate)
+{
+ d->url.setHost(host, mode);
+ d->expiry = expiry;
+ d->includeSubDomains = flags.testFlag(IncludeSubDomains);
+}
+
+/*!
+ Creates a copy of \a other object.
+*/
+QHstsPolicy::QHstsPolicy(const QHstsPolicy &other)
+ : d(new QHstsPolicyPrivate(*other.d))
+{
+}
+
+/*!
+ Destructor.
+*/
+QHstsPolicy::~QHstsPolicy()
+{
+}
+
+/*!
+ Copy-assignment operator, makes a copy of \a other.
+*/
+QHstsPolicy &QHstsPolicy::operator=(const QHstsPolicy &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Sets a host, \a host data is interpreted according to \a mode parameter.
+
+ \sa host(), QUrl::setHost(), QUrl::ParsingMode
+*/
+void QHstsPolicy::setHost(const QString &host, QUrl::ParsingMode mode)
+{
+ d->url.setHost(host, mode);
+}
+
+/*!
+ Returns a host for a given policy, formatted according to \a options.
+
+ \sa setHost(), QUrl::host(), QUrl::ComponentFormattingOptions
+*/
+QString QHstsPolicy::host(QUrl::ComponentFormattingOptions options) const
+{
+ return d->url.host(options);
+}
+
+/*!
+ Sets the expiration date for the policy (in UTC) to \a expiry.
+
+ \sa expiry()
+*/
+void QHstsPolicy::setExpiry(const QDateTime &expiry)
+{
+ d->expiry = expiry;
+}
+
+/*!
+ Returns the expiration date for the policy (in UTC).
+
+ \sa setExpiry()
+*/
+QDateTime QHstsPolicy::expiry() const
+{
+ return d->expiry;
+}
+
+/*!
+ Sets whether subdomains are included for this policy to \a include.
+
+ \sa includesSubDomains()
+*/
+void QHstsPolicy::setIncludesSubDomains(bool include)
+{
+ d->includeSubDomains = include;
+}
+
+/*!
+ Returns \c true if this policy also includes subdomains.
+
+ \sa setIncludesSubDomains()
+ */
+bool QHstsPolicy::includesSubDomains() const
+{
+ return d->includeSubDomains;
+}
+
+/*!
+ Return \c true if this policy has a valid expiration date and this date
+ is greater than QDateTime::currentGetDateTimeUtc().
+
+ \sa setExpiry(), expiry()
+*/
+bool QHstsPolicy::isExpired() const
+{
+ return !d->expiry.isValid() || d->expiry <= QDateTime::currentDateTimeUtc();
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhstspolicy.h b/src/network/access/qhstspolicy.h
new file mode 100644
index 0000000000..176a8fa635
--- /dev/null
+++ b/src/network/access/qhstspolicy.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHSTSPOLICY_H
+#define QHSTSPOLICY_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qflags.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHstsPolicyPrivate;
+class QDateTime;
+class QString;
+class Q_NETWORK_EXPORT QHstsPolicy
+{
+public:
+ enum PolicyFlag
+ {
+ IncludeSubDomains = 1
+ };
+ Q_DECLARE_FLAGS(PolicyFlags, PolicyFlag)
+
+ QHstsPolicy();
+ QHstsPolicy(const QDateTime &expiry, PolicyFlags flags, const QString &host,
+ QUrl::ParsingMode mode = QUrl::DecodedMode);
+ QHstsPolicy(const QHstsPolicy &rhs);
+ QHstsPolicy &operator=(const QHstsPolicy &rhs);
+ QHstsPolicy &operator=(QHstsPolicy &&other) Q_DECL_NOTHROW { swap(other); return *this; }
+ ~QHstsPolicy();
+
+ void swap(QHstsPolicy &other) Q_DECL_NOTHROW { qSwap(d, other.d); }
+
+ void setHost(const QString &host, QUrl::ParsingMode mode = QUrl::DecodedMode);
+ QString host(QUrl::ComponentFormattingOptions options = QUrl::FullyDecoded) const;
+ void setExpiry(const QDateTime &expiry);
+ QDateTime expiry() const;
+ void setIncludesSubDomains(bool include);
+ bool includesSubDomains() const;
+
+ bool isExpired() const;
+
+private:
+
+ QSharedDataPointer<QHstsPolicyPrivate> d;
+
+ friend Q_NETWORK_EXPORT bool operator==(const QHstsPolicy &lhs, const QHstsPolicy &rhs);
+};
+
+Q_DECLARE_SHARED(QHstsPolicy)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QHstsPolicy::PolicyFlags)
+
+Q_NETWORK_EXPORT bool operator==(const QHstsPolicy &lhs, const QHstsPolicy &rhs);
+
+inline bool operator!=(const QHstsPolicy &lhs, const QHstsPolicy &rhs)
+{
+ return !(lhs == rhs);
+}
+
+
+QT_END_NAMESPACE
+
+#endif // QHSTSPOLICY_H
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index 3fa0c18dc0..555f1ba0ef 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -53,6 +53,10 @@
#include <QtCore/qlist.h>
#include <QtCore/qurl.h>
+#ifndef QT_NO_NETWORKPROXY
+#include <QtNetwork/qnetworkproxy.h>
+#endif
+
#include <algorithm>
#include <vector>
@@ -61,7 +65,8 @@ QT_BEGIN_NAMESPACE
namespace
{
-HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxHeaderListSize)
+HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxHeaderListSize,
+ bool useProxy)
{
using namespace HPack;
@@ -73,7 +78,7 @@ HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxH
const auto auth = request.url().authority(QUrl::FullyEncoded | QUrl::RemoveUserInfo).toLatin1();
header.push_back(HeaderField(":authority", auth));
header.push_back(HeaderField(":method", request.methodName()));
- header.push_back(HeaderField(":path", request.uri(false)));
+ header.push_back(HeaderField(":path", request.uri(useProxy)));
header.push_back(HeaderField(":scheme", request.url().scheme().toLatin1()));
HeaderSize size = header_size(header);
@@ -208,7 +213,7 @@ void QHttp2ProtocolHandler::_q_receiveReply()
Q_ASSERT(m_socket);
Q_ASSERT(m_channel);
- do {
+ while (!goingAway || activeStreams.size()) {
const auto result = frameReader.read(*m_socket);
switch (result) {
case FrameStatus::incompleteFrame:
@@ -264,13 +269,19 @@ void QHttp2ProtocolHandler::_q_receiveReply()
// 5.1 - ignore unknown frames.
break;
}
- } while (!goingAway || activeStreams.size());
+ }
}
bool QHttp2ProtocolHandler::sendRequest()
{
- if (goingAway)
+ if (goingAway) {
+ // Stop further calls to this method: we have received GOAWAY
+ // so we cannot create new streams.
+ m_channel->emitFinishedWithError(QNetworkReply::ProtocolUnknownError,
+ "GOAWAY received, cannot start a request");
+ m_channel->spdyRequestsToSend.clear();
return false;
+ }
if (!prefaceSent && !sendClientPreface())
return false;
@@ -397,7 +408,11 @@ bool QHttp2ProtocolHandler::sendHEADERS(Stream &stream)
frameWriter.append(quint32()); // No stream dependency in Qt.
frameWriter.append(stream.weight());
- const auto headers = build_headers(stream.request(), maxHeaderListSize);
+ bool useProxy = false;
+#ifndef QT_NO_NETWORKPROXY
+ useProxy = m_connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy;
+#endif
+ const auto headers = build_headers(stream.request(), maxHeaderListSize, useProxy);
if (!headers.size()) // nothing fits into maxHeaderListSize
return false;
@@ -756,14 +771,10 @@ void QHttp2ProtocolHandler::handleGOAWAY()
// "The last stream identifier can be set to 0 if no
// streams were processed."
lastStreamID = 1;
- }
-
- if (!(lastStreamID & 0x1)) {
+ } else if (!(lastStreamID & 0x1)) {
// 5.1.1 - we (client) use only odd numbers as stream identifiers.
return connectionError(PROTOCOL_ERROR, "GOAWAY with invalid last stream ID");
- }
-
- if (lastStreamID >= nextID) {
+ } else if (lastStreamID >= nextID) {
// "A server that is attempting to gracefully shut down a connection SHOULD
// send an initial GOAWAY frame with the last stream identifier set to 2^31-1
// and a NO_ERROR code."
@@ -776,6 +787,13 @@ void QHttp2ProtocolHandler::handleGOAWAY()
goingAway = true;
+ // For the requests (and streams) we did not start yet, we have to report an
+ // error.
+ m_channel->emitFinishedWithError(QNetworkReply::ProtocolUnknownError,
+ "GOAWAY received, cannot start a request");
+ // Also, prevent further calls to sendRequest:
+ m_channel->spdyRequestsToSend.clear();
+
QNetworkReply::NetworkError error = QNetworkReply::NoError;
QString message;
qt_error(errorCode, error, message);
@@ -970,7 +988,7 @@ bool QHttp2ProtocolHandler::acceptSetting(Http2::Settings identifier, quint32 ne
}
if (identifier == Settings::MAX_CONCURRENT_STREAMS_ID) {
- if (maxConcurrentStreams > maxPeerConcurrentStreams) {
+ if (newValue > maxPeerConcurrentStreams) {
connectionError(PROTOCOL_ERROR, "SETTINGS invalid number of concurrent streams");
return false;
}
@@ -1369,6 +1387,8 @@ void QHttp2ProtocolHandler::initReplyFromPushPromise(const HttpMessagePair &mess
{
Q_ASSERT(promisedData.contains(cacheKey));
auto promise = promisedData.take(cacheKey);
+ Q_ASSERT(message.second);
+ message.second->setSpdyWasUsed(true);
qCDebug(QT_HTTP2) << "found cached/promised response on stream" << promise.reservedID;
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 1f14049a44..da055de2da 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -327,7 +327,7 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
acceptLanguage = systemLocale + QLatin1String(",*");
else
acceptLanguage = systemLocale + QLatin1String(",en,*");
- request.setHeaderField("Accept-Language", acceptLanguage.toLatin1());
+ request.setHeaderField("Accept-Language", std::move(acceptLanguage).toLatin1());
}
// set the User Agent
@@ -526,17 +526,17 @@ QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socke
if (!reply->request().isFollowRedirects())
return QUrl();
- QUrl rUrl;
+ QUrl redirectUrl;
const QList<QPair<QByteArray, QByteArray> > fields = reply->header();
for (const QNetworkReply::RawHeaderPair &header : fields) {
if (header.first.toLower() == "location") {
- rUrl = QUrl::fromEncoded(header.second);
+ redirectUrl = QUrl::fromEncoded(header.second);
break;
}
}
// If the location url is invalid/empty, we emit ProtocolUnknownError
- if (!rUrl.isValid()) {
+ if (!redirectUrl.isValid()) {
emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
return QUrl();
}
@@ -548,24 +548,38 @@ QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socke
}
// Resolve the URL if it's relative
- if (rUrl.isRelative())
- rUrl = reply->request().url().resolved(rUrl);
+ if (redirectUrl.isRelative())
+ redirectUrl = reply->request().url().resolved(redirectUrl);
// Check redirect url protocol
- QString scheme = rUrl.scheme();
- if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) {
- QString previousUrlScheme = reply->request().url().scheme();
- // Check if we're doing an unsecure redirect (https -> http)
- if (previousUrlScheme == QLatin1String("https")
- && scheme == QLatin1String("http")) {
- emitReplyError(socket, reply, QNetworkReply::InsecureRedirectError);
- return QUrl();
+ const QUrl priorUrl(reply->request().url());
+ if (redirectUrl.scheme() == QLatin1String("http") || redirectUrl.scheme() == QLatin1String("https")) {
+ switch (reply->request().redirectPolicy()) {
+ case QNetworkRequest::NoLessSafeRedirectPolicy:
+ // Here we could handle https->http redirects as InsecureProtocolError.
+ // However, if HSTS is enabled and redirectUrl.host() is a known STS
+ // host, then we'll replace its scheme and this won't downgrade protocol,
+ // after all. We cannot access QNAM's STS cache from here, so delegate
+ // this check to QNetworkReplyHttpImpl.
+ break;
+ case QNetworkRequest::SameOriginRedirectPolicy:
+ if (priorUrl.host() != redirectUrl.host()
+ || priorUrl.scheme() != redirectUrl.scheme()
+ || priorUrl.port() != redirectUrl.port()) {
+ emitReplyError(socket, reply, QNetworkReply::InsecureRedirectError);
+ return QUrl();
+ }
+ break;
+ case QNetworkRequest::UserVerifiedRedirectPolicy:
+ break;
+ default:
+ Q_ASSERT(!"Unexpected redirect policy");
}
} else {
emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
return QUrl();
}
- return rUrl;
+ return redirectUrl;
}
void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request)
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index a11fc7e807..c86cc9d8c9 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -180,9 +180,7 @@ void QHttpNetworkConnectionChannel::init()
sslSocket->setSslConfiguration(sslConfiguration);
} else {
#endif // !QT_NO_SSL
- if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2)
- protocolHandler.reset(new QHttp2ProtocolHandler(this));
- else
+ if (connection->connectionType() != QHttpNetworkConnection::ConnectionTypeHTTP2)
protocolHandler.reset(new QHttpProtocolHandler(this));
#ifndef QT_NO_SSL
}
@@ -839,6 +837,9 @@ void QHttpNetworkConnectionChannel::_q_connected()
} else {
state = QHttpNetworkConnectionChannel::IdleState;
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) {
+ // We have to reset QHttp2ProtocolHandler's state machine, it's a new
+ // connection and the handler's state is unique per connection.
+ protocolHandler.reset(new QHttp2ProtocolHandler(this));
if (spdyRequestsToSend.count() > 0) {
// wait for data from the server first (e.g. initial window, max concurrent requests)
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
@@ -1116,6 +1117,10 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
emitFinishedWithError(QNetworkReply::SslHandshakeFailedError,
"detected unknown Next Protocol Negotiation protocol");
}
+ } else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) {
+ // We have to reset QHttp2ProtocolHandler's state machine, it's a new
+ // connection and the handler's state is unique per connection.
+ protocolHandler.reset(new QHttp2ProtocolHandler(this));
}
if (!socket)
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 24ada3a81f..612abb9044 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -299,6 +299,11 @@ void QHttpNetworkReply::setSpdyWasUsed(bool spdy)
d_func()->spdyUsed = spdy;
}
+qint64 QHttpNetworkReply::removedContentLength() const
+{
+ return d_func()->removedContentLength;
+}
+
bool QHttpNetworkReply::isRedirecting() const
{
return d_func()->isRedirecting();
@@ -326,6 +331,7 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl)
currentlyReceivedDataInWindow(0),
currentlyUploadedDataInWindow(0),
totallyUploadedData(0),
+ removedContentLength(-1),
connection(0),
autoDecompress(false), responseData(), requestIsPrepared(false)
,pipeliningUsed(false), spdyUsed(false), downstreamLimited(false)
@@ -398,12 +404,12 @@ void QHttpNetworkReplyPrivate::removeAutoDecompressHeader()
end = fields.end();
while (it != end) {
if (qstricmp(name.constData(), it->first.constData()) == 0) {
+ removedContentLength = strtoull(it->second.constData(), nullptr, 0);
fields.erase(it);
break;
}
++it;
}
-
}
bool QHttpNetworkReplyPrivate::findChallenge(bool forProxy, QByteArray &challenge) const
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index f3b007f594..faab03f056 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -139,6 +139,7 @@ public:
bool isPipeliningUsed() const;
bool isSpdyUsed() const;
void setSpdyWasUsed(bool spdy);
+ qint64 removedContentLength() const;
bool isRedirecting() const;
@@ -255,6 +256,7 @@ public:
qint32 currentlyReceivedDataInWindow; // only for SPDY
qint32 currentlyUploadedDataInWindow; // only for SPDY
qint64 totallyUploadedData; // only for SPDY
+ qint64 removedContentLength;
QPointer<QHttpNetworkConnection> connection;
QPointer<QHttpNetworkConnectionChannel> connectionChannel;
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index 802043d847..60b566299f 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -48,7 +48,8 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Oper
QHttpNetworkRequest::Priority pri, const QUrl &newUrl)
: QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0),
autoDecompress(false), pipeliningAllowed(false), spdyAllowed(false), http2Allowed(false),
- withCredentials(true), preConnect(false), followRedirect(false), redirectCount(0)
+ withCredentials(true), preConnect(false), redirectCount(0),
+ redirectPolicy(QNetworkRequest::ManualRedirectPolicy)
{
}
@@ -65,8 +66,8 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest
withCredentials(other.withCredentials),
ssl(other.ssl),
preConnect(other.preConnect),
- followRedirect(other.followRedirect),
- redirectCount(other.redirectCount)
+ redirectCount(other.redirectCount),
+ redirectPolicy(other.redirectPolicy)
{
}
@@ -88,7 +89,8 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot
&& (operation != QHttpNetworkRequest::Custom || (customVerb == other.customVerb))
&& (withCredentials == other.withCredentials)
&& (ssl == other.ssl)
- && (preConnect == other.preConnect);
+ && (preConnect == other.preConnect)
+ && (redirectPolicy == other.redirectPolicy);
}
QByteArray QHttpNetworkRequest::methodName() const
@@ -229,12 +231,17 @@ void QHttpNetworkRequest::setPreConnect(bool preConnect)
bool QHttpNetworkRequest::isFollowRedirects() const
{
- return d->followRedirect;
+ return d->redirectPolicy != QNetworkRequest::ManualRedirectPolicy;
}
-void QHttpNetworkRequest::setFollowRedirects(bool followRedirect)
+void QHttpNetworkRequest::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)
{
- d->followRedirect = followRedirect;
+ d->redirectPolicy = policy;
+}
+
+QNetworkRequest::RedirectPolicy QHttpNetworkRequest::redirectPolicy() const
+{
+ return d->redirectPolicy;
}
int QHttpNetworkRequest::redirectCount() const
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index d1abb76e28..ecf8856ded 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -55,6 +55,7 @@
#ifndef QT_NO_HTTP
#include <private/qhttpnetworkheader_p.h>
+#include <QtNetwork/qnetworkrequest.h>
#include <qmetatype.h>
QT_BEGIN_NAMESPACE
@@ -130,7 +131,8 @@ public:
void setPreConnect(bool preConnect);
bool isFollowRedirects() const;
- void setFollowRedirects(bool followRedirect);
+ void setRedirectPolicy(QNetworkRequest::RedirectPolicy policy);
+ QNetworkRequest::RedirectPolicy redirectPolicy() const;
int redirectCount() const;
void setRedirectCount(int count);
@@ -173,8 +175,8 @@ public:
bool withCredentials;
bool ssl;
bool preConnect;
- bool followRedirect;
int redirectCount;
+ QNetworkRequest::RedirectPolicy redirectPolicy;
};
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index 1dca7f02fb..9d874b4d94 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -67,7 +67,7 @@ static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const
break;
case 403: // Access denied
- code = QNetworkReply::ContentOperationNotPermittedError;
+ code = QNetworkReply::ContentAccessDenied;
break;
case 404: // Not Found
@@ -169,7 +169,7 @@ static QByteArray makeCacheKey(QUrl &url, QNetworkProxy *proxy)
Q_UNUSED(proxy)
#endif
- return "http-connection:" + result.toLatin1();
+ return "http-connection:" + std::move(result).toLatin1();
}
class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection,
@@ -234,6 +234,7 @@ QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) :
, isPipeliningUsed(false)
, isSpdyUsed(false)
, incomingContentLength(-1)
+ , removedContentLength(-1)
, incomingErrorCode(QNetworkReply::NoError)
, downloadBuffer()
, httpConnection(0)
@@ -623,6 +624,7 @@ void QHttpThreadDelegate::headerChangedSlot()
incomingReasonPhrase = httpReply->reasonPhrase();
isPipeliningUsed = httpReply->isPipeliningUsed();
incomingContentLength = httpReply->contentLength();
+ removedContentLength = httpReply->removedContentLength();
isSpdyUsed = httpReply->isSpdyUsed();
emit downloadMetaData(incomingHeaders,
@@ -631,6 +633,7 @@ void QHttpThreadDelegate::headerChangedSlot()
isPipeliningUsed,
downloadBuffer,
incomingContentLength,
+ removedContentLength,
isSpdyUsed);
}
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
index 64c58cf648..6d1ea11f29 100644
--- a/src/network/access/qhttpthreaddelegate_p.h
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -112,6 +112,7 @@ public:
bool isPipeliningUsed;
bool isSpdyUsed;
qint64 incomingContentLength;
+ qint64 removedContentLength;
QNetworkReply::NetworkError incomingErrorCode;
QString incomingErrorDetail;
#ifndef QT_NO_BEARERMANAGEMENT
@@ -141,7 +142,7 @@ signals:
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *);
#endif
void downloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &, bool,
- QSharedPointer<char>, qint64, bool);
+ QSharedPointer<char>, qint64, qint64, bool);
void downloadProgress(qint64, qint64);
void downloadData(const QByteArray &);
void error(QNetworkReply::NetworkError, const QString &);
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index 7f39c942a3..4b5422ce29 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -63,7 +63,6 @@ class QNetworkProxyQuery;
class QNetworkRequest;
class QStringList;
class QUrl;
-class QUrlInfo;
class QSslConfiguration;
class QNetworkAccessManagerPrivate;
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 6d5b2400f1..d898f93403 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -45,6 +45,8 @@
#include "qnetworkcookie.h"
#include "qnetworkcookiejar.h"
#include "qabstractnetworkcache.h"
+#include "qhstspolicy.h"
+#include "qhsts_p.h"
#include "QtNetwork/qnetworksession.h"
#include "QtNetwork/private/qsharednetworksession_p.h"
@@ -693,6 +695,80 @@ void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
}
/*!
+ \since 5.9
+
+ If \a enabled is \c true, QNetworkAccessManager follows the HTTP Strict Transport
+ Security policy (HSTS, RFC6797). When processing a request, QNetworkAccessManager
+ automatically replaces the "http" scheme with "https" and uses a secure transport
+ for HSTS hosts. If it's set explicitly, port 80 is replaced by port 443.
+
+ When HSTS is enabled, for each HTTP response containing HSTS header and
+ received over a secure transport, QNetworkAccessManager will update its HSTS
+ cache, either remembering a host with a valid policy or removing a host with
+ an expired or disabled HSTS policy.
+
+ \sa isStrictTransportSecurityEnabled()
+*/
+void QNetworkAccessManager::setStrictTransportSecurityEnabled(bool enabled)
+{
+ Q_D(QNetworkAccessManager);
+ d->stsEnabled = enabled;
+}
+
+/*!
+ \since 5.9
+
+ Returns true if HTTP Strict Transport Security (HSTS) was enabled. By default
+ HSTS is disabled.
+
+ \sa setStrictTransportSecurityEnabled()
+*/
+bool QNetworkAccessManager::isStrictTransportSecurityEnabled() const
+{
+ Q_D(const QNetworkAccessManager);
+ return d->stsEnabled;
+}
+
+/*!
+ \since 5.9
+
+ Adds HTTP Strict Transport Security policies into HSTS cache.
+
+ \note An expired policy will remove a known host from the cache, if previously
+ present.
+
+ \note While processing HTTP responses, QNetworkAccessManager can also update
+ the HSTS cache, removing or updating exitsting policies or introducing new
+ known hosts. The current implementation thus is server-driven, client code
+ can provide QNetworkAccessManager with previously known or discovered
+ policies, but this information can be overridden by "Strict-Transport-Security"
+ response headers.
+
+ \sa addStrictTransportSecurityHosts(), QHstsPolicy
+*/
+
+void QNetworkAccessManager::addStrictTransportSecurityHosts(const QVector<QHstsPolicy> &knownHosts)
+{
+ Q_D(QNetworkAccessManager);
+ d->stsCache.updateFromPolicies(knownHosts);
+}
+
+/*!
+ \since 5.9
+
+ Returns the list of HTTP Strict Transport Security policies. This list can
+ differ from what was initially set via addStrictTransportSecurityHosts() if
+ HSTS cache was updated from a "Strict-Transport-Security" response header.
+
+ \sa addStrictTransportSecurityHosts(), QHstsPolicy
+*/
+QVector<QHstsPolicy> QNetworkAccessManager::strictTransportSecurityHosts() const
+{
+ Q_D(const QNetworkAccessManager);
+ return d->stsCache.policies();
+}
+
+/*!
Posts a request to obtain the network headers for \a request
and returns a new QNetworkReply object which will contain such headers.
@@ -969,7 +1045,7 @@ QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccess
{
Q_D(const QNetworkAccessManager);
- if (d->networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined))
+ if (d->customNetworkConfiguration && d->networkConfiguration.state().testFlag(QNetworkConfiguration::Undefined))
return UnknownAccessibility;
if (d->networkSessionRequired) {
@@ -1079,6 +1155,45 @@ void QNetworkAccessManager::connectToHost(const QString &hostName, quint16 port)
}
/*!
+ \since 5.9
+
+ Sets the manager's redirect policy to be the \a policy specified. This policy
+ will affect all subsequent requests created by the manager.
+
+ Use this function to enable or disable HTTP redirects on the manager's level.
+
+ \note When creating a request QNetworkRequest::RedirectAttributePolicy has
+ the highest priority, next by priority is QNetworkRequest::FollowRedirectsAttribute.
+ Finally, the manager's policy has the lowest priority.
+
+ For backwards compatibility the default value is QNetworkRequest::ManualRedirectPolicy.
+ This may change in the future and some type of auto-redirect policy will become
+ the default; clients relying on manual redirect handling are encouraged to set
+ this policy explicitly in their code.
+
+ \sa redirectPolicy(), QNetworkRequest::RedirectPolicy,
+ QNetworkRequest::FollowRedirectsAttribute
+*/
+void QNetworkAccessManager::setRedirectPolicy(QNetworkRequest::RedirectPolicy policy)
+{
+ Q_D(QNetworkAccessManager);
+ d->redirectPolicy = policy;
+}
+
+/*!
+ \since 5.9
+
+ Returns the redirect policy that is used when creating new requests.
+
+ \sa setRedirectPolicy(), QNetworkRequest::RedirectPolicy
+*/
+QNetworkRequest::RedirectPolicy QNetworkAccessManager::redirectPolicy() const
+{
+ Q_D(const QNetworkAccessManager);
+ return d->redirectPolicy;
+}
+
+/*!
\since 4.7
Sends a custom request to the server identified by the URL of \a request.
@@ -1147,9 +1262,9 @@ QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &r
/*!
Returns a new QNetworkReply object to handle the operation \a op
- and request \a req. The device \a outgoingData is always 0 for Get and
- Head requests, but is the value passed to post() and put() in
- those operations (the QByteArray variants will pass a QBuffer
+ and request \a originalReq. The device \a outgoingData is always 0
+ for Get and Head requests, but is the value passed to post() and
+ put() in those operations (the QByteArray variants will pass a QBuffer
object).
The default implementation calls QNetworkCookieJar::cookiesForUrl()
@@ -1159,11 +1274,18 @@ QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &r
The returned object must be in an open state.
*/
QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
- const QNetworkRequest &req,
+ const QNetworkRequest &originalReq,
QIODevice *outgoingData)
{
Q_D(QNetworkAccessManager);
+ QNetworkRequest req(originalReq);
+ if (redirectPolicy() != QNetworkRequest::ManualRedirectPolicy
+ && req.attribute(QNetworkRequest::RedirectPolicyAttribute).isNull()
+ && req.attribute(QNetworkRequest::FollowRedirectsAttribute).isNull()) {
+ req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, redirectPolicy());
+ }
+
bool isLocalFile = req.url().isLocalFile();
QString scheme = req.url().scheme();
@@ -1251,6 +1373,24 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
|| scheme == QLatin1String("https") || scheme == QLatin1String("preconnect-https")
#endif
) {
+#ifndef QT_NO_SSL
+ if (isStrictTransportSecurityEnabled() && d->stsCache.isKnownHost(request.url())) {
+ QUrl stsUrl(request.url());
+ // RFC6797, 8.3:
+ // The UA MUST replace the URI scheme with "https" [RFC2818],
+ // and if the URI contains an explicit port component of "80",
+ // then the UA MUST convert the port component to be "443", or
+ // if the URI contains an explicit port component that is not
+ // equal to "80", the port component value MUST be preserved;
+ // otherwise,
+ // if the URI does not contain an explicit port component, the UA
+ // MUST NOT add one.
+ if (stsUrl.port() == 80)
+ stsUrl.setPort(443);
+ stsUrl.setScheme(QLatin1String("https"));
+ request.setUrl(stsUrl);
+ }
+#endif
QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData);
#ifndef QT_NO_BEARERMANAGEMENT
connect(this, SIGNAL(networkSessionConnected()),
@@ -1352,10 +1492,26 @@ QStringList QNetworkAccessManager::supportedSchemesImplementation() const
This function is useful for doing auto tests.
+ \sa clearConnectionCache()
*/
void QNetworkAccessManager::clearAccessCache()
{
- QNetworkAccessManagerPrivate::clearCache(this);
+ QNetworkAccessManagerPrivate::clearAuthenticationCache(this);
+ QNetworkAccessManagerPrivate::clearConnectionCache(this);
+}
+
+/*!
+ \since 5.9
+
+ Flushes the internal cache of network connections.
+ In contrast to clearAccessCache() the authentication data
+ is preserved.
+
+ \sa clearAccessCache()
+*/
+void QNetworkAccessManager::clearConnectionCache()
+{
+ QNetworkAccessManagerPrivate::clearConnectionCache(this);
}
void QNetworkAccessManagerPrivate::_q_replyFinished()
@@ -1552,11 +1708,14 @@ QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProx
}
#endif
-void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager)
+void QNetworkAccessManagerPrivate::clearAuthenticationCache(QNetworkAccessManager *manager)
{
- manager->d_func()->objectCache.clear();
manager->d_func()->authenticationManager->clearCache();
+}
+void QNetworkAccessManagerPrivate::clearConnectionCache(QNetworkAccessManager *manager)
+{
+ manager->d_func()->objectCache.clear();
manager->d_func()->destroyThread();
}
@@ -1682,6 +1841,7 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession
} else if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
reallyOnline = true;
}
+ online = reallyOnline;
if (!reallyOnline) {
if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
@@ -1697,7 +1857,6 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession
emit q->networkAccessibleChanged(networkAccessible);
}
}
- online = reallyOnline;
if (online && (state != QNetworkSession::Connected && state != QNetworkSession::Roaming)) {
_q_networkSessionClosed();
createSession(q->configuration());
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index 4b8c4ddf0e..f035ac5b00 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -41,6 +41,8 @@
#define QNETWORKACCESSMANAGER_H
#include <QtNetwork/qtnetworkglobal.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtCore/QVector>
#include <QtCore/QObject>
#ifndef QT_NO_SSL
#include <QtNetwork/QSslConfiguration>
@@ -49,7 +51,6 @@
QT_BEGIN_NAMESPACE
-
class QIODevice;
class QAbstractNetworkCache;
class QAuthenticator;
@@ -57,11 +58,11 @@ class QByteArray;
template<typename T> class QList;
class QNetworkCookie;
class QNetworkCookieJar;
-class QNetworkRequest;
class QNetworkReply;
class QNetworkProxy;
class QNetworkProxyFactory;
class QSslError;
+class QHstsPolicy;
#ifndef QT_NO_BEARERMANAGEMENT
class QNetworkConfiguration;
#endif
@@ -106,6 +107,8 @@ public:
void clearAccessCache();
+ void clearConnectionCache();
+
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy proxy() const;
void setProxy(const QNetworkProxy &proxy);
@@ -119,6 +122,11 @@ public:
QNetworkCookieJar *cookieJar() const;
void setCookieJar(QNetworkCookieJar *cookieJar);
+ void setStrictTransportSecurityEnabled(bool enabled);
+ bool isStrictTransportSecurityEnabled() const;
+ void addStrictTransportSecurityHosts(const QVector<QHstsPolicy> &knownHosts);
+ QVector<QHstsPolicy> strictTransportSecurityHosts() const;
+
QNetworkReply *head(const QNetworkRequest &request);
QNetworkReply *get(const QNetworkRequest &request);
QNetworkReply *post(const QNetworkRequest &request, QIODevice *data);
@@ -147,6 +155,9 @@ public:
#endif
void connectToHost(const QString &hostName, quint16 port = 80);
+ void setRedirectPolicy(QNetworkRequest::RedirectPolicy policy);
+ QNetworkRequest::RedirectPolicy redirectPolicy() const;
+
Q_SIGNALS:
#ifndef QT_NO_NETWORKPROXY
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index bb4641ab8b..13a26a54f1 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -55,6 +55,8 @@
#include "qnetworkaccessmanager.h"
#include "qnetworkaccesscache_p.h"
#include "qnetworkaccessbackend_p.h"
+#include "qnetworkrequest.h"
+#include "qhsts_p.h"
#include "private/qobject_p.h"
#include "QtNetwork/qnetworkproxy.h"
#include "QtNetwork/qnetworksession.h"
@@ -91,6 +93,7 @@ public:
#endif
cookieJarCreated(false),
defaultAccessControl(true),
+ redirectPolicy(QNetworkRequest::ManualRedirectPolicy),
authenticationManager(QSharedPointer<QNetworkAccessAuthenticationManager>::create())
{
#ifndef QT_NO_BEARERMANAGEMENT
@@ -193,6 +196,7 @@ public:
bool cookieJarCreated;
bool defaultAccessControl;
+ QNetworkRequest::RedirectPolicy redirectPolicy;
// The cache with authorization data:
QSharedPointer<QNetworkAccessAuthenticationManager> authenticationManager;
@@ -202,7 +206,13 @@ public:
QNetworkAccessCache objectCache;
static inline QNetworkAccessCache *getObjectCache(QNetworkAccessBackend *backend)
{ return &backend->manager->objectCache; }
- Q_AUTOTEST_EXPORT static void clearCache(QNetworkAccessManager *manager);
+
+ Q_AUTOTEST_EXPORT static void clearAuthenticationCache(QNetworkAccessManager *manager);
+ Q_AUTOTEST_EXPORT static void clearConnectionCache(QNetworkAccessManager *manager);
+
+ QHstsCache stsCache;
+ bool stsEnabled = false;
+
#ifndef QT_NO_BEARERMANAGEMENT
Q_AUTOTEST_EXPORT static const QWeakPointer<const QNetworkSession> getNetworkSession(const QNetworkAccessManager *manager);
#endif
diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp
index ce3b773c64..d72791c1f0 100644
--- a/src/network/access/qnetworkdiskcache.cpp
+++ b/src/network/access/qnetworkdiskcache.cpp
@@ -606,7 +606,7 @@ QString QNetworkDiskCachePrivate::uniqueFileName(const QUrl &url)
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(cleanUrl.toEncoded());
// convert sha1 to base36 form and return first 8 bytes for use as string
- QByteArray id = QByteArray::number(*(qlonglong*)hash.result().data(), 36).left(8);
+ const QByteArray id = QByteArray::number(*(qlonglong*)hash.result().constData(), 36).left(8);
// generates <one-char subdir>/<8-char filname.d>
uint code = (uint)id.at(id.length()-1) % 16;
QString pathFragment = QString::number(code, 16) + QLatin1Char('/')
diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index 3f17b68e79..79afd21a1a 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -166,7 +166,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
any credentials offered (if any)
\value ContentAccessDenied the access to the remote
- content was denied (similar to HTTP error 401)
+ content was denied (similar to HTTP error 403)
\value ContentOperationNotPermittedError the operation requested
on the remote content is not permitted
@@ -305,6 +305,20 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
*/
/*!
+ \fn void QNetworkReply::redirectAllowed()
+ \since 5.9
+
+ When client code handling the redirected() signal has verified the new URL,
+ it emits this signal to allow the redirect to go ahead. This protocol applies
+ to network requests whose redirects policy is set to
+ QNetworkRequest::UserVerifiedRedirectsPolicy.
+
+ \sa QNetworkRequest::UserVerifiedRedirectsPolicy
+ QNetworkAccessManager::setRedirectsPolicy(),
+ QNetworkRequest::RedirectsPolicyAttribute
+*/
+
+/*!
\fn void QNetworkReply::metaDataChanged()
\omit FIXME: Update name? \endomit
@@ -718,7 +732,11 @@ void QNetworkReply::setSslConfiguration(const QSslConfiguration &config)
You can clear the list of errors you want to ignore by calling this
function with an empty list.
- \sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors()
+ \note If HTTP Strict Transport Security is enabled for QNetworkAccessManager,
+ this function has no effect.
+
+ \sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors(),
+ QNetworkAccessManager::setStrictTransportSecurityEnabled()
*/
void QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors)
{
@@ -785,6 +803,9 @@ void QNetworkReply::ignoreSslErrorsImplementation(const QList<QSslError> &)
sslErrors() signal, which indicates which errors were
found.
+ \note If HTTP Strict Transport Security is enabled for QNetworkAccessManager,
+ this function has no effect.
+
\sa sslConfiguration(), sslErrors(), QSslSocket::ignoreSslErrors()
*/
void QNetworkReply::ignoreSslErrors()
diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h
index 1419db8597..d858e07d84 100644
--- a/src/network/access/qnetworkreply.h
+++ b/src/network/access/qnetworkreply.h
@@ -163,6 +163,7 @@ Q_SIGNALS:
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator);
#endif
void redirected(const QUrl &url);
+ void redirectAllowed();
void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 6f5e68d9c2..bdb23ede1d 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -52,6 +52,7 @@
#include "QtCore/qelapsedtimer.h"
#include "QtNetwork/qsslconfiguration.h"
#include "qhttpthreaddelegate_p.h"
+#include "qhsts_p.h"
#include "qthread.h"
#include "QtCore/qcoreapplication.h"
@@ -384,6 +385,12 @@ void QNetworkReplyHttpImpl::ignoreSslErrors()
{
Q_D(QNetworkReplyHttpImpl);
+ if (d->managerPrivate && d->managerPrivate->stsEnabled
+ && d->managerPrivate->stsCache.isKnownHost(url())) {
+ // We cannot ignore any Security Transport-related errors for this host.
+ return;
+ }
+
d->pendingIgnoreAllSslErrors = true;
}
@@ -391,6 +398,12 @@ void QNetworkReplyHttpImpl::ignoreSslErrorsImplementation(const QList<QSslError>
{
Q_D(QNetworkReplyHttpImpl);
+ if (d->managerPrivate && d->managerPrivate->stsEnabled
+ && d->managerPrivate->stsCache.isKnownHost(url())) {
+ // We cannot ignore any Security Transport-related errors for this host.
+ return;
+ }
+
// the pending list is set if QNetworkReply::ignoreSslErrors(const QList<QSslError> &errors)
// is called before QNetworkAccessManager::get() (or post(), etc.)
d->pendingIgnoreSslErrorsList = errors;
@@ -655,8 +668,14 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
}
#endif
- if (newHttpRequest.attribute(QNetworkRequest::FollowRedirectsAttribute).toBool())
- httpRequest.setFollowRedirects(true);
+ auto redirectPolicy = QNetworkRequest::ManualRedirectPolicy;
+ const QVariant value = newHttpRequest.attribute(QNetworkRequest::RedirectPolicyAttribute);
+ if (value.isValid())
+ redirectPolicy = value.value<QNetworkRequest::RedirectPolicy>();
+ else if (newHttpRequest.attribute(QNetworkRequest::FollowRedirectsAttribute).toBool())
+ redirectPolicy = QNetworkRequest::NoLessSafeRedirectPolicy;
+
+ httpRequest.setRedirectPolicy(redirectPolicy);
httpRequest.setPriority(convert(newHttpRequest.priority()));
@@ -803,10 +822,11 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
Qt::QueuedConnection);
QObject::connect(delegate, SIGNAL(downloadMetaData(QList<QPair<QByteArray,QByteArray> >,
int, QString, bool,
- QSharedPointer<char>, qint64, bool)),
+ QSharedPointer<char>, qint64, qint64,
+ bool)),
q, SLOT(replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,
int, QString, bool,
- QSharedPointer<char>, qint64, bool)),
+ QSharedPointer<char>, qint64, qint64, bool)),
Qt::QueuedConnection);
QObject::connect(delegate, SIGNAL(downloadProgress(qint64,qint64)),
q, SLOT(replyDownloadProgressSlot(qint64,qint64)),
@@ -817,12 +837,16 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
QObject::connect(delegate, SIGNAL(redirected(QUrl,int,int)),
q, SLOT(onRedirected(QUrl,int,int)),
Qt::QueuedConnection);
+
+ QObject::connect(q, SIGNAL(redirectAllowed()), q, SLOT(followRedirect()),
+ Qt::QueuedConnection);
+
#ifndef QT_NO_SSL
QObject::connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)),
q, SLOT(replySslConfigurationChanged(QSslConfiguration)),
Qt::QueuedConnection);
#endif
- // Those need to report back, therefire BlockingQueuedConnection
+ // Those need to report back, therefore BlockingQueuedConnection
QObject::connect(delegate, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
q, SLOT(httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
Qt::BlockingQueuedConnection);
@@ -911,6 +935,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
delegate->isPipeliningUsed,
QSharedPointer<char>(),
delegate->incomingContentLength,
+ delegate->removedContentLength,
delegate->isSpdyUsed);
replyDownloadData(delegate->synchronousDownloadData);
httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail);
@@ -922,6 +947,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
delegate->isPipeliningUsed,
QSharedPointer<char>(),
delegate->incomingContentLength,
+ delegate->removedContentLength,
delegate->isSpdyUsed);
replyDownloadData(delegate->synchronousDownloadData);
}
@@ -1109,22 +1135,53 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
if (isFinished)
return;
+ const QString schemeBefore(url.scheme());
if (httpRequest.isFollowRedirects()) // update the reply's url as it could've changed
url = redirectUrl;
- QNetworkRequest redirectRequest = createRedirectRequest(originalRequest, redirectUrl, maxRedirectsRemaining);
+ if (managerPrivate->stsEnabled && managerPrivate->stsCache.isKnownHost(url)) {
+ // RFC6797, 8.3:
+ // The UA MUST replace the URI scheme with "https" [RFC2818],
+ // and if the URI contains an explicit port component of "80",
+ // then the UA MUST convert the port component to be "443", or
+ // if the URI contains an explicit port component that is not
+ // equal to "80", the port component value MUST be preserved;
+ // otherwise, if the URI does not contain an explicit port
+ // component, the UA MUST NOT add one.
+ url.setScheme(QLatin1String("https"));
+ if (url.port() == 80)
+ url.setPort(443);
+ }
+
+ const bool isLessSafe = schemeBefore == QLatin1String("https")
+ && url.scheme() == QLatin1String("http");
+ if (httpRequest.redirectPolicy() == QNetworkRequest::NoLessSafeRedirectPolicy
+ && isLessSafe) {
+ error(QNetworkReply::InsecureRedirectError,
+ QCoreApplication::translate("QHttp", "Insecure redirect"));
+ return;
+ }
+
+ redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining);
operation = getRedirectOperation(operation, httpStatus);
+ if (httpRequest.redirectPolicy() != QNetworkRequest::UserVerifiedRedirectPolicy)
+ followRedirect();
+
+ emit q->redirected(url);
+}
+
+void QNetworkReplyHttpImplPrivate::followRedirect()
+{
+ Q_Q(QNetworkReplyHttpImpl);
+
cookedHeaders.clear();
if (managerPrivate->thread)
managerPrivate->thread->disconnect();
- // Recurse
QMetaObject::invokeMethod(q, "start", Qt::QueuedConnection,
Q_ARG(QNetworkRequest, redirectRequest));
-
- emit q->redirected(redirectUrl);
}
void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
@@ -1149,7 +1206,9 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &hm,
int sc, const QString &rp, bool pu,
QSharedPointer<char> db,
- qint64 contentLength, bool spdyWasUsed)
+ qint64 contentLength,
+ qint64 removedContentLength,
+ bool spdyWasUsed)
{
Q_Q(QNetworkReplyHttpImpl);
Q_UNUSED(contentLength);
@@ -1157,6 +1216,15 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
statusCode = sc;
reasonPhrase = rp;
+#ifndef QT_NO_SSL
+ // We parse this header only if we're using secure transport:
+ //
+ // RFC6797, 8.1
+ // If an HTTP response is received over insecure transport, the UA MUST
+ // ignore any present STS header field(s).
+ if (url.scheme() == QLatin1String("https") && managerPrivate->stsEnabled)
+ managerPrivate->stsCache.updateFromHeaders(hm, url);
+#endif
// Download buffer
if (!db.isNull()) {
downloadBufferPointer = db;
@@ -1166,7 +1234,14 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
}
q->setAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu);
- q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, spdyWasUsed);
+ const QVariant http2Allowed = request.attribute(QNetworkRequest::HTTP2AllowedAttribute);
+ if (http2Allowed.isValid() && http2Allowed.toBool()) {
+ q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, spdyWasUsed);
+ q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, false);
+ } else {
+ q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, spdyWasUsed);
+ q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, false);
+ }
// reconstruct the HTTP header
QList<QPair<QByteArray, QByteArray> > headerMap = hm;
@@ -1195,6 +1270,8 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase);
+ if (removedContentLength != -1)
+ q->setAttribute(QNetworkRequest::OriginalContentLengthAttribute, removedContentLength);
// is it a redirection?
if (!isHttpRedirectResponse())
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
index 868fa617b6..9383149124 100644
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
@@ -114,7 +114,7 @@ public:
Q_PRIVATE_SLOT(d_func(), void replyFinished())
Q_PRIVATE_SLOT(d_func(), void replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,
int, QString, bool, QSharedPointer<char>,
- qint64, bool))
+ qint64, qint64, bool))
Q_PRIVATE_SLOT(d_func(), void replyDownloadProgressSlot(qint64,qint64))
Q_PRIVATE_SLOT(d_func(), void httpAuthenticationRequired(const QHttpNetworkRequest &, QAuthenticator *))
Q_PRIVATE_SLOT(d_func(), void httpError(QNetworkReply::NetworkError, const QString &))
@@ -136,6 +136,7 @@ public:
Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose())
Q_PRIVATE_SLOT(d_func(), void _q_metaDataChanged())
Q_PRIVATE_SLOT(d_func(), void onRedirected(const QUrl &, int, int))
+ Q_PRIVATE_SLOT(d_func(), void followRedirect())
#ifndef QT_NO_SSL
protected:
@@ -212,6 +213,7 @@ public:
QSharedPointer<QRingBuffer> outgoingDataBuffer;
void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal); // dup?
void onRedirected(const QUrl &redirectUrl, int httpStatus, int maxRedirectsRemainig);
+ void followRedirect();
qint64 bytesUploaded;
@@ -263,6 +265,7 @@ public:
QList<QSslError> pendingIgnoreSslErrorsList;
#endif
+ QNetworkRequest redirectRequest;
bool loadFromCacheIfAllowed(QHttpNetworkRequest &httpRequest);
void invalidateCache();
@@ -280,7 +283,7 @@ public:
void replyDownloadData(QByteArray);
void replyFinished();
void replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &,
- bool, QSharedPointer<char>, qint64, bool);
+ bool, QSharedPointer<char>, qint64, qint64, bool);
void replyDownloadProgressSlot(qint64,qint64);
void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth);
void httpError(QNetworkReply::NetworkError error, const QString &errorString);
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index 29362b81e2..60701d45be 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -266,7 +266,10 @@ QT_BEGIN_NAMESPACE
allowed to use HTTP/2 with this request. This applies
to SSL requests or 'cleartext' HTTP/2.
- \omitvalue HTTP2WasUsedAttribute
+ \value HTTP2WasUsedAttribute
+ Replies only, type: QMetaType::Bool (default: false)
+ Indicates whether HTTP/2 was used for receiving this reply.
+ (This value was introduced in 5.9.)
\value EmitAllUploadProgressSignalsAttribute
Requests only, type: QMetaType::Bool (default: false)
@@ -282,6 +285,19 @@ QT_BEGIN_NAMESPACE
that is redirecting from "https" to "http" protocol, are not allowed.
(This value was introduced in 5.6.)
+ \value OriginalContentLengthAttribute
+ Replies only, type QMetaType::Int
+ Holds the original content-length attribute before being invalidated and
+ removed from the header when the data is compressed and the request was
+ marked to be decompressed automatically.
+ (This value was introduced in 5.9.)
+
+ \value RedirectPolicyAttribute
+ Requests only, type: QMetaType::Int, should be one of the
+ QNetworkRequest::RedirectPolicy values (default: ManualRedirectPolicy).
+ This attribute obsoletes FollowRedirectsAttribute.
+ (This value was introduced in 5.9.)
+
\value User
Special type. Additional information can be passed in
QVariants with types ranging from User to UserMax. The default
@@ -329,6 +345,36 @@ QT_BEGIN_NAMESPACE
\value Manual indicates behaviour has been manually overridden.
*/
+/*!
+ \enum QNetworkRequest::RedirectPolicy
+ \since 5.9
+
+ Indicates whether the Network Access API should automatically follow a
+ HTTP redirect response or not.
+
+ \value ManualRedirectPolicy Default value: not following any redirects.
+
+ \value NoLessSafeRedirectPolicy Only "http"->"http", "http" -> "https"
+ or "https" -> "https" redirects are allowed.
+ Equivalent to setting the old FollowRedirectsAttribute
+ to true
+
+ \value SameOriginRedirectPolicy Require the same protocol, host and port.
+ Note, http://example.com and http://example.com:80
+ will fail with this policy (implicit/explicit ports
+ are considered to be a mismatch).
+
+ \value UserVerifiedRedirectPolicy Client decides whether to follow each
+ redirect by handling the redirected()
+ signal, emitting redirectAllowed() on
+ the QNetworkReply object to allow
+ the redirect or aborting/finishing it to
+ reject the redirect. This can be used,
+ for example, to ask the user whether to
+ accept the redirect, or to decide
+ based on some app-specific configuration.
+*/
+
class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate
{
public:
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index ad8f5bddd9..68d4ae6d6b 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -48,7 +48,6 @@
QT_BEGIN_NAMESPACE
-
class QSslConfiguration;
class QNetworkRequestPrivate;
@@ -91,6 +90,8 @@ public:
FollowRedirectsAttribute,
HTTP2AllowedAttribute,
HTTP2WasUsedAttribute,
+ OriginalContentLengthAttribute,
+ RedirectPolicyAttribute,
User = 1000,
UserMax = 32767
@@ -112,6 +113,14 @@ public:
LowPriority = 5
};
+ enum RedirectPolicy {
+ ManualRedirectPolicy,
+ NoLessSafeRedirectPolicy,
+ SameOriginRedirectPolicy,
+ UserVerifiedRedirectPolicy
+ };
+
+
explicit QNetworkRequest(const QUrl &url = QUrl());
QNetworkRequest(const QNetworkRequest &other);
~QNetworkRequest();
@@ -168,5 +177,6 @@ Q_DECLARE_SHARED(QNetworkRequest)
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QNetworkRequest)
+Q_DECLARE_METATYPE(QNetworkRequest::RedirectPolicy)
#endif
diff --git a/src/network/bearer/qnetworkconfiguration.cpp b/src/network/bearer/qnetworkconfiguration.cpp
index 533a27357c..f1619ab7c0 100644
--- a/src/network/bearer/qnetworkconfiguration.cpp
+++ b/src/network/bearer/qnetworkconfiguration.cpp
@@ -326,6 +326,44 @@ bool QNetworkConfiguration::isValid() const
}
/*!
+ \since 5.9
+
+ Returns the connect timeout of this configuration.
+
+ \sa setConnectTimeout
+*/
+int QNetworkConfiguration::connectTimeout() const
+{
+ if (!d)
+ return QNetworkConfigurationPrivate::DefaultTimeout;
+ QMutexLocker locker(&d->mutex);
+ return d->timeout;
+}
+
+/*!
+ \since 5.9
+
+ Sets the connect timeout of this configuration to \a timeout.
+ This allows control of the timeout used by \c QAbstractSocket
+ to establish a connection.
+
+ \warning This will have no effect if the bearer plugin doesn't have
+ the CanStartAndStopInterfaces capability.
+
+ Returns true if succeeded.
+
+ \sa connectTimeout
+*/
+bool QNetworkConfiguration::setConnectTimeout(int timeout)
+{
+ if (!d)
+ return false;
+ QMutexLocker locker(&d->mutex);
+ d->timeout = timeout;
+ return true;
+}
+
+/*!
Returns the current state of the configuration.
*/
QNetworkConfiguration::StateFlags QNetworkConfiguration::state() const
diff --git a/src/network/bearer/qnetworkconfiguration.h b/src/network/bearer/qnetworkconfiguration.h
index 208f9f4692..e7b74034fc 100644
--- a/src/network/bearer/qnetworkconfiguration.h
+++ b/src/network/bearer/qnetworkconfiguration.h
@@ -120,6 +120,9 @@ public:
QString name() const;
bool isValid() const;
+ int connectTimeout() const;
+ bool setConnectTimeout(int timeout);
+
private:
friend class QNetworkConfigurationPrivate;
friend class QNetworkConfigurationManager;
diff --git a/src/network/bearer/qnetworkconfiguration_p.h b/src/network/bearer/qnetworkconfiguration_p.h
index 12d9676b59..2fdb490ea0 100644
--- a/src/network/bearer/qnetworkconfiguration_p.h
+++ b/src/network/bearer/qnetworkconfiguration_p.h
@@ -69,7 +69,8 @@ public:
type(QNetworkConfiguration::Invalid),
purpose(QNetworkConfiguration::UnknownPurpose),
bearerType(QNetworkConfiguration::BearerUnknown),
- isValid(false), roamingSupported(false)
+ isValid(false), roamingSupported(false),
+ timeout(DefaultTimeout)
{}
virtual ~QNetworkConfigurationPrivate()
{
@@ -91,6 +92,9 @@ public:
bool isValid;
bool roamingSupported;
+ int timeout;
+
+ static Q_CONSTEXPR int DefaultTimeout = 30000;
private:
Q_DISABLE_COPY(QNetworkConfigurationPrivate)
diff --git a/src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp b/src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp
index 3783a6f939..ac181f950c 100644
--- a/src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp
+++ b/src/network/doc/snippets/code/src_network_socket_qsctpsocket.cpp
@@ -1,12 +1,22 @@
/****************************************************************************
**
** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
-** You may use this file under the terms of the BSD license as follows:
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri
index 005f000c25..a80b2d387e 100644
--- a/src/network/kernel/kernel.pri
+++ b/src/network/kernel/kernel.pri
@@ -56,8 +56,7 @@ win32: {
mac {
LIBS_PRIVATE += -framework CoreFoundation
- !uikit: LIBS_PRIVATE += -framework CoreServices
- !if(watchos:CONFIG(device, simulator|device)): LIBS_PRIVATE += -framework SystemConfiguration
+ !uikit: LIBS_PRIVATE += -framework CoreServices -framework SystemConfiguration
}
osx:SOURCES += kernel/qnetworkproxy_mac.cpp
diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp
index 02df00a590..6203ba37b3 100644
--- a/src/network/kernel/qdnslookup.cpp
+++ b/src/network/kernel/qdnslookup.cpp
@@ -58,7 +58,7 @@ static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1
return r1.preference() < r2.preference();
}
-/*!
+/*
Sorts a list of QDnsMailExchangeRecord objects according to RFC 5321.
*/
@@ -100,7 +100,7 @@ static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QD
&& r1.weight() == 0 && r2.weight() > 0);
}
-/*!
+/*
Sorts a list of QDnsServiceRecord objects according to RFC 2782.
*/
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp
index fc753204a9..b8c0584a62 100644
--- a/src/network/kernel/qhostaddress.cpp
+++ b/src/network/kernel/qhostaddress.cpp
@@ -63,12 +63,6 @@
QT_BEGIN_NAMESPACE
-#define QT_ENSURE_PARSED(a) \
- do { \
- if (!(a)->d->isParsed) \
- (a)->d->parse(); \
- } while (0)
-
#ifdef Q_OS_WIN
// sockaddr_in6 size changed between old and new SDK
// Only the new version is the correct one, so always
@@ -100,7 +94,7 @@ typedef struct {
#endif
-class QHostAddressPrivate
+class QHostAddressPrivate : public QSharedData
{
public:
QHostAddressPrivate();
@@ -109,10 +103,9 @@ public:
void setAddress(const quint8 *a_);
void setAddress(const Q_IPV6ADDR &a_);
- bool parse();
+ bool parse(const QString &ipString);
void clear();
- QString ipString;
QString scopeId;
union {
@@ -122,13 +115,12 @@ public:
};
quint32 a; // IPv4 address
qint8 protocol;
- bool isParsed;
friend class QHostAddress;
};
QHostAddressPrivate::QHostAddressPrivate()
- : a(0), protocol(QAbstractSocket::UnknownNetworkLayerProtocol), isParsed(true)
+ : a(0), protocol(QAbstractSocket::UnknownNetworkLayerProtocol)
{
memset(&a6, 0, sizeof(a6));
}
@@ -137,7 +129,6 @@ void QHostAddressPrivate::setAddress(quint32 a_)
{
a = a_;
protocol = QAbstractSocket::IPv4Protocol;
- isParsed = true;
//create mapped address, except for a_ == 0 (any)
a6_64.c[0] = 0;
@@ -187,7 +178,6 @@ static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6, const QHostAddress::
void QHostAddressPrivate::setAddress(const quint8 *a_)
{
protocol = QAbstractSocket::IPv6Protocol;
- isParsed = true;
memcpy(a6.c, a_, sizeof(a6));
a = 0;
convertToIpv4(a, a6, (QHostAddress::ConvertV4MappedToIPv4
@@ -201,10 +191,10 @@ void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_)
static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr, QString *scopeId)
{
- QString tmp = address;
+ QStringRef tmp(&address);
int scopeIdPos = tmp.lastIndexOf(QLatin1Char('%'));
if (scopeIdPos != -1) {
- *scopeId = tmp.mid(scopeIdPos + 1);
+ *scopeId = tmp.mid(scopeIdPos + 1).toString();
tmp.chop(tmp.size() - scopeIdPos);
} else {
scopeId->clear();
@@ -212,9 +202,8 @@ static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr,
return QIPAddressUtils::parseIp6(addr, tmp.constBegin(), tmp.constEnd()) == 0;
}
-Q_NEVER_INLINE bool QHostAddressPrivate::parse()
+bool QHostAddressPrivate::parse(const QString &ipString)
{
- isParsed = true;
protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
QString a = ipString.simplified();
if (a.isEmpty())
@@ -242,13 +231,13 @@ void QHostAddressPrivate::clear()
{
a = 0;
protocol = QAbstractSocket::UnknownNetworkLayerProtocol;
- isParsed = true;
memset(&a6, 0, sizeof(a6));
}
bool QNetmaskAddress::setAddress(const QString &address)
{
+ d.detach();
length = -1;
QHostAddress other;
return other.setAddress(address) && setAddress(other);
@@ -256,6 +245,8 @@ bool QNetmaskAddress::setAddress(const QString &address)
bool QNetmaskAddress::setAddress(const QHostAddress &address)
{
+ d.detach();
+
static const quint8 zeroes[16] = { 0 };
union {
quint32 v4;
@@ -349,6 +340,7 @@ int QNetmaskAddress::prefixLength() const
void QNetmaskAddress::setPrefixLength(QAbstractSocket::NetworkLayerProtocol proto, int newLength)
{
+ d.detach();
length = newLength;
if (length < 0 || length > (proto == QAbstractSocket::IPv4Protocol ? 32 :
proto == QAbstractSocket::IPv6Protocol ? 128 : -1)) {
@@ -377,6 +369,7 @@ void QNetmaskAddress::setPrefixLength(QAbstractSocket::NetworkLayerProtocol prot
\class QHostAddress
\brief The QHostAddress class provides an IP address.
\ingroup network
+ \ingroup shared
\inmodule QtNetwork
This class holds an IPv4 or IPv6 address in a platform- and
@@ -484,8 +477,7 @@ QHostAddress::QHostAddress(const Q_IPV6ADDR &ip6Addr)
QHostAddress::QHostAddress(const QString &address)
: d(new QHostAddressPrivate)
{
- d->ipString = address;
- d->isParsed = false;
+ d->parse(address);
}
/*!
@@ -513,7 +505,7 @@ QHostAddress::QHostAddress(const struct sockaddr *sockaddr)
Constructs a copy of the given \a address.
*/
QHostAddress::QHostAddress(const QHostAddress &address)
- : d(new QHostAddressPrivate(*address.d.data()))
+ : d(address.d)
{
}
@@ -582,7 +574,7 @@ QHostAddress::~QHostAddress()
*/
QHostAddress &QHostAddress::operator=(const QHostAddress &address)
{
- *d.data() = *address.d.data();
+ d = address.d;
return *this;
}
@@ -633,6 +625,7 @@ QHostAddress &QHostAddress::operator=(SpecialAddress address)
*/
void QHostAddress::clear()
{
+ d.detach();
d->clear();
}
@@ -641,6 +634,7 @@ void QHostAddress::clear()
*/
void QHostAddress::setAddress(quint32 ip4Addr)
{
+ d.detach();
d->setAddress(ip4Addr);
}
@@ -654,6 +648,7 @@ void QHostAddress::setAddress(quint32 ip4Addr)
*/
void QHostAddress::setAddress(quint8 *ip6Addr)
{
+ d.detach();
d->setAddress(ip6Addr);
}
@@ -668,6 +663,7 @@ void QHostAddress::setAddress(quint8 *ip6Addr)
*/
void QHostAddress::setAddress(const quint8 *ip6Addr)
{
+ d.detach();
d->setAddress(ip6Addr);
}
@@ -678,6 +674,7 @@ void QHostAddress::setAddress(const quint8 *ip6Addr)
*/
void QHostAddress::setAddress(const Q_IPV6ADDR &ip6Addr)
{
+ d.detach();
d->setAddress(ip6Addr);
}
@@ -691,8 +688,8 @@ void QHostAddress::setAddress(const Q_IPV6ADDR &ip6Addr)
*/
bool QHostAddress::setAddress(const QString &address)
{
- d->ipString = address;
- return d->parse();
+ d.detach();
+ return d->parse(address);
}
/*!
@@ -705,6 +702,7 @@ bool QHostAddress::setAddress(const QString &address)
*/
void QHostAddress::setAddress(const struct sockaddr *sockaddr)
{
+ d.detach();
#ifndef Q_OS_WINRT
clear();
if (sockaddr->sa_family == AF_INET)
@@ -752,7 +750,6 @@ quint32 QHostAddress::toIPv4Address() const
*/
quint32 QHostAddress::toIPv4Address(bool *ok) const
{
- QT_ENSURE_PARSED(this);
quint32 dummy;
if (ok)
*ok = d->protocol == QAbstractSocket::IPv4Protocol || d->protocol == QAbstractSocket::AnyIPProtocol
@@ -767,7 +764,6 @@ quint32 QHostAddress::toIPv4Address(bool *ok) const
*/
QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol() const
{
- QT_ENSURE_PARSED(this);
return QAbstractSocket::NetworkLayerProtocol(d->protocol);
}
@@ -787,7 +783,6 @@ QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol() const
*/
Q_IPV6ADDR QHostAddress::toIPv6Address() const
{
- QT_ENSURE_PARSED(this);
return d->a6;
}
@@ -803,7 +798,6 @@ Q_IPV6ADDR QHostAddress::toIPv6Address() const
*/
QString QHostAddress::toString() const
{
- QT_ENSURE_PARSED(this);
QString s;
if (d->protocol == QAbstractSocket::IPv4Protocol
|| d->protocol == QAbstractSocket::AnyIPProtocol) {
@@ -855,7 +849,6 @@ QString QHostAddress::toString() const
*/
QString QHostAddress::scopeId() const
{
- QT_ENSURE_PARSED(this);
return (d->protocol == QAbstractSocket::IPv6Protocol) ? d->scopeId : QString();
}
@@ -873,7 +866,7 @@ QString QHostAddress::scopeId() const
*/
void QHostAddress::setScopeId(const QString &id)
{
- QT_ENSURE_PARSED(this);
+ d.detach();
if (d->protocol == QAbstractSocket::IPv6Protocol)
d->scopeId = id;
}
@@ -886,7 +879,7 @@ void QHostAddress::setScopeId(const QString &id)
*/
bool QHostAddress::operator==(const QHostAddress &other) const
{
- return isEqual(other, StrictConversion);
+ return d == other.d || isEqual(other, StrictConversion);
}
/*!
@@ -903,8 +896,8 @@ bool QHostAddress::operator==(const QHostAddress &other) const
*/
bool QHostAddress::isEqual(const QHostAddress &other, ConversionMode mode) const
{
- QT_ENSURE_PARSED(this);
- QT_ENSURE_PARSED(&other);
+ if (d == other.d)
+ return true;
if (d->protocol == QAbstractSocket::IPv4Protocol) {
switch (other.d->protocol) {
@@ -956,7 +949,6 @@ bool QHostAddress::isEqual(const QHostAddress &other, ConversionMode mode) const
*/
bool QHostAddress::operator ==(SpecialAddress other) const
{
- QT_ENSURE_PARSED(this);
quint32 ip4 = INADDR_ANY;
switch (other) {
case Null:
@@ -996,7 +988,6 @@ bool QHostAddress::operator ==(SpecialAddress other) const
*/
bool QHostAddress::isNull() const
{
- QT_ENSURE_PARSED(this);
return d->protocol == QAbstractSocket::UnknownNetworkLayerProtocol;
}
@@ -1021,7 +1012,6 @@ bool QHostAddress::isNull() const
*/
bool QHostAddress::isInSubnet(const QHostAddress &subnet, int netmask) const
{
- QT_ENSURE_PARSED(this);
if (subnet.protocol() != d->protocol || netmask < 0)
return false;
@@ -1120,7 +1110,7 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
return invalid;
int slash = subnet.indexOf(QLatin1Char('/'));
- QString netStr = subnet;
+ QStringRef netStr(&subnet);
if (slash != -1)
netStr.truncate(slash);
@@ -1151,7 +1141,7 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
netmask = 128;
QHostAddress net;
- if (!net.setAddress(netStr))
+ if (!net.setAddress(netStr.toString()))
return invalid; // failed to parse the IP
clearBits(net.d->a6.c, netmask, 128);
@@ -1162,7 +1152,7 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
return invalid; // invalid netmask
// parse the address manually
- auto parts = netStr.splitRef(QLatin1Char('.'));
+ auto parts = netStr.split(QLatin1Char('.'));
if (parts.isEmpty() || parts.count() > 4)
return invalid; // invalid IPv4 address
@@ -1204,7 +1194,6 @@ QPair<QHostAddress, int> QHostAddress::parseSubnet(const QString &subnet)
*/
bool QHostAddress::isLoopback() const
{
- QT_ENSURE_PARSED(this);
if ((d->a & 0xFF000000) == 0x7F000000)
return true; // v4 range (including IPv6 wrapped IPv4 addresses)
if (d->protocol == QAbstractSocket::IPv6Protocol) {
@@ -1230,7 +1219,6 @@ bool QHostAddress::isLoopback() const
*/
bool QHostAddress::isMulticast() const
{
- QT_ENSURE_PARSED(this);
if ((d->a & 0xF0000000) == 0xE0000000)
return true; // 224.0.0.0-239.255.255.255 (including v4-mapped IPv6 addresses)
if (d->protocol == QAbstractSocket::IPv6Protocol)
@@ -1256,10 +1244,8 @@ QDebug operator<<(QDebug d, const QHostAddress &address)
\relates QHostAddress
Returns a hash of the host address \a key, using \a seed to seed the calculation.
*/
-uint qHash(const QHostAddress &key, uint seed)
+uint qHash(const QHostAddress &key, uint seed) Q_DECL_NOTHROW
{
- // both lines might throw
- QT_ENSURE_PARSED(&key);
return qHashBits(key.d->a6.c, 16, seed);
}
@@ -1272,6 +1258,18 @@ uint qHash(const QHostAddress &key, uint seed)
\sa isEqual()
*/
+
+/*!
+ \relates QHostAddress
+ \since 5.9
+ \fn operator!=(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
+
+ Returns \c false if special address \a lhs is the same as host address \a rhs;
+ otherwise returns \c true.
+
+ \sa isEqual()
+*/
+
#ifndef QT_NO_DATASTREAM
/*! \relates QHostAddress
diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h
index 10fe33f6fa..fdbdbfc72c 100644
--- a/src/network/kernel/qhostaddress.h
+++ b/src/network/kernel/qhostaddress.h
@@ -44,7 +44,7 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/qpair.h>
#include <QtCore/qstring.h>
-#include <QtCore/qscopedpointer.h>
+#include <QtCore/qshareddata.h>
#include <QtNetwork/qabstractsocket.h>
struct sockaddr;
@@ -66,7 +66,7 @@ typedef QIPv6Address Q_IPV6ADDR;
class QHostAddress;
// qHash is a friend, but we can't use default arguments for friends (§8.3.6.4)
-Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed = 0);
+Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed = 0) Q_DECL_NOTHROW;
class Q_NETWORK_EXPORT QHostAddress
{
@@ -152,15 +152,17 @@ public:
static QPair<QHostAddress, int> parseSubnet(const QString &subnet);
- friend Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed);
+ friend Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed) Q_DECL_NOTHROW;
protected:
- QScopedPointer<QHostAddressPrivate> d;
+ QExplicitlySharedDataPointer<QHostAddressPrivate> d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QHostAddress::ConversionMode)
Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QHostAddress)
inline bool operator ==(QHostAddress::SpecialAddress address1, const QHostAddress &address2)
{ return address2 == address1; }
+inline bool operator!=(QHostAddress::SpecialAddress lhs, const QHostAddress &rhs)
+{ return rhs != lhs; }
#ifndef QT_NO_DEBUG_STREAM
Q_NETWORK_EXPORT QDebug operator<<(QDebug, const QHostAddress &);
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index 88df65dbcb..46123eb8a7 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -95,6 +95,38 @@ std::pair<OutputIt1, OutputIt2> separate_if(InputIt first, InputIt last, OutputI
}
return std::make_pair(dest1, dest2);
}
+
+int get_signal_index()
+{
+ static auto senderMetaObject = &QHostInfoResult::staticMetaObject;
+ static auto signal = &QHostInfoResult::resultsReady;
+ int signal_index = -1;
+ void *args[] = { &signal_index, &signal };
+ senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
+ return signal_index + QMetaObjectPrivate::signalOffset(senderMetaObject);
+}
+
+void emit_results_ready(const QHostInfo &hostInfo, const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj)
+{
+ static const int signal_index = get_signal_index();
+ auto result = new QHostInfoResult(receiver, slotObj);
+ Q_CHECK_PTR(result);
+ const int nargs = 2;
+ auto types = reinterpret_cast<int *>(malloc(nargs * sizeof(int)));
+ Q_CHECK_PTR(types);
+ types[0] = QMetaType::type("void");
+ types[1] = QMetaType::type("QHostInfo");
+ auto args = reinterpret_cast<void **>(malloc(nargs * sizeof(void *)));
+ Q_CHECK_PTR(args);
+ args[0] = 0;
+ args[1] = QMetaType::create(types[1], &hostInfo);
+ Q_CHECK_PTR(args[1]);
+ auto metaCallEvent = new QMetaCallEvent(slotObj, nullptr, signal_index, nargs, types, args);
+ Q_CHECK_PTR(metaCallEvent);
+ qApp->postEvent(result, metaCallEvent);
+}
+
}
/*!
@@ -151,7 +183,11 @@ std::pair<OutputIt1, OutputIt2> separate_if(InputIt first, InputIt last, OutputI
\sa QAbstractSocket, {http://www.rfc-editor.org/rfc/rfc3492.txt}{RFC 3492}
*/
-static QBasicAtomicInt theIdCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
+static int nextId()
+{
+ static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
+ return 1 + counter.fetchAndAddRelaxed(1);
+}
/*!
Looks up the IP address(es) associated with host name \a name, and
@@ -197,7 +233,7 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver,
qRegisterMetaType<QHostInfo>();
- int id = theIdCounter.fetchAndAddRelaxed(1); // generate unique ID
+ int id = nextId(); // generate unique ID
if (name.isEmpty()) {
if (!receiver)
@@ -243,6 +279,67 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver,
}
/*!
+ \fn int QHostInfo::lookupHost(const QString &name, const QObject *receiver, PointerToMemberFunction function)
+
+ \since 5.9
+
+ \overload
+
+ Looks up the IP address(es) associated with host name \a name, and
+ returns an ID for the lookup. When the result of the lookup is
+ ready, the slot or signal \a function in \a receiver is called with
+ a QHostInfo argument. The QHostInfo object can then be inspected
+ to get the results of the lookup.
+
+ \note There is no guarantee on the order the signals will be emitted
+ if you start multiple requests with lookupHost().
+
+ \sa abortHostLookup(), addresses(), error(), fromName()
+*/
+
+/*!
+ \fn int QHostInfo::lookupHost(const QString &name, Functor functor)
+
+ \since 5.9
+
+ \overload
+
+ Looks up the IP address(es) associated with host name \a name, and
+ returns an ID for the lookup. When the result of the lookup is
+ ready, the \a functor is called with a QHostInfo argument. The
+ QHostInfo object can then be inspected to get the results of the
+ lookup.
+ \note There is no guarantee on the order the signals will be emitted
+ if you start multiple requests with lookupHost().
+
+ \sa abortHostLookup(), addresses(), error(), fromName()
+*/
+
+/*!
+ \fn int QHostInfo::lookupHost(const QString &name, const QObject *context, Functor functor)
+
+ \since 5.9
+
+ \overload
+
+ Looks up the IP address(es) associated with host name \a name, and
+ returns an ID for the lookup. When the result of the lookup is
+ ready, the \a functor is called with a QHostInfo argument. The
+ QHostInfo object can then be inspected to get the results of the
+ lookup.
+
+ If \a context is destroyed before the lookup completes, the
+ \a functor will not be called. The \a functor will be run in the
+ thread of \a context. The context's thread must have a running Qt
+ event loop.
+
+ \note There is no guarantee on the order the signals will be emitted
+ if you start multiple requests with lookupHost().
+
+ \sa abortHostLookup(), addresses(), error(), fromName()
+*/
+
+/*!
Aborts the host lookup with the ID \a id, as returned by lookupHost().
\sa lookupHost(), lookupId()
@@ -487,11 +584,66 @@ QString QHostInfo::localHostName()
\sa hostName()
*/
+int QHostInfo::lookupHostImpl(const QString &name,
+ const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj)
+{
+#if defined QHOSTINFO_DEBUG
+ qDebug("QHostInfo::lookupHost(\"%s\", %p, %p)",
+ name.toLatin1().constData(), receiver, slotObj);
+#endif
+
+ if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
+ qWarning("QHostInfo::lookupHost() called with no event dispatcher");
+ return -1;
+ }
+
+ qRegisterMetaType<QHostInfo>();
+
+ int id = nextId(); // generate unique ID
+
+ if (Q_UNLIKELY(name.isEmpty())) {
+ QHostInfo hostInfo(id);
+ hostInfo.setError(QHostInfo::HostNotFound);
+ hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given"));
+ emit_results_ready(hostInfo, receiver, slotObj);
+ return id;
+ }
+
+ QHostInfoLookupManager *manager = theHostInfoLookupManager();
+
+ if (Q_LIKELY(manager)) {
+ // the application is still alive
+ if (manager->cache.isEnabled()) {
+ // check cache first
+ bool valid = false;
+ QHostInfo info = manager->cache.get(name, &valid);
+ if (valid) {
+ info.setLookupId(id);
+ emit_results_ready(info, receiver, slotObj);
+ return id;
+ }
+ }
+
+ // cache is not enabled or it was not in the cache, do normal lookup
+ QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id, receiver, slotObj);
+ manager->scheduleLookup(runnable);
+ }
+ return id;
+}
+
QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i) : toBeLookedUp(hn), id(i)
{
setAutoDelete(true);
}
+QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj) :
+ toBeLookedUp(hn), id(i), resultEmitter(receiver, slotObj)
+{
+ setAutoDelete(true);
+}
+
// the QHostInfoLookupManager will at some point call this via a QThreadPool
void QHostInfoRunnable::run()
{
diff --git a/src/network/kernel/qhostinfo.h b/src/network/kernel/qhostinfo.h
index 9b4a4853d9..4484d718bd 100644
--- a/src/network/kernel/qhostinfo.h
+++ b/src/network/kernel/qhostinfo.h
@@ -87,8 +87,71 @@ public:
static QString localHostName();
static QString localDomainName();
+#ifdef Q_QDOC
+ template<typename PointerToMemberFunction>
+ static int QHostInfo::lookupHost(const QString &name, const QObject *receiver,
+ PointerToMemberFunction function);
+ template<typename Functor>
+ static int QHostInfo::lookupHost(const QString &name, Functor functor);
+ template<typename Functor>
+ static int QHostInfo::lookupHost(const QString &name, const QObject *context, Functor functor);
+#else
+ // lookupHost to a QObject slot
+ template <typename Func>
+ static inline int lookupHost(const QString &name,
+ const typename QtPrivate::FunctionPointer<Func>::Object *receiver,
+ Func slot)
+ {
+ typedef QtPrivate::FunctionPointer<Func> SlotType;
+
+ typedef QtPrivate::FunctionPointer<void (*)(QHostInfo)> SignalType;
+ Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
+ "The slot requires more arguments than the signal provides.");
+ Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments,
+ typename SlotType::Arguments>::value),
+ "Signal and slot arguments are not compatible.");
+ Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType,
+ typename SignalType::ReturnType>::value),
+ "Return type of the slot is not compatible "
+ "with the return type of the signal.");
+
+ auto slotObj = new QtPrivate::QSlotObject<Func, typename SlotType::Arguments, void>(slot);
+ return lookupHostImpl(name, receiver, slotObj);
+ }
+
+ // lookupHost to a callable (without context)
+ template <typename Func>
+ static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction &&
+ !std::is_same<const char *, Func>::value, int>::type
+ lookupHost(const QString &name, Func slot)
+ {
+ return lookupHost(name, nullptr, slot);
+ }
+
+ // lookupHost to a functor or function pointer (with context)
+ template <typename Func1>
+ static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
+ !std::is_same<const char*, Func1>::value, int>::type
+ lookupHost(const QString &name, QObject *context, Func1 slot)
+ {
+ typedef QtPrivate::FunctionPointer<Func1> SlotType;
+
+ Q_STATIC_ASSERT_X(int(SlotType::ArgumentCount) <= 1,
+ "The slot must not require more than one argument");
+
+ auto slotObj = new QtPrivate::QFunctorSlotObject<Func1, 1,
+ typename QtPrivate::List<QHostInfo>,
+ void>(slot);
+ return lookupHostImpl(name, context, slotObj);
+ }
+#endif // Q_QDOC
+
private:
QScopedPointer<QHostInfoPrivate> d;
+
+ static int lookupHostImpl(const QString &name,
+ const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj);
};
QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h
index ba342bf533..dd46818a19 100644
--- a/src/network/kernel/qhostinfo_p.h
+++ b/src/network/kernel/qhostinfo_p.h
@@ -54,6 +54,7 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include "QtCore/qcoreapplication.h"
#include "private/qcoreapplication_p.h"
+#include "private/qmetaobject_p.h"
#include "QtNetwork/qhostinfo.h"
#include "QtCore/qmutex.h"
#include "QtCore/qwaitcondition.h"
@@ -77,10 +78,47 @@ QT_BEGIN_NAMESPACE
class QHostInfoResult : public QObject
{
Q_OBJECT
+
+ QPointer<const QObject> receiver = nullptr;
+ QtPrivate::QSlotObjectBase *slotObj = nullptr;
+
+public:
+ QHostInfoResult() = default;
+ QHostInfoResult(const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj) :
+ receiver(receiver),
+ slotObj(slotObj)
+ {
+ connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this,
+ &QObject::deleteLater);
+ if (slotObj && receiver)
+ moveToThread(receiver->thread());
+ }
+
public Q_SLOTS:
inline void emitResultsReady(const QHostInfo &info)
{
- emit resultsReady(info);
+ if (slotObj) {
+ QHostInfo copy = info;
+ void *args[2] = { 0, reinterpret_cast<void *>(&copy) };
+ slotObj->call(const_cast<QObject*>(receiver.data()), args);
+ slotObj->destroyIfLastRef();
+ } else {
+ emit resultsReady(info);
+ }
+ }
+
+protected:
+ bool event(QEvent *event)
+ {
+ if (event->type() == QEvent::MetaCall) {
+ auto metaCallEvent = static_cast<QMetaCallEvent *>(event);
+ auto args = metaCallEvent->args();
+ auto hostInfo = reinterpret_cast<QHostInfo *>(args[1]);
+ emitResultsReady(*hostInfo);
+ deleteLater();
+ return true;
+ }
+ return QObject::event(event);
}
Q_SIGNALS:
@@ -154,6 +192,8 @@ class QHostInfoRunnable : public QRunnable
{
public:
QHostInfoRunnable(const QString &hn, int i);
+ QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj);
void run() Q_DECL_OVERRIDE;
QString toBeLookedUp;
diff --git a/src/network/kernel/qnetworkdatagram.cpp b/src/network/kernel/qnetworkdatagram.cpp
index 88ca763187..dd412b69d1 100644
--- a/src/network/kernel/qnetworkdatagram.cpp
+++ b/src/network/kernel/qnetworkdatagram.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 Intel Corporation.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
diff --git a/src/network/kernel/qnetworkdatagram.h b/src/network/kernel/qnetworkdatagram.h
index a20d69185a..fa994d6170 100644
--- a/src/network/kernel/qnetworkdatagram.h
+++ b/src/network/kernel/qnetworkdatagram.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 Intel Corporation.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
diff --git a/src/network/kernel/qnetworkdatagram_p.h b/src/network/kernel/qnetworkdatagram_p.h
index e55651a78b..5b5c037488 100644
--- a/src/network/kernel/qnetworkdatagram_p.h
+++ b/src/network/kernel/qnetworkdatagram_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2015 Intel Corporation.
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp
index 0be8a7f79e..11e8fa6264 100644
--- a/src/network/kernel/qnetworkproxy.cpp
+++ b/src/network/kernel/qnetworkproxy.cpp
@@ -1636,10 +1636,6 @@ QList<QNetworkProxy> QNetworkProxyFactory::proxyForQuery(const QNetworkProxyQuer
}
#ifndef QT_NO_DEBUG_STREAM
-/*!
- \since 5.0
- Outputs a QNetworkProxy details to a debug stream
-*/
QDebug operator<<(QDebug debug, const QNetworkProxy &proxy)
{
QDebugStateSaver saver(debug);
@@ -1688,6 +1684,21 @@ QDebug operator<<(QDebug debug, const QNetworkProxy &proxy)
debug << '[' << scaps.join(QLatin1Char(' ')) << ']';
return debug;
}
+
+QDebug operator<<(QDebug debug, const QNetworkProxyQuery &proxyQuery)
+{
+ QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace()
+ << "ProxyQuery("
+ << "type: " << proxyQuery.queryType()
+ << ", protocol: " << proxyQuery.protocolTag()
+ << ", peerPort: " << proxyQuery.peerPort()
+ << ", peerHostName: " << proxyQuery.peerHostName()
+ << ", localPort: " << proxyQuery.localPort()
+ << ", url: " << proxyQuery.url()
+ << ')';
+ return debug;
+}
#endif
QT_END_NAMESPACE
diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h
index 8fcb7e33cf..8699c313e9 100644
--- a/src/network/kernel/qnetworkproxy.h
+++ b/src/network/kernel/qnetworkproxy.h
@@ -56,6 +56,8 @@ class QNetworkConfiguration;
class QNetworkProxyQueryPrivate;
class Q_NETWORK_EXPORT QNetworkProxyQuery
{
+ Q_GADGET
+
public:
enum QueryType {
TcpSocket,
@@ -65,6 +67,7 @@ public:
UrlRequest,
SctpServer
};
+ Q_ENUM(QueryType)
QNetworkProxyQuery();
explicit QNetworkProxyQuery(const QUrl &requestUrl, QueryType queryType = UrlRequest);
@@ -222,6 +225,7 @@ public:
#ifndef QT_NO_DEBUG_STREAM
Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkProxy &proxy);
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkProxyQuery &proxyQuery);
#endif
QT_END_NAMESPACE
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 57c40194a3..7ecbf35489 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -491,7 +491,6 @@
#ifndef QABSTRACTSOCKET_BUFFERSIZE
#define QABSTRACTSOCKET_BUFFERSIZE 32768
#endif
-#define QT_CONNECT_TIMEOUT 30000
#define QT_TRANSFER_TIMEOUT 120000
QT_BEGIN_NAMESPACE
@@ -1142,7 +1141,15 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
q, SLOT(_q_abortConnectionAttempt()),
Qt::DirectConnection);
}
- connectTimer->start(QT_CONNECT_TIMEOUT);
+ int connectTimeout = QNetworkConfigurationPrivate::DefaultTimeout;
+#ifndef QT_NO_BEARERMANAGEMENT
+ QSharedPointer<QNetworkSession> networkSession = qvariant_cast< QSharedPointer<QNetworkSession> >(q->property("_q_networksession"));
+ if (networkSession) {
+ QNetworkConfiguration networkConfiguration = networkSession->configuration();
+ connectTimeout = networkConfiguration.connectTimeout();
+ }
+#endif
+ connectTimer->start(connectTimeout);
}
// Wait for a write notification that will eventually call
@@ -1279,11 +1286,11 @@ bool QAbstractSocketPrivate::readFromSocket()
}
if (!socketEngine->isValid()) {
- setErrorAndEmit(socketEngine->error(), socketEngine->errorString());
#if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::readFromSocket() read failed: %s",
- q->errorString().toLatin1().constData());
+ socketEngine->errorString().toLatin1().constData());
#endif
+ setErrorAndEmit(socketEngine->error(), socketEngine->errorString());
resetSocketLayer();
return false;
}
@@ -2100,6 +2107,10 @@ bool QAbstractSocket::waitForConnected(int msecs)
QElapsedTimer stopWatch;
stopWatch.start();
+#ifndef QT_NO_BEARERMANAGEMENT
+ QSharedPointer<QNetworkSession> networkSession = qvariant_cast< QSharedPointer<QNetworkSession> >(property("_q_networksession"));
+#endif
+
if (d->state == HostLookupState) {
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForConnected(%i) doing host name lookup", msecs);
@@ -2107,10 +2118,7 @@ bool QAbstractSocket::waitForConnected(int msecs)
QHostInfo::abortHostLookup(d->hostLookupId);
d->hostLookupId = -1;
#ifndef QT_NO_BEARERMANAGEMENT
- QSharedPointer<QNetworkSession> networkSession;
- QVariant v(property("_q_networksession"));
- if (v.isValid()) {
- networkSession = qvariant_cast< QSharedPointer<QNetworkSession> >(v);
+ if (networkSession) {
d->_q_startConnecting(QHostInfoPrivate::fromName(d->hostName, networkSession));
} else
#endif
@@ -2128,14 +2136,21 @@ bool QAbstractSocket::waitForConnected(int msecs)
if (state() == UnconnectedState)
return false; // connect not im progress anymore!
+ int connectTimeout = QNetworkConfigurationPrivate::DefaultTimeout;
+#ifndef QT_NO_BEARERMANAGEMENT
+ if (networkSession) {
+ QNetworkConfiguration networkConfiguration = networkSession->configuration();
+ connectTimeout = networkConfiguration.connectTimeout();
+ }
+#endif
bool timedOut = true;
#if defined (QABSTRACTSOCKET_DEBUG)
int attempt = 1;
#endif
while (state() == ConnectingState && (msecs == -1 || stopWatch.elapsed() < msecs)) {
int timeout = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
- if (msecs != -1 && timeout > QT_CONNECT_TIMEOUT)
- timeout = QT_CONNECT_TIMEOUT;
+ if (msecs != -1 && timeout > connectTimeout)
+ timeout = connectTimeout;
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForConnected(%i) waiting %.2f secs for connection attempt #%i",
msecs, timeout / 1000.0, attempt++);
@@ -2448,7 +2463,6 @@ bool QAbstractSocket::atEnd() const
\sa write(), waitForBytesWritten()
*/
-// Note! docs copied to QSslSocket::flush()
bool QAbstractSocket::flush()
{
return d_func()->flush();
diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h
index 786885b6cd..52c533141f 100644
--- a/src/network/socket/qlocalserver.h
+++ b/src/network/socket/qlocalserver.h
@@ -56,7 +56,6 @@ class Q_NETWORK_EXPORT QLocalServer : public QObject
Q_OBJECT
Q_DECLARE_PRIVATE(QLocalServer)
Q_PROPERTY(SocketOptions socketOptions READ socketOptions WRITE setSocketOptions)
- Q_FLAGS(SocketOption SocketOptions)
Q_SIGNALS:
void newConnection();
@@ -69,7 +68,9 @@ public:
OtherAccessOption = 0x4,
WorldAccessOption = 0x7
};
+ Q_FLAG(SocketOption)
Q_DECLARE_FLAGS(SocketOptions, SocketOption)
+ Q_FLAG(SocketOptions)
explicit QLocalServer(QObject *parent = Q_NULLPTR);
~QLocalServer();
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index b56d460b8c..b796934199 100644
--- a/src/network/socket/qnativesocketengine.cpp
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -129,6 +129,10 @@
# include "qtcpserver.h"
#endif
+#if !defined(QT_NO_SCTP)
+# include "qsctpserver.h"
+#endif
+
QT_BEGIN_NAMESPACE
//#define QNATIVESOCKETENGINE_DEBUG
@@ -358,17 +362,41 @@ bool QNativeSocketEnginePrivate::checkProxy(const QHostAddress &address)
#if !defined(QT_NO_NETWORKPROXY)
QObject *parent = q_func()->parent();
QNetworkProxy proxy;
+ QNetworkProxyQuery::QueryType queryType = QNetworkProxyQuery::TcpSocket;
if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(parent)) {
proxy = socket->proxy();
+ switch (socket->socketType()) {
+ case QAbstractSocket::UdpSocket:
+ queryType = QNetworkProxyQuery::UdpSocket;
+ break;
+ case QAbstractSocket::SctpSocket:
+ queryType = QNetworkProxyQuery::SctpSocket;
+ break;
+ case QAbstractSocket::TcpSocket:
+ case QAbstractSocket::UnknownSocketType:
+ queryType = QNetworkProxyQuery::TcpSocket;
+ }
} else if (QTcpServer *server = qobject_cast<QTcpServer *>(parent)) {
proxy = server->proxy();
+ queryType = QNetworkProxyQuery::TcpServer;
+#ifndef QT_NO_SCTP
+ if (qobject_cast<QSctpServer *>(server))
+ queryType = QNetworkProxyQuery::SctpServer;
+#endif
} else {
// no parent -> no proxy
return true;
}
- if (proxy.type() == QNetworkProxy::DefaultProxy)
- proxy = QNetworkProxy::applicationProxy();
+ if (proxy.type() == QNetworkProxy::DefaultProxy) {
+ // This is similar to what we have in QNetworkProxy::applicationProxy,
+ // the only difference is that we provide the correct query type instead of
+ // always using TcpSocket unconditionally (this is the default type for
+ // QNetworkProxyQuery).
+ QNetworkProxyQuery query;
+ query.setQueryType(queryType);
+ proxy = QNetworkProxyFactory::systemProxyForQuery(query).constFirst();
+ }
if (proxy.type() != QNetworkProxy::DefaultProxy &&
proxy.type() != QNetworkProxy::NoProxy) {
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
index 46c7ae5c55..08e72072ef 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -108,9 +108,9 @@ union qt_sockaddr {
namespace {
namespace SetSALen {
- template <typename T> void set(T *sa, typename QtPrivate::QEnableIf<(&T::sa_len, true), QT_SOCKLEN_T>::Type len)
+ template <typename T> void set(T *sa, typename std::enable_if<(&T::sa_len, true), QT_SOCKLEN_T>::type len)
{ sa->sa_len = len; }
- template <typename T> void set(T *sin6, typename QtPrivate::QEnableIf<(&T::sin6_len, true), QT_SOCKLEN_T>::Type len)
+ template <typename T> void set(T *sin6, typename std::enable_if<(&T::sin6_len, true), QT_SOCKLEN_T>::type len)
{ sin6->sin6_len = len; }
template <typename T> void set(T *, ...) {}
}
@@ -286,8 +286,10 @@ public:
bool checkProxy(const QHostAddress &address);
bool fetchConnectionParameters();
+#if QT_CONFIG(networkinterface)
static uint scopeIdFromString(const QString &scopeid)
{ return QNetworkInterface::interfaceIndexFromName(scopeid); }
+#endif
/*! \internal
Sets \a address and \a port in the \a aa sockaddr structure and the size in \a sockAddrSize.
@@ -301,7 +303,9 @@ public:
|| socketProtocol == QAbstractSocket::AnyIPProtocol) {
memset(&aa->a6, 0, sizeof(sockaddr_in6));
aa->a6.sin6_family = AF_INET6;
+#if QT_CONFIG(networkinterface)
aa->a6.sin6_scope_id = scopeIdFromString(address.scopeId());
+#endif
aa->a6.sin6_port = htons(port);
Q_IPV6ADDR tmp = address.toIPv6Address();
memcpy(&aa->a6.sin6_addr, &tmp, sizeof(tmp));
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index e140b33ce9..3cf65b3553 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -121,8 +121,10 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po
QHostAddress tmpAddress;
tmpAddress.setAddress(tmp);
*addr = tmpAddress;
+#if QT_CONFIG(networkinterface)
if (s->a6.sin6_scope_id)
addr->setScopeId(QNetworkInterface::interfaceNameFromIndex(s->a6.sin6_scope_id));
+#endif
}
if (port)
*port = ntohs(s->a6.sin6_port);
@@ -985,7 +987,8 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
if (cmsgptr->cmsg_len == CMSG_LEN(sizeof(int))
&& ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT)
|| (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) {
- header->hopLimit = *reinterpret_cast<int *>(CMSG_DATA(cmsgptr));
+ Q_STATIC_ASSERT(sizeof(header->hopLimit) == sizeof(int));
+ memcpy(&header->hopLimit, CMSG_DATA(cmsgptr), sizeof(header->hopLimit));
}
#ifndef QT_NO_SCTP
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index e203571a63..28aea6be3d 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -51,6 +51,7 @@
#include <qdebug.h>
#include <qdatetime.h>
#include <qnetworkinterface.h>
+#include <qoperatingsystemversion.h>
//#define QNATIVESOCKETENGINE_DEBUG
#if defined(QNATIVESOCKETENGINE_DEBUG)
@@ -334,11 +335,9 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
return false;
}
- QSysInfo::WinVersion osver = QSysInfo::windowsVersion();
-
//Windows XP and 2003 support IPv6 but not dual stack sockets
int protocol = (socketProtocol == QAbstractSocket::IPv6Protocol
- || (socketProtocol == QAbstractSocket::AnyIPProtocol && osver >= QSysInfo::WV_6_0)) ? AF_INET6 : AF_INET;
+ || (socketProtocol == QAbstractSocket::AnyIPProtocol)) ? AF_INET6 : AF_INET;
int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM;
// MSDN KB179942 states that on winnt 4 WSA_FLAG_OVERLAPPED is needed if socket is to be non blocking
@@ -350,14 +349,11 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc
#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
#endif
- SOCKET socket = INVALID_SOCKET;
- // Windows 7 or later, try the new API
- if ((osver & QSysInfo::WV_NT_based) >= QSysInfo::WV_6_1)
- socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
+ SOCKET socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
// previous call fails if the windows 7 service pack 1 or hot fix isn't installed.
- // Try the old API if the new one failed on Windows 7, or always on earlier versions
- if (socket == INVALID_SOCKET && ((osver & QSysInfo::WV_NT_based) <= QSysInfo::WV_6_1)) {
+ // Try the old API if the new one failed on Windows 7
+ if (socket == INVALID_SOCKET && QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) {
socket = ::WSASocket(protocol, type, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
#ifdef HANDLE_FLAG_INHERIT
if (socket != INVALID_SOCKET) {
diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp
index 8b36406c67..7b20b47aa9 100644
--- a/src/network/socket/qnativesocketengine_winrt.cpp
+++ b/src/network/socket/qnativesocketengine_winrt.cpp
@@ -779,7 +779,6 @@ void QNativeSocketEngine::close()
}
}
-#if _MSC_VER >= 1900
if (d->socketType == QAbstractSocket::TcpSocket) {
hr = QEventDispatcherWinRT::runOnXamlThread([d]() {
HRESULT hr;
@@ -803,7 +802,6 @@ void QNativeSocketEngine::close()
});
Q_ASSERT_SUCCEEDED(hr);
}
-#endif // _MSC_VER >= 1900
if (d->socketDescriptor != -1) {
ComPtr<IClosable> socket;
diff --git a/src/network/socket/qsctpserver.h b/src/network/socket/qsctpserver.h
index f39257485d..1afdab28a0 100644
--- a/src/network/socket/qsctpserver.h
+++ b/src/network/socket/qsctpserver.h
@@ -45,7 +45,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_SCTP
+#if !defined(QT_NO_SCTP) || defined(Q_CLANG_QDOC)
class QSctpServerPrivate;
class QSctpSocket;
diff --git a/src/network/socket/qsctpsocket.h b/src/network/socket/qsctpsocket.h
index 3e5a545c4b..9bed1890ff 100644
--- a/src/network/socket/qsctpsocket.h
+++ b/src/network/socket/qsctpsocket.h
@@ -45,7 +45,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_SCTP
+#if !defined(QT_NO_SCTP) || defined(Q_CLANG_QDOC)
class QSctpSocketPrivate;
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 6db09f94cf..2847b910f3 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -54,6 +54,7 @@
#include "qurl.h"
#include "qauthenticator.h"
#include "private/qiodevice_p.h"
+#include "private/qringbuffer_p.h"
#include <qendian.h>
#include <qnetworkinterface.h>
@@ -280,7 +281,7 @@ struct QSocks5Data
struct QSocks5ConnectData : public QSocks5Data
{
- QByteArray readBuffer;
+ QRingBuffer readBuffer;
};
struct QSocks5BindData : public QSocks5Data
@@ -1001,13 +1002,17 @@ QSocks5SocketEngine::~QSocks5SocketEngine()
delete d->bindData;
}
-static QBasicAtomicInt descriptorCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
+static int nextDescriptor()
+{
+ static QBasicAtomicInt counter;
+ return 1 + counter.fetchAndAddRelaxed(1);
+}
bool QSocks5SocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol)
{
Q_D(QSocks5SocketEngine);
- d->socketDescriptor = descriptorCounter.fetchAndAddRelaxed(1);
+ d->socketDescriptor = nextDescriptor();
d->socketType = type;
d->socketProtocol = protocol;
@@ -1193,7 +1198,7 @@ void QSocks5SocketEnginePrivate::_q_controlSocketReadNotification()
}
if (buf.size()) {
QSOCKS5_DEBUG << dump(buf);
- connectData->readBuffer += buf;
+ connectData->readBuffer.append(buf);
emitReadNotification();
}
break;
@@ -1506,7 +1511,7 @@ qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
Q_D(QSocks5SocketEngine);
QSOCKS5_Q_DEBUG << "read( , maxlen = " << maxlen << ')';
if (d->mode == QSocks5SocketEnginePrivate::ConnectMode) {
- if (d->connectData->readBuffer.size() == 0) {
+ if (d->connectData->readBuffer.isEmpty()) {
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
//imitate remote closed
close();
@@ -1518,9 +1523,7 @@ qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
return 0; // nothing to be read
}
}
- qint64 copy = qMin<qint64>(d->connectData->readBuffer.size(), maxlen);
- memcpy(data, d->connectData->readBuffer.constData(), copy);
- d->connectData->readBuffer.remove(0, copy);
+ const qint64 copy = d->connectData->readBuffer.read(data, maxlen);
QSOCKS5_DEBUG << "read" << dump(QByteArray(data, copy));
return copy;
#ifndef QT_NO_UDPSOCKET
diff --git a/src/network/ssl/qssldiffiehellmanparameters.cpp b/src/network/ssl/qssldiffiehellmanparameters.cpp
index de7eab9a9e..cb6c474861 100644
--- a/src/network/ssl/qssldiffiehellmanparameters.cpp
+++ b/src/network/ssl/qssldiffiehellmanparameters.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
diff --git a/src/network/ssl/qssldiffiehellmanparameters.h b/src/network/ssl/qssldiffiehellmanparameters.h
index 4533ea4ed2..497d2bebfb 100644
--- a/src/network/ssl/qssldiffiehellmanparameters.h
+++ b/src/network/ssl/qssldiffiehellmanparameters.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
diff --git a/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp b/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp
index 220c017f4c..8fcf141f73 100644
--- a/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp
+++ b/src/network/ssl/qssldiffiehellmanparameters_dummy.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
diff --git a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp b/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
index 949da1b7df..90687b05c5 100644
--- a/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
+++ b/src/network/ssl/qssldiffiehellmanparameters_openssl.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
diff --git a/src/network/ssl/qssldiffiehellmanparameters_p.h b/src/network/ssl/qssldiffiehellmanparameters_p.h
index 06ecf292ff..dd69895dae 100644
--- a/src/network/ssl/qssldiffiehellmanparameters_p.h
+++ b/src/network/ssl/qssldiffiehellmanparameters_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
diff --git a/src/network/ssl/qsslerror.cpp b/src/network/ssl/qsslerror.cpp
index c779651959..3f79d1a037 100644
--- a/src/network/ssl/qsslerror.cpp
+++ b/src/network/ssl/qsslerror.cpp
@@ -105,13 +105,13 @@ public:
QSslCertificate certificate;
};
+// RVCT compiler in debug build does not like about default values in const-
+// So as an workaround we define all constructor overloads here explicitly
/*!
Constructs a QSslError object with no error and default certificate.
*/
-// RVCT compiler in debug build does not like about default values in const-
-// So as an workaround we define all constructor overloads here explicitly
QSslError::QSslError()
: d(new QSslErrorPrivate)
{
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 166907780b..84b8f3a8d9 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -835,7 +835,6 @@ bool QSslSocket::atEnd() const
\sa write(), waitForBytesWritten()
*/
-// Note! docs copied from QAbstractSocket::flush()
bool QSslSocket::flush()
{
return d_func()->flush();
@@ -973,6 +972,13 @@ QList<QSslCertificate> QSslSocket::localCertificateChain() const
sockets, but are also rarely used by client sockets if the server requires
the client to authenticate.
+ \note Secure Transport SSL backend on macOS may update the default keychain
+ (the default is probably your login keychain) by importing your local certificates
+ and keys. This can also result in system dialogs showing up and asking for
+ permission when your application is using these private keys. If such behavior
+ is undesired, set the QT_SSL_USE_TEMPORARY_KEYCHAIN environment variable to a
+ non-zero value; this will prompt QSslSocket to use its own temporary keychain.
+
\sa localCertificate(), setPrivateKey()
*/
void QSslSocket::setLocalCertificate(const QSslCertificate &certificate)
diff --git a/src/network/ssl/qsslsocket_mac.cpp b/src/network/ssl/qsslsocket_mac.cpp
index 0548aa3909..a2dee75895 100644
--- a/src/network/ssl/qsslsocket_mac.cpp
+++ b/src/network/ssl/qsslsocket_mac.cpp
@@ -53,9 +53,12 @@
#include <QtCore/qvector.h>
#include <QtCore/qmutex.h>
#include <QtCore/qdebug.h>
+#include <QtCore/quuid.h>
+#include <QtCore/qdir.h>
#include <algorithm>
#include <cstddef>
+#include <vector>
#include <QtCore/private/qcore_mac_p.h>
@@ -65,6 +68,102 @@
QT_BEGIN_NAMESPACE
+namespace
+{
+#ifdef Q_OS_MACOS
+/*
+
+Our own temporarykeychain is needed only on macOS where SecPKCS12Import changes
+the default keychain and where we see annoying pop-ups asking about accessing a
+private key.
+
+*/
+
+struct EphemeralSecKeychain
+{
+ EphemeralSecKeychain();
+ ~EphemeralSecKeychain();
+
+ SecKeychainRef keychain = nullptr;
+ Q_DISABLE_COPY(EphemeralSecKeychain)
+};
+
+EphemeralSecKeychain::EphemeralSecKeychain()
+{
+ const auto uuid = QUuid::createUuid();
+ if (uuid.isNull()) {
+ qCWarning(lcSsl) << "Failed to create an unique keychain name";
+ return;
+ }
+
+ QString uuidAsString(uuid.toString());
+ Q_ASSERT(uuidAsString.size() > 2);
+ Q_ASSERT(uuidAsString.startsWith(QLatin1Char('{'))
+ && uuidAsString.endsWith(QLatin1Char('}')));
+ uuidAsString = uuidAsString.mid(1, uuidAsString.size() - 2);
+
+ QString keychainName(QDir::tempPath());
+ keychainName.append(QDir::separator());
+ keychainName += uuidAsString;
+ keychainName += QLatin1String(".keychain");
+ // SecKeychainCreate, pathName parameter:
+ //
+ // "A constant character string representing the POSIX path indicating where
+ // to store the keychain."
+ //
+ // Internally they seem to use std::string, but this does not really help.
+ // Fortunately, CFString has a convenient API.
+ QCFType<CFStringRef> cfName = keychainName.toCFString();
+ std::vector<char> posixPath;
+ // "Extracts the contents of a string as a NULL-terminated 8-bit string
+ // appropriate for passing to POSIX APIs."
+ posixPath.resize(CFStringGetMaximumSizeOfFileSystemRepresentation(cfName));
+ const auto ok = CFStringGetFileSystemRepresentation(cfName, &posixPath[0],
+ CFIndex(posixPath.size()));
+ if (!ok) {
+ qCWarning(lcSsl) << "Failed to create a unique keychain name from"
+ << "QDir::tempPath()";
+ return;
+ }
+
+ std::vector<uint8_t> passUtf8(256);
+ if (SecRandomCopyBytes(kSecRandomDefault, passUtf8.size(), &passUtf8[0])) {
+ qCWarning(lcSsl) << "SecRandomCopyBytes: failed to create a key";
+ return;
+ }
+
+ const OSStatus status = SecKeychainCreate(&posixPath[0], passUtf8.size(),
+ &passUtf8[0], FALSE, nullptr,
+ &keychain);
+ if (status != errSecSuccess || !keychain) {
+ qCWarning(lcSsl) << "SecKeychainCreate: failed to create a custom keychain";
+ if (keychain) {
+ SecKeychainDelete(keychain);
+ CFRelease(keychain);
+ keychain = nullptr;
+ }
+ }
+
+#ifdef QSSLSOCKET_DEBUG
+ if (keychain) {
+ qCDebug(lcSsl) << "Custom keychain with name" << keychainName << "was created"
+ << "successfully";
+ }
+#endif
+}
+
+EphemeralSecKeychain::~EphemeralSecKeychain()
+{
+ if (keychain) {
+ // clear file off disk
+ SecKeychainDelete(keychain);
+ CFRelease(keychain);
+ }
+}
+
+#endif // Q_OS_MACOS
+}
+
static SSLContextRef qt_createSecureTransportContext(QSslSocket::SslMode mode)
{
const bool isServer = mode == QSslSocket::SslServerMode;
@@ -82,98 +181,6 @@ static void qt_releaseSecureTransportContext(SSLContextRef context)
CFRelease(context);
}
-static bool qt_setSessionProtocol(SSLContextRef context, const QSslConfigurationPrivate &configuration,
- QTcpSocket *plainSocket)
-{
- Q_ASSERT(context);
-
-#ifndef QSSLSOCKET_DEBUG
- Q_UNUSED(plainSocket)
-#endif
-
- OSStatus err = noErr;
-
- if (configuration.protocol == QSsl::SslV3) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : SSLv3";
- #endif
- err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kSSLProtocol3);
- } else if (configuration.protocol == QSsl::TlsV1_0) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.0";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
- } else if (configuration.protocol == QSsl::TlsV1_1) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
- } else if (configuration.protocol == QSsl::TlsV1_2) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::AnyProtocol) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : any";
- #endif
- // kSSLProtocol3, since kSSLProtocol2 is disabled:
- err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::TlsV1SslV3) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : SSLv3 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::SecureProtocols) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::TlsV1_0OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::TlsV1_1OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else if (configuration.protocol == QSsl::TlsV1_2OrLater) {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
- #endif
- err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
- if (err == noErr)
- err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
- } else {
- #ifdef QSSLSOCKET_DEBUG
- qCDebug(lcSsl) << plainSocket << "no protocol version found in the configuration";
- #endif
- return false;
- }
-
- return err == noErr;
-}
-
QSecureTransportContext::QSecureTransportContext(SSLContextRef c)
: context(c)
{
@@ -568,6 +575,7 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSui
{
QSslCipher ciph;
switch (cipher) {
+ // Sorted as in CipherSuite.h (and groupped by their RFC)
case SSL_RSA_WITH_NULL_MD5:
ciph.d->name = QLatin1String("NULL-MD5");
ciph.d->protocol = QSsl::SslV3;
@@ -585,38 +593,21 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSui
ciph.d->protocol = QSsl::SslV3;
break;
- case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("DES-CBC3-SHA");
- break;
+ // TLS addenda using AES, per RFC 3268
case TLS_RSA_WITH_AES_128_CBC_SHA:
ciph.d->name = QLatin1String("AES128-SHA");
break;
- case TLS_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("AES128-SHA256");
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("AES256-SHA");
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- ciph.d->name = QLatin1String("AES256-SHA256");
- break;
-
- case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("DHE-RSA-DES-CBC3-SHA");
- break;
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
ciph.d->name = QLatin1String("DHE-RSA-AES128-SHA");
break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("DHE-RSA-AES128-SHA256");
+ case TLS_RSA_WITH_AES_256_CBC_SHA:
+ ciph.d->name = QLatin1String("AES256-SHA");
break;
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
ciph.d->name = QLatin1String("DHE-RSA-AES256-SHA");
break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
- ciph.d->name = QLatin1String("DHE-RSA-AES256-SHA256");
- break;
+ // ECDSA addenda, RFC 4492
case TLS_ECDH_ECDSA_WITH_NULL_SHA:
ciph.d->name = QLatin1String("ECDH-ECDSA-NULL-SHA");
break;
@@ -629,21 +620,29 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSui
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
ciph.d->name = QLatin1String("ECDH-ECDSA-AES128-SHA");
break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES128-SHA256");
- break;
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
ciph.d->name = QLatin1String("ECDH-ECDSA-AES256-SHA");
break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDH-ECDSA-AES256-SHA384");
+ case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ ciph.d->name = QLatin1String("ECDHE-ECDSA-NULL-SHA");
+ break;
+ case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ ciph.d->name = QLatin1String("ECDHE-ECDSA-RC4-SHA");
+ break;
+ case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ ciph.d->name = QLatin1String("ECDHE-ECDSA-DES-CBC3-SHA");
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ ciph.d->name = QLatin1String("ECDHE-ECDSA-AES128-SHA");
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ ciph.d->name = QLatin1String("ECDHE-ECDSA-AES256-SHA");
break;
-
case TLS_ECDH_RSA_WITH_NULL_SHA:
ciph.d->name = QLatin1String("ECDH-RSA-NULL-SHA");
break;
case TLS_ECDH_RSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDH-RSA-AES256-SHA");
+ ciph.d->name = QLatin1String("ECDH-RSA-RC4-SHA");
break;
case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
ciph.d->name = QLatin1String("ECDH-RSA-DES-CBC3-SHA");
@@ -651,62 +650,91 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSLCipherSuite(SSLCipherSui
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
ciph.d->name = QLatin1String("ECDH-RSA-AES128-SHA");
break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDH-RSA-AES128-SHA256");
- break;
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
ciph.d->name = QLatin1String("ECDH-RSA-AES256-SHA");
break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDH-RSA-AES256-SHA384");
+ case TLS_ECDHE_RSA_WITH_NULL_SHA:
+ ciph.d->name = QLatin1String("ECDHE-RSA-NULL-SHA");
+ break;
+ case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ ciph.d->name = QLatin1String("ECDHE-RSA-RC4-SHA");
+ break;
+ case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ ciph.d->name = QLatin1String("ECDHE-RSA-DES-CBC3-SHA");
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ ciph.d->name = QLatin1String("ECDHE-RSA-AES128-SHA");
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ ciph.d->name = QLatin1String("ECDHE-RSA-AES256-SHA");
break;
- case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-NULL-SHA");
+ // TLS 1.2 addenda, RFC 5246
+ case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ ciph.d->name = QLatin1String("DES-CBC3-SHA");
break;
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-RC4-SHA");
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ ciph.d->name = QLatin1String("AES128-SHA256");
break;
- case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-DES-CBC3-SHA");
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ ciph.d->name = QLatin1String("AES256-SHA256");
break;
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES128-SHA");
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ ciph.d->name = QLatin1String("DHE-RSA-DES-CBC3-SHA");
break;
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES128-SHA256");
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ ciph.d->name = QLatin1String("DHE-RSA-AES128-SHA256");
break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES256-SHA");
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ ciph.d->name = QLatin1String("DHE-RSA-AES256-SHA256");
break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- ciph.d->name = QLatin1String("ECDHE-ECDSA-AES256-SHA384");
+
+ // Addendum from RFC 4279, TLS PSK
+ // all missing atm.
+
+ // RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption
+ // all missing atm.
+
+ // Addenda from rfc 5288 AES Galois Counter Mode (CGM) Cipher Suites for TLS
+ case TLS_RSA_WITH_AES_256_GCM_SHA384:
+ ciph.d->name = QLatin1String("AES256-GCM-SHA384");
break;
- case TLS_ECDHE_RSA_WITH_NULL_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-NULL-SHA");
+ // RFC 5487 - PSK with SHA-256/384 and AES GCM
+ // all missing atm.
+
+ // Addenda from rfc 5289 Elliptic Curve Cipher Suites with HMAC SHA-256/384
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ ciph.d->name = QLatin1String("ECDHE-ECDSA-AES128-SHA256");
break;
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES256-SHA");
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ ciph.d->name = QLatin1String("ECDHE-ECDSA-AES256-SHA384");
break;
- case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-DES-CBC3-SHA");
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ ciph.d->name = QLatin1String("ECDH-ECDSA-AES128-SHA256");
break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES128-SHA");
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ ciph.d->name = QLatin1String("ECDH-ECDSA-AES256-SHA384");
break;
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
ciph.d->name = QLatin1String("ECDHE-RSA-AES128-SHA256");
break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- ciph.d->name = QLatin1String("ECDHE-RSA-AES256-SHA");
- break;
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
ciph.d->name = QLatin1String("ECDHE-RSA-AES256-SHA384");
break;
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ ciph.d->name = QLatin1String("ECDH-RSA-AES128-SHA256");
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ ciph.d->name = QLatin1String("ECDH-RSA-AES256-SHA384");
+ break;
+
+ // Addenda from rfc 5289 Elliptic Curve Cipher Suites
+ // with SHA-256/384 and AES Galois Counter Mode (GCM)
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
ciph.d->name = QLatin1String("ECDHE-RSA-AES256-GCM-SHA384");
break;
+
default:
return ciph;
}
@@ -886,11 +914,24 @@ bool QSslSocketBackendPrivate::setSessionCertificate(QString &errorDescription,
QCFType<CFDataRef> pkcs12 = _q_makePkcs12(configuration.localCertificateChain,
configuration.privateKey, passPhrase).toCFData();
QCFType<CFStringRef> password = passPhrase.toCFString();
- const void *keys[] = { kSecImportExportPassphrase };
- const void *values[] = { password };
- QCFType<CFDictionaryRef> options(CFDictionaryCreate(Q_NULLPTR, keys, values, 1,
- Q_NULLPTR, Q_NULLPTR));
- CFArrayRef items = Q_NULLPTR;
+ const void *keys[2] = { kSecImportExportPassphrase };
+ const void *values[2] = { password };
+ CFIndex nKeys = 1;
+#ifdef Q_OS_MACOS
+ bool envOk = false;
+ const int env = qEnvironmentVariableIntValue("QT_SSL_USE_TEMPORARY_KEYCHAIN", &envOk);
+ if (envOk && env) {
+ static const EphemeralSecKeychain temporaryKeychain;
+ if (temporaryKeychain.keychain) {
+ nKeys = 2;
+ keys[1] = kSecImportExportKeychain;
+ values[1] = temporaryKeychain.keychain;
+ }
+ }
+#endif
+ QCFType<CFDictionaryRef> options = CFDictionaryCreate(nullptr, keys, values, nKeys,
+ nullptr, nullptr);
+ CFArrayRef items = nullptr;
OSStatus err = SecPKCS12Import(pkcs12, options, &items);
if (err != noErr) {
#ifdef QSSLSOCKET_DEBUG
@@ -922,7 +963,7 @@ bool QSslSocketBackendPrivate::setSessionCertificate(QString &errorDescription,
return false;
}
- QCFType<CFMutableArrayRef> certs = CFArrayCreateMutable(Q_NULLPTR, 0, &kCFTypeArrayCallBacks);
+ QCFType<CFMutableArrayRef> certs = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
if (!certs) {
errorCode = QAbstractSocket::SslInternalError;
errorDescription = QStringLiteral("Failed to allocate certificates array");
@@ -956,7 +997,7 @@ bool QSslSocketBackendPrivate::setSessionProtocol()
{
Q_ASSERT_X(context, Q_FUNC_INFO, "invalid SSL context (null)");
- // QSsl::SslV2 == kSSLProtocol2 is disabled in secure transport and
+ // QSsl::SslV2 == kSSLProtocol2 is disabled in Secure Transport and
// always fails with errSSLIllegalParam:
// if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION)
// return errSSLIllegalParam;
@@ -966,7 +1007,87 @@ bool QSslSocketBackendPrivate::setSessionProtocol()
return false;
}
- return qt_setSessionProtocol(context, configuration, plainSocket);
+ OSStatus err = noErr;
+
+ if (configuration.protocol == QSsl::SslV3) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : SSLv3";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kSSLProtocol3);
+ } else if (configuration.protocol == QSsl::TlsV1_0) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.0";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol1);
+ } else if (configuration.protocol == QSsl::TlsV1_1) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol11);
+ } else if (configuration.protocol == QSsl::TlsV1_2) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::AnyProtocol) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : any";
+ #endif
+ // kSSLProtocol3, since kSSLProtocol2 is disabled:
+ err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::TlsV1SslV3) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : SSLv3 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kSSLProtocol3);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::SecureProtocols) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::TlsV1_0OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol1);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::TlsV1_1OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.1 - TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol11);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else if (configuration.protocol == QSsl::TlsV1_2OrLater) {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "requesting : TLSv1.2";
+ #endif
+ err = SSLSetProtocolVersionMin(context, kTLSProtocol12);
+ if (err == noErr)
+ err = SSLSetProtocolVersionMax(context, kTLSProtocol12);
+ } else {
+ #ifdef QSSLSOCKET_DEBUG
+ qCDebug(lcSsl) << plainSocket << "no protocol version found in the configuration";
+ #endif
+ return false;
+ }
+
+ return err == noErr;
}
bool QSslSocketBackendPrivate::canIgnoreTrustVerificationFailure() const
diff --git a/src/network/ssl/qsslsocket_winrt.cpp b/src/network/ssl/qsslsocket_winrt.cpp
index f5dc9fcdcd..ca65f8a015 100644
--- a/src/network/ssl/qsslsocket_winrt.cpp
+++ b/src/network/ssl/qsslsocket_winrt.cpp
@@ -181,13 +181,7 @@ long QSslSocketPrivate::sslLibraryVersionNumber()
QString QSslSocketPrivate::sslLibraryVersionString()
{
- switch (QSysInfo::windowsVersion()) {
- case QSysInfo::WV_WINDOWS8_1:
- return QStringLiteral("Windows Runtime 8.1 SSL library");
- default:
- break;
- }
- return QStringLiteral("Windows Runtime SSL library");
+ return QStringLiteral("Windows Runtime, ") + QSysInfo::prettyProductName();
}
long QSslSocketPrivate::sslLibraryBuildVersionNumber()
diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
index 047b681bcb..d5ce4efd1a 100644
--- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
+++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
@@ -45,7 +45,11 @@
QT_BEGIN_NAMESPACE
-QBasicAtomicInt qgltextureglyphcache_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1);
+static int next_qgltextureglyphcache_serial_number()
+{
+ static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0);
+ return 1 + serial.fetchAndAddRelaxed(1);
+}
QGLTextureGlyphCache::QGLTextureGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix)
: QImageTextureGlyphCache(format, matrix)
@@ -53,7 +57,7 @@ QGLTextureGlyphCache::QGLTextureGlyphCache(QFontEngine::GlyphFormat format, cons
, pex(0)
, m_blitProgram(0)
, m_filterMode(Nearest)
- , m_serialNumber(qgltextureglyphcache_serial_number.fetchAndAddRelaxed(1))
+ , m_serialNumber(next_qgltextureglyphcache_serial_number())
{
#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, QOpenGLContext::currentContext());
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index a97ddb2b27..ab418c191a 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -51,6 +51,15 @@
#include <QtGui/QSurfaceFormat>
+#if defined(Q_CLANG_QDOC)
+#undef GLint
+typedef int GLint;
+#undef GLuint
+typedef unsigned int GLuint;
+#undef GLenum
+typedef unsigned int GLenum;
+#endif
+
QT_BEGIN_NAMESPACE
diff --git a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h
index d0826bdb50..e51c2fde67 100644
--- a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h
+++ b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.h
@@ -90,6 +90,15 @@ public:
if (func)
func(behavior);
}
+
+ typedef bool (*IsTabletModeType)();
+ static const QByteArray isTabletModeIdentifier() { return QByteArrayLiteral("WindowsIsTabletMode"); }
+
+ static bool isTabletMode()
+ {
+ IsTabletModeType func = reinterpret_cast<IsTabletModeType>(QGuiApplication::platformFunction(isTabletModeIdentifier()));
+ return func && func();
+ }
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowsWindowFunctions::TouchWindowTouchTypes)
diff --git a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc
index 24e4847042..898b1bbb29 100644
--- a/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc
+++ b/src/platformheaders/windowsfunctions/qwindowswindowfunctions.qdoc
@@ -144,3 +144,35 @@
\sa QWidget::activateWindow(), QWindow::requestActivate()
\since 5.7
*/
+
+/*!
+ \typedef QWindowsWindowFunctions::IsTabletModeType
+
+ This is the typedef for the function returned by QGuiApplication::platformFunction()
+ when passed isTabletModeIdentifier().
+
+ \since 5.9
+*/
+
+/*!
+ \fn QByteArray QWindowsWindowFunctions::isTabletModeIdentifier()
+
+ Returns a bytearray that can be used to query
+ QGuiApplication::platformFunction() to retrieve the IsTabletModeType
+ function.
+
+ \since 5.9
+*/
+
+/*!
+ \fn bool QWindowsWindowFunctions::isTabletMode()
+
+ This is a convenience function that can be used directly instead of resolving
+ the function pointer. The function can be used to query whether Windows 10
+ operates in \e{Tablet Mode}. In this mode, Windows forces all application
+ main windows to open in maximized state. Applications should then avoid
+ resizing windows or restoring geometries to non-maximized states.
+
+ \sa QWidget::showMaximized(), QWidget::saveGeometry(), QWidget::restoreGeometry()
+ \since 5.9
+*/
diff --git a/src/platformheaders/xcbfunctions/qxcbscreenfunctions.h b/src/platformheaders/xcbfunctions/qxcbscreenfunctions.h
index 7773c275b9..99624bd5d6 100644
--- a/src/platformheaders/xcbfunctions/qxcbscreenfunctions.h
+++ b/src/platformheaders/xcbfunctions/qxcbscreenfunctions.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_p.h b/src/platformsupport/devicediscovery/qdevicediscovery_p.h
index d4962fb7d6..e3c22b0b37 100644
--- a/src/platformsupport/devicediscovery/qdevicediscovery_p.h
+++ b/src/platformsupport/devicediscovery/qdevicediscovery_p.h
@@ -68,7 +68,6 @@ QT_BEGIN_NAMESPACE
class QDeviceDiscovery : public QObject
{
Q_OBJECT
- Q_ENUMS(QDeviceType)
public:
enum QDeviceType {
@@ -84,6 +83,7 @@ public:
Device_InputMask = Device_Mouse | Device_Touchpad | Device_Touchscreen | Device_Keyboard | Device_Tablet | Device_Joystick,
Device_VideoMask = Device_DRM
};
+ Q_ENUM(QDeviceType)
Q_DECLARE_FLAGS(QDeviceTypes, QDeviceType)
static QDeviceDiscovery *create(QDeviceTypes type, QObject *parent = 0);
diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp b/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp
index 5c72dbe7e2..a1575677f5 100644
--- a/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp
+++ b/src/platformsupport/devicediscovery/qdevicediscovery_static.cpp
@@ -47,7 +47,11 @@
#include <QLoggingCategory>
#include <QtCore/private/qcore_unix_p.h>
+#ifdef Q_OS_FREEBSD
+#include <dev/evdev/input.h>
+#else
#include <linux/input.h>
+#endif
#include <fcntl.h>
/* android (and perhaps some other linux-derived stuff) don't define everything
diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp
index da41cfeabf..020d035bf7 100644
--- a/src/platformsupport/eglconvenience/qeglconvenience.cpp
+++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp
@@ -100,18 +100,24 @@ QVector<EGLint> q_createConfigAttributesFromFormat(const QSurfaceFormat &format)
configAttributes.append(EGL_ALPHA_SIZE);
configAttributes.append(alphaSize > 0 ? alphaSize : 0);
- configAttributes.append(EGL_DEPTH_SIZE);
- configAttributes.append(depthSize > 0 ? depthSize : 0);
-
- configAttributes.append(EGL_STENCIL_SIZE);
- configAttributes.append(stencilSize > 0 ? stencilSize : 0);
-
configAttributes.append(EGL_SAMPLES);
configAttributes.append(sampleCount > 0 ? sampleCount : 0);
configAttributes.append(EGL_SAMPLE_BUFFERS);
configAttributes.append(sampleCount > 0);
+ if (format.renderableType() != QSurfaceFormat::OpenVG) {
+ configAttributes.append(EGL_DEPTH_SIZE);
+ configAttributes.append(depthSize > 0 ? depthSize : 0);
+
+ configAttributes.append(EGL_STENCIL_SIZE);
+ configAttributes.append(stencilSize > 0 ? stencilSize : 0);
+ } else {
+ // OpenVG needs alpha mask for clipping
+ configAttributes.append(EGL_ALPHA_MASK_SIZE);
+ configAttributes.append(8);
+ }
+
return configAttributes;
}
diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp
index 6a3bc25418..674ab29012 100644
--- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp
+++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp
@@ -167,6 +167,13 @@ void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLCont
: EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
}
}
+
+ // Special Options for OpenVG surfaces
+ if (m_format.renderableType() == QSurfaceFormat::OpenVG) {
+ contextAttrs.append(EGL_ALPHA_MASK_SIZE);
+ contextAttrs.append(8);
+ }
+
contextAttrs.append(EGL_NONE);
m_contextAttrs = contextAttrs;
@@ -450,7 +457,352 @@ QFunctionPointer QEGLPlatformContext::getProcAddress(const char *procName)
#if !defined(Q_OS_WIN) && !defined(Q_OS_INTEGRITY)
if (!proc)
proc = (QFunctionPointer) dlsym(RTLD_DEFAULT, procName);
+#elif !defined(QT_OPENGL_DYNAMIC)
+ // On systems without KHR_get_all_proc_addresses and without
+ // dynamic linking there still has to be a way to access the
+ // standard GLES functions. QOpenGL(Extra)Functions never makes
+ // direct GL API calls since Qt 5.7, so all such workarounds are
+ // expected to be handled in the platform plugin.
+ if (!proc) {
+ static struct StdFunc {
+ const char *name;
+ QFunctionPointer func;
+ } standardFuncs[] = {
+#ifdef QT_OPENGL_ES_2
+ { "glBindTexture", (QFunctionPointer) ::glBindTexture },
+ { "glBlendFunc", (QFunctionPointer) ::glBlendFunc },
+ { "glClear", (QFunctionPointer) ::glClear },
+ { "glClearColor", (QFunctionPointer) ::glClearColor },
+ { "glClearStencil", (QFunctionPointer) ::glClearStencil },
+ { "glColorMask", (QFunctionPointer) ::glColorMask },
+ { "glCopyTexImage2D", (QFunctionPointer) ::glCopyTexImage2D },
+ { "glCopyTexSubImage2D", (QFunctionPointer) ::glCopyTexSubImage2D },
+ { "glCullFace", (QFunctionPointer) ::glCullFace },
+ { "glDeleteTextures", (QFunctionPointer) ::glDeleteTextures },
+ { "glDepthFunc", (QFunctionPointer) ::glDepthFunc },
+ { "glDepthMask", (QFunctionPointer) ::glDepthMask },
+ { "glDisable", (QFunctionPointer) ::glDisable },
+ { "glDrawArrays", (QFunctionPointer) ::glDrawArrays },
+ { "glDrawElements", (QFunctionPointer) ::glDrawElements },
+ { "glEnable", (QFunctionPointer) ::glEnable },
+ { "glFinish", (QFunctionPointer) ::glFinish },
+ { "glFlush", (QFunctionPointer) ::glFlush },
+ { "glFrontFace", (QFunctionPointer) ::glFrontFace },
+ { "glGenTextures", (QFunctionPointer) ::glGenTextures },
+ { "glGetBooleanv", (QFunctionPointer) ::glGetBooleanv },
+ { "glGetError", (QFunctionPointer) ::glGetError },
+ { "glGetFloatv", (QFunctionPointer) ::glGetFloatv },
+ { "glGetIntegerv", (QFunctionPointer) ::glGetIntegerv },
+ { "glGetString", (QFunctionPointer) ::glGetString },
+ { "glGetTexParameterfv", (QFunctionPointer) ::glGetTexParameterfv },
+ { "glGetTexParameteriv", (QFunctionPointer) ::glGetTexParameteriv },
+ { "glHint", (QFunctionPointer) ::glHint },
+ { "glIsEnabled", (QFunctionPointer) ::glIsEnabled },
+ { "glIsTexture", (QFunctionPointer) ::glIsTexture },
+ { "glLineWidth", (QFunctionPointer) ::glLineWidth },
+ { "glPixelStorei", (QFunctionPointer) ::glPixelStorei },
+ { "glPolygonOffset", (QFunctionPointer) ::glPolygonOffset },
+ { "glReadPixels", (QFunctionPointer) ::glReadPixels },
+ { "glScissor", (QFunctionPointer) ::glScissor },
+ { "glStencilFunc", (QFunctionPointer) ::glStencilFunc },
+ { "glStencilMask", (QFunctionPointer) ::glStencilMask },
+ { "glStencilOp", (QFunctionPointer) ::glStencilOp },
+ { "glTexImage2D", (QFunctionPointer) ::glTexImage2D },
+ { "glTexParameterf", (QFunctionPointer) ::glTexParameterf },
+ { "glTexParameterfv", (QFunctionPointer) ::glTexParameterfv },
+ { "glTexParameteri", (QFunctionPointer) ::glTexParameteri },
+ { "glTexParameteriv", (QFunctionPointer) ::glTexParameteriv },
+ { "glTexSubImage2D", (QFunctionPointer) ::glTexSubImage2D },
+ { "glViewport", (QFunctionPointer) ::glViewport },
+
+ { "glActiveTexture", (QFunctionPointer) ::glActiveTexture },
+ { "glAttachShader", (QFunctionPointer) ::glAttachShader },
+ { "glBindAttribLocation", (QFunctionPointer) ::glBindAttribLocation },
+ { "glBindBuffer", (QFunctionPointer) ::glBindBuffer },
+ { "glBindFramebuffer", (QFunctionPointer) ::glBindFramebuffer },
+ { "glBindRenderbuffer", (QFunctionPointer) ::glBindRenderbuffer },
+ { "glBlendColor", (QFunctionPointer) ::glBlendColor },
+ { "glBlendEquation", (QFunctionPointer) ::glBlendEquation },
+ { "glBlendEquationSeparate", (QFunctionPointer) ::glBlendEquationSeparate },
+ { "glBlendFuncSeparate", (QFunctionPointer) ::glBlendFuncSeparate },
+ { "glBufferData", (QFunctionPointer) ::glBufferData },
+ { "glBufferSubData", (QFunctionPointer) ::glBufferSubData },
+ { "glCheckFramebufferStatus", (QFunctionPointer) ::glCheckFramebufferStatus },
+ { "glCompileShader", (QFunctionPointer) ::glCompileShader },
+ { "glCompressedTexImage2D", (QFunctionPointer) ::glCompressedTexImage2D },
+ { "glCompressedTexSubImage2D", (QFunctionPointer) ::glCompressedTexSubImage2D },
+ { "glCreateProgram", (QFunctionPointer) ::glCreateProgram },
+ { "glCreateShader", (QFunctionPointer) ::glCreateShader },
+ { "glDeleteBuffers", (QFunctionPointer) ::glDeleteBuffers },
+ { "glDeleteFramebuffers", (QFunctionPointer) ::glDeleteFramebuffers },
+ { "glDeleteProgram", (QFunctionPointer) ::glDeleteProgram },
+ { "glDeleteRenderbuffers", (QFunctionPointer) ::glDeleteRenderbuffers },
+ { "glDeleteShader", (QFunctionPointer) ::glDeleteShader },
+ { "glDetachShader", (QFunctionPointer) ::glDetachShader },
+ { "glDisableVertexAttribArray", (QFunctionPointer) ::glDisableVertexAttribArray },
+ { "glEnableVertexAttribArray", (QFunctionPointer) ::glEnableVertexAttribArray },
+ { "glFramebufferRenderbuffer", (QFunctionPointer) ::glFramebufferRenderbuffer },
+ { "glFramebufferTexture2D", (QFunctionPointer) ::glFramebufferTexture2D },
+ { "glGenBuffers", (QFunctionPointer) ::glGenBuffers },
+ { "glGenerateMipmap", (QFunctionPointer) ::glGenerateMipmap },
+ { "glGenFramebuffers", (QFunctionPointer) ::glGenFramebuffers },
+ { "glGenRenderbuffers", (QFunctionPointer) ::glGenRenderbuffers },
+ { "glGetActiveAttrib", (QFunctionPointer) ::glGetActiveAttrib },
+ { "glGetActiveUniform", (QFunctionPointer) ::glGetActiveUniform },
+ { "glGetAttachedShaders", (QFunctionPointer) ::glGetAttachedShaders },
+ { "glGetAttribLocation", (QFunctionPointer) ::glGetAttribLocation },
+ { "glGetBufferParameteriv", (QFunctionPointer) ::glGetBufferParameteriv },
+ { "glGetFramebufferAttachmentParameteriv", (QFunctionPointer) ::glGetFramebufferAttachmentParameteriv },
+ { "glGetProgramiv", (QFunctionPointer) ::glGetProgramiv },
+ { "glGetProgramInfoLog", (QFunctionPointer) ::glGetProgramInfoLog },
+ { "glGetRenderbufferParameteriv", (QFunctionPointer) ::glGetRenderbufferParameteriv },
+ { "glGetShaderiv", (QFunctionPointer) ::glGetShaderiv },
+ { "glGetShaderInfoLog", (QFunctionPointer) ::glGetShaderInfoLog },
+ { "glGetShaderPrecisionFormat", (QFunctionPointer) ::glGetShaderPrecisionFormat },
+ { "glGetShaderSource", (QFunctionPointer) ::glGetShaderSource },
+ { "glGetUniformfv", (QFunctionPointer) ::glGetUniformfv },
+ { "glGetUniformiv", (QFunctionPointer) ::glGetUniformiv },
+ { "glGetUniformLocation", (QFunctionPointer) ::glGetUniformLocation },
+ { "glGetVertexAttribfv", (QFunctionPointer) ::glGetVertexAttribfv },
+ { "glGetVertexAttribiv", (QFunctionPointer) ::glGetVertexAttribiv },
+ { "glGetVertexAttribPointerv", (QFunctionPointer) ::glGetVertexAttribPointerv },
+ { "glIsBuffer", (QFunctionPointer) ::glIsBuffer },
+ { "glIsFramebuffer", (QFunctionPointer) ::glIsFramebuffer },
+ { "glIsProgram", (QFunctionPointer) ::glIsProgram },
+ { "glIsRenderbuffer", (QFunctionPointer) ::glIsRenderbuffer },
+ { "glIsShader", (QFunctionPointer) ::glIsShader },
+ { "glLinkProgram", (QFunctionPointer) ::glLinkProgram },
+ { "glReleaseShaderCompiler", (QFunctionPointer) ::glReleaseShaderCompiler },
+ { "glRenderbufferStorage", (QFunctionPointer) ::glRenderbufferStorage },
+ { "glSampleCoverage", (QFunctionPointer) ::glSampleCoverage },
+ { "glShaderBinary", (QFunctionPointer) ::glShaderBinary },
+ { "glShaderSource", (QFunctionPointer) ::glShaderSource },
+ { "glStencilFuncSeparate", (QFunctionPointer) ::glStencilFuncSeparate },
+ { "glStencilMaskSeparate", (QFunctionPointer) ::glStencilMaskSeparate },
+ { "glStencilOpSeparate", (QFunctionPointer) ::glStencilOpSeparate },
+ { "glUniform1f", (QFunctionPointer) ::glUniform1f },
+ { "glUniform1fv", (QFunctionPointer) ::glUniform1fv },
+ { "glUniform1i", (QFunctionPointer) ::glUniform1i },
+ { "glUniform1iv", (QFunctionPointer) ::glUniform1iv },
+ { "glUniform2f", (QFunctionPointer) ::glUniform2f },
+ { "glUniform2fv", (QFunctionPointer) ::glUniform2fv },
+ { "glUniform2i", (QFunctionPointer) ::glUniform2i },
+ { "glUniform2iv", (QFunctionPointer) ::glUniform2iv },
+ { "glUniform3f", (QFunctionPointer) ::glUniform3f },
+ { "glUniform3fv", (QFunctionPointer) ::glUniform3fv },
+ { "glUniform3i", (QFunctionPointer) ::glUniform3i },
+ { "glUniform3iv", (QFunctionPointer) ::glUniform3iv },
+ { "glUniform4f", (QFunctionPointer) ::glUniform4f },
+ { "glUniform4fv", (QFunctionPointer) ::glUniform4fv },
+ { "glUniform4i", (QFunctionPointer) ::glUniform4i },
+ { "glUniform4iv", (QFunctionPointer) ::glUniform4iv },
+ { "glUniformMatrix2fv", (QFunctionPointer) ::glUniformMatrix2fv },
+ { "glUniformMatrix3fv", (QFunctionPointer) ::glUniformMatrix3fv },
+ { "glUniformMatrix4fv", (QFunctionPointer) ::glUniformMatrix4fv },
+ { "glUseProgram", (QFunctionPointer) ::glUseProgram },
+ { "glValidateProgram", (QFunctionPointer) ::glValidateProgram },
+ { "glVertexAttrib1f", (QFunctionPointer) ::glVertexAttrib1f },
+ { "glVertexAttrib1fv", (QFunctionPointer) ::glVertexAttrib1fv },
+ { "glVertexAttrib2f", (QFunctionPointer) ::glVertexAttrib2f },
+ { "glVertexAttrib2fv", (QFunctionPointer) ::glVertexAttrib2fv },
+ { "glVertexAttrib3f", (QFunctionPointer) ::glVertexAttrib3f },
+ { "glVertexAttrib3fv", (QFunctionPointer) ::glVertexAttrib3fv },
+ { "glVertexAttrib4f", (QFunctionPointer) ::glVertexAttrib4f },
+ { "glVertexAttrib4fv", (QFunctionPointer) ::glVertexAttrib4fv },
+ { "glVertexAttribPointer", (QFunctionPointer) ::glVertexAttribPointer },
+
+ { "glClearDepthf", (QFunctionPointer) ::glClearDepthf },
+ { "glDepthRangef", (QFunctionPointer) ::glDepthRangef },
+#endif // QT_OPENGL_ES_2
+
+#ifdef QT_OPENGL_ES_3
+ { "glBeginQuery", (QFunctionPointer) ::glBeginQuery },
+ { "glBeginTransformFeedback", (QFunctionPointer) ::glBeginTransformFeedback },
+ { "glBindBufferBase", (QFunctionPointer) ::glBindBufferBase },
+ { "glBindBufferRange", (QFunctionPointer) ::glBindBufferRange },
+ { "glBindSampler", (QFunctionPointer) ::glBindSampler },
+ { "glBindTransformFeedback", (QFunctionPointer) ::glBindTransformFeedback },
+ { "glBindVertexArray", (QFunctionPointer) ::glBindVertexArray },
+ { "glBlitFramebuffer", (QFunctionPointer) ::glBlitFramebuffer },
+ { "glClearBufferfi", (QFunctionPointer) ::glClearBufferfi },
+ { "glClearBufferfv", (QFunctionPointer) ::glClearBufferfv },
+ { "glClearBufferiv", (QFunctionPointer) ::glClearBufferiv },
+ { "glClearBufferuiv", (QFunctionPointer) ::glClearBufferuiv },
+ { "glClientWaitSync", (QFunctionPointer) ::glClientWaitSync },
+ { "glCompressedTexImage3D", (QFunctionPointer) ::glCompressedTexImage3D },
+ { "glCompressedTexSubImage3D", (QFunctionPointer) ::glCompressedTexSubImage3D },
+ { "glCopyBufferSubData", (QFunctionPointer) ::glCopyBufferSubData },
+ { "glCopyTexSubImage3D", (QFunctionPointer) ::glCopyTexSubImage3D },
+ { "glDeleteQueries", (QFunctionPointer) ::glDeleteQueries },
+ { "glDeleteSamplers", (QFunctionPointer) ::glDeleteSamplers },
+ { "glDeleteSync", (QFunctionPointer) ::glDeleteSync },
+ { "glDeleteTransformFeedbacks", (QFunctionPointer) ::glDeleteTransformFeedbacks },
+ { "glDeleteVertexArrays", (QFunctionPointer) ::glDeleteVertexArrays },
+ { "glDrawArraysInstanced", (QFunctionPointer) ::glDrawArraysInstanced },
+ { "glDrawBuffers", (QFunctionPointer) ::glDrawBuffers },
+ { "glDrawElementsInstanced", (QFunctionPointer) ::glDrawElementsInstanced },
+ { "glDrawRangeElements", (QFunctionPointer) ::glDrawRangeElements },
+ { "glEndQuery", (QFunctionPointer) ::glEndQuery },
+ { "glEndTransformFeedback", (QFunctionPointer) ::glEndTransformFeedback },
+ { "glFenceSync", (QFunctionPointer) ::glFenceSync },
+ { "glFlushMappedBufferRange", (QFunctionPointer) ::glFlushMappedBufferRange },
+ { "glFramebufferTextureLayer", (QFunctionPointer) ::glFramebufferTextureLayer },
+ { "glGenQueries", (QFunctionPointer) ::glGenQueries },
+ { "glGenSamplers", (QFunctionPointer) ::glGenSamplers },
+ { "glGenTransformFeedbacks", (QFunctionPointer) ::glGenTransformFeedbacks },
+ { "glGenVertexArrays", (QFunctionPointer) ::glGenVertexArrays },
+ { "glGetActiveUniformBlockName", (QFunctionPointer) ::glGetActiveUniformBlockName },
+ { "glGetActiveUniformBlockiv", (QFunctionPointer) ::glGetActiveUniformBlockiv },
+ { "glGetActiveUniformsiv", (QFunctionPointer) ::glGetActiveUniformsiv },
+ { "glGetBufferParameteri64v", (QFunctionPointer) ::glGetBufferParameteri64v },
+ { "glGetBufferPointerv", (QFunctionPointer) ::glGetBufferPointerv },
+ { "glGetFragDataLocation", (QFunctionPointer) ::glGetFragDataLocation },
+ { "glGetInteger64i_v", (QFunctionPointer) ::glGetInteger64i_v },
+ { "glGetInteger64v", (QFunctionPointer) ::glGetInteger64v },
+ { "glGetIntegeri_v", (QFunctionPointer) ::glGetIntegeri_v },
+ { "glGetInternalformativ", (QFunctionPointer) ::glGetInternalformativ },
+ { "glGetProgramBinary", (QFunctionPointer) ::glGetProgramBinary },
+ { "glGetQueryObjectuiv", (QFunctionPointer) ::glGetQueryObjectuiv },
+ { "glGetQueryiv", (QFunctionPointer) ::glGetQueryiv },
+ { "glGetSamplerParameterfv", (QFunctionPointer) ::glGetSamplerParameterfv },
+ { "glGetSamplerParameteriv", (QFunctionPointer) ::glGetSamplerParameteriv },
+ { "glGetStringi", (QFunctionPointer) ::glGetStringi },
+ { "glGetSynciv", (QFunctionPointer) ::glGetSynciv },
+ { "glGetTransformFeedbackVarying", (QFunctionPointer) ::glGetTransformFeedbackVarying },
+ { "glGetUniformBlockIndex", (QFunctionPointer) ::glGetUniformBlockIndex },
+ { "glGetUniformIndices", (QFunctionPointer) ::glGetUniformIndices },
+ { "glGetUniformuiv", (QFunctionPointer) ::glGetUniformuiv },
+ { "glGetVertexAttribIiv", (QFunctionPointer) ::glGetVertexAttribIiv },
+ { "glGetVertexAttribIuiv", (QFunctionPointer) ::glGetVertexAttribIuiv },
+ { "glInvalidateFramebuffer", (QFunctionPointer) ::glInvalidateFramebuffer },
+ { "glInvalidateSubFramebuffer", (QFunctionPointer) ::glInvalidateSubFramebuffer },
+ { "glIsQuery", (QFunctionPointer) ::glIsQuery },
+ { "glIsSampler", (QFunctionPointer) ::glIsSampler },
+ { "glIsSync", (QFunctionPointer) ::glIsSync },
+ { "glIsTransformFeedback", (QFunctionPointer) ::glIsTransformFeedback },
+ { "glIsVertexArray", (QFunctionPointer) ::glIsVertexArray },
+ { "glMapBufferRange", (QFunctionPointer) ::glMapBufferRange },
+ { "glPauseTransformFeedback", (QFunctionPointer) ::glPauseTransformFeedback },
+ { "glProgramBinary", (QFunctionPointer) ::glProgramBinary },
+ { "glProgramParameteri", (QFunctionPointer) ::glProgramParameteri },
+ { "glReadBuffer", (QFunctionPointer) ::glReadBuffer },
+ { "glRenderbufferStorageMultisample", (QFunctionPointer) ::glRenderbufferStorageMultisample },
+ { "glResumeTransformFeedback", (QFunctionPointer) ::glResumeTransformFeedback },
+ { "glSamplerParameterf", (QFunctionPointer) ::glSamplerParameterf },
+ { "glSamplerParameterfv", (QFunctionPointer) ::glSamplerParameterfv },
+ { "glSamplerParameteri", (QFunctionPointer) ::glSamplerParameteri },
+ { "glSamplerParameteriv", (QFunctionPointer) ::glSamplerParameteriv },
+ { "glTexImage3D", (QFunctionPointer) ::glTexImage3D },
+ { "glTexStorage2D", (QFunctionPointer) ::glTexStorage2D },
+ { "glTexStorage3D", (QFunctionPointer) ::glTexStorage3D },
+ { "glTexSubImage3D", (QFunctionPointer) ::glTexSubImage3D },
+ { "glTransformFeedbackVaryings", (QFunctionPointer) ::glTransformFeedbackVaryings },
+ { "glUniform1ui", (QFunctionPointer) ::glUniform1ui },
+ { "glUniform1uiv", (QFunctionPointer) ::glUniform1uiv },
+ { "glUniform2ui", (QFunctionPointer) ::glUniform2ui },
+ { "glUniform2uiv", (QFunctionPointer) ::glUniform2uiv },
+ { "glUniform3ui", (QFunctionPointer) ::glUniform3ui },
+ { "glUniform3uiv", (QFunctionPointer) ::glUniform3uiv },
+ { "glUniform4ui", (QFunctionPointer) ::glUniform4ui },
+ { "glUniform4uiv", (QFunctionPointer) ::glUniform4uiv },
+ { "glUniformBlockBinding", (QFunctionPointer) ::glUniformBlockBinding },
+ { "glUniformMatrix2x3fv", (QFunctionPointer) ::glUniformMatrix2x3fv },
+ { "glUniformMatrix2x4fv", (QFunctionPointer) ::glUniformMatrix2x4fv },
+ { "glUniformMatrix3x2fv", (QFunctionPointer) ::glUniformMatrix3x2fv },
+ { "glUniformMatrix3x4fv", (QFunctionPointer) ::glUniformMatrix3x4fv },
+ { "glUniformMatrix4x2fv", (QFunctionPointer) ::glUniformMatrix4x2fv },
+ { "glUniformMatrix4x3fv", (QFunctionPointer) ::glUniformMatrix4x3fv },
+ { "glUnmapBuffer", (QFunctionPointer) ::glUnmapBuffer },
+ { "glVertexAttribDivisor", (QFunctionPointer) ::glVertexAttribDivisor },
+ { "glVertexAttribI4i", (QFunctionPointer) ::glVertexAttribI4i },
+ { "glVertexAttribI4iv", (QFunctionPointer) ::glVertexAttribI4iv },
+ { "glVertexAttribI4ui", (QFunctionPointer) ::glVertexAttribI4ui },
+ { "glVertexAttribI4uiv", (QFunctionPointer) ::glVertexAttribI4uiv },
+ { "glVertexAttribIPointer", (QFunctionPointer) ::glVertexAttribIPointer },
+ { "glWaitSync", (QFunctionPointer) ::glWaitSync },
+#endif // QT_OPENGL_ES_3
+
+#ifdef QT_OPENGL_ES_3_1
+ { "glActiveShaderProgram", (QFunctionPointer) ::glActiveShaderProgram },
+ { "glBindImageTexture", (QFunctionPointer) ::glBindImageTexture },
+ { "glBindProgramPipeline", (QFunctionPointer) ::glBindProgramPipeline },
+ { "glBindVertexBuffer", (QFunctionPointer) ::glBindVertexBuffer },
+ { "glCreateShaderProgramv", (QFunctionPointer) ::glCreateShaderProgramv },
+ { "glDeleteProgramPipelines", (QFunctionPointer) ::glDeleteProgramPipelines },
+ { "glDispatchCompute", (QFunctionPointer) ::glDispatchCompute },
+ { "glDispatchComputeIndirect", (QFunctionPointer) ::glDispatchComputeIndirect },
+ { "glDrawArraysIndirect", (QFunctionPointer) ::glDrawArraysIndirect },
+ { "glDrawElementsIndirect", (QFunctionPointer) ::glDrawElementsIndirect },
+ { "glFramebufferParameteri", (QFunctionPointer) ::glFramebufferParameteri },
+ { "glGenProgramPipelines", (QFunctionPointer) ::glGenProgramPipelines },
+ { "glGetBooleani_v", (QFunctionPointer) ::glGetBooleani_v },
+ { "glGetFramebufferParameteriv", (QFunctionPointer) ::glGetFramebufferParameteriv },
+ { "glGetMultisamplefv", (QFunctionPointer) ::glGetMultisamplefv },
+ { "glGetProgramInterfaceiv", (QFunctionPointer) ::glGetProgramInterfaceiv },
+ { "glGetProgramPipelineInfoLog", (QFunctionPointer) ::glGetProgramPipelineInfoLog },
+ { "glGetProgramPipelineiv", (QFunctionPointer) ::glGetProgramPipelineiv },
+ { "glGetProgramResourceIndex", (QFunctionPointer) ::glGetProgramResourceIndex },
+ { "glGetProgramResourceLocation", (QFunctionPointer) ::glGetProgramResourceLocation },
+ { "glGetProgramResourceName", (QFunctionPointer) ::glGetProgramResourceName },
+ { "glGetProgramResourceiv", (QFunctionPointer) ::glGetProgramResourceiv },
+ { "glGetTexLevelParameterfv", (QFunctionPointer) ::glGetTexLevelParameterfv },
+ { "glGetTexLevelParameteriv", (QFunctionPointer) ::glGetTexLevelParameteriv },
+ { "glIsProgramPipeline", (QFunctionPointer) ::glIsProgramPipeline },
+ { "glMemoryBarrier", (QFunctionPointer) ::glMemoryBarrier },
+ { "glMemoryBarrierByRegion", (QFunctionPointer) ::glMemoryBarrierByRegion },
+ { "glProgramUniform1f", (QFunctionPointer) ::glProgramUniform1f },
+ { "glProgramUniform1fv", (QFunctionPointer) ::glProgramUniform1fv },
+ { "glProgramUniform1i", (QFunctionPointer) ::glProgramUniform1i },
+ { "glProgramUniform1iv", (QFunctionPointer) ::glProgramUniform1iv },
+ { "glProgramUniform1ui", (QFunctionPointer) ::glProgramUniform1ui },
+ { "glProgramUniform1uiv", (QFunctionPointer) ::glProgramUniform1uiv },
+ { "glProgramUniform2f", (QFunctionPointer) ::glProgramUniform2f },
+ { "glProgramUniform2fv", (QFunctionPointer) ::glProgramUniform2fv },
+ { "glProgramUniform2i", (QFunctionPointer) ::glProgramUniform2i },
+ { "glProgramUniform2iv", (QFunctionPointer) ::glProgramUniform2iv },
+ { "glProgramUniform2ui", (QFunctionPointer) ::glProgramUniform2ui },
+ { "glProgramUniform2uiv", (QFunctionPointer) ::glProgramUniform2uiv },
+ { "glProgramUniform3f", (QFunctionPointer) ::glProgramUniform3f },
+ { "glProgramUniform3fv", (QFunctionPointer) ::glProgramUniform3fv },
+ { "glProgramUniform3i", (QFunctionPointer) ::glProgramUniform3i },
+ { "glProgramUniform3iv", (QFunctionPointer) ::glProgramUniform3iv },
+ { "glProgramUniform3ui", (QFunctionPointer) ::glProgramUniform3ui },
+ { "glProgramUniform3uiv", (QFunctionPointer) ::glProgramUniform3uiv },
+ { "glProgramUniform4f", (QFunctionPointer) ::glProgramUniform4f },
+ { "glProgramUniform4fv", (QFunctionPointer) ::glProgramUniform4fv },
+ { "glProgramUniform4i", (QFunctionPointer) ::glProgramUniform4i },
+ { "glProgramUniform4iv", (QFunctionPointer) ::glProgramUniform4iv },
+ { "glProgramUniform4ui", (QFunctionPointer) ::glProgramUniform4ui },
+ { "glProgramUniform4uiv", (QFunctionPointer) ::glProgramUniform4uiv },
+ { "glProgramUniformMatrix2fv", (QFunctionPointer) ::glProgramUniformMatrix2fv },
+ { "glProgramUniformMatrix2x3fv", (QFunctionPointer) ::glProgramUniformMatrix2x3fv },
+ { "glProgramUniformMatrix2x4fv", (QFunctionPointer) ::glProgramUniformMatrix2x4fv },
+ { "glProgramUniformMatrix3fv", (QFunctionPointer) ::glProgramUniformMatrix3fv },
+ { "glProgramUniformMatrix3x2fv", (QFunctionPointer) ::glProgramUniformMatrix3x2fv },
+ { "glProgramUniformMatrix3x4fv", (QFunctionPointer) ::glProgramUniformMatrix3x4fv },
+ { "glProgramUniformMatrix4fv", (QFunctionPointer) ::glProgramUniformMatrix4fv },
+ { "glProgramUniformMatrix4x2fv", (QFunctionPointer) ::glProgramUniformMatrix4x2fv },
+ { "glProgramUniformMatrix4x3fv", (QFunctionPointer) ::glProgramUniformMatrix4x3fv },
+ { "glSampleMaski", (QFunctionPointer) ::glSampleMaski },
+ { "glTexStorage2DMultisample", (QFunctionPointer) ::glTexStorage2DMultisample },
+ { "glUseProgramStages", (QFunctionPointer) ::glUseProgramStages },
+ { "glValidateProgramPipeline", (QFunctionPointer) ::glValidateProgramPipeline },
+ { "glVertexAttribBinding", (QFunctionPointer) ::glVertexAttribBinding },
+ { "glVertexAttribFormat", (QFunctionPointer) ::glVertexAttribFormat },
+ { "glVertexAttribIFormat", (QFunctionPointer) ::glVertexAttribIFormat },
+ { "glVertexBindingDivisor", (QFunctionPointer) ::glVertexBindingDivisor },
+#endif // QT_OPENGL_ES_3_1
+ };
+
+ for (size_t i = 0; i < sizeof(standardFuncs) / sizeof(StdFunc); ++i) {
+ if (!qstrcmp(procName, standardFuncs[i].name)) {
+ proc = standardFuncs[i].func;
+ break;
+ }
+ }
+ }
#endif
+
return proc;
}
diff --git a/src/platformsupport/fbconvenience/qfbcursor.cpp b/src/platformsupport/fbconvenience/qfbcursor.cpp
index 004c586de3..7daf3f4d0c 100644
--- a/src/platformsupport/fbconvenience/qfbcursor.cpp
+++ b/src/platformsupport/fbconvenience/qfbcursor.cpp
@@ -60,8 +60,8 @@ QFbCursor::QFbCursor(QFbScreen *screen)
mScreen(screen),
mDirty(false),
mOnScreen(false),
- mGraphic(0),
- mDeviceListener(0)
+ mCursorImage(nullptr),
+ mDeviceListener(nullptr)
{
QByteArray hideCursorVal = qgetenv("QT_QPA_FB_HIDECURSOR");
if (!hideCursorVal.isEmpty())
@@ -69,7 +69,7 @@ QFbCursor::QFbCursor(QFbScreen *screen)
if (!mVisible)
return;
- mGraphic = new QPlatformCursorImage(0, 0, 0, 0, 0, 0);
+ mCursorImage = new QPlatformCursorImage(0, 0, 0, 0, 0, 0);
setCursor(Qt::ArrowCursor);
mDeviceListener = new QFbCursorDeviceListener(this);
@@ -85,8 +85,8 @@ QFbCursor::~QFbCursor()
QRect QFbCursor::getCurrentRect()
{
- QRect rect = mGraphic->image()->rect().translated(-mGraphic->hotspot().x(),
- -mGraphic->hotspot().y());
+ QRect rect = mCursorImage->image()->rect().translated(-mCursorImage->hotspot().x(),
+ -mCursorImage->hotspot().y());
rect.translate(m_pos);
QPoint mScreenOffset = mScreen->geometry().topLeft();
rect.translate(-mScreenOffset); // global to local translation
@@ -133,7 +133,7 @@ QRect QFbCursor::drawCursor(QPainter & painter)
return QRect();
mPrevRect = mCurrentRect;
- painter.drawImage(mPrevRect, *mGraphic->image());
+ painter.drawImage(mPrevRect, *mCursorImage->image());
mOnScreen = true;
return mPrevRect;
}
@@ -149,17 +149,17 @@ QRect QFbCursor::dirtyRect()
void QFbCursor::setCursor(Qt::CursorShape shape)
{
- mGraphic->set(shape);
+ mCursorImage->set(shape);
}
void QFbCursor::setCursor(const QImage &image, int hotx, int hoty)
{
- mGraphic->set(image, hotx, hoty);
+ mCursorImage->set(image, hotx, hoty);
}
void QFbCursor::setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY)
{
- mGraphic->set(data, mask, width, height, hotX, hotY);
+ mCursorImage->set(data, mask, width, height, hotX, hotY);
}
#ifndef QT_NO_CURSOR
diff --git a/src/platformsupport/fbconvenience/qfbcursor_p.h b/src/platformsupport/fbconvenience/qfbcursor_p.h
index f08babd45b..beda10a5f3 100644
--- a/src/platformsupport/fbconvenience/qfbcursor_p.h
+++ b/src/platformsupport/fbconvenience/qfbcursor_p.h
@@ -87,11 +87,11 @@ public:
virtual QRect drawCursor(QPainter &painter);
// input methods
- void pointerEvent(const QMouseEvent &event) Q_DECL_OVERRIDE;
- QPoint pos() const Q_DECL_OVERRIDE;
- void setPos(const QPoint &pos) Q_DECL_OVERRIDE;
+ void pointerEvent(const QMouseEvent &event) override;
+ QPoint pos() const override;
+ void setPos(const QPoint &pos) override;
#ifndef QT_NO_CURSOR
- void changeCursor(QCursor *widgetCursor, QWindow *window) Q_DECL_OVERRIDE;
+ void changeCursor(QCursor *widgetCursor, QWindow *window) override;
#endif
virtual void setDirty();
@@ -113,7 +113,7 @@ private:
QRect mPrevRect; // last place the cursor was drawn
bool mDirty;
bool mOnScreen;
- QPlatformCursorImage *mGraphic;
+ QPlatformCursorImage *mCursorImage;
QFbCursorDeviceListener *mDeviceListener;
QPoint m_pos;
};
@@ -121,4 +121,3 @@ private:
QT_END_NAMESPACE
#endif // QFBCURSOR_P_H
-
diff --git a/src/platformsupport/fbconvenience/qfbscreen.cpp b/src/platformsupport/fbconvenience/qfbscreen.cpp
index 216f2722a4..2b4498157c 100644
--- a/src/platformsupport/fbconvenience/qfbscreen.cpp
+++ b/src/platformsupport/fbconvenience/qfbscreen.cpp
@@ -51,19 +51,23 @@
QT_BEGIN_NAMESPACE
-QFbScreen::QFbScreen() : mUpdatePending(false), mCursor(0), mGeometry(), mDepth(16), mFormat(QImage::Format_RGB16), mScreenImage(0), mCompositePainter(0), mIsUpToDate(false)
+QFbScreen::QFbScreen()
+ : mUpdatePending(false),
+ mCursor(0),
+ mDepth(16),
+ mFormat(QImage::Format_RGB16),
+ mPainter(nullptr)
{
}
QFbScreen::~QFbScreen()
{
- delete mCompositePainter;
- delete mScreenImage;
+ delete mPainter;
}
void QFbScreen::initializeCompositor()
{
- mScreenImage = new QImage(mGeometry.size(), mFormat);
+ mScreenImage = QImage(mGeometry.size(), mFormat);
scheduleUpdate();
}
@@ -93,7 +97,6 @@ void QFbScreen::addWindow(QFbWindow *window)
}
}
}
- invalidateRectCache();
setDirty(window->geometry());
QWindow *w = topWindow();
QWindowSystemInterface::handleWindowActivated(w);
@@ -103,7 +106,6 @@ void QFbScreen::addWindow(QFbWindow *window)
void QFbScreen::removeWindow(QFbWindow *window)
{
mWindowStack.removeOne(window);
- invalidateRectCache();
setDirty(window->geometry());
QWindow *w = topWindow();
QWindowSystemInterface::handleWindowActivated(w);
@@ -116,7 +118,6 @@ void QFbScreen::raise(QFbWindow *window)
if (index <= 0)
return;
mWindowStack.move(index, 0);
- invalidateRectCache();
setDirty(window->geometry());
QWindow *w = topWindow();
QWindowSystemInterface::handleWindowActivated(w);
@@ -129,7 +130,6 @@ void QFbScreen::lower(QFbWindow *window)
if (index == -1 || index == (mWindowStack.size() - 1))
return;
mWindowStack.move(index, mWindowStack.size() - 1);
- invalidateRectCache();
setDirty(window->geometry());
QWindow *w = topWindow();
QWindowSystemInterface::handleWindowActivated(w);
@@ -142,7 +142,7 @@ QWindow *QFbScreen::topWindow() const
if (fbw->window()->type() == Qt::Window || fbw->window()->type() == Qt::Dialog)
return fbw->window();
}
- return 0;
+ return nullptr;
}
QWindow *QFbScreen::topLevelAt(const QPoint & p) const
@@ -151,14 +151,19 @@ QWindow *QFbScreen::topLevelAt(const QPoint & p) const
if (fbw->geometry().contains(p, false) && fbw->window()->isVisible())
return fbw->window();
}
- return 0;
+ return nullptr;
+}
+
+int QFbScreen::windowCount() const
+{
+ return mWindowStack.count();
}
void QFbScreen::setDirty(const QRect &rect)
{
- QRect intersection = rect.intersected(mGeometry);
- QPoint screenOffset = mGeometry.topLeft();
- mRepaintRegion += intersection.translated(-screenOffset); // global to local translation
+ const QRect intersection = rect.intersected(mGeometry);
+ const QPoint screenOffset = mGeometry.topLeft();
+ mRepaintRegion += intersection.translated(-screenOffset); // global to local translation
scheduleUpdate();
}
@@ -177,141 +182,81 @@ void QFbScreen::setPhysicalSize(const QSize &size)
void QFbScreen::setGeometry(const QRect &rect)
{
- delete mCompositePainter;
- mCompositePainter = 0;
- delete mScreenImage;
+ delete mPainter;
+ mPainter = nullptr;
mGeometry = rect;
- mScreenImage = new QImage(mGeometry.size(), mFormat);
- invalidateRectCache();
+ mScreenImage = QImage(mGeometry.size(), mFormat);
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
resizeMaximizedWindows();
}
-void QFbScreen::generateRects()
+bool QFbScreen::initialize()
{
- mCachedRects.clear();
- QPoint screenOffset = mGeometry.topLeft();
- QRegion remainingScreen(mGeometry.translated(-screenOffset)); // global to local translation
-
- for (int i = 0; i < mWindowStack.length(); i++) {
- if (remainingScreen.isEmpty())
- break;
-#if 0
- if (!mWindowStack[i]->isVisible())
- continue;
- if (mWindowStack[i]->isMinimized())
- continue;
-
- if (!mWindowStack[i]->testAttribute(Qt::WA_TranslucentBackground)) {
- QRect localGeometry = mWindowStack.at(i)->geometry().translated(-screenOffset); // global to local translation
- remainingScreen -= localGeometry;
- QRegion windowRegion(localGeometry);
- windowRegion -= remainingScreen;
- for (const QRect &rect : windowRegion)
- mCachedRects += QPair<QRect, int>(rect, i);
- }
-#endif
- }
- mCachedRects.reserve(mCachedRects.count() + remainingScreen.rectCount());
- for (const QRect &rect : remainingScreen)
- mCachedRects += QPair<QRect, int>(rect, -1);
- mIsUpToDate = true;
+ return true;
}
QRegion QFbScreen::doRedraw()
{
- QPoint screenOffset = mGeometry.topLeft();
+ const QPoint screenOffset = mGeometry.topLeft();
QRegion touchedRegion;
if (mCursor && mCursor->isDirty() && mCursor->isOnScreen()) {
- QRect lastCursor = mCursor->dirtyRect();
+ const QRect lastCursor = mCursor->dirtyRect();
mRepaintRegion += lastCursor;
}
- if (mRepaintRegion.isEmpty() && (!mCursor || !mCursor->isDirty())) {
+ if (mRepaintRegion.isEmpty() && (!mCursor || !mCursor->isDirty()))
return touchedRegion;
- }
- QVector<QRect> rects = mRepaintRegion.rects();
-
- if (!mIsUpToDate)
- generateRects();
-
- if (!mCompositePainter)
- mCompositePainter = new QPainter(mScreenImage);
+ if (!mPainter)
+ mPainter = new QPainter(&mScreenImage);
+ const QVector<QRect> rects = mRepaintRegion.rects();
+ const QRect screenRect = mGeometry.translated(-screenOffset);
for (int rectIndex = 0; rectIndex < mRepaintRegion.rectCount(); rectIndex++) {
- QRegion rectRegion = rects[rectIndex];
+ const QRect rect = rects[rectIndex].intersected(screenRect);
+ if (rect.isEmpty())
+ continue;
- for (int i = 0; i < mCachedRects.length(); i++) {
- QRect screenSubRect = mCachedRects[i].first;
- int layer = mCachedRects[i].second;
- QRegion intersect = rectRegion.intersected(screenSubRect);
+ mPainter->setCompositionMode(QPainter::CompositionMode_Source);
+ mPainter->fillRect(rect, mScreenImage.hasAlphaChannel() ? Qt::transparent : Qt::black);
- if (intersect.isEmpty())
+ for (int layerIndex = mWindowStack.size() - 1; layerIndex != -1; layerIndex--) {
+ if (!mWindowStack[layerIndex]->window()->isVisible())
continue;
- rectRegion -= intersect;
-
- // we only expect one rectangle, but defensive coding...
- for (const QRect &rect : intersect) {
- bool firstLayer = true;
- if (layer == -1) {
- mCompositePainter->setCompositionMode(QPainter::CompositionMode_Source);
- mCompositePainter->fillRect(rect, mScreenImage->hasAlphaChannel() ? Qt::transparent : Qt::black);
- firstLayer = false;
- layer = mWindowStack.size() - 1;
- }
-
- for (int layerIndex = layer; layerIndex != -1; layerIndex--) {
- if (!mWindowStack[layerIndex]->window()->isVisible())
- continue;
- // if (mWindowStack[layerIndex]->isMinimized())
- // continue;
-
- QRect windowRect = mWindowStack[layerIndex]->geometry().translated(-screenOffset);
- QRect windowIntersect = rect.translated(-windowRect.left(),
- -windowRect.top());
-
-
- QFbBackingStore *backingStore = mWindowStack[layerIndex]->backingStore();
-
- if (backingStore) {
- backingStore->lock();
- mCompositePainter->drawImage(rect, backingStore->image(), windowIntersect);
- backingStore->unlock();
- }
- if (firstLayer) {
- firstLayer = false;
- }
- }
+ const QRect windowRect = mWindowStack[layerIndex]->geometry().translated(-screenOffset);
+ const QRect windowIntersect = rect.translated(-windowRect.left(), -windowRect.top());
+ QFbBackingStore *backingStore = mWindowStack[layerIndex]->backingStore();
+ if (backingStore) {
+ backingStore->lock();
+ mPainter->drawImage(rect, backingStore->image(), windowIntersect);
+ backingStore->unlock();
}
}
}
- QRect cursorRect;
if (mCursor && (mCursor->isDirty() || mRepaintRegion.intersects(mCursor->lastPainted()))) {
- mCompositePainter->setCompositionMode(QPainter::CompositionMode_SourceOver);
- cursorRect = mCursor->drawCursor(*mCompositePainter);
- touchedRegion += cursorRect;
+ mPainter->setCompositionMode(QPainter::CompositionMode_SourceOver);
+ touchedRegion += mCursor->drawCursor(*mPainter);
}
touchedRegion += mRepaintRegion;
mRepaintRegion = QRegion();
-
-
-// qDebug() << "QFbScreen::doRedraw" << mWindowStack.size() << mScreenImage->size() << touchedRegion;
-
return touchedRegion;
}
QFbWindow *QFbScreen::windowForId(WId wid) const
{
- for (int i = 0; i < mWindowStack.count(); ++i)
+ for (int i = 0; i < mWindowStack.count(); ++i) {
if (mWindowStack[i]->winId() == wid)
return mWindowStack[i];
+ }
+ return nullptr;
+}
+QFbScreen::Flags QFbScreen::flags() const
+{
return 0;
}
QT_END_NAMESPACE
-
diff --git a/src/platformsupport/fbconvenience/qfbscreen_p.h b/src/platformsupport/fbconvenience/qfbscreen_p.h
index e9b570aa1c..1c27a941cc 100644
--- a/src/platformsupport/fbconvenience/qfbscreen_p.h
+++ b/src/platformsupport/fbconvenience/qfbscreen_p.h
@@ -66,10 +66,18 @@ class QFbBackingStore;
class QFbScreen : public QObject, public QPlatformScreen
{
Q_OBJECT
+
public:
+ enum Flag {
+ DontForceFirstWindowToFullScreen = 0x01
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
QFbScreen();
~QFbScreen();
+ virtual bool initialize();
+
QRect geometry() const Q_DECL_OVERRIDE { return mGeometry; }
int depth() const Q_DECL_OVERRIDE { return mDepth; }
QImage::Format format() const Q_DECL_OVERRIDE { return mFormat; }
@@ -85,6 +93,8 @@ public:
virtual void raise(QFbWindow *window);
virtual void lower(QFbWindow *window);
virtual void topWindowChanged(QWindow *) {}
+ virtual int windowCount() const;
+ virtual Flags flags() const;
void addPendingBackingStore(QFbBackingStore *bs) { mPendingBackingStores << bs; }
@@ -112,20 +122,17 @@ protected:
int mDepth;
QImage::Format mFormat;
QSizeF mPhysicalSize;
- QImage *mScreenImage;
+ QImage mScreenImage;
private:
- void invalidateRectCache() { mIsUpToDate = false; }
- void generateRects();
-
- QPainter *mCompositePainter;
- QVector<QPair<QRect, int> > mCachedRects;
+ QPainter *mPainter;
QList<QFbBackingStore*> mPendingBackingStores;
friend class QFbWindow;
- bool mIsUpToDate;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QFbScreen::Flags)
+
QT_END_NAMESPACE
#endif // QFBSCREEN_P_H
diff --git a/src/platformsupport/fbconvenience/qfbwindow.cpp b/src/platformsupport/fbconvenience/qfbwindow.cpp
index 2d5570fe5d..7e016f2f49 100644
--- a/src/platformsupport/fbconvenience/qfbwindow.cpp
+++ b/src/platformsupport/fbconvenience/qfbwindow.cpp
@@ -66,41 +66,55 @@ void QFbWindow::setGeometry(const QRect &rect)
// store previous geometry for screen update
mOldGeometry = geometry();
- platformScreen()->invalidateRectCache();
QWindowSystemInterface::handleGeometryChange(window(), rect);
QPlatformWindow::setGeometry(rect);
+
+ if (mOldGeometry != rect)
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
}
void QFbWindow::setVisible(bool visible)
{
+ QRect newGeom;
+ QFbScreen *fbScreen = platformScreen();
if (visible) {
- if (mWindowState & Qt::WindowFullScreen)
- setGeometry(platformScreen()->geometry());
+ bool convOk = false;
+ static bool envDisableForceFullScreen = qEnvironmentVariableIntValue("QT_QPA_FB_FORCE_FULLSCREEN", &convOk) == 0 && convOk;
+ const bool platformDisableForceFullScreen = fbScreen->flags().testFlag(QFbScreen::DontForceFirstWindowToFullScreen);
+ const bool forceFullScreen = !envDisableForceFullScreen && !platformDisableForceFullScreen && fbScreen->windowCount() == 0;
+ if (forceFullScreen || (mWindowState & Qt::WindowFullScreen))
+ newGeom = platformScreen()->geometry();
else if (mWindowState & Qt::WindowMaximized)
- setGeometry(platformScreen()->availableGeometry());
+ newGeom = platformScreen()->availableGeometry();
}
QPlatformWindow::setVisible(visible);
if (visible)
- platformScreen()->addWindow(this);
+ fbScreen->addWindow(this);
else
- platformScreen()->removeWindow(this);
-}
+ fbScreen->removeWindow(this);
+ if (!newGeom.isEmpty())
+ setGeometry(newGeom); // may or may not generate an expose
+
+ if (newGeom.isEmpty() || newGeom == mOldGeometry) {
+ // QWindow::isExposed() maps to QWindow::visible() by default so simply
+ // generating an expose event regardless of this being a show or hide is
+ // just what is needed here.
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
+ }
+}
void QFbWindow::setWindowState(Qt::WindowState state)
{
QPlatformWindow::setWindowState(state);
mWindowState = state;
- platformScreen()->invalidateRectCache();
}
-
void QFbWindow::setWindowFlags(Qt::WindowFlags flags)
{
mWindowFlags = flags;
- platformScreen()->invalidateRectCache();
}
Qt::WindowFlags QFbWindow::windowFlags() const
@@ -111,29 +125,26 @@ Qt::WindowFlags QFbWindow::windowFlags() const
void QFbWindow::raise()
{
platformScreen()->raise(this);
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
}
void QFbWindow::lower()
{
platformScreen()->lower(this);
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
}
void QFbWindow::repaint(const QRegion &region)
{
- QRect currentGeometry = geometry();
-
- QRect dirtyClient = region.boundingRect();
- QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(),
- currentGeometry.top() + dirtyClient.top(),
- dirtyClient.width(),
- dirtyClient.height());
- QRect mOldGeometryLocal = mOldGeometry;
+ const QRect currentGeometry = geometry();
+ const QRect dirtyClient = region.boundingRect();
+ const QRect dirtyRegion = dirtyClient.translated(currentGeometry.topLeft());
+ const QRect oldGeometryLocal = mOldGeometry;
mOldGeometry = currentGeometry;
// If this is a move, redraw the previous location
- if (mOldGeometryLocal != currentGeometry)
- platformScreen()->setDirty(mOldGeometryLocal);
+ if (oldGeometryLocal != currentGeometry)
+ platformScreen()->setDirty(oldGeometryLocal);
platformScreen()->setDirty(dirtyRegion);
}
QT_END_NAMESPACE
-
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
index 2c5ce3e87d..a997bf0ba1 100644
--- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
@@ -677,6 +677,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
fid.filename = QFile::encodeName(fontfile->fileName);
fid.index = fontfile->indexValue;
+ // FIXME: Unify with logic in QFontEngineFT::create()
QFontEngineFT *engine = new QFontEngineFT(f);
engine->face_id = fid;
@@ -692,7 +693,7 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
QFontEngine *QFontconfigDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
{
- QFontEngineFT *engine = static_cast<QFontEngineFT*>(QBasicFontDatabase::fontEngine(fontData, pixelSize, hintingPreference));
+ QFontEngineFT *engine = static_cast<QFontEngineFT*>(QFreeTypeFontDatabase::fontEngine(fontData, pixelSize, hintingPreference));
if (engine == 0)
return 0;
@@ -844,7 +845,7 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData,
QString QFontconfigDatabase::resolveFontFamilyAlias(const QString &family) const
{
- QString resolved = QBasicFontDatabase::resolveFontFamilyAlias(family);
+ QString resolved = QFreeTypeFontDatabase::resolveFontFamilyAlias(family);
if (!resolved.isEmpty() && resolved != family)
return resolved;
FcPattern *pattern = FcPatternCreate();
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h
index f7e3172b65..6a3261de30 100644
--- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase_p.h
@@ -52,13 +52,13 @@
//
#include <qpa/qplatformfontdatabase.h>
-#include <QtFontDatabaseSupport/private/qbasicfontdatabase_p.h>
+#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
QT_BEGIN_NAMESPACE
class QFontEngineFT;
-class QFontconfigDatabase : public QBasicFontDatabase
+class QFontconfigDatabase : public QFreeTypeFontDatabase
{
public:
void populateFontDatabase() Q_DECL_OVERRIDE;
diff --git a/src/platformsupport/fontdatabases/fontdatabases.pro b/src/platformsupport/fontdatabases/fontdatabases.pro
index 9376c3b702..d2726d08a0 100644
--- a/src/platformsupport/fontdatabases/fontdatabases.pro
+++ b/src/platformsupport/fontdatabases/fontdatabases.pro
@@ -7,11 +7,11 @@ CONFIG += static internal_module
DEFINES += QT_NO_CAST_FROM_ASCII
PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h
-darwin:!if(watchos:CONFIG(simulator, simulator|device)) {
+darwin {
include($$PWD/mac/coretext.pri)
} else {
qtConfig(freetype) {
- include($$PWD/basic/basic.pri)
+ include($$PWD/freetype/freetype.pri)
}
unix {
diff --git a/src/platformsupport/fontdatabases/basic/basic.pri b/src/platformsupport/fontdatabases/freetype/freetype.pri
index 0617bf74d7..7bda687ef4 100644
--- a/src/platformsupport/fontdatabases/basic/basic.pri
+++ b/src/platformsupport/fontdatabases/freetype/freetype.pri
@@ -1,9 +1,9 @@
HEADERS += \
- $$PWD/qbasicfontdatabase_p.h \
+ $$PWD/qfreetypefontdatabase_p.h \
$$PWD/qfontengine_ft_p.h
SOURCES += \
- $$PWD/qbasicfontdatabase.cpp \
+ $$PWD/qfreetypefontdatabase.cpp \
$$PWD/qfontengine_ft.cpp
QMAKE_USE_PRIVATE += freetype
diff --git a/src/platformsupport/fontdatabases/basic/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
index de6da88245..39b6814a57 100644
--- a/src/platformsupport/fontdatabases/basic/qfontengine_ft.cpp
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
@@ -44,6 +44,10 @@
#include "qfontengine_ft_p.h"
#include "private/qimage_p.h"
#include <private/qstringiterator_p.h>
+#include <qguiapplication.h>
+#include <qscreen.h>
+#include <qpa/qplatformscreen.h>
+#include <QtCore/QUuid>
#ifndef QT_NO_FREETYPE
@@ -61,17 +65,19 @@
#include FT_TRUETYPE_TABLES_H
#include FT_TYPE1_TABLES_H
#include FT_GLYPH_H
+#include FT_MODULE_H
#if defined(FT_LCD_FILTER_H)
#include FT_LCD_FILTER_H
+#define QT_USE_FREETYPE_LCDFILTER
#endif
#if defined(FT_CONFIG_OPTIONS_H)
#include FT_CONFIG_OPTIONS_H
#endif
-#if defined(FT_LCD_FILTER_H)
-#define QT_USE_FREETYPE_LCDFILTER
+#if defined(FT_FONT_FORMATS_H)
+#include FT_FONT_FORMATS_H
#endif
#ifdef QT_LINUXBASE
@@ -151,6 +157,14 @@ QtFreetypeData *qt_getFreetypeData()
QtFreetypeData *&freetypeData = theFreetypeData()->localData();
if (!freetypeData)
freetypeData = new QtFreetypeData;
+ if (!freetypeData->library) {
+ FT_Init_FreeType(&freetypeData->library);
+#if defined(FT_FONT_FORMATS_H)
+ // Freetype defaults to disabling stem-darkening on CFF, we re-enable it.
+ FT_Bool no_darkening = false;
+ FT_Property_Set(freetypeData->library, "cff", "no-stem-darkening", &no_darkening);
+#endif
+ }
return freetypeData;
}
#endif
@@ -158,8 +172,7 @@ QtFreetypeData *qt_getFreetypeData()
FT_Library qt_getFreetype()
{
QtFreetypeData *freetypeData = qt_getFreetypeData();
- if (!freetypeData->library)
- FT_Init_FreeType(&freetypeData->library);
+ Q_ASSERT(freetypeData->library);
return freetypeData->library;
}
@@ -218,8 +231,6 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
return 0;
QtFreetypeData *freetypeData = qt_getFreetypeData();
- if (!freetypeData->library)
- FT_Init_FreeType(&freetypeData->library);
QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
if (freetype) {
@@ -659,6 +670,93 @@ static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height,
}
}
+static QFontEngine::SubpixelAntialiasingType subpixelAntialiasingTypeHint()
+{
+ static int type = -1;
+ if (type == -1) {
+ if (QScreen *screen = QGuiApplication::primaryScreen())
+ type = screen->handle()->subpixelAntialiasingTypeHint();
+ }
+ return static_cast<QFontEngine::SubpixelAntialiasingType>(type);
+}
+
+QFontEngineFT *QFontEngineFT::create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData)
+{
+ QScopedPointer<QFontEngineFT> engine(new QFontEngineFT(fontDef));
+
+ QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono;
+ const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
+
+ if (antialias) {
+ QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint();
+ if (subpixelType == QFontEngine::Subpixel_None || (fontDef.styleStrategy & QFont::NoSubpixelAntialias)) {
+ format = QFontEngineFT::Format_A8;
+ engine->subpixelType = QFontEngine::Subpixel_None;
+ } else {
+ format = QFontEngineFT::Format_A32;
+ engine->subpixelType = subpixelType;
+ }
+ }
+
+ if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) {
+ qWarning("QFontEngineFT: Failed to create FreeType font engine");
+ return nullptr;
+ }
+
+ engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
+ return engine.take();
+}
+
+namespace {
+ class QFontEngineFTRawData: public QFontEngineFT
+ {
+ public:
+ QFontEngineFTRawData(const QFontDef &fontDef) : QFontEngineFT(fontDef)
+ {
+ }
+
+ void updateFamilyNameAndStyle()
+ {
+ fontDef.family = QString::fromLatin1(freetype->face->family_name);
+
+ if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)
+ fontDef.style = QFont::StyleItalic;
+
+ if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD)
+ fontDef.weight = QFont::Bold;
+ }
+
+ bool initFromData(const QByteArray &fontData)
+ {
+ FaceId faceId;
+ faceId.filename = "";
+ faceId.index = 0;
+ faceId.uuid = QUuid::createUuid().toByteArray();
+
+ return init(faceId, true, Format_None, fontData);
+ }
+ };
+}
+
+QFontEngineFT *QFontEngineFT::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
+{
+ QFontDef fontDef;
+ fontDef.pixelSize = pixelSize;
+ fontDef.stretch = QFont::Unstretched;
+ fontDef.hintingPreference = hintingPreference;
+
+ QFontEngineFTRawData *fe = new QFontEngineFTRawData(fontDef);
+ if (!fe->initFromData(fontData)) {
+ delete fe;
+ return 0;
+ }
+
+ fe->updateFamilyNameAndStyle();
+ fe->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
+
+ return fe;
+}
+
QFontEngineFT::QFontEngineFT(const QFontDef &fd)
: QFontEngine(Freetype)
{
@@ -687,6 +785,7 @@ QFontEngineFT::QFontEngineFT(const QFontDef &fd)
cacheEnabled = env.isEmpty() || env.toInt() == 0;
m_subPixelPositionCount = 4;
forceAutoHint = false;
+ stemDarkeningDriver = false;
}
QFontEngineFT::~QFontEngineFT()
@@ -798,6 +897,17 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
}
}
}
+#if defined(FT_FONT_FORMATS_H)
+ const char *fmt = FT_Get_Font_Format(face);
+ if (fmt && qstrncmp(fmt, "CFF", 4) == 0) {
+ FT_Bool no_stem_darkening = true;
+ FT_Error err = FT_Property_Get(qt_getFreetype(), "cff", "no-stem-darkening", &no_stem_darkening);
+ if (err == FT_Err_Ok)
+ stemDarkeningDriver = !no_stem_darkening;
+ else
+ stemDarkeningDriver = false;
+ }
+#endif
fontDef.styleName = QString::fromUtf8(face->style_name);
@@ -841,6 +951,11 @@ void QFontEngineFT::setDefaultHintStyle(HintStyle style)
default_hint_style = style;
}
+bool QFontEngineFT::expectsGammaCorrectedBlending() const
+{
+ return stemDarkeningDriver;
+}
+
int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
bool &hsubpixel, int &vfactor) const
{
diff --git a/src/platformsupport/fontdatabases/basic/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
index c5f3b0443e..2993e3b616 100644
--- a/src/platformsupport/fontdatabases/basic/qfontengine_ft_p.h
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
@@ -246,6 +246,7 @@ private:
QPoint *offset) Q_DECL_OVERRIDE;
bool hasInternalCaching() const Q_DECL_OVERRIDE { return cacheEnabled; }
void unlockAlphaMapForGlyph() Q_DECL_OVERRIDE;
+ bool expectsGammaCorrectedBlending() const Q_DECL_OVERRIDE;
void removeGlyphFromCache(glyph_t glyph) Q_DECL_OVERRIDE;
int glyphMargin(QFontEngine::GlyphFormat /* format */) Q_DECL_OVERRIDE { return 0; }
@@ -291,6 +292,10 @@ private:
bool initFromFontEngine(const QFontEngineFT *fontEngine);
HintStyle defaultHintStyle() const { return default_hint_style; }
+
+ static QFontEngineFT *create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData = QByteArray());
+ static QFontEngineFT *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
+
protected:
QFreetypeFace *freetype;
@@ -305,12 +310,12 @@ protected:
bool embeddedbitmap;
bool cacheEnabled;
bool forceAutoHint;
+ bool stemDarkeningDriver;
private:
friend class QFontEngineFTRawFont;
friend class QFontconfigDatabase;
- friend class QBasicFontDatabase;
- friend class QCoreTextFontDatabase;
+ friend class QFreeTypeFontDatabase;
friend class QFontEngineMultiFontConfig;
int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase.cpp
index 8cf572b1af..2caa47658a 100644
--- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp
+++ b/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase.cpp
@@ -37,7 +37,7 @@
**
****************************************************************************/
-#include "qbasicfontdatabase_p.h"
+#include "qfreetypefontdatabase_p.h"
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformscreen.h>
@@ -45,7 +45,6 @@
#include <QtCore/QFile>
#include <QtCore/QLibraryInfo>
#include <QtCore/QDir>
-#include <QtCore/QUuid>
#include <QtCore/QtEndian>
#undef QT_NO_FREETYPE
@@ -57,7 +56,7 @@
QT_BEGIN_NAMESPACE
-void QBasicFontDatabase::populateFontDatabase()
+void QFreeTypeFontDatabase::populateFontDatabase()
{
QString fontpath = fontDir();
QDir dir(fontpath);
@@ -79,100 +78,32 @@ void QBasicFontDatabase::populateFontDatabase()
const auto fis = dir.entryInfoList(nameFilters, QDir::Files);
for (const QFileInfo &fi : fis) {
const QByteArray file = QFile::encodeName(fi.absoluteFilePath());
- QBasicFontDatabase::addTTFile(QByteArray(), file);
+ QFreeTypeFontDatabase::addTTFile(QByteArray(), file);
}
}
-QFontEngine *QBasicFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPtr)
+QFontEngine *QFreeTypeFontDatabase::fontEngine(const QFontDef &fontDef, void *usrPtr)
{
- FontFile *fontfile = static_cast<FontFile *> (usrPtr);
- QFontEngine::FaceId fid;
- fid.filename = QFile::encodeName(fontfile->fileName);
- fid.index = fontfile->indexValue;
-
- bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
- QFontEngineFT *engine = new QFontEngineFT(fontDef);
- QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono;
- if (antialias) {
- QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint();
- if (subpixelType == QFontEngine::Subpixel_None || (fontDef.styleStrategy & QFont::NoSubpixelAntialias)) {
- format = QFontEngineFT::Format_A8;
- engine->subpixelType = QFontEngine::Subpixel_None;
- } else {
- format = QFontEngineFT::Format_A32;
- engine->subpixelType = subpixelType;
- }
- }
-
- if (!engine->init(fid, antialias, format) || engine->invalid()) {
- delete engine;
- engine = 0;
- } else {
- engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
- }
-
- return engine;
-}
-
-namespace {
-
- class QFontEngineFTRawData: public QFontEngineFT
- {
- public:
- QFontEngineFTRawData(const QFontDef &fontDef) : QFontEngineFT(fontDef)
- {
- }
-
- void updateFamilyNameAndStyle()
- {
- fontDef.family = QString::fromLatin1(freetype->face->family_name);
-
- if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)
- fontDef.style = QFont::StyleItalic;
-
- if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD)
- fontDef.weight = QFont::Bold;
- }
-
- bool initFromData(const QByteArray &fontData)
- {
- FaceId faceId;
- faceId.filename = "";
- faceId.index = 0;
- faceId.uuid = QUuid::createUuid().toByteArray();
-
- return init(faceId, true, Format_None, fontData);
- }
- };
+ FontFile *fontfile = static_cast<FontFile *>(usrPtr);
+ QFontEngine::FaceId faceId;
+ faceId.filename = QFile::encodeName(fontfile->fileName);
+ faceId.index = fontfile->indexValue;
+ return QFontEngineFT::create(fontDef, faceId);
}
-QFontEngine *QBasicFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize,
+QFontEngine *QFreeTypeFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize,
QFont::HintingPreference hintingPreference)
{
- QFontDef fontDef;
- fontDef.pixelSize = pixelSize;
- fontDef.stretch = QFont::Unstretched;
- fontDef.hintingPreference = hintingPreference;
-
- QFontEngineFTRawData *fe = new QFontEngineFTRawData(fontDef);
- if (!fe->initFromData(fontData)) {
- delete fe;
- return 0;
- }
-
- fe->updateFamilyNameAndStyle();
- fe->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
-
- return fe;
+ return QFontEngineFT::create(fontData, pixelSize, hintingPreference);
}
-QStringList QBasicFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
+QStringList QFreeTypeFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
{
- return QBasicFontDatabase::addTTFile(fontData, fileName.toLocal8Bit());
+ return QFreeTypeFontDatabase::addTTFile(fontData, fileName.toLocal8Bit());
}
-void QBasicFontDatabase::releaseHandle(void *handle)
+void QFreeTypeFontDatabase::releaseHandle(void *handle)
{
FontFile *file = static_cast<FontFile *>(handle);
delete file;
@@ -180,7 +111,7 @@ void QBasicFontDatabase::releaseHandle(void *handle)
extern FT_Library qt_getFreetype();
-QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file)
+QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file)
{
FT_Library library = qt_getFreetype();
diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h b/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase_p.h
index 8d8f61973b..6d51361400 100644
--- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h
+++ b/src/platformsupport/fontdatabases/freetype/qfreetypefontdatabase_p.h
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef QBASICFONTDATABASE_H
-#define QBASICFONTDATABASE_H
+#ifndef QFREETYPEFONTDATABASE_H
+#define QFREETYPEFONTDATABASE_H
//
// W A R N I N G
@@ -63,7 +63,7 @@ struct FontFile
int indexValue;
};
-class QBasicFontDatabase : public QPlatformFontDatabase
+class QFreeTypeFontDatabase : public QPlatformFontDatabase
{
public:
void populateFontDatabase() Q_DECL_OVERRIDE;
@@ -77,4 +77,4 @@ public:
QT_END_NAMESPACE
-#endif // QBASICFONTDATABASE_H
+#endif // QFREETYPEFONTDATABASE_H
diff --git a/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h b/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h
index 37c667eeb3..ccf5ad6d13 100644
--- a/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h
+++ b/src/platformsupport/fontdatabases/genericunix/qgenericunixfontdatabase_p.h
@@ -57,8 +57,8 @@
#include <QtFontDatabaseSupport/private/qfontconfigdatabase_p.h>
typedef QFontconfigDatabase QGenericUnixFontDatabase;
#else
-#include <QtFontDatabaseSupport/private/qbasicfontdatabase_p.h>
-typedef QBasicFontDatabase QGenericUnixFontDatabase;
+#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
+typedef QFreeTypeFontDatabase QGenericUnixFontDatabase;
#endif //Q_FONTCONFIGDATABASE
#endif // QGENERICUNIXFONTDATABASE_H
diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri
index 50dafc3f89..a533234c26 100644
--- a/src/platformsupport/fontdatabases/mac/coretext.pri
+++ b/src/platformsupport/fontdatabases/mac/coretext.pri
@@ -3,14 +3,29 @@ OBJECTIVE_SOURCES += $$PWD/qfontengine_coretext.mm $$PWD/qcoretextfontdatabase.m
qtConfig(freetype) {
QMAKE_USE_PRIVATE += freetype
- HEADERS += basic/qfontengine_ft_p.h
- SOURCES += basic/qfontengine_ft.cpp
+ HEADERS += freetype/qfontengine_ft_p.h
+ SOURCES += freetype/qfontengine_ft.cpp
}
uikit: \
# On iOS/tvOS/watchOS CoreText and CoreGraphics are stand-alone frameworks
LIBS_PRIVATE += -framework CoreText -framework CoreGraphics
else: \
- # On Mac OS they are part of the ApplicationServices umbrella framework,
- # even in 10.8 where they were also made available stand-alone.
- LIBS_PRIVATE += -framework ApplicationServices
+ # On macOS they are re-exported by the AppKit framework
+ LIBS_PRIVATE += -framework AppKit
+
+# CoreText is documented to be available on watchOS, but the headers aren't present
+# in the watchOS Simulator SDK like they are supposed to be. Work around the problem
+# by adding the device SDK's headers to the search path as a fallback.
+# rdar://25314492, rdar://27844864
+watchos:simulator {
+ simulator_system_frameworks = $$xcodeSDKInfo(Path, $${simulator.sdk})/System/Library/Frameworks
+ device_system_frameworks = $$xcodeSDKInfo(Path, $${device.sdk})/System/Library/Frameworks
+ for (arch, QMAKE_APPLE_SIMULATOR_ARCHS) {
+ QMAKE_CXXFLAGS += \
+ -Xarch_$${arch} \
+ -F$$simulator_system_frameworks \
+ -Xarch_$${arch} \
+ -F$$device_system_frameworks
+ }
+}
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
index 3d94982f60..3b9a456be0 100644
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
@@ -112,12 +112,8 @@ static NSInteger languageMapSort(id obj1, id obj2, void *context)
}
#endif
-QCoreTextFontDatabase::QCoreTextFontDatabase(bool useFreeType)
-#ifndef QT_NO_FREETYPE
- : m_useFreeType(useFreeType)
-#endif
+QCoreTextFontDatabase::QCoreTextFontDatabase()
{
- Q_UNUSED(useFreeType)
#ifdef Q_OS_MACX
QSettings appleSettings(QLatin1String("apple.com"));
QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold"));
@@ -203,10 +199,6 @@ static CFArrayRef availableFamilyNames()
void QCoreTextFontDatabase::populateFontDatabase()
{
- // The caller (QFontDB) expects the db to be populate only with system fonts, so we need
- // to make sure that any previously registered app fonts become invisible.
- removeApplicationFonts();
-
QCFType<CFArrayRef> familyNames = availableFamilyNames();
const int numberOfFamilies = CFArrayGetCount(familyNames);
for (int i = 0; i < numberOfFamilies; ++i) {
@@ -362,66 +354,43 @@ void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font, con
fd.pixelSize, fd.fixedPitch, fd.writingSystems, (void *) font);
}
-void QCoreTextFontDatabase::releaseHandle(void *handle)
+static NSString * const kQtFontDataAttribute = @"QtFontDataAttribute";
+
+template <typename T>
+T *descriptorAttribute(CTFontDescriptorRef descriptor, CFStringRef name)
{
- CFRelease(CTFontDescriptorRef(handle));
+ return [static_cast<T *>(CTFontDescriptorCopyAttribute(descriptor, name)) autorelease];
}
-#ifndef QT_NO_FREETYPE
-static QByteArray filenameForCFUrl(CFURLRef url)
+void QCoreTextFontDatabase::releaseHandle(void *handle)
{
- // The on-stack buffer prevents that a QByteArray allocated for the worst case (MAXPATHLEN)
- // stays around for the lifetime of the font. Additionally, it helps to move the char
- // signedness cast to an acceptable place.
- uchar buffer[MAXPATHLEN];
- QByteArray filename;
-
- if (!CFURLGetFileSystemRepresentation(url, true, buffer, sizeof(buffer))) {
- qWarning("QCoreTextFontDatabase::filenameForCFUrl: could not resolve file for URL %s",
- url ? qPrintable(QString::fromCFString(CFURLGetString(url))) : "(null)");
- } else {
- QCFType<CFStringRef> scheme = CFURLCopyScheme(url);
- if (QString::fromCFString(scheme) == QLatin1String("qrc"))
- filename = ":";
-
- filename += reinterpret_cast<char *>(buffer);
+ CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(handle);
+ if (NSValue *fontDataValue = descriptorAttribute<NSValue>(descriptor, (CFStringRef)kQtFontDataAttribute)) {
+ QByteArray *fontData = static_cast<QByteArray *>(fontDataValue.pointerValue);
+ delete fontData;
}
-
- return filename;
+ CFRelease(descriptor);
}
-#endif
extern CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef);
-QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr)
+template <>
+QFontEngine *QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::fontEngine(const QFontDef &fontDef, void *usrPtr)
{
CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(usrPtr);
-#ifndef QT_NO_FREETYPE
- if (m_useFreeType) {
- QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute)));
-
- QByteArray filename;
- if (url)
- filename = filenameForCFUrl(url);
-
- return freeTypeFontEngine(f, filename);
- }
-#endif
-
// Since we do not pass in the destination DPI to CoreText when making
// the font, we need to pass in a point size which is scaled to include
// the DPI. The default DPI for the screen is 72, thus the scale factor
// is destinationDpi / 72, but since pixelSize = pointSize / 72 * dpi,
// the pixelSize is actually the scaled point size for the destination
// DPI, and we can use that directly.
- qreal scaledPointSize = f.pixelSize;
+ qreal scaledPointSize = fontDef.pixelSize;
- CGAffineTransform matrix = qt_transform_from_fontdef(f);
+ CGAffineTransform matrix = qt_transform_from_fontdef(fontDef);
CTFontRef font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix);
if (font) {
- QFontEngine *engine = new QCoreTextFontEngine(font, f);
- engine->fontDef = f;
+ QFontEngine *engine = new QCoreTextFontEngine(font, fontDef);
CFRelease(font);
return engine;
}
@@ -429,60 +398,39 @@ QFontEngine *QCoreTextFontDatabase::fontEngine(const QFontDef &f, void *usrPtr)
return NULL;
}
-static void releaseFontData(void* info, const void* data, size_t size)
+#ifndef QT_NO_FREETYPE
+template <>
+QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const QFontDef &fontDef, void *usrPtr)
{
- Q_UNUSED(data);
- Q_UNUSED(size);
- delete (QByteArray*)info;
-}
+ CTFontDescriptorRef descriptor = static_cast<CTFontDescriptorRef>(usrPtr);
-QFontEngine *QCoreTextFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
-{
-#ifndef QT_NO_FREETYPE
- if (m_useFreeType) {
- QByteArray *fontDataCopy = new QByteArray(fontData);
- QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
- fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
- QCFType<CGFontRef> cgFont(CGFontCreateWithDataProvider(dataProvider));
-
- if (!cgFont) {
- qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed");
- return Q_NULLPTR;
- }
+ if (NSURL *url = descriptorAttribute<NSURL>(descriptor, kCTFontURLAttribute)) {
+ Q_ASSERT(url.fileURL);
+ QFontEngine::FaceId faceId;
+ faceId.filename = QString::fromNSString(url.path).toUtf8();
+ return QFontEngineFT::create(fontDef, faceId);
- QFontDef fontDef;
- fontDef.pixelSize = pixelSize;
- fontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi();
- fontDef.hintingPreference = hintingPreference;
- CGAffineTransform transform = qt_transform_from_fontdef(fontDef);
- QCFType<CTFontRef> ctFont(CTFontCreateWithGraphicsFont(cgFont, fontDef.pixelSize, &transform, Q_NULLPTR));
- QCFType<CFURLRef> url(static_cast<CFURLRef>(CTFontCopyAttribute(ctFont, kCTFontURLAttribute)));
- return freeTypeFontEngine(fontDef, filenameForCFUrl(url), fontData);
+ } else if (NSValue *fontDataValue = descriptorAttribute<NSValue>(descriptor, (CFStringRef)kQtFontDataAttribute)) {
+ QByteArray *fontData = static_cast<QByteArray *>(fontDataValue.pointerValue);
+ return QFontEngineFT::create(*fontData, fontDef.pixelSize,
+ static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
}
+ Q_UNREACHABLE();
+}
#endif
- Q_UNUSED(hintingPreference);
-
- QByteArray* fontDataCopy = new QByteArray(fontData);
- QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
- fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
-
- CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider);
-
- QFontEngine *fontEngine = NULL;
- if (cgFont == NULL) {
- qWarning("QCoreTextFontDatabase::fontEngine: CGFontCreateWithDataProvider failed");
- } else {
- QFontDef def;
- def.pixelSize = pixelSize;
- def.pointSize = pixelSize * 72.0 / qt_defaultDpi();
- fontEngine = new QCoreTextFontEngine(cgFont, def);
- CFRelease(cgFont);
- }
-
- return fontEngine;
+template <class T>
+QFontEngine *QCoreTextFontDatabaseEngineFactory<T>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
+{
+ return T::create(fontData, pixelSize, hintingPreference);
}
+// Explicitly instantiate so that we don't need the plugin to involve FreeType
+template class QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>;
+#ifndef QT_NO_FREETYPE
+template class QCoreTextFontDatabaseEngineFactory<QFontEngineFT>;
+#endif
+
QFont::StyleHint styleHintFromNSString(NSString *style)
{
if ([style isEqual: @"sans-serif"])
@@ -615,84 +563,41 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo
return fallbackLists[styleLookupKey.arg(styleHint)];
}
-static CFArrayRef createDescriptorArrayForFont(CTFontRef font, const QString &fileName = QString())
-{
- CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- QCFType<CTFontDescriptorRef> descriptor = CTFontCopyFontDescriptor(font);
-
- Q_UNUSED(fileName)
-#ifndef QT_NO_FREETYPE
- // The physical font source URL (usually a local file or Qt resource) is only required for
- // FreeType, when using non-system fonts, and needs some hackery to attach in a format
- // agreeable to OSX.
- if (!fileName.isEmpty()) {
- QCFType<CFURLRef> fontURL;
-
- if (fileName.startsWith(QLatin1String(":/"))) {
- // QUrl::fromLocalFile() doesn't accept qrc pseudo-paths like ":/fonts/myfont.ttf".
- // Therefore construct from QString with the qrc:// scheme -> "qrc:///fonts/myfont.ttf".
- fontURL = QUrl(QStringLiteral("qrc://") + fileName.mid(1)).toCFURL();
- } else {
- // At this point we hope that filename is in a format that QUrl can handle.
- fontURL = QUrl::fromLocalFile(fileName).toCFURL();
- }
-
- QCFType<CFMutableDictionaryRef> attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 1,
- &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFDictionaryAddValue(attributes, kCTFontURLAttribute, fontURL);
- descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, attributes);
- }
-#endif
-
- CFArrayAppendValue(array, descriptor);
- return array;
-}
-
QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
{
QCFType<CFArrayRef> fonts;
- QStringList families;
- CFErrorRef error = 0;
if (!fontData.isEmpty()) {
- QByteArray* fontDataCopy = new QByteArray(fontData);
- QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(fontDataCopy,
- fontDataCopy->constData(), fontDataCopy->size(), releaseFontData);
- QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider);
- if (cgFont) {
- if (CTFontManagerRegisterGraphicsFont(cgFont, &error)) {
- QCFType<CTFontRef> font = CTFontCreateWithGraphicsFont(cgFont, 0.0, NULL, NULL);
- fonts = createDescriptorArrayForFont(font
-#ifndef QT_NO_FREETYPE
- , m_useFreeType ? fileName : QString()
-#endif
- );
- m_applicationFonts.append(QVariant::fromValue(QCFType<CGFontRef>::constructFromGet(cgFont)));
- }
+ QCFType<CFDataRef> fontDataReference = fontData.toRawCFData();
+ if (QCFType<CTFontDescriptorRef> descriptor = CTFontManagerCreateFontDescriptorFromData(fontDataReference)) {
+ // There's no way to get the data back out of a font descriptor created with
+ // CTFontManagerCreateFontDescriptorFromData, so we attach the data manually.
+ NSDictionary *attributes = @{ kQtFontDataAttribute : [NSValue valueWithPointer:new QByteArray(fontData)] };
+ descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, (CFDictionaryRef)attributes);
+ CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ CFArrayAppendValue(array, descriptor);
+ fonts = array;
}
} else {
- QCFType<CFURLRef> fontURL = CFURLCreateWithFileSystemPath(NULL, QCFString(fileName), kCFURLPOSIXPathStyle, false);
- if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error)) {
- fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL);
- m_applicationFonts.append(QVariant::fromValue(QCFType<CFURLRef>::constructFromGet(fontURL)));
- }
+ QCFType<CFURLRef> fontURL = QUrl::fromLocalFile(fileName).toCFURL();
+ fonts = CTFontManagerCreateFontDescriptorsFromURL(fontURL);
}
- if (error) {
- NSLog(@"Unable to register font: %@", error);
- CFRelease(error);
- }
+ if (!fonts)
+ return QStringList();
- if (fonts) {
- const int numFonts = CFArrayGetCount(fonts);
- for (int i = 0; i < numFonts; ++i) {
- CTFontDescriptorRef fontDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fonts, i));
- populateFromDescriptor(fontDescriptor);
- QCFType<CFStringRef> familyName = CFStringRef(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute));
- families.append(QCFString(familyName));
- }
+ QStringList families;
+ const int numFonts = CFArrayGetCount(fonts);
+ for (int i = 0; i < numFonts; ++i) {
+ CTFontDescriptorRef fontDescriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(fonts, i));
+ populateFromDescriptor(fontDescriptor);
+ QCFType<CFStringRef> familyName = CFStringRef(CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute));
+ families.append(QString::fromCFString(familyName));
}
+ // Note: We don't do font matching via CoreText for application fonts, so we don't
+ // need to enable font matching for them via CTFontManagerEnableFontDescriptors.
+
return families;
}
@@ -708,71 +613,71 @@ static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f)
{
switch (f) {
case QPlatformTheme::SystemFont:
- return kCTFontSystemFontType;
+ return kCTFontUIFontSystem;
case QPlatformTheme::MenuFont:
case QPlatformTheme::MenuBarFont:
case QPlatformTheme::MenuItemFont:
- return kCTFontMenuItemFontType;
+ return kCTFontUIFontMenuItem;
case QPlatformTheme::MessageBoxFont:
- return kCTFontEmphasizedSystemFontType;
+ return kCTFontUIFontEmphasizedSystem;
case QPlatformTheme::LabelFont:
- return kCTFontSystemFontType;
+ return kCTFontUIFontSystem;
case QPlatformTheme::TipLabelFont:
return kCTFontToolTipFontType;
case QPlatformTheme::StatusBarFont:
- return kCTFontSystemFontType;
+ return kCTFontUIFontSystem;
case QPlatformTheme::TitleBarFont:
- return kCTFontWindowTitleFontType;
+ return kCTFontUIFontWindowTitle;
case QPlatformTheme::MdiSubWindowTitleFont:
case QPlatformTheme::DockWidgetTitleFont:
- return kCTFontSystemFontType;
+ return kCTFontUIFontSystem;
case QPlatformTheme::PushButtonFont:
- return kCTFontPushButtonFontType;
+ return kCTFontUIFontPushButton;
case QPlatformTheme::CheckBoxFont:
case QPlatformTheme::RadioButtonFont:
- return kCTFontSystemFontType;
+ return kCTFontUIFontSystem;
case QPlatformTheme::ToolButtonFont:
- return kCTFontSmallToolbarFontType;
+ return kCTFontUIFontSmallToolbar;
case QPlatformTheme::ItemViewFont:
- return kCTFontSystemFontType;
+ return kCTFontUIFontSystem;
case QPlatformTheme::ListViewFont:
- return kCTFontViewsFontType;
+ return kCTFontUIFontViews;
case QPlatformTheme::HeaderViewFont:
- return kCTFontSmallSystemFontType;
+ return kCTFontUIFontSmallSystem;
case QPlatformTheme::ListBoxFont:
- return kCTFontViewsFontType;
+ return kCTFontUIFontViews;
case QPlatformTheme::ComboMenuItemFont:
- return kCTFontSystemFontType;
+ return kCTFontUIFontSystem;
case QPlatformTheme::ComboLineEditFont:
- return kCTFontViewsFontType;
+ return kCTFontUIFontViews;
case QPlatformTheme::SmallFont:
- return kCTFontSmallSystemFontType;
+ return kCTFontUIFontSmallSystem;
case QPlatformTheme::MiniFont:
- return kCTFontMiniSystemFontType;
+ return kCTFontUIFontMiniSystem;
case QPlatformTheme::FixedFont:
- return kCTFontUserFixedPitchFontType;
+ return kCTFontUIFontUserFixedPitch;
default:
- return kCTFontSystemFontType;
+ return kCTFontUIFontSystem;
}
}
@@ -848,7 +753,7 @@ QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const
QFont QCoreTextFontDatabase::defaultFont() const
{
if (defaultFontName.isEmpty()) {
- QCFType<CTFontRef> font = CTFontCreateUIFontForLanguage(kCTFontSystemFontType, 12.0, NULL);
+ QCFType<CTFontRef> font = CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, 12.0, NULL);
defaultFontName = (QString) QCFString(CTFontCopyFullName(font));
}
@@ -871,53 +776,5 @@ QList<int> QCoreTextFontDatabase::standardSizes() const
return ret;
}
-void QCoreTextFontDatabase::removeApplicationFonts()
-{
- if (m_applicationFonts.isEmpty())
- return;
-
- for (const QVariant &font : qAsConst(m_applicationFonts)) {
- CFErrorRef error;
- if (font.canConvert(qMetaTypeId<QCFType<CGFontRef> >())) {
- CTFontManagerUnregisterGraphicsFont(font.value<QCFType<CGFontRef> >(), &error);
- } else if (font.canConvert(qMetaTypeId<QCFType<CFURLRef> >())) {
- CTFontManagerUnregisterFontsForURL(font.value<QCFType<CFURLRef> >(), kCTFontManagerScopeProcess, &error);
- }
- }
-
- m_applicationFonts.clear();
-}
-
-#ifndef QT_NO_FREETYPE
-QFontEngine *QCoreTextFontDatabase::freeTypeFontEngine(const QFontDef &fontDef, const QByteArray &filename,
- const QByteArray &fontData)
-{
- QFontEngine::FaceId faceId;
- faceId.filename = filename;
- const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
-
- QScopedPointer<QFontEngineFT> engine(new QFontEngineFT(fontDef));
- QFontEngineFT::GlyphFormat format = QFontEngineFT::Format_Mono;
- if (antialias) {
- QFontEngine::SubpixelAntialiasingType subpixelType = subpixelAntialiasingTypeHint();
- if (subpixelType == QFontEngine::Subpixel_None || (fontDef.styleStrategy & QFont::NoSubpixelAntialias)) {
- format = QFontEngineFT::Format_A8;
- engine->subpixelType = QFontEngine::Subpixel_None;
- } else {
- format = QFontEngineFT::Format_A32;
- engine->subpixelType = subpixelType;
- }
- }
-
- if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) {
- qWarning("QCoreTextFontDatabase::freeTypefontEngine Failed to create engine");
- return Q_NULLPTR;
- }
- engine->setQtDefaultHintStyle(static_cast<QFont::HintingPreference>(fontDef.hintingPreference));
-
- return engine.take();
-}
-#endif
-
QT_END_NAMESPACE
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h
index 3b1be2e6a1..a7529b7fb0 100644
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase_p.h
@@ -72,13 +72,11 @@ QT_BEGIN_NAMESPACE
class QCoreTextFontDatabase : public QPlatformFontDatabase
{
public:
- QCoreTextFontDatabase(bool useFreeType = false);
+ QCoreTextFontDatabase();
~QCoreTextFontDatabase();
void populateFontDatabase() Q_DECL_OVERRIDE;
void populateFamily(const QString &familyName) Q_DECL_OVERRIDE;
- QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) Q_DECL_OVERRIDE;
- QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) Q_DECL_OVERRIDE;
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const Q_DECL_OVERRIDE;
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) Q_DECL_OVERRIDE;
void releaseHandle(void *handle) Q_DECL_OVERRIDE;
@@ -94,20 +92,23 @@ public:
private:
void populateFromDescriptor(CTFontDescriptorRef font, const QString &familyName = QString());
-#ifndef QT_NO_FREETYPE
- bool m_useFreeType;
- QFontEngine *freeTypeFontEngine(const QFontDef &fontDef, const QByteArray &filename,
- const QByteArray &fontData = QByteArray());
-#endif
mutable QString defaultFontName;
- void removeApplicationFonts();
-
- QVector<QVariant> m_applicationFonts;
mutable QSet<CTFontDescriptorRef> m_systemFontDescriptors;
mutable QHash<QPlatformTheme::Font, QFont *> m_themeFonts;
};
+// Split out into separate template class so that the compiler doesn't have
+// to generate code for each override in QCoreTextFontDatabase for each T.
+
+template <class T>
+class QCoreTextFontDatabaseEngineFactory : public QCoreTextFontDatabase
+{
+public:
+ QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
+ QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
+};
+
QT_END_NAMESPACE
#endif // QCORETEXTFONTDATABASE_H
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
index 7a06d5f1c9..49a6049c4b 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
@@ -141,7 +141,7 @@ static void loadAdvancesForGlyphs(CTFontRef ctfont,
{
Q_UNUSED(flags);
QVarLengthArray<CGSize> advances(len);
- CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len);
+ CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), len);
for (int i = 0; i < len; ++i) {
if (glyphs->glyphs[i] & 0xff000000)
@@ -177,6 +177,43 @@ CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef)
return transform;
}
+// Keeps font data alive until engine is disposed
+class QCoreTextRawFontEngine : public QCoreTextFontEngine
+{
+public:
+ QCoreTextRawFontEngine(CGFontRef font, const QFontDef &def, const QByteArray &fontData)
+ : QCoreTextFontEngine(font, def)
+ , m_fontData(fontData)
+ {}
+ QByteArray m_fontData;
+};
+
+QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
+{
+ Q_UNUSED(hintingPreference);
+
+ QCFType<CFDataRef> fontDataReference = fontData.toRawCFData();
+ QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithCFData(fontDataReference);
+
+ // Note: CTFontCreateWithGraphicsFont (which we call from the QCoreTextFontEngine
+ // constructor) has a bug causing it to retain the CGFontRef but never release it.
+ // The result is that we are leaking the CGFont, CGDataProvider, and CGData, but
+ // as the CGData is created from the raw QByteArray data, which we deref in the
+ // subclass above during destruction, we're at least not leaking the font data,
+ // (unless CoreText copies it internally). http://stackoverflow.com/questions/40805382/
+ QCFType<CGFontRef> cgFont = CGFontCreateWithDataProvider(dataProvider);
+
+ if (!cgFont) {
+ qWarning("QCoreTextFontEngine::create: CGFontCreateWithDataProvider failed");
+ return nullptr;
+ }
+
+ QFontDef def;
+ def.pixelSize = pixelSize;
+ def.pointSize = pixelSize * 72.0 / qt_defaultDpi();
+ return new QCoreTextRawFontEngine(cgFont, def, fontData);
+}
+
QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def)
: QFontEngine(Mac)
{
@@ -320,7 +357,7 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *
return true;
QVarLengthArray<CGSize> advances(glyph_pos);
- CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), glyph_pos);
+ CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), glyph_pos);
for (int i = 0; i < glyph_pos; ++i) {
if (glyphs->glyphs[i] & 0xff000000)
@@ -351,7 +388,7 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
{
glyph_metrics_t ret;
CGGlyph g = glyph;
- CGRect rect = CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, 0, 1);
+ CGRect rect = CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontOrientationHorizontal, &g, 0, 1);
if (synthesisFlags & QFontEngine::SynthesizedItalic) {
rect.size.width += rect.size.height * SYNTHETIC_ITALIC_SKEW;
}
@@ -360,7 +397,7 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
ret.x = QFixed::fromReal(rect.origin.x);
ret.y = -QFixed::fromReal(rect.origin.y) - ret.height;
CGSize advances[1];
- CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, advances, 1);
+ CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, &g, advances, 1);
ret.xoff = QFixed::fromReal(advances[0].width);
ret.yoff = QFixed::fromReal(advances[0].height);
@@ -602,6 +639,11 @@ glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed s
return br;
}
+bool QCoreTextFontEngine::expectsGammaCorrectedBlending() const
+{
+ // Only works well when font-smoothing is enabled
+ return (glyphFormat == Format_A32) && !(fontDef.styleStrategy & (QFont::NoAntialias | QFont::NoSubpixelAntialias));
+}
QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool aa, const QTransform &matrix)
{
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h
index d9ffbb5697..2986f0aaec 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h
@@ -110,6 +110,7 @@ public:
void doKerning(QGlyphLayout *g, ShaperFlags flags) const Q_DECL_OVERRIDE;
bool supportsTransformation(const QTransform &transform) const Q_DECL_OVERRIDE;
+ bool expectsGammaCorrectedBlending() const Q_DECL_OVERRIDE;
QFontEngine *cloneWithSize(qreal pixelSize) const Q_DECL_OVERRIDE;
Qt::HANDLE handle() const Q_DECL_OVERRIDE;
@@ -122,6 +123,8 @@ public:
static int antialiasingThreshold;
static QFontEngine::GlyphFormat defaultGlyphFormat;
+
+ static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
private:
void init();
QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool colorful, const QTransform &m);
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
index c457246354..d3e4daa341 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
@@ -591,12 +591,7 @@ namespace {
*/
QWindowsFontEngineData::QWindowsFontEngineData()
- : clearTypeEnabled(false)
- , fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma())
-#if !defined(QT_NO_DIRECTWRITE)
- , directWriteFactory(0)
- , directWriteGdiInterop(0)
-#endif
+ : fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma())
{
// from qapplication_win.cpp
UINT result = 0;
@@ -1221,8 +1216,6 @@ QWindowsFontEngineDataPtr sharedFontData()
}
#endif // QT_NO_THREAD
-extern Q_GUI_EXPORT bool qt_needs_a8_gamma_correction;
-
QWindowsFontDatabase::QWindowsFontDatabase()
{
// Properties accessed by QWin32PrintEngine (Qt Print Support)
@@ -1236,7 +1229,6 @@ QWindowsFontDatabase::QWindowsFontDatabase()
qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: "
<< data->clearTypeEnabled << "gamma: " << data->fontSmoothingGamma;
}
- qt_needs_a8_gamma_correction = true;
}
QWindowsFontDatabase::~QWindowsFontDatabase()
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp
index 65947ab7da..3f03b30f10 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp
@@ -393,14 +393,14 @@ void QWindowsFontDatabaseFT::populateFontDatabase()
QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, void *handle)
{
- QFontEngine *fe = QBasicFontDatabase::fontEngine(fontDef, handle);
+ QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontDef, handle);
qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.family << fe << handle;
return fe;
}
QFontEngine *QWindowsFontDatabaseFT::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
{
- QFontEngine *fe = QBasicFontDatabase::fontEngine(fontData, pixelSize, hintingPreference);
+ QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontData, pixelSize, hintingPreference);
qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe;
return fe;
}
@@ -410,7 +410,7 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QF
QStringList result;
result.append(QWindowsFontDatabase::familyForStyleHint(styleHint));
result.append(QWindowsFontDatabase::extraTryFontsForFamily(family));
- result.append(QBasicFontDatabase::fallbacksForFamily(family, style, styleHint, script));
+ result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script));
qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
<< script << result;
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h
index 3a432842e5..2df81274ad 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h
@@ -51,13 +51,13 @@
// We mean it.
//
-#include <QtFontDatabaseSupport/private/qbasicfontdatabase_p.h>
+#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
#include <QtCore/QSharedPointer>
#include <QtCore/qt_windows.h>
QT_BEGIN_NAMESPACE
-class QWindowsFontDatabaseFT : public QBasicFontDatabase
+class QWindowsFontDatabaseFT : public QFreeTypeFontDatabase
{
public:
void populateFontDatabase() Q_DECL_OVERRIDE;
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h
index 325f522335..15172c09da 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h
@@ -74,12 +74,12 @@ public:
uint pow_gamma[256];
- bool clearTypeEnabled;
+ bool clearTypeEnabled = false;
qreal fontSmoothingGamma;
- HDC hdc;
+ HDC hdc = 0;
#if !defined(QT_NO_DIRECTWRITE)
- IDWriteFactory *directWriteFactory;
- IDWriteGdiInterop *directWriteGdiInterop;
+ IDWriteFactory *directWriteFactory = nullptr;
+ IDWriteGdiInterop *directWriteGdiInterop = nullptr;
#endif
};
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
index 5af73a6f2b..6e95fb5a05 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
@@ -239,21 +239,9 @@ QWindowsFontEngine::QWindowsFontEngine(const QString &name,
: QFontEngine(Win),
m_fontEngineData(fontEngineData),
_name(name),
- hfont(0),
m_logfont(lf),
ttf(0),
- hasOutline(0),
- cmap(0),
- cmapSize(0),
- lbearing(SHRT_MIN),
- rbearing(SHRT_MIN),
- x_height(-1),
- synthesized_flags(-1),
- lineWidth(-1),
- widthCache(0),
- widthCacheSize(0),
- designAdvances(0),
- designAdvancesSize(0)
+ hasOutline(0)
{
qCDebug(lcQpaFonts) << __FUNCTION__ << name << lf.lfHeight;
hfont = CreateFontIndirect(&m_logfont);
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h
index 709de7d11d..5119adc0eb 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h
@@ -145,29 +145,29 @@ private:
const QString _name;
QString uniqueFamilyName;
- HFONT hfont;
+ HFONT hfont = 0;
const LOGFONT m_logfont;
uint ttf : 1;
uint hasOutline : 1;
uint hasUnreliableOutline : 1;
uint cffTable : 1;
TEXTMETRIC tm;
- const unsigned char *cmap;
- int cmapSize;
+ const unsigned char *cmap = nullptr;
+ int cmapSize = 0;
QByteArray cmapTable;
- mutable qreal lbearing;
- mutable qreal rbearing;
+ mutable qreal lbearing = SHRT_MIN;
+ mutable qreal rbearing = SHRT_MIN;
QFixed designToDevice;
- int unitsPerEm;
- QFixed x_height;
+ int unitsPerEm = 0;
+ QFixed x_height = -1;
FaceId _faceId;
- mutable int synthesized_flags;
- mutable QFixed lineWidth;
- mutable unsigned char *widthCache;
- mutable uint widthCacheSize;
- mutable QFixed *designAdvances;
- mutable int designAdvancesSize;
+ mutable int synthesized_flags = -1;
+ mutable QFixed lineWidth = -1;
+ mutable unsigned char *widthCache = nullptr;
+ mutable uint widthCacheSize = 0;
+ mutable QFixed *designAdvances = nullptr;
+ mutable int designAdvancesSize = 0;
};
class QWindowsMultiFontEngine : public QFontEngineMulti
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
index 683b7f65ad..f07e711048 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
@@ -355,6 +355,13 @@ void QWindowsFontEngineDirectWrite::collectMetrics()
m_faceId.filename = QFile::encodeName(filenameFromFontFile(fontFile));
fontFile->Release();
}
+
+ QByteArray table = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ const int advanceWidthMaxLocation = 10;
+ if (table.size() >= advanceWidthMaxLocation + int(sizeof(quint16))) {
+ quint16 advanceWidthMax = qFromBigEndian<quint16>(table.constData() + advanceWidthMaxLocation);
+ m_maxAdvanceWidth = DESIGN_TO_LOGICAL(advanceWidthMax);
+ }
}
QFixed QWindowsFontEngineDirectWrite::underlinePosition() const
@@ -607,8 +614,9 @@ QFixed QWindowsFontEngineDirectWrite::xHeight() const
qreal QWindowsFontEngineDirectWrite::maxCharWidth() const
{
- // ###
- return 0;
+ return fontDef.styleStrategy & QFont::ForceIntegerMetrics
+ ? m_maxAdvanceWidth.round().toReal()
+ : m_maxAdvanceWidth.toReal();
}
QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h
index 65b16b9ba7..db4e79e44f 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h
@@ -143,6 +143,7 @@ private:
QFixed m_descent;
QFixed m_xHeight;
QFixed m_lineGap;
+ QFixed m_maxAdvanceWidth;
FaceId m_faceId;
QString m_uniqueFamilyName;
};
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp
index 7022615511..f8fcff952a 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp
@@ -110,9 +110,7 @@ static inline HBITMAP createDIB(HDC hdc, int width, int height,
QWindowsNativeImage::QWindowsNativeImage(int width, int height,
QImage::Format format) :
- m_hdc(createDC()),
- m_bitmap(0),
- m_null_bitmap(0)
+ m_hdc(createDC())
{
if (width != 0 && height != 0) {
uchar *bits;
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h
index c27c0d1e98..6c47a527d2 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h
@@ -80,8 +80,8 @@ private:
const HDC m_hdc;
QImage m_image;
- HBITMAP m_bitmap;
- HBITMAP m_null_bitmap;
+ HBITMAP m_bitmap = 0;
+ HBITMAP m_null_bitmap = 0;
};
QT_END_NAMESPACE
diff --git a/src/platformsupport/fontdatabases/windows/windows.pri b/src/platformsupport/fontdatabases/windows/windows.pri
index 4ca0080ad9..0e64084cf1 100644
--- a/src/platformsupport/fontdatabases/windows/windows.pri
+++ b/src/platformsupport/fontdatabases/windows/windows.pri
@@ -26,3 +26,4 @@ qtConfig(directwrite) {
}
LIBS += -lole32 -lgdi32 -luser32 -ladvapi32
+mingw: LIBS += -luuid
diff --git a/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase.cpp b/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase.cpp
index eb5a38855e..2a95ca26a9 100644
--- a/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase.cpp
+++ b/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase.cpp
@@ -144,7 +144,7 @@ QWinRTFontDatabase::~QWinRTFontDatabase()
QString QWinRTFontDatabase::fontDir() const
{
qCDebug(lcQpaFonts) << __FUNCTION__;
- QString fontDirectory = QBasicFontDatabase::fontDir();
+ QString fontDirectory = QFreeTypeFontDatabase::fontDir();
if (!QFile::exists(fontDirectory)) {
// Fall back to app directory + fonts, and just app directory after that
const QString applicationDirPath = QCoreApplication::applicationDirPath();
@@ -176,7 +176,7 @@ void QWinRTFontDatabase::populateFontDatabase()
HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, __uuidof(IDWriteFactory1), &factory);
if (FAILED(hr)) {
qWarning("Failed to create DirectWrite factory: %s", qPrintable(qt_error_string(hr)));
- QBasicFontDatabase::populateFontDatabase();
+ QFreeTypeFontDatabase::populateFontDatabase();
return;
}
@@ -184,7 +184,7 @@ void QWinRTFontDatabase::populateFontDatabase()
hr = factory->GetSystemFontCollection(&fontCollection);
if (FAILED(hr)) {
qWarning("Failed to open system font collection: %s", qPrintable(qt_error_string(hr)));
- QBasicFontDatabase::populateFontDatabase();
+ QFreeTypeFontDatabase::populateFontDatabase();
return;
}
@@ -222,7 +222,7 @@ void QWinRTFontDatabase::populateFontDatabase()
registerFontFamily(familyName);
}
- QBasicFontDatabase::populateFontDatabase();
+ QFreeTypeFontDatabase::populateFontDatabase();
}
void QWinRTFontDatabase::populateFamily(const QString &familyName)
@@ -399,7 +399,7 @@ QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handl
IDWriteFontFile *fontFile = reinterpret_cast<IDWriteFontFile *>(handle);
if (!m_fonts.contains(fontFile))
- return QBasicFontDatabase::fontEngine(fontDef, handle);
+ return QFreeTypeFontDatabase::fontEngine(fontDef, handle);
const void *referenceKey;
quint32 referenceKeySize;
@@ -444,15 +444,8 @@ QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handl
const FontDescription description = m_fonts.value(fontFile);
faceId.uuid = description.uuid;
faceId.index = description.index;
- const bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
- QFontEngineFT::GlyphFormat format = antialias ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono;
- QFontEngineFT *engine = new QFontEngineFT(fontDef);
- if (!engine->init(faceId, antialias, format, fontData) || engine->invalid()) {
- delete engine;
- return 0;
- }
- return engine;
+ return QFontEngineFT::create(fontDef, faceId, fontData);
}
QStringList QWinRTFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style,
@@ -468,7 +461,7 @@ QStringList QWinRTFontDatabase::fallbacksForFamily(const QString &family, QFont:
QStringList result;
if (family == QLatin1String("Helvetica"))
result.append(QStringLiteral("Arial"));
- result.append(QBasicFontDatabase::fallbacksForFamily(family, style, styleHint, script));
+ result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script));
return result;
}
@@ -486,7 +479,7 @@ void QWinRTFontDatabase::releaseHandle(void *handle)
return;
}
- QBasicFontDatabase::releaseHandle(handle);
+ QFreeTypeFontDatabase::releaseHandle(handle);
}
QT_END_NAMESPACE
diff --git a/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase_p.h b/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase_p.h
index 3b803d7613..9a2bf00fab 100644
--- a/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase_p.h
+++ b/src/platformsupport/fontdatabases/winrt/qwinrtfontdatabase_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include <QtFontDatabaseSupport/private/qbasicfontdatabase_p.h>
+#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
#include <QtCore/QLoggingCategory>
struct IDWriteFontFile;
@@ -67,7 +67,7 @@ struct FontDescription
QByteArray uuid;
};
-class QWinRTFontDatabase : public QBasicFontDatabase
+class QWinRTFontDatabase : public QFreeTypeFontDatabase
{
public:
~QWinRTFontDatabase();
diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboard_defaultmap_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboard_defaultmap_p.h
index bc0485232d..17bf0fb797 100644
--- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboard_defaultmap_p.h
+++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboard_defaultmap_p.h
@@ -52,7 +52,11 @@
//
#include "qnamespace.h"
+#ifdef Q_OS_FREEBSD
+#include <dev/evdev/input.h>
+#else
#include "linux/input.h"
+#endif
// no QT_BEGIN_NAMESPACE, since we include it internally...
diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
index 0eb6fc0847..5c87cb7c9c 100644
--- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
+++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp
@@ -49,7 +49,11 @@
#include <qpa/qwindowsysteminterface.h>
#include <private/qcore_unix_p.h>
+#ifdef Q_OS_FREEBSD
+#include <dev/evdev/input.h>
+#else
#include <linux/input.h>
+#endif
QT_BEGIN_NAMESPACE
diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp
index d5ea04bee8..9b4bcf1575 100644
--- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp
+++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp
@@ -53,8 +53,12 @@
#include <errno.h>
+#ifdef Q_OS_FREEBSD
+#include <dev/evdev/input.h>
+#else
#include <linux/kd.h>
#include <linux/input.h>
+#endif
#define TEST_BIT(array, bit) (array[bit/8] & (1<<(bit%8)))
diff --git a/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp b/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp
index dc03daedda..86f8a00b13 100644
--- a/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp
+++ b/src/platformsupport/input/evdevtablet/qevdevtablethandler.cpp
@@ -45,7 +45,11 @@
#include <QLoggingCategory>
#include <QtCore/private/qcore_unix_p.h>
#include <qpa/qwindowsysteminterface.h>
+#ifdef Q_OS_FREEBSD
+#include <dev/evdev/input.h>
+#else
#include <linux/input.h>
+#endif
QT_BEGIN_NAMESPACE
diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h
new file mode 100644
index 0000000000..ff6085d725
--- /dev/null
+++ b/src/platformsupport/input/evdevtouch/qevdevtouchfilter_p.h
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qglobal.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+struct QEvdevTouchFilter
+{
+ QEvdevTouchFilter();
+
+ void initialize(float pos, float velocity);
+ void update(float pos, float velocity, float timeDelta);
+
+ float position() const { return x.x; }
+ float velocity() const { return x.y; }
+
+private:
+ struct vec2 {
+ vec2(float x = 0.0f, float y = 0.0f) : x(x), y(y) { }
+ float x, y;
+
+ vec2 operator-(vec2 v) {
+ return vec2(x - v.x, y - v.y);
+ }
+
+ vec2 operator+(vec2 v) {
+ return vec2(x + v.x, y + v.y);
+ }
+ };
+
+ struct mat2 {
+ float a, b, c, d;
+ mat2(float a = 1.0f, float b = 0.0f, float c = 0.0f, float d = 1.0f)
+ : a(a)
+ , b(b)
+ , c(c)
+ , d(d)
+ {
+ }
+
+ mat2 transposed() const {
+ return mat2(a, c,
+ b, d);
+ }
+
+ mat2 inverted() const {
+ float det = 1.0f / (a * d - b * c);
+ return mat2( d * det, -b * det,
+ -c * det, a * det);
+ }
+
+ mat2 operator+(mat2 m) const {
+ return mat2(a + m.a, b + m.b,
+ c + m.c, d + m.d);
+ }
+
+ mat2 operator-(mat2 m) const {
+ return mat2(a - m.a, b - m.b,
+ c - m.c, d - m.d);
+ }
+
+ vec2 operator*(vec2 v) const {
+ return vec2(a * v.x + b * v.y,
+ c * v.x + d * v.y);
+ }
+
+ mat2 operator*(mat2 M) const {
+ return mat2(a * M.a + b * M.c,
+ a * M.b + b * M.d,
+ c * M.a + d * M.c,
+ c * M.b + d * M.d);
+ }
+ };
+
+ vec2 x;
+ mat2 A;
+ mat2 P;
+ mat2 Q;
+ mat2 R;
+ mat2 H;
+};
+
+inline QEvdevTouchFilter::QEvdevTouchFilter()
+{
+}
+
+inline void QEvdevTouchFilter::initialize(float pos, float velocity)
+{
+ x = vec2(pos, velocity);
+
+ P = mat2(0.0f, 0.0f,
+ 0.0f, 0.0f);
+
+ Q = mat2(0.0f, 0.0f,
+ 0.0f, 0.1f);
+ R = mat2(0.1f, 0.0f,
+ 0.0f, 0.1f);
+}
+
+inline void QEvdevTouchFilter::update(float pos, float velocity, float dT)
+{
+ A.b = dT;
+
+ // Prediction setp
+ x = A * x;
+ P = A * P * A.transposed() + Q;
+
+ // Correction step (complete with H)
+ // mat2 S = H * P * H.transposed() + R;
+ // mat2 K = P * H.transposed() * S.inverted();
+ // vec2 m(pos, velocity);
+ // vec2 y = m - H * x;
+ // x = x + K * y;
+ // P = (mat2() - K * H) * P;
+
+ // Correction step (without H as H is currently set to I, so we can ignore
+ // it in the calculations...)
+ mat2 S = P + R;
+ mat2 K = P * S.inverted();
+ vec2 m(pos, velocity);
+ vec2 y = m - x;
+ x = x + K * y;
+ P = (mat2() - K) * P;
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
index d53a317fc5..11f7311bb7 100644
--- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
+++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins module of the Qt Toolkit.
@@ -48,7 +49,11 @@
#include <QtCore/private/qcore_unix_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/private/qguiapplication_p.h>
+#ifdef Q_OS_FREEBSD
+#include <dev/evdev/input.h>
+#else
#include <linux/input.h>
+#endif
#if QT_CONFIG(mtdev)
extern "C" {
@@ -96,6 +101,7 @@ public:
QEvdevTouchScreenHandler *q;
int m_lastEventType;
QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
+ QList<QWindowSystemInterface::TouchPoint> m_lastTouchPoints;
struct Contact {
int trackingId;
@@ -114,11 +120,16 @@ public:
Contact m_currentData;
int m_currentSlot;
+ double m_timeStamp;
+ double m_lastTimeStamp;
+
int findClosestContact(const QHash<int, Contact> &contacts, int x, int y, int *dist);
void addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates);
void reportPoints();
void loadMultiScreenMappings();
+ QRect screenGeometry() const;
+
int hw_range_x_min;
int hw_range_x_max;
int hw_range_y_min;
@@ -132,19 +143,40 @@ public:
QTransform m_rotate;
bool m_singleTouch;
QString m_screenName;
- QPointer<QScreen> m_screen;
+ mutable QPointer<QScreen> m_screen;
+
+ // Touch filtering and prediction are part of the same thing. The default
+ // prediction is 0ms, but sensible results can be acheived by setting it
+ // to, for instance, 16ms.
+ // For filtering to work well, the QPA plugin should provide a dead-steady
+ // implementation of QPlatformWindow::requestUpdate().
+ bool m_filtered;
+ int m_prediction;
+
+ // When filtering is enabled, protect the access to current and last
+ // timeStamp and touchPoints, as these are being read on the gui thread.
+ QMutex m_mutex;
};
QEvdevTouchScreenData::QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, const QStringList &args)
: q(q_ptr),
m_lastEventType(-1),
m_currentSlot(0),
+ m_timeStamp(0), m_lastTimeStamp(0),
hw_range_x_min(0), hw_range_x_max(0),
hw_range_y_min(0), hw_range_y_max(0),
hw_pressure_min(0), hw_pressure_max(0),
- m_typeB(false), m_singleTouch(false)
+ m_forceToActiveWindow(false), m_typeB(false), m_singleTouch(false),
+ m_filtered(false), m_prediction(0)
{
- m_forceToActiveWindow = args.contains(QLatin1String("force_window"));
+ for (const QString &arg : args) {
+ if (arg == QStringLiteral("force_window"))
+ m_forceToActiveWindow = true;
+ else if (arg == QStringLiteral("filtered"))
+ m_filtered = true;
+ else if (arg.startsWith(QStringLiteral("prediction=")))
+ m_prediction = arg.mid(11).toInt();
+ }
}
#define LONG_BITS (sizeof(long) << 3)
@@ -228,9 +260,14 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const
#endif
d->deviceNode = device;
-
- qCDebug(qLcEvdevTouch, "evdevtouch: %s: Protocol type %c %s (%s)", qPrintable(d->deviceNode),
- d->m_typeB ? 'B' : 'A', mtdevStr, d->m_singleTouch ? "single" : "multi");
+ qCDebug(qLcEvdevTouch,
+ "evdevtouch: %s: Protocol type %c %s (%s), filtered=%s",
+ qPrintable(d->deviceNode),
+ d->m_typeB ? 'B' : 'A', mtdevStr,
+ d->m_singleTouch ? "single" : "multi",
+ d->m_filtered ? "yes" : "no");
+ if (d->m_filtered)
+ qCDebug(qLcEvdevTouch, " - prediction=%d", d->m_prediction);
input_absinfo absInfo;
memset(&absInfo, 0, sizeof(input_absinfo));
@@ -327,6 +364,11 @@ QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler()
unregisterTouchDevice();
}
+bool QEvdevTouchScreenHandler::isFiltered() const
+{
+ return d->m_filtered;
+}
+
QTouchDevice *QEvdevTouchScreenHandler::touchDevice() const
{
return m_device;
@@ -516,6 +558,14 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data)
if (!m_contacts.isEmpty() && m_contacts.constBegin().value().trackingId == -1)
assignIds();
+ if (m_filtered)
+ m_mutex.lock();
+
+ // update timestamps
+ m_lastTimeStamp = m_timeStamp;
+ m_timeStamp = data->time.tv_sec + data->time.tv_usec / 1000000.0;
+
+ m_lastTouchPoints = m_touchPoints;
m_touchPoints.clear();
Qt::TouchPointStates combinedStates;
@@ -593,8 +643,12 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data)
if (!m_typeB && !m_singleTouch)
m_contacts.clear();
+
if (!m_touchPoints.isEmpty() && combinedStates != Qt::TouchPointStationary)
reportPoints();
+
+ if (m_filtered)
+ m_mutex.unlock();
}
m_lastEventType = data->type;
@@ -653,41 +707,45 @@ void QEvdevTouchScreenData::assignIds()
m_contacts = newContacts;
}
-void QEvdevTouchScreenData::reportPoints()
+QRect QEvdevTouchScreenData::screenGeometry() const
{
- QRect winRect;
if (m_forceToActiveWindow) {
QWindow *win = QGuiApplication::focusWindow();
- if (!win)
- return;
- winRect = QHighDpi::toNativePixels(win->geometry(), win);
- } else {
- // Now it becomes tricky. Traditionally we picked the primaryScreen()
- // and were done with it. But then, enter multiple screens, and
- // suddenly it was all broken.
- //
- // For now we only support the display configuration of the KMS/DRM
- // backends of eglfs. See QTouchOutputMapping.
- //
- // The good news it that once winRect refers to the correct screen
- // geometry in the full virtual desktop space, there is nothing else
- // left to do since qguiapp will handle the rest.
- QScreen *screen = QGuiApplication::primaryScreen();
- if (!m_screenName.isEmpty()) {
- if (!m_screen) {
- const QList<QScreen *> screens = QGuiApplication::screens();
- for (QScreen *s : screens) {
- if (s->name() == m_screenName) {
- m_screen = s;
- break;
- }
+ return win ? QHighDpi::toNativePixels(win->geometry(), win) : QRect();
+ }
+
+ // Now it becomes tricky. Traditionally we picked the primaryScreen()
+ // and were done with it. But then, enter multiple screens, and
+ // suddenly it was all broken.
+ //
+ // For now we only support the display configuration of the KMS/DRM
+ // backends of eglfs. See QTouchOutputMapping.
+ //
+ // The good news it that once winRect refers to the correct screen
+ // geometry in the full virtual desktop space, there is nothing else
+ // left to do since qguiapp will handle the rest.
+ QScreen *screen = QGuiApplication::primaryScreen();
+ if (!m_screenName.isEmpty()) {
+ if (!m_screen) {
+ const QList<QScreen *> screens = QGuiApplication::screens();
+ for (QScreen *s : screens) {
+ if (s->name() == m_screenName) {
+ m_screen = s;
+ break;
}
}
- if (m_screen)
- screen = m_screen;
}
- winRect = QHighDpi::toNativePixels(screen->geometry(), screen);
+ if (m_screen)
+ screen = m_screen;
}
+ return QHighDpi::toNativePixels(screen->geometry(), screen);
+}
+
+void QEvdevTouchScreenData::reportPoints()
+{
+ QRect winRect = screenGeometry();
+ if (winRect.isNull())
+ return;
const int hw_w = hw_range_x_max - hw_range_x_min;
const int hw_h = hw_range_y_max - hw_range_y_min;
@@ -718,13 +776,17 @@ void QEvdevTouchScreenData::reportPoints()
}
// Let qguiapp pick the target window.
- QWindowSystemInterface::handleTouchEvent(Q_NULLPTR, q->touchDevice(), m_touchPoints);
+ if (m_filtered)
+ emit q->touchPointsUpdated();
+ else
+ QWindowSystemInterface::handleTouchEvent(Q_NULLPTR, q->touchDevice(), m_touchPoints);
}
-
-
QEvdevTouchScreenHandlerThread::QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent)
: QDaemonThread(parent), m_device(device), m_spec(spec), m_handler(Q_NULLPTR), m_touchDeviceRegistered(false)
+ , m_touchUpdatePending(false)
+ , m_filterWindow(Q_NULLPTR)
+ , m_touchRate(-1)
{
start();
}
@@ -738,6 +800,10 @@ QEvdevTouchScreenHandlerThread::~QEvdevTouchScreenHandlerThread()
void QEvdevTouchScreenHandlerThread::run()
{
m_handler = new QEvdevTouchScreenHandler(m_device, m_spec);
+
+ if (m_handler->isFiltered())
+ connect(m_handler, &QEvdevTouchScreenHandler::touchPointsUpdated, this, &QEvdevTouchScreenHandlerThread::scheduleTouchPointUpdate);
+
// Report the registration to the parent thread by invoking the method asynchronously
QMetaObject::invokeMethod(this, "notifyTouchDeviceRegistered", Qt::QueuedConnection);
@@ -758,5 +824,137 @@ void QEvdevTouchScreenHandlerThread::notifyTouchDeviceRegistered()
emit touchDeviceRegistered();
}
+void QEvdevTouchScreenHandlerThread::scheduleTouchPointUpdate()
+{
+ QWindow *window = QGuiApplication::focusWindow();
+ if (window != m_filterWindow) {
+ if (m_filterWindow)
+ m_filterWindow->removeEventFilter(this);
+ m_filterWindow = window;
+ if (m_filterWindow)
+ m_filterWindow->installEventFilter(this);
+ }
+ if (m_filterWindow) {
+ m_touchUpdatePending = true;
+ m_filterWindow->requestUpdate();
+ }
+}
+
+bool QEvdevTouchScreenHandlerThread::eventFilter(QObject *object, QEvent *event)
+{
+ if (m_touchUpdatePending && object == m_filterWindow && event->type() == QEvent::UpdateRequest) {
+ m_touchUpdatePending = false;
+ filterAndSendTouchPoints();
+ }
+ return false;
+}
+
+void QEvdevTouchScreenHandlerThread::filterAndSendTouchPoints()
+{
+ QRect winRect = m_handler->d->screenGeometry();
+ if (winRect.isNull())
+ return;
+
+ float vsyncDelta = 1.0f / QGuiApplication::primaryScreen()->refreshRate();
+
+ QHash<int, FilteredTouchPoint> filteredPoints;
+
+ m_handler->d->m_mutex.lock();
+
+ double time = m_handler->d->m_timeStamp;
+ double lastTime = m_handler->d->m_lastTimeStamp;
+ double touchDelta = time - lastTime;
+ if (m_touchRate < 0 || touchDelta > vsyncDelta) {
+ // We're at the very start, with nothing to go on, so make a guess
+ // that the touch rate will be somewhere in the range of half a vsync.
+ // This doesn't have to be accurate as we will calibrate it over time,
+ // but it gives us a better starting point so calibration will be
+ // slightly quicker. If, on the other hand, we already have an
+ // estimate, we'll leave it as is and keep it.
+ if (m_touchRate < 0)
+ m_touchRate = (1.0 / QGuiApplication::primaryScreen()->refreshRate()) / 2.0;
+
+ } else {
+ // Update our estimate for the touch rate. We're making the assumption
+ // that this value will be mostly accurate with the occational bump,
+ // so we're weighting the existing value high compared to the update.
+ const double ratio = 0.9;
+ m_touchRate = sqrt(m_touchRate * m_touchRate * ratio + touchDelta * touchDelta * (1.0 - ratio));
+ }
+
+ QList<QWindowSystemInterface::TouchPoint> points = m_handler->d->m_touchPoints;
+ const QList<QWindowSystemInterface::TouchPoint> &lastPoints = m_handler->d->m_lastTouchPoints;
+
+ m_handler->d->m_mutex.unlock();
+
+ for (int i=0; i<points.size(); ++i) {
+ QWindowSystemInterface::TouchPoint &tp = points[i];
+ QPointF pos = tp.normalPosition;
+ FilteredTouchPoint f;
+
+ QWindowSystemInterface::TouchPoint ltp;
+ ltp.id = -1;
+ for (int j=0; j<lastPoints.size(); ++j) {
+ if (lastPoints.at(j).id == tp.id) {
+ ltp = lastPoints.at(j);
+ break;
+ }
+ }
+
+ QPointF velocity;
+ if (lastTime != 0 && ltp.id >= 0)
+ velocity = (pos - ltp.normalPosition) / m_touchRate;
+ if (m_filteredPoints.contains(tp.id)) {
+ f = m_filteredPoints.take(tp.id);
+ f.x.update(pos.x(), velocity.x(), vsyncDelta);
+ f.y.update(pos.y(), velocity.y(), vsyncDelta);
+ pos = QPointF(f.x.position(), f.y.position());
+ } else {
+ f.x.initialize(pos.x(), velocity.x());
+ f.y.initialize(pos.y(), velocity.y());
+ // Make sure the first instance of a touch point we send has the
+ // 'pressed' state.
+ if (tp.state != Qt::TouchPointPressed)
+ tp.state = Qt::TouchPointPressed;
+ }
+
+ tp.velocity = QVector2D(f.x.velocity() * winRect.width(), f.y.velocity() * winRect.height());
+
+ qreal filteredNormalizedX = f.x.position() + f.x.velocity() * m_handler->d->m_prediction / 1000.0;
+ qreal filteredNormalizedY = f.y.position() + f.y.velocity() * m_handler->d->m_prediction / 1000.0;
+
+ // Clamp to the screen
+ tp.normalPosition = QPointF(qBound<qreal>(0, filteredNormalizedX, 1),
+ qBound<qreal>(0, filteredNormalizedY, 1));
+
+ qreal x = winRect.x() + (tp.normalPosition.x() * (winRect.width() - 1));
+ qreal y = winRect.y() + (tp.normalPosition.y() * (winRect.height() - 1));
+
+ tp.area.moveCenter(QPointF(x, y));
+
+ // Store the touch point for later so we can release it if we've
+ // missed the actual release between our last update and this.
+ f.touchPoint = tp;
+
+ // Don't store the point for future reference if it is a release.
+ if (tp.state != Qt::TouchPointReleased)
+ filteredPoints[tp.id] = f;
+ }
+
+ for (QHash<int, FilteredTouchPoint>::const_iterator it = m_filteredPoints.constBegin(), end = m_filteredPoints.constEnd(); it != end; ++it) {
+ const FilteredTouchPoint &f = it.value();
+ QWindowSystemInterface::TouchPoint tp = f.touchPoint;
+ tp.state = Qt::TouchPointReleased;
+ tp.velocity = QVector2D();
+ points.append(tp);
+ }
+
+ m_filteredPoints = filteredPoints;
+
+ QWindowSystemInterface::handleTouchEvent(Q_NULLPTR,
+ m_handler->touchDevice(),
+ points);
+}
+
QT_END_NAMESPACE
diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h
index 6554d4998c..d22aca3266 100644
--- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h
+++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins module of the Qt Toolkit.
@@ -58,6 +59,7 @@
#include <QThread>
#include <QtCore/private/qthread_p.h>
#include <qpa/qwindowsysteminterface.h>
+#include "qevdevtouchfilter_p.h"
#if QT_CONFIG(mtdev)
struct mtdev;
@@ -78,10 +80,18 @@ public:
QTouchDevice *touchDevice() const;
+ bool isFiltered() const;
+
private slots:
void readData();
+signals:
+ void touchPointsUpdated();
+
private:
+ friend class QEvdevTouchScreenData;
+ friend class QEvdevTouchScreenHandlerThread;
+
void registerTouchDevice();
void unregisterTouchDevice();
@@ -104,16 +114,36 @@ public:
bool isTouchDeviceRegistered() const;
+ bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE;
+
+public slots:
+ void scheduleTouchPointUpdate();
+
signals:
void touchDeviceRegistered();
private:
Q_INVOKABLE void notifyTouchDeviceRegistered();
+ void filterAndSendTouchPoints();
+ QRect targetScreenGeometry() const;
+
QString m_device;
QString m_spec;
QEvdevTouchScreenHandler *m_handler;
bool m_touchDeviceRegistered;
+
+ bool m_touchUpdatePending;
+ QWindow *m_filterWindow;
+
+ struct FilteredTouchPoint {
+ QEvdevTouchFilter x;
+ QEvdevTouchFilter y;
+ QWindowSystemInterface::TouchPoint touchPoint;
+ };
+ QHash<int, FilteredTouchPoint> m_filteredPoints;
+
+ float m_touchRate;
};
QT_END_NAMESPACE
diff --git a/src/platformsupport/kmsconvenience/kmsconvenience.pro b/src/platformsupport/kmsconvenience/kmsconvenience.pro
new file mode 100644
index 0000000000..d0ff0d4efb
--- /dev/null
+++ b/src/platformsupport/kmsconvenience/kmsconvenience.pro
@@ -0,0 +1,20 @@
+TARGET = QtKmsSupport
+MODULE = kms_support
+
+QT = core-private gui-private
+CONFIG += static internal_module
+
+DEFINES += QT_NO_CAST_FROM_ASCII
+PRECOMPILED_HEADER = ../../corelib/global/qt_pch.h
+
+HEADERS +=
+ qkmsdevice_p.h
+
+SOURCES += \
+ qkmsdevice.cpp
+
+QMAKE_USE += drm
+
+LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
+
+load(qt_module)
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
new file mode 100644
index 0000000000..669abab331
--- /dev/null
+++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
@@ -0,0 +1,662 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Pelagicore AG
+** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qkmsdevice_p.h"
+
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+#include <QtCore/QFile>
+#include <QtCore/QLoggingCategory>
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcKmsDebug, "qt.qpa.eglfs.kms")
+
+enum OutputConfiguration {
+ OutputConfigOff,
+ OutputConfigPreferred,
+ OutputConfigCurrent,
+ OutputConfigMode,
+ OutputConfigModeline
+};
+
+int QKmsDevice::crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector)
+{
+ for (int i = 0; i < connector->count_encoders; i++) {
+ drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->encoders[i]);
+ if (!encoder) {
+ qWarning("Failed to get encoder");
+ continue;
+ }
+
+ quint32 possibleCrtcs = encoder->possible_crtcs;
+ drmModeFreeEncoder(encoder);
+
+ for (int j = 0; j < resources->count_crtcs; j++) {
+ bool isPossible = possibleCrtcs & (1 << j);
+ bool isAvailable = !(m_crtc_allocator & 1 << resources->crtcs[j]);
+
+ if (isPossible && isAvailable)
+ return j;
+ }
+ }
+
+ return -1;
+}
+
+static const char * const connector_type_names[] = { // must match DRM_MODE_CONNECTOR_*
+ "None",
+ "VGA",
+ "DVI",
+ "DVI",
+ "DVI",
+ "Composite",
+ "TV",
+ "LVDS",
+ "CTV",
+ "DIN",
+ "DP",
+ "HDMI",
+ "HDMI",
+ "TV",
+ "eDP",
+ "Virtual",
+ "DSI"
+};
+
+static QByteArray nameForConnector(const drmModeConnectorPtr connector)
+{
+ QByteArray connectorName("UNKNOWN");
+
+ if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
+ connectorName = connector_type_names[connector->connector_type];
+
+ connectorName += QByteArray::number(connector->connector_type_id);
+
+ return connectorName;
+}
+
+static bool parseModeline(const QByteArray &text, drmModeModeInfoPtr mode)
+{
+ char hsync[16];
+ char vsync[16];
+ float fclock;
+
+ mode->type = DRM_MODE_TYPE_USERDEF;
+ mode->hskew = 0;
+ mode->vscan = 0;
+ mode->vrefresh = 0;
+ mode->flags = 0;
+
+ if (sscanf(text.constData(), "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
+ &fclock,
+ &mode->hdisplay,
+ &mode->hsync_start,
+ &mode->hsync_end,
+ &mode->htotal,
+ &mode->vdisplay,
+ &mode->vsync_start,
+ &mode->vsync_end,
+ &mode->vtotal, hsync, vsync) != 11)
+ return false;
+
+ mode->clock = fclock * 1000;
+
+ if (strcmp(hsync, "+hsync") == 0)
+ mode->flags |= DRM_MODE_FLAG_PHSYNC;
+ else if (strcmp(hsync, "-hsync") == 0)
+ mode->flags |= DRM_MODE_FLAG_NHSYNC;
+ else
+ return false;
+
+ if (strcmp(vsync, "+vsync") == 0)
+ mode->flags |= DRM_MODE_FLAG_PVSYNC;
+ else if (strcmp(vsync, "-vsync") == 0)
+ mode->flags |= DRM_MODE_FLAG_NVSYNC;
+ else
+ return false;
+
+ return true;
+}
+
+QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
+ drmModeConnectorPtr connector,
+ VirtualDesktopInfo *vinfo)
+{
+ const QByteArray connectorName = nameForConnector(connector);
+
+ const int crtc = crtcForConnector(resources, connector);
+ if (crtc < 0) {
+ qWarning() << "No usable crtc/encoder pair for connector" << connectorName;
+ return Q_NULLPTR;
+ }
+
+ OutputConfiguration configuration;
+ QSize configurationSize;
+ drmModeModeInfo configurationModeline;
+
+ auto userConfig = m_screenConfig->outputSettings();
+ auto userConnectorConfig = userConfig.value(QString::fromUtf8(connectorName));
+ // default to the preferred mode unless overridden in the config
+ const QByteArray mode = userConnectorConfig.value(QStringLiteral("mode"), QStringLiteral("preferred"))
+ .toByteArray().toLower();
+ if (mode == "off") {
+ configuration = OutputConfigOff;
+ } else if (mode == "preferred") {
+ configuration = OutputConfigPreferred;
+ } else if (mode == "current") {
+ configuration = OutputConfigCurrent;
+ } else if (sscanf(mode.constData(), "%dx%d", &configurationSize.rwidth(), &configurationSize.rheight()) == 2) {
+ configuration = OutputConfigMode;
+ } else if (parseModeline(mode, &configurationModeline)) {
+ configuration = OutputConfigModeline;
+ } else {
+ qWarning("Invalid mode \"%s\" for output %s", mode.constData(), connectorName.constData());
+ configuration = OutputConfigPreferred;
+ }
+ if (vinfo) {
+ *vinfo = VirtualDesktopInfo();
+ vinfo->virtualIndex = userConnectorConfig.value(QStringLiteral("virtualIndex"), INT_MAX).toInt();
+ if (userConnectorConfig.contains(QStringLiteral("virtualPos"))) {
+ const QByteArray vpos = userConnectorConfig.value(QStringLiteral("virtualPos")).toByteArray();
+ const QByteArrayList vposComp = vpos.split(',');
+ if (vposComp.count() == 2)
+ vinfo->virtualPos = QPoint(vposComp[0].trimmed().toInt(), vposComp[1].trimmed().toInt());
+ }
+ if (userConnectorConfig.value(QStringLiteral("primary")).toBool())
+ vinfo->isPrimary = true;
+ }
+
+ const uint32_t crtc_id = resources->crtcs[crtc];
+
+ if (configuration == OutputConfigOff) {
+ qCDebug(qLcKmsDebug) << "Turning off output" << connectorName;
+ drmModeSetCrtc(m_dri_fd, crtc_id, 0, 0, 0, 0, 0, Q_NULLPTR);
+ return Q_NULLPTR;
+ }
+
+ // Skip disconnected output
+ if (configuration == OutputConfigPreferred && connector->connection == DRM_MODE_DISCONNECTED) {
+ qCDebug(qLcKmsDebug) << "Skipping disconnected output" << connectorName;
+ return Q_NULLPTR;
+ }
+
+ // Get the current mode on the current crtc
+ drmModeModeInfo crtc_mode;
+ memset(&crtc_mode, 0, sizeof crtc_mode);
+ if (drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->connector_id)) {
+ drmModeCrtcPtr crtc = drmModeGetCrtc(m_dri_fd, encoder->crtc_id);
+ drmModeFreeEncoder(encoder);
+
+ if (!crtc)
+ return Q_NULLPTR;
+
+ if (crtc->mode_valid)
+ crtc_mode = crtc->mode;
+
+ drmModeFreeCrtc(crtc);
+ }
+
+ QList<drmModeModeInfo> modes;
+ modes.reserve(connector->count_modes);
+ qCDebug(qLcKmsDebug) << connectorName << "mode count:" << connector->count_modes;
+ for (int i = 0; i < connector->count_modes; i++) {
+ const drmModeModeInfo &mode = connector->modes[i];
+ qCDebug(qLcKmsDebug) << "mode" << i << mode.hdisplay << "x" << mode.vdisplay
+ << '@' << mode.vrefresh << "hz";
+ modes << connector->modes[i];
+ }
+
+ int preferred = -1;
+ int current = -1;
+ int configured = -1;
+ int best = -1;
+
+ for (int i = modes.size() - 1; i >= 0; i--) {
+ const drmModeModeInfo &m = modes.at(i);
+
+ if (configuration == OutputConfigMode &&
+ m.hdisplay == configurationSize.width() &&
+ m.vdisplay == configurationSize.height()) {
+ configured = i;
+ }
+
+ if (!memcmp(&crtc_mode, &m, sizeof m))
+ current = i;
+
+ if (m.type & DRM_MODE_TYPE_PREFERRED)
+ preferred = i;
+
+ best = i;
+ }
+
+ if (configuration == OutputConfigModeline) {
+ modes << configurationModeline;
+ configured = modes.size() - 1;
+ }
+
+ if (current < 0 && crtc_mode.clock != 0) {
+ modes << crtc_mode;
+ current = mode.size() - 1;
+ }
+
+ if (configuration == OutputConfigCurrent)
+ configured = current;
+
+ int selected_mode = -1;
+
+ if (configured >= 0)
+ selected_mode = configured;
+ else if (preferred >= 0)
+ selected_mode = preferred;
+ else if (current >= 0)
+ selected_mode = current;
+ else if (best >= 0)
+ selected_mode = best;
+
+ if (selected_mode < 0) {
+ qWarning() << "No modes available for output" << connectorName;
+ return Q_NULLPTR;
+ } else {
+ int width = modes[selected_mode].hdisplay;
+ int height = modes[selected_mode].vdisplay;
+ int refresh = modes[selected_mode].vrefresh;
+ qCDebug(qLcKmsDebug) << "Selected mode" << selected_mode << ":" << width << "x" << height
+ << '@' << refresh << "hz for output" << connectorName;
+ }
+
+ // physical size from connector < config values < env vars
+ int pwidth = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_WIDTH");
+ if (!pwidth)
+ pwidth = qEnvironmentVariableIntValue("QT_QPA_PHYSICAL_WIDTH");
+ int pheight = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_HEIGHT");
+ if (!pheight)
+ pheight = qEnvironmentVariableIntValue("QT_QPA_PHYSICAL_HEIGHT");
+ QSizeF physSize(pwidth, pheight);
+ if (physSize.isEmpty()) {
+ physSize = QSize(userConnectorConfig.value(QStringLiteral("physicalWidth")).toInt(),
+ userConnectorConfig.value(QStringLiteral("physicalHeight")).toInt());
+ if (physSize.isEmpty()) {
+ physSize.setWidth(connector->mmWidth);
+ physSize.setHeight(connector->mmHeight);
+ }
+ }
+ qCDebug(qLcKmsDebug) << "Physical size is" << physSize << "mm" << "for output" << connectorName;
+
+ QKmsOutput output = {
+ QString::fromUtf8(connectorName),
+ connector->connector_id,
+ crtc_id,
+ physSize,
+ selected_mode,
+ false,
+ drmModeGetCrtc(m_dri_fd, crtc_id),
+ modes,
+ connector->subpixel,
+ connectorProperty(connector, QByteArrayLiteral("DPMS")),
+ false,
+ 0,
+ false
+ };
+
+ bool ok;
+ int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_PLANE_INDEX", &ok);
+ if (ok) {
+ drmModePlaneRes *planeResources = drmModeGetPlaneResources(m_dri_fd);
+ if (planeResources) {
+ if (idx >= 0 && idx < int(planeResources->count_planes)) {
+ drmModePlane *plane = drmModeGetPlane(m_dri_fd, planeResources->planes[idx]);
+ if (plane) {
+ output.wants_plane = true;
+ output.plane_id = plane->plane_id;
+ qCDebug(qLcKmsDebug, "Forcing plane index %d, plane id %u (belongs to crtc id %u)",
+ idx, plane->plane_id, plane->crtc_id);
+ drmModeFreePlane(plane);
+ }
+ } else {
+ qWarning("Invalid plane index %d, must be between 0 and %u", idx, planeResources->count_planes - 1);
+ }
+ }
+ }
+
+ m_crtc_allocator |= (1 << output.crtc_id);
+ m_connector_allocator |= (1 << output.connector_id);
+
+ return createScreen(output);
+}
+
+drmModePropertyPtr QKmsDevice::connectorProperty(drmModeConnectorPtr connector, const QByteArray &name)
+{
+ drmModePropertyPtr prop;
+
+ for (int i = 0; i < connector->count_props; i++) {
+ prop = drmModeGetProperty(m_dri_fd, connector->props[i]);
+ if (!prop)
+ continue;
+ if (strcmp(prop->name, name.constData()) == 0)
+ return prop;
+ drmModeFreeProperty(prop);
+ }
+
+ return Q_NULLPTR;
+}
+
+QKmsDevice::QKmsDevice(QKmsScreenConfig *screenConfig, const QString &path)
+ : m_screenConfig(screenConfig)
+ , m_path(path)
+ , m_dri_fd(-1)
+ , m_crtc_allocator(0)
+ , m_connector_allocator(0)
+{
+ if (m_path.isEmpty()) {
+ m_path = m_screenConfig->devicePath();
+ qCDebug(qLcKmsDebug, "Using DRM device %s specified in config file", qPrintable(m_path));
+ if (m_path.isEmpty())
+ qFatal("No DRM device given");
+ } else {
+ qCDebug(qLcKmsDebug, "Using backend-provided DRM device %s", qPrintable(m_path));
+ }
+}
+
+QKmsDevice::~QKmsDevice()
+{
+}
+
+struct OrderedScreen
+{
+ OrderedScreen() : screen(nullptr) { }
+ OrderedScreen(QPlatformScreen *screen, const QKmsDevice::VirtualDesktopInfo &vinfo)
+ : screen(screen), vinfo(vinfo) { }
+ QPlatformScreen *screen;
+ QKmsDevice::VirtualDesktopInfo vinfo;
+};
+
+QDebug operator<<(QDebug dbg, const OrderedScreen &s)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "OrderedScreen(QPlatformScreen=" << s.screen << " (" << s.screen->name() << ") : "
+ << s.vinfo.virtualIndex
+ << " / " << s.vinfo.virtualPos
+ << " / primary: " << s.vinfo.isPrimary
+ << ")";
+ return dbg;
+}
+
+static bool orderedScreenLessThan(const OrderedScreen &a, const OrderedScreen &b)
+{
+ return a.vinfo.virtualIndex < b.vinfo.virtualIndex;
+}
+
+void QKmsDevice::createScreens()
+{
+ drmModeResPtr resources = drmModeGetResources(m_dri_fd);
+ if (!resources) {
+ qWarning("drmModeGetResources failed");
+ return;
+ }
+
+ QVector<OrderedScreen> screens;
+
+ int wantedConnectorIndex = -1;
+ bool ok;
+ int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_CONNECTOR_INDEX", &ok);
+ if (ok) {
+ if (idx >= 0 && idx < resources->count_connectors)
+ wantedConnectorIndex = idx;
+ else
+ qWarning("Invalid connector index %d, must be between 0 and %u", idx, resources->count_connectors - 1);
+ }
+
+ for (int i = 0; i < resources->count_connectors; i++) {
+ if (wantedConnectorIndex >= 0 && i != wantedConnectorIndex)
+ continue;
+
+ drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
+ if (!connector)
+ continue;
+
+ VirtualDesktopInfo vinfo;
+ QPlatformScreen *screen = createScreenForConnector(resources, connector, &vinfo);
+ if (screen)
+ screens.append(OrderedScreen(screen, vinfo));
+
+ drmModeFreeConnector(connector);
+ }
+
+ drmModeFreeResources(resources);
+
+ // Use stable sort to preserve the original (DRM connector) order
+ // for outputs with unspecified indices.
+ std::stable_sort(screens.begin(), screens.end(), orderedScreenLessThan);
+ qCDebug(qLcKmsDebug) << "Sorted screen list:" << screens;
+
+ QPoint pos(0, 0);
+ QList<QPlatformScreen *> siblings;
+ QVector<QPoint> virtualPositions;
+ int primarySiblingIdx = -1;
+
+ for (const OrderedScreen &orderedScreen : screens) {
+ QPlatformScreen *s = orderedScreen.screen;
+ QPoint virtualPos(0, 0);
+ // set up a horizontal or vertical virtual desktop
+ if (orderedScreen.vinfo.virtualPos.isNull()) {
+ virtualPos = pos;
+ if (m_screenConfig->virtualDesktopLayout() == QKmsScreenConfig::VirtualDesktopLayoutVertical)
+ pos.ry() += s->geometry().height();
+ else
+ pos.rx() += s->geometry().width();
+ } else {
+ virtualPos = orderedScreen.vinfo.virtualPos;
+ }
+ qCDebug(qLcKmsDebug) << "Adding QPlatformScren" << s << "(" << s->name() << ")"
+ << "to QPA with geometry" << s->geometry()
+ << "and isPrimary=" << orderedScreen.vinfo.isPrimary;
+ // The order in qguiapp's screens list will match the order set by
+ // virtualIndex. This is not only handy but also required since for instance
+ // evdevtouch relies on it when performing touch device - screen mapping.
+ if (!m_screenConfig->separateScreens()) {
+ siblings.append(s);
+ virtualPositions.append(virtualPos);
+ if (orderedScreen.vinfo.isPrimary)
+ primarySiblingIdx = siblings.count() - 1;
+ } else {
+ registerScreen(s, orderedScreen.vinfo.isPrimary, virtualPos, QList<QPlatformScreen *>() << s);
+ }
+ }
+
+ if (!m_screenConfig->separateScreens()) {
+ // enable the virtual desktop
+ for (int i = 0; i < siblings.count(); ++i)
+ registerScreen(siblings[i], i == primarySiblingIdx, virtualPositions[i], siblings);
+ }
+}
+
+int QKmsDevice::fd() const
+{
+ return m_dri_fd;
+}
+
+QString QKmsDevice::devicePath() const
+{
+ return m_path;
+}
+
+void QKmsDevice::setFd(int fd)
+{
+ m_dri_fd = fd;
+}
+
+QKmsScreenConfig *QKmsDevice::screenConfig() const
+{
+ return m_screenConfig;
+}
+
+QKmsScreenConfig::QKmsScreenConfig()
+ : m_hwCursor(true)
+ , m_separateScreens(false)
+ , m_pbuffers(false)
+ , m_virtualDesktopLayout(VirtualDesktopLayoutHorizontal)
+{
+ loadConfig();
+}
+
+void QKmsScreenConfig::loadConfig()
+{
+ QByteArray json = qgetenv("QT_QPA_EGLFS_KMS_CONFIG");
+ if (json.isEmpty()) {
+ json = qgetenv("QT_QPA_KMS_CONFIG");
+ if (json.isEmpty())
+ return;
+ }
+
+ qCDebug(qLcKmsDebug) << "Loading KMS setup from" << json;
+
+ QFile file(QString::fromUtf8(json));
+ if (!file.open(QFile::ReadOnly)) {
+ qCWarning(qLcKmsDebug) << "Could not open config file"
+ << json << "for reading";
+ return;
+ }
+
+ const QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
+ if (!doc.isObject()) {
+ qCWarning(qLcKmsDebug) << "Invalid config file" << json
+ << "- no top-level JSON object";
+ return;
+ }
+
+ const QJsonObject object = doc.object();
+
+ m_hwCursor = object.value(QLatin1String("hwcursor")).toBool(m_hwCursor);
+ m_pbuffers = object.value(QLatin1String("pbuffers")).toBool(m_pbuffers);
+ m_devicePath = object.value(QLatin1String("device")).toString();
+ m_separateScreens = object.value(QLatin1String("separateScreens")).toBool(m_separateScreens);
+
+ const QString vdOriString = object.value(QLatin1String("virtualDesktopLayout")).toString();
+ if (!vdOriString.isEmpty()) {
+ if (vdOriString == QLatin1String("horizontal"))
+ m_virtualDesktopLayout = VirtualDesktopLayoutHorizontal;
+ else if (vdOriString == QLatin1String("vertical"))
+ m_virtualDesktopLayout = VirtualDesktopLayoutVertical;
+ else
+ qCWarning(qLcKmsDebug) << "Unknown virtualDesktopOrientation value" << vdOriString;
+ }
+
+ const QJsonArray outputs = object.value(QLatin1String("outputs")).toArray();
+ for (int i = 0; i < outputs.size(); i++) {
+ const QVariantMap outputSettings = outputs.at(i).toObject().toVariantMap();
+
+ if (outputSettings.contains(QStringLiteral("name"))) {
+ const QString name = outputSettings.value(QStringLiteral("name")).toString();
+
+ if (m_outputSettings.contains(name)) {
+ qCDebug(qLcKmsDebug) << "Output" << name << "configured multiple times!";
+ }
+
+ m_outputSettings.insert(name, outputSettings);
+ }
+ }
+
+ qCDebug(qLcKmsDebug) << "Requested configuration (some settings may be ignored):\n"
+ << "\thwcursor:" << m_hwCursor << "\n"
+ << "\tpbuffers:" << m_pbuffers << "\n"
+ << "\tseparateScreens:" << m_separateScreens << "\n"
+ << "\tvirtualDesktopLayout:" << m_virtualDesktopLayout << "\n"
+ << "\toutputs:" << m_outputSettings;
+}
+
+void QKmsOutput::restoreMode(QKmsDevice *device)
+{
+ if (mode_set && saved_crtc) {
+ drmModeSetCrtc(device->fd(),
+ saved_crtc->crtc_id,
+ saved_crtc->buffer_id,
+ 0, 0,
+ &connector_id, 1,
+ &saved_crtc->mode);
+ mode_set = false;
+ }
+}
+
+void QKmsOutput::cleanup(QKmsDevice *device)
+{
+ if (dpms_prop) {
+ drmModeFreeProperty(dpms_prop);
+ dpms_prop = nullptr;
+ }
+
+ restoreMode(device);
+
+ if (saved_crtc) {
+ drmModeFreeCrtc(saved_crtc);
+ saved_crtc = nullptr;
+ }
+}
+
+QPlatformScreen::SubpixelAntialiasingType QKmsOutput::subpixelAntialiasingTypeHint() const
+{
+ switch (subpixel) {
+ default:
+ case DRM_MODE_SUBPIXEL_UNKNOWN:
+ case DRM_MODE_SUBPIXEL_NONE:
+ return QPlatformScreen::Subpixel_None;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
+ return QPlatformScreen::Subpixel_RGB;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
+ return QPlatformScreen::Subpixel_BGR;
+ case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
+ return QPlatformScreen::Subpixel_VRGB;
+ case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
+ return QPlatformScreen::Subpixel_VBGR;
+ }
+}
+
+void QKmsOutput::setPowerState(QKmsDevice *device, QPlatformScreen::PowerState state)
+{
+ if (dpms_prop)
+ drmModeConnectorSetProperty(device->fd(), connector_id,
+ dpms_prop->prop_id, (int) state);
+}
+
+QT_END_NAMESPACE
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice_p.h b/src/platformsupport/kmsconvenience/qkmsdevice_p.h
new file mode 100644
index 0000000000..35a51c18b1
--- /dev/null
+++ b/src/platformsupport/kmsconvenience/qkmsdevice_p.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2016 Pelagicore AG
+** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QKMSDEVICE_P_H
+#define QKMSDEVICE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qpa/qplatformscreen.h>
+#include <QtCore/QMap>
+#include <QtCore/QVariant>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+QT_BEGIN_NAMESPACE
+
+class QKmsDevice;
+
+class QKmsScreenConfig
+{
+public:
+ enum VirtualDesktopLayout {
+ VirtualDesktopLayoutHorizontal,
+ VirtualDesktopLayoutVertical
+ };
+
+ QKmsScreenConfig();
+
+ QString devicePath() const { return m_devicePath; }
+
+ bool hwCursor() const { return m_hwCursor; }
+ bool separateScreens() const { return m_separateScreens; }
+ bool supportsPBuffers() const { return m_pbuffers; }
+ VirtualDesktopLayout virtualDesktopLayout() const { return m_virtualDesktopLayout; }
+
+ QMap<QString, QVariantMap> outputSettings() const { return m_outputSettings; }
+
+private:
+ void loadConfig();
+
+ QString m_devicePath;
+ bool m_hwCursor;
+ bool m_separateScreens;
+ bool m_pbuffers;
+ VirtualDesktopLayout m_virtualDesktopLayout;
+ QMap<QString, QVariantMap> m_outputSettings;
+};
+
+struct QKmsOutput
+{
+ QString name;
+ uint32_t connector_id;
+ uint32_t crtc_id;
+ QSizeF physical_size;
+ int mode; // index of selected mode in list below
+ bool mode_set;
+ drmModeCrtcPtr saved_crtc;
+ QList<drmModeModeInfo> modes;
+ int subpixel;
+ drmModePropertyPtr dpms_prop;
+ bool wants_plane;
+ uint32_t plane_id;
+ bool plane_set;
+
+ void restoreMode(QKmsDevice *device);
+ void cleanup(QKmsDevice *device);
+ QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const;
+ void setPowerState(QKmsDevice *device, QPlatformScreen::PowerState state);
+};
+
+class QKmsDevice
+{
+public:
+ struct VirtualDesktopInfo {
+ VirtualDesktopInfo() : virtualIndex(0), isPrimary(false) { }
+ int virtualIndex;
+ QPoint virtualPos;
+ bool isPrimary;
+ };
+
+ QKmsDevice(QKmsScreenConfig *screenConfig, const QString &path = QString());
+ virtual ~QKmsDevice();
+
+ virtual bool open() = 0;
+ virtual void close() = 0;
+ virtual void *nativeDisplay() const = 0;
+
+ void createScreens();
+
+ int fd() const;
+ QString devicePath() const;
+
+ QKmsScreenConfig *screenConfig() const;
+
+protected:
+ virtual QPlatformScreen *createScreen(const QKmsOutput &output) = 0;
+ virtual void registerScreen(QPlatformScreen *screen,
+ bool isPrimary,
+ const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings) = 0;
+
+ void setFd(int fd);
+ int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector);
+ QPlatformScreen *createScreenForConnector(drmModeResPtr resources,
+ drmModeConnectorPtr connector,
+ VirtualDesktopInfo *vinfo);
+ drmModePropertyPtr connectorProperty(drmModeConnectorPtr connector, const QByteArray &name);
+
+ QKmsScreenConfig *m_screenConfig;
+ QString m_path;
+ int m_dri_fd;
+
+ quint32 m_crtc_allocator;
+ quint32 m_connector_allocator;
+
+private:
+ Q_DISABLE_COPY(QKmsDevice)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
index 70c4aa563c..6561e95a0d 100644
--- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
+++ b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
@@ -1398,7 +1398,7 @@ bool AtSpiAdaptor::accessibleInterface(QAccessibleInterface *interface, const QS
sendReply(connection, message, QVariant::fromValue(
QDBusVariant(QVariant::fromValue(QSpiObjectReference(connection, QDBusObjectPath(path))))));
} else if (function == QLatin1String("GetChildAtIndex")) {
- int index = message.arguments().first().toInt();
+ const int index = message.arguments().at(0).toInt();
if (index < 0) {
sendReply(connection, message, QVariant::fromValue(
QSpiObjectReference(connection, QDBusObjectPath(ATSPI_DBUS_PATH_NULL))));
diff --git a/src/platformsupport/platformcompositor/qopenglcompositor_p.h b/src/platformsupport/platformcompositor/qopenglcompositor_p.h
index dece41f676..41a3288240 100644
--- a/src/platformsupport/platformcompositor/qopenglcompositor_p.h
+++ b/src/platformsupport/platformcompositor/qopenglcompositor_p.h
@@ -65,6 +65,7 @@ class QPlatformTextureList;
class QOpenGLCompositorWindow
{
public:
+ virtual ~QOpenGLCompositorWindow() { }
virtual QWindow *sourceWindow() const = 0;
virtual const QPlatformTextureList *textures() const = 0;
virtual void beginCompositing() { }
diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro
index 09e2922505..7a97a12bae 100644
--- a/src/platformsupport/platformsupport.pro
+++ b/src/platformsupport/platformsupport.pro
@@ -7,7 +7,7 @@ SUBDIRS = \
fbconvenience \
themes
-qtConfig(freetype)|if(darwin:!if(watchos:CONFIG(simulator, simulator|device)))|win32: \
+qtConfig(freetype)|darwin|win32: \
SUBDIRS += fontdatabases
qtConfig(evdev)|qtConfig(tslib)|qtConfig(libinput) {
@@ -24,6 +24,8 @@ qtConfig(egl): \
SUBDIRS += eglconvenience
qtConfig(xlib):qtConfig(opengl):!qtConfig(opengles2): \
SUBDIRS += glxconvenience
+qtConfig(kms): \
+ SUBDIRS += kmsconvenience
qtConfig(accessibility) {
SUBDIRS += accessibility
diff --git a/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp
index 352e4dfd56..09470bccc6 100644
--- a/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp
+++ b/src/platformsupport/themes/genericunix/dbusmenu/qdbusmenuconnection.cpp
@@ -37,6 +37,8 @@
**
****************************************************************************/
+#include <QtGui/qtgui-config.h>
+
#ifndef QT_NO_SYSTEMTRAYICON
#include "qdbustrayicon_p.h"
#endif
diff --git a/src/platformsupport/themes/genericunix/genericunix.pri b/src/platformsupport/themes/genericunix/genericunix.pri
index 27019b4aa2..11da533bc4 100644
--- a/src/platformsupport/themes/genericunix/genericunix.pri
+++ b/src/platformsupport/themes/genericunix/genericunix.pri
@@ -3,5 +3,8 @@ SOURCES += $$PWD/qgenericunixthemes.cpp
qtConfig(dbus) {
include(dbusmenu/dbusmenu.pri)
- include(dbustray/dbustray.pri)
+
+ qtConfig(systemtrayicon) {
+ include(dbustray/dbustray.pri)
+ }
}
diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp
index 4eefcace0f..e9116223bd 100644
--- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp
+++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp
@@ -555,6 +555,7 @@ QIcon QKdeTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions
#if QT_CONFIG(mimetype)
return xdgFileIcon(fileInfo);
#else
+ Q_UNUSED(fileInfo);
return QIcon();
#endif
}
@@ -720,6 +721,7 @@ QIcon QGnomeTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptio
#if QT_CONFIG(mimetype)
return xdgFileIcon(fileInfo);
#else
+ Q_UNUSED(fileInfo);
return QIcon();
#endif
}
diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm
index 7cf9365513..341d3bccf2 100644
--- a/src/plugins/bearer/corewlan/qcorewlanengine.mm
+++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm
@@ -61,14 +61,14 @@ extern "C" { // Otherwise it won't find CWKeychain* symbols at link time
#include <net/if.h>
#include <ifaddrs.h>
-@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject
+@interface QT_MANGLE_NAMESPACE(QNSListener) : NSObject <CWEventDelegate>
{
NSNotificationCenter *notificationCenter;
- CWInterface *currentInterface;
+ CWWiFiClient *client;
QCoreWlanEngine *engine;
NSLock *locker;
}
-- (void)notificationHandler:(NSNotification *)notification;
+- (void)powerStateDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName;
- (void)remove;
- (void)setEngine:(QCoreWlanEngine *)coreEngine;
- (QCoreWlanEngine *)engine;
@@ -85,8 +85,9 @@ extern "C" { // Otherwise it won't find CWKeychain* symbols at link time
[locker lock];
QMacAutoReleasePool pool;
notificationCenter = [NSNotificationCenter defaultCenter];
- currentInterface = [CWInterface interface];
- [notificationCenter addObserver:self selector:@selector(notificationHandler:) name:CWPowerDidChangeNotification object:nil];
+ client = [CWWiFiClient sharedWiFiClient];
+ client.delegate = self;
+ [client startMonitoringEventWithType:CWEventTypePowerDidChange error:nil];
[locker unlock];
return self;
}
@@ -95,6 +96,7 @@ static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0;
-(void)dealloc
{
+ client.delegate = nil;
listener = nil;
[super dealloc];
}
@@ -115,13 +117,13 @@ static QT_MANGLE_NAMESPACE(QNSListener) *listener = 0;
-(void)remove
{
[locker lock];
- [notificationCenter removeObserver:self];
+ [client stopMonitoringAllEventsAndReturnError:nil];
[locker unlock];
}
-- (void)notificationHandler:(NSNotification *)notification
+- (void)powerStateDidChangeForWiFiInterfaceWithName:(NSString *)interfaceName
{
- Q_UNUSED(notification);
+ Q_UNUSED(interfaceName);
engine->requestUpdate();
}
@end
@@ -162,7 +164,8 @@ void QScanThread::run()
QMacAutoReleasePool pool;
QStringList found;
mutex.lock();
- CWInterface *currentInterface = [CWInterface interfaceWithName:interfaceName.toNSString()];
+ CWInterface *currentInterface = [[CWWiFiClient sharedWiFiClient]
+ interfaceWithName:interfaceName.toNSString()];
mutex.unlock();
const bool currentInterfaceServiceActive = currentInterface.serviceActive;
@@ -284,10 +287,10 @@ void QScanThread::getUserConfigurations()
QMacAutoReleasePool pool;
userProfiles.clear();
- NSSet *wifiInterfaces = [CWInterface interfaceNames];
+ NSArray<NSString *> *wifiInterfaces = [CWWiFiClient interfaceNames];
for (NSString *ifName in wifiInterfaces) {
- CWInterface *wifiInterface = [CWInterface interfaceWithName:ifName];
+ CWInterface *wifiInterface = [[CWWiFiClient sharedWiFiClient] interfaceWithName:ifName];
NSString *nsInterfaceName = wifiInterface.ssid;
// add user configured system networks
@@ -442,7 +445,7 @@ void QCoreWlanEngine::initialize()
QMutexLocker locker(&mutex);
QMacAutoReleasePool pool;
- if ([[CWInterface interfaceNames] count] > 0 && !listener) {
+ if ([[CWWiFiClient interfaceNames] count] > 0 && !listener) {
listener = [[QT_MANGLE_NAMESPACE(QNSListener) alloc] init];
listener.engine = this;
hasWifi = true;
@@ -476,7 +479,7 @@ void QCoreWlanEngine::connectToId(const QString &id)
QString interfaceString = getInterfaceFromId(id);
CWInterface *wifiInterface =
- [CWInterface interfaceWithName:interfaceString.toNSString()];
+ [[CWWiFiClient sharedWiFiClient] interfaceWithName:interfaceString.toNSString()];
if (wifiInterface.powerOn) {
NSError *err = nil;
@@ -559,7 +562,7 @@ void QCoreWlanEngine::disconnectFromId(const QString &id)
QMacAutoReleasePool pool;
CWInterface *wifiInterface =
- [CWInterface interfaceWithName:interfaceString.toNSString()];
+ [[CWWiFiClient sharedWiFiClient] interfaceWithName:interfaceString.toNSString()];
disconnectedInterfaceString = interfaceString;
[wifiInterface disassociate];
@@ -573,8 +576,8 @@ void QCoreWlanEngine::checkDisconnect()
if (!disconnectedInterfaceString.isEmpty()) {
QMacAutoReleasePool pool;
- CWInterface *wifiInterface =
- [CWInterface interfaceWithName:disconnectedInterfaceString.toNSString()];
+ CWInterface *wifiInterface = [[CWWiFiClient sharedWiFiClient]
+ interfaceWithName:disconnectedInterfaceString.toNSString()];
const QString networkSsid = QString::fromNSString([wifiInterface ssid]);
if (!networkSsid.isEmpty()) {
@@ -599,7 +602,7 @@ void QCoreWlanEngine::doRequestUpdate()
QMacAutoReleasePool pool;
- NSSet *wifiInterfaces = [CWInterface interfaceNames];
+ NSArray<NSString *> *wifiInterfaces = [CWWiFiClient interfaceNames];
for (NSString *ifName in wifiInterfaces) {
scanThread->interfaceName = QString::fromNSString(ifName);
scanThread->start();
@@ -615,7 +618,8 @@ bool QCoreWlanEngine::isWifiReady(const QString &wifiDeviceName)
bool haswifi = false;
if(hasWifi) {
QMacAutoReleasePool pool;
- CWInterface *defaultInterface = [CWInterface interfaceWithName:wifiDeviceName.toNSString()];
+ CWInterface *defaultInterface = [[CWWiFiClient sharedWiFiClient]
+ interfaceWithName:wifiDeviceName.toNSString()];
if (defaultInterface.powerOn) {
haswifi = true;
}
diff --git a/src/plugins/generic/bsdkeyboard/main.cpp b/src/plugins/generic/bsdkeyboard/main.cpp
index f48af0ae28..b65d500230 100644
--- a/src/plugins/generic/bsdkeyboard/main.cpp
+++ b/src/plugins/generic/bsdkeyboard/main.cpp
@@ -3,29 +3,35 @@
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp b/src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp
index 6f34d066c6..784ec54542 100644
--- a/src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp
+++ b/src/plugins/generic/bsdkeyboard/qbsdkeyboard.cpp
@@ -3,29 +3,35 @@
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/generic/bsdkeyboard/qbsdkeyboard.h b/src/plugins/generic/bsdkeyboard/qbsdkeyboard.h
index 1a7cbc1f9a..46d8988d3a 100644
--- a/src/plugins/generic/bsdkeyboard/qbsdkeyboard.h
+++ b/src/plugins/generic/bsdkeyboard/qbsdkeyboard.h
@@ -3,29 +3,35 @@
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h b/src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h
index 45cf5944bc..69c03b3daf 100644
--- a/src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h
+++ b/src/plugins/generic/bsdkeyboard/qbsdkeyboard_defaultmap.h
@@ -1,32 +1,38 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/generic/bsdmouse/main.cpp b/src/plugins/generic/bsdmouse/main.cpp
index 4abc7609c1..d676d5a1bb 100644
--- a/src/plugins/generic/bsdmouse/main.cpp
+++ b/src/plugins/generic/bsdmouse/main.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/generic/bsdmouse/qbsdmouse.cpp b/src/plugins/generic/bsdmouse/qbsdmouse.cpp
index 4875fd96bd..55905199b8 100644
--- a/src/plugins/generic/bsdmouse/qbsdmouse.cpp
+++ b/src/plugins/generic/bsdmouse/qbsdmouse.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/generic/bsdmouse/qbsdmouse.h b/src/plugins/generic/bsdmouse/qbsdmouse.h
index 9a4cb8dd82..724b9c8484 100644
--- a/src/plugins/generic/bsdmouse/qbsdmouse.h
+++ b/src/plugins/generic/bsdmouse/qbsdmouse.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/generic/generic.pro b/src/plugins/generic/generic.pro
index 996e57d015..e323f32d2c 100644
--- a/src/plugins/generic/generic.pro
+++ b/src/plugins/generic/generic.pro
@@ -2,7 +2,9 @@ TEMPLATE = subdirs
QT_FOR_CONFIG += gui-private network-private
qtConfig(evdev) {
- SUBDIRS += evdevmouse evdevtouch evdevkeyboard evdevtablet
+ SUBDIRS += evdevmouse evdevtouch evdevkeyboard
+ qtConfig(tabletevent): \
+ SUBDIRS += evdevtablet
}
qtConfig(tslib) {
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro
index bd3fe5a6cc..03592bfa7d 100644
--- a/src/plugins/platforms/android/android.pro
+++ b/src/plugins/platforms/android/android.pro
@@ -43,7 +43,8 @@ SOURCES += $$PWD/androidplatformplugin.cpp \
$$PWD/qandroidplatformbackingstore.cpp \
$$PWD/qandroidplatformopenglcontext.cpp \
$$PWD/qandroidplatformforeignwindow.cpp \
- $$PWD/qandroideventdispatcher.cpp
+ $$PWD/qandroideventdispatcher.cpp \
+ $$PWD/qandroidplatformoffscreensurface.cpp
HEADERS += $$PWD/qandroidplatformintegration.h \
$$PWD/androiddeadlockprotector.h \
@@ -71,7 +72,8 @@ HEADERS += $$PWD/qandroidplatformintegration.h \
$$PWD/qandroidplatformbackingstore.h \
$$PWD/qandroidplatformopenglcontext.h \
$$PWD/qandroidplatformforeignwindow.h \
- $$PWD/qandroideventdispatcher.h
+ $$PWD/qandroideventdispatcher.h \
+ $$PWD/qandroidplatformoffscreensurface.h
qtConfig(android-style-assets): SOURCES += $$PWD/extract.cpp
else: SOURCES += $$PWD/extract-dummy.cpp
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index d3bb089aa4..8372bf6484 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -206,7 +206,8 @@ namespace QtAndroidInput
m_touchPoints.clear();
}
- static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y, jfloat size, jfloat pressure)
+ static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y,
+ jfloat major, jfloat minor, jfloat rotation, jfloat pressure)
{
Qt::TouchPointState state = Qt::TouchPointStationary;
switch (action) {
@@ -229,12 +230,13 @@ namespace QtAndroidInput
QWindowSystemInterface::TouchPoint touchPoint;
touchPoint.id = id;
touchPoint.pressure = pressure;
+ touchPoint.rotation = rotation * 180 / M_PI;
touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh));
touchPoint.state = state;
- touchPoint.area = QRectF(x - double(dw*size) / 2.0,
- y - double(dh*size) / 2.0,
- double(dw*size),
- double(dh*size));
+ touchPoint.area = QRectF(x - double(minor),
+ y - double(major),
+ double(minor * 2),
+ double(major * 2));
m_touchPoints.push_back(touchPoint);
if (state == Qt::TouchPointPressed) {
@@ -817,7 +819,7 @@ namespace QtAndroidInput
static JNINativeMethod methods[] = {
{"touchBegin","(I)V",(void*)touchBegin},
- {"touchAdd","(IIIZIIFF)V",(void*)touchAdd},
+ {"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd},
{"touchEnd","(II)V",(void*)touchEnd},
{"mouseDown", "(III)V", (void *)mouseDown},
{"mouseUp", "(III)V", (void *)mouseUp},
diff --git a/src/plugins/platforms/android/extract.cpp b/src/plugins/platforms/android/extract.cpp
index 8620aa4fe8..e6636e37d4 100644
--- a/src/plugins/platforms/android/extract.cpp
+++ b/src/plugins/platforms/android/extract.cpp
@@ -1,26 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL3-COMM$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
index a14271c8f5..2fdf269566 100644
--- a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
+++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
@@ -66,7 +66,7 @@ void QAndroidPlatformFontDatabase::populateFontDatabase()
const auto entries = dir.entryInfoList(nameFilters, QDir::Files);
for (const QFileInfo &fi : entries) {
const QByteArray file = QFile::encodeName(fi.absoluteFilePath());
- QBasicFontDatabase::addTTFile(QByteArray(), file);
+ QFreeTypeFontDatabase::addTTFile(QByteArray(), file);
}
}
@@ -82,7 +82,7 @@ QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &fami
result.append(QString(qgetenv("QT_ANDROID_FONTS_SERIF")).split(QLatin1Char(';')));
else
result.append(QString(qgetenv("QT_ANDROID_FONTS")).split(QLatin1Char(';')));
- result.append(QBasicFontDatabase::fallbacksForFamily(family, style, styleHint, script));
+ result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script));
return result;
}
diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.h b/src/plugins/platforms/android/qandroidplatformfontdatabase.h
index 533d6e50a9..166a590698 100644
--- a/src/plugins/platforms/android/qandroidplatformfontdatabase.h
+++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.h
@@ -40,11 +40,11 @@
#ifndef QANDROIDPLATFORMFONTDATABASE_H
#define QANDROIDPLATFORMFONTDATABASE_H
-#include <QtFontDatabaseSupport/private/qbasicfontdatabase_p.h>
+#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
QT_BEGIN_NAMESPACE
-class QAndroidPlatformFontDatabase: public QBasicFontDatabase
+class QAndroidPlatformFontDatabase: public QFreeTypeFontDatabase
{
public:
QString fontDir() const override;
diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp
index 8c1f0ea8d2..1c920c0af9 100644
--- a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp
@@ -45,12 +45,11 @@
QT_BEGIN_NAMESPACE
-QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window)
+QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle)
: QAndroidPlatformWindow(window),
m_surfaceId(-1)
{
- const WId wId = window->property("_q_foreignWinId").value<WId>();
- m_view = reinterpret_cast<jobject>(wId);
+ m_view = reinterpret_cast<jobject>(nativeHandle);
if (m_view.isValid())
QtAndroid::setViewVisibility(m_view.object(), false);
}
diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h
index d42c36dcee..af1eee5499 100644
--- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h
@@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE
class QAndroidPlatformForeignWindow : public QAndroidPlatformWindow
{
public:
- explicit QAndroidPlatformForeignWindow(QWindow *window);
+ explicit QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle);
~QAndroidPlatformForeignWindow();
void lower() override;
void raise() override;
@@ -57,6 +57,7 @@ public:
void setVisible(bool visible) override;
void applicationStateChanged(Qt::ApplicationState state) override;
void setParent(const QPlatformWindow *window) override;
+ bool isForeignWindow() const override { return true; }
private:
int m_surfaceId;
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 44b4668585..d8bba4f8e9 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -65,6 +65,7 @@
#include "qandroidplatformservices.h"
#include "qandroidplatformtheme.h"
#include "qandroidsystemlocale.h"
+#include "qandroidplatformoffscreensurface.h"
#include <QtPlatformHeaders/QEGLNativeContext>
@@ -267,12 +268,20 @@ QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenS
{
if (!QtAndroid::activity())
return nullptr;
+
QSurfaceFormat format(surface->requestedFormat());
format.setAlphaBufferSize(8);
format.setRedBufferSize(8);
format.setGreenBufferSize(8);
format.setBlueBufferSize(8);
+ if (surface->nativeHandle()) {
+ // Adopt existing offscreen Surface
+ // The expectation is that nativeHandle is an ANativeWindow* representing
+ // an android.view.Surface
+ return new QAndroidPlatformOffscreenSurface(m_eglDisplay, format, surface);
+ }
+
return new QEGLPbuffer(m_eglDisplay, format, surface);
}
@@ -280,10 +289,13 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind
{
if (!QtAndroid::activity())
return nullptr;
- if (window->type() == Qt::ForeignWindow)
- return new QAndroidPlatformForeignWindow(window);
- else
- return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay);
+
+ return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay);
+}
+
+QPlatformWindow *QAndroidPlatformIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
+{
+ return new QAndroidPlatformForeignWindow(window, nativeHandle);
}
QAbstractEventDispatcher *QAndroidPlatformIntegration::createEventDispatcher() const
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h
index 208bb705b7..923670b9e6 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.h
+++ b/src/plugins/platforms/android/qandroidplatformintegration.h
@@ -81,6 +81,7 @@ public:
bool hasCapability(QPlatformIntegration::Capability cap) const override;
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
QAbstractEventDispatcher *createEventDispatcher() const override;
diff --git a/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp b/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp
new file mode 100644
index 0000000000..c7d832efb6
--- /dev/null
+++ b/src/plugins/platforms/android/qandroidplatformoffscreensurface.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformoffscreensurface.h"
+
+#include <QtGui/QOffscreenSurface>
+#include <QtEglSupport/private/qeglconvenience_p.h>
+
+#include <android/native_window.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidPlatformOffscreenSurface::QAndroidPlatformOffscreenSurface(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface)
+ : QPlatformOffscreenSurface(offscreenSurface)
+ , m_format(format)
+ , m_display(display)
+ , m_surface(EGL_NO_SURFACE)
+{
+ // Get native handle
+ ANativeWindow *surfaceTexture = (ANativeWindow*)offscreenSurface->nativeHandle();
+
+ EGLConfig config = q_configFromGLFormat(m_display, m_format, false);
+ if (config) {
+ const EGLint attributes[] = {
+ EGL_NONE
+ };
+ m_surface = eglCreateWindowSurface(m_display, config, surfaceTexture, attributes);
+ }
+}
+
+QAndroidPlatformOffscreenSurface::~QAndroidPlatformOffscreenSurface()
+{
+ eglDestroySurface(m_display, m_surface);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/android/qandroidplatformoffscreensurface.h b/src/plugins/platforms/android/qandroidplatformoffscreensurface.h
new file mode 100644
index 0000000000..461f949254
--- /dev/null
+++ b/src/plugins/platforms/android/qandroidplatformoffscreensurface.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMOFFSCREENSURFACETEXTURE_H
+#define QANDROIDPLATFORMOFFSCREENSURFACETEXTURE_H
+
+#include <qpa/qplatformoffscreensurface.h>
+#include <QtEglSupport/private/qeglplatformcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+class QOffscreenSurface;
+class QAndroidPlatformOffscreenSurface : public QPlatformOffscreenSurface
+{
+public:
+ QAndroidPlatformOffscreenSurface(EGLDisplay display, const QSurfaceFormat &format,
+ QOffscreenSurface *offscreenSurface);
+ ~QAndroidPlatformOffscreenSurface();
+
+ QSurfaceFormat format() const override { return m_format; }
+ bool isValid() const override { return m_surface != EGL_NO_SURFACE; }
+
+ EGLSurface surface() const { return m_surface; }
+private:
+ QSurfaceFormat m_format;
+ EGLDisplay m_display;
+ EGLSurface m_surface;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDPLATFORMOFFSCREENSURFACETEXTURE_H
diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
index bef6bb9d42..8d98882e9e 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
+++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
@@ -41,11 +41,13 @@
#include "qandroidplatformopenglcontext.h"
#include "qandroidplatformopenglwindow.h"
#include "qandroidplatformintegration.h"
+#include "qandroidplatformoffscreensurface.h"
#include <QtEglSupport/private/qeglpbuffer_p.h>
#include <QSurface>
#include <QtGui/private/qopenglcontext_p.h>
+#include <QtGui/QOffscreenSurface>
QT_BEGIN_NAMESPACE
@@ -72,10 +74,15 @@ bool QAndroidPlatformOpenGLContext::makeCurrent(QPlatformSurface *surface)
EGLSurface QAndroidPlatformOpenGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
- if (surface->surface()->surfaceClass() == QSurface::Window)
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
return static_cast<QAndroidPlatformOpenGLWindow *>(surface)->eglSurface(eglConfig());
- else
- return static_cast<QEGLPbuffer *>(surface)->pbuffer();
+ } else {
+ auto platformOffscreenSurface = static_cast<QPlatformOffscreenSurface*>(surface);
+ if (platformOffscreenSurface->offscreenSurface()->nativeHandle())
+ return static_cast<QAndroidPlatformOffscreenSurface *>(surface)->surface();
+ else
+ return static_cast<QEGLPbuffer *>(surface)->pbuffer();
+ }
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h
index 87e5cbaa4f..91cb1e76e6 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformwindow.h
@@ -71,7 +71,7 @@ public:
void requestActivateWindow() override;
void updateStatusBarVisibility();
inline bool isRaster() const {
- if ((window()->flags() & Qt::ForeignWindow) == Qt::ForeignWindow)
+ if (isForeignWindow())
return false;
return window()->surfaceType() == QSurface::RasterSurface
diff --git a/src/plugins/platforms/bsdfb/main.cpp b/src/plugins/platforms/bsdfb/main.cpp
index f4ab3dee39..b2cd1373a7 100644
--- a/src/plugins/platforms/bsdfb/main.cpp
+++ b/src/plugins/platforms/bsdfb/main.cpp
@@ -1,32 +1,38 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
index 1fa13183f8..6a7d445e69 100644
--- a/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
+++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.cpp
@@ -1,32 +1,38 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/bsdfb/qbsdfbintegration.h b/src/plugins/platforms/bsdfb/qbsdfbintegration.h
index 2be5ea260d..81195edf7e 100644
--- a/src/plugins/platforms/bsdfb/qbsdfbintegration.h
+++ b/src/plugins/platforms/bsdfb/qbsdfbintegration.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp b/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp
index 0ef57d37e5..067a26a7b1 100644
--- a/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp
+++ b/src/plugins/platforms/bsdfb/qbsdfbscreen.cpp
@@ -1,32 +1,38 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -243,7 +249,7 @@ QRegion QBsdFbScreen::doRedraw()
const auto rects = touched.rects();
for (const QRect &rect : rects)
- m_blitter->drawImage(rect, *mScreenImage, rect);
+ m_blitter->drawImage(rect, mScreenImage, rect);
return touched;
}
diff --git a/src/plugins/platforms/bsdfb/qbsdfbscreen.h b/src/plugins/platforms/bsdfb/qbsdfbscreen.h
index 3e244e3460..890a2eb757 100644
--- a/src/plugins/platforms/bsdfb/qbsdfbscreen.h
+++ b/src/plugins/platforms/bsdfb/qbsdfbscreen.h
@@ -1,32 +1,38 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index 0664841c2d..62935210be 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -86,6 +86,8 @@ QT += \
accessibility_support-private clipboard_support-private theme_support-private \
fontdatabase_support-private graphics_support-private cgl_support-private
+CONFIG += no_app_extension_api_only
+
qtHaveModule(widgets) {
OBJECTIVE_SOURCES += \
qpaintengine_mac.mm \
diff --git a/src/plugins/platforms/cocoa/images/copyarrowcursor.png b/src/plugins/platforms/cocoa/images/copyarrowcursor.png
deleted file mode 100644
index 13dfca95bc..0000000000
--- a/src/plugins/platforms/cocoa/images/copyarrowcursor.png
+++ /dev/null
Binary files differ
diff --git a/src/plugins/platforms/cocoa/images/forbiddencursor.png b/src/plugins/platforms/cocoa/images/forbiddencursor.png
deleted file mode 100644
index a9f21b4a5e..0000000000
--- a/src/plugins/platforms/cocoa/images/forbiddencursor.png
+++ /dev/null
Binary files differ
diff --git a/src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.png b/src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.png
deleted file mode 100644
index 6716597046..0000000000
--- a/src/plugins/platforms/cocoa/images/leopard-unified-toolbar-on.png
+++ /dev/null
Binary files differ
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.mm b/src/plugins/platforms/cocoa/qcocoaapplication.mm
index c5ae4bc2bf..3b950efa55 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.mm
@@ -76,6 +76,7 @@
#include "qcocoaintrospection.h"
#include "qcocoaapplicationdelegate.h"
#include "qcocoahelpers.h"
+#include "qcocoawindow.h"
#include <qguiapplication.h>
#include <qdebug.h>
@@ -148,6 +149,21 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE
@end
+static void qt_maybeSendKeyEquivalentUpEvent(NSEvent *event)
+{
+ // Cocoa is known for not sending key up events for key
+ // equivalents, regardless of whether it's an actual
+ // recognized key equivalent. We decide to force fate
+ // and forward the key event to the key (focus) window.
+ // However, non-Qt windows will not (and should not) get
+ // any special treatment, only QWindow-owned NSWindows.
+ if (event.type == NSKeyUp && (event.modifierFlags & NSCommandKeyMask)) {
+ NSWindow *targetWindow = event.window;
+ if ([targetWindow.class conformsToProtocol:@protocol(QNSWindowProtocol)])
+ [targetWindow sendEvent:event];
+ }
+}
+
@implementation QT_MANGLE_NAMESPACE(QNSApplication)
- (void)QT_MANGLE_NAMESPACE(qt_sendEvent_original):(NSEvent *)event
@@ -164,16 +180,20 @@ static const QByteArray q_macLocalEventType = QByteArrayLiteral("mac_generic_NSE
// be called instead of sendEvent if redirection occurs.
// 'self' will then be an instance of NSApplication
// (and not QNSApplication)
- if (![NSApp QT_MANGLE_NAMESPACE(qt_filterEvent):event])
+ if (![NSApp QT_MANGLE_NAMESPACE(qt_filterEvent):event]) {
[self QT_MANGLE_NAMESPACE(qt_sendEvent_original):event];
+ qt_maybeSendKeyEquivalentUpEvent(event);
+ }
}
- (void)sendEvent:(NSEvent *)event
{
// This method will be called if
// no redirection occurs
- if (![NSApp QT_MANGLE_NAMESPACE(qt_filterEvent):event])
+ if (![NSApp QT_MANGLE_NAMESPACE(qt_filterEvent):event]) {
[super sendEvent:event];
+ qt_maybeSendKeyEquivalentUpEvent(event);
+ }
}
@end
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index a74995319b..1d7ad772dc 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -57,7 +57,8 @@ QCocoaBackingStore::~QCocoaBackingStore()
QImage::Format QCocoaBackingStore::format() const
{
- if (static_cast<QCocoaWindow *>(window()->handle())->m_drawContentBorderGradient)
+ QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle());
+ if (cocoaWindow && cocoaWindow->m_drawContentBorderGradient)
return QImage::Format_ARGB32_Premultiplied;
return QRasterBackingStore::format();
diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
index e53c085e41..a8974c4de5 100644
--- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm
@@ -80,7 +80,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
mHelper = 0;
mStolenContentView = 0;
mPanelButtons = nil;
- mResultCode = NSCancelButton;
+ mResultCode = NSModalResponseCancel;
mDialogIsExecuting = false;
mResultSet = false;
mClosingDueToKnownButton = false;
@@ -168,7 +168,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
mClosingDueToKnownButton = true;
[mColorPanel close];
[self updateQtColor];
- [self finishOffWithCode:NSOKButton];
+ [self finishOffWithCode:NSModalResponseOK];
}
- (void)onCancelClicked
@@ -177,7 +177,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
mClosingDueToKnownButton = true;
[mColorPanel close];
mQtColor = QColor();
- [self finishOffWithCode:NSCancelButton];
+ [self finishOffWithCode:NSModalResponseCancel];
}
}
@@ -238,12 +238,12 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
[NSApp runModalForWindow:mColorPanel];
mDialogIsExecuting = false;
- return (mResultCode == NSOKButton);
+ return (mResultCode == NSModalResponseOK);
}
- (QPlatformDialogHelper::DialogCode)dialogResultCode
{
- return (mResultCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
+ return (mResultCode == NSModalResponseOK) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
}
- (BOOL)windowShouldClose:(id)window
@@ -252,7 +252,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
if (!mPanelButtons)
[self updateQtColor];
if (mDialogIsExecuting) {
- [self finishOffWithCode:NSCancelButton];
+ [self finishOffWithCode:NSModalResponseCancel];
} else {
mResultSet = true;
if (mHelper)
@@ -278,7 +278,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate);
// This check will prevent any such recursion.
if (!mResultSet) {
mResultSet = true;
- if (mResultCode == NSCancelButton) {
+ if (mResultCode == NSModalResponseCancel) {
emit mHelper->reject();
} else {
emit mHelper->accept();
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index 3df2a7c962..99a136d384 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -97,6 +97,9 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
case Qt::ArrowCursor:
cocoaCursor= [NSCursor arrowCursor];
break;
+ case Qt::ForbiddenCursor:
+ cocoaCursor = [NSCursor operationNotAllowedCursor];
+ break;
case Qt::CrossCursor:
cocoaCursor = [NSCursor crosshairCursor];
break;
@@ -123,7 +126,7 @@ NSCursor *QCocoaCursor::convertCursor(QCursor *cursor)
cocoaCursor = [NSCursor crosshairCursor];
break;
case Qt::DragCopyCursor:
- cocoaCursor = [NSCursor crosshairCursor];
+ cocoaCursor = [NSCursor dragCopyCursor];
break;
case Qt::DragLinkCursor:
cocoaCursor = [NSCursor dragLinkCursor];
@@ -235,10 +238,6 @@ NSCursor *QCocoaCursor::createCursorData(QCursor *cursor)
QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/waitcursor.png"));
return createCursorFromPixmap(pixmap, hotspot);
break; }
- case Qt::ForbiddenCursor: {
- QPixmap pixmap = QPixmap(QLatin1String(":/qt-project.org/mac/cursors/images/forbiddencursor.png"));
- return createCursorFromPixmap(pixmap, hotspot);
- break; }
#define QT_USE_APPROXIMATE_CURSORS
#ifdef QT_USE_APPROXIMATE_CURSORS
case Qt::SizeVerCursor:
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index a0967750e7..c71e80d191 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -132,7 +132,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o)
QPixmap pm = dragPixmap(m_drag, hotSpot);
QSize pmDeviceIndependentSize = pm.size() / pm.devicePixelRatio();
NSImage *nsimage = qt_mac_create_nsimage(pm);
- [nsimage setSize:pmDeviceIndependentSize.toCGSize()];
+ [nsimage setSize:NSSizeFromCGSize(pmDeviceIndependentSize.toCGSize())];
QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacInternalPasteboardMime::MIME_DND);
m_drag->mimeData()->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy"));
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index 72c7856c2d..d2f985ec87 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -401,7 +401,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// [NSApp run], which is the normal code path for cocoa applications.
if (NSModalSession session = d->currentModalSession()) {
QBoolBlocker execGuard(d->currentExecIsNSAppRun, false);
- while ([NSApp runModalSession:session] == NSRunContinuesResponse && !d->interrupt)
+ while ([NSApp runModalSession:session] == NSModalResponseContinue && !d->interrupt)
qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
if (!d->interrupt && session == d->currentModalSessionCached) {
@@ -435,7 +435,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
if (flags & QEventLoop::WaitForMoreEvents)
qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
NSInteger status = [NSApp runModalSession:session];
- if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) {
+ if (status != NSModalResponseContinue && session == d->currentModalSessionCached) {
// INVARIANT: Someone called [NSApp stopModal:] from outside the event
// dispatcher (e.g to stop a native dialog). But that call wrongly stopped
// 'session' as well. As a result, we need to restart all internal sessions:
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 2aaad38659..4ba3dcb9a6 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -63,6 +63,7 @@
#include <stdlib.h>
#include <qabstracteventdispatcher.h>
#include <qsysinfo.h>
+#include <qoperatingsystemversion.h>
#include <qglobal.h>
#include <QDir>
@@ -100,7 +101,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
}
- (NSString *)strip:(const QString &)label;
-- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
+- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url;
- (void)filterChanged:(id)sender;
- (void)showModelessPanel;
- (BOOL)runApplicationModalPanel;
@@ -164,7 +165,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate);
[mSavePanel setDelegate:self];
#if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_11)
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_11)
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXElCapitan)
mOpenPanel.accessoryViewDisclosed = YES;
#endif
@@ -221,12 +222,12 @@ static QString strippedText(QString s)
if (mOpenPanel){
QFileInfo info(*mCurrentSelection);
NSString *filepath = info.filePath().toNSString();
+ NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
- || [self panel:nil shouldShowFilename:filepath];
+ || [self panel:nil shouldEnableURL:url];
[self updateProperties];
QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
- [mOpenPanel setAllowedFileTypes:nil];
[mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""];
[mOpenPanel beginWithCompletionHandler:^(NSInteger result){
@@ -241,8 +242,9 @@ static QString strippedText(QString s)
{
QFileInfo info(*mCurrentSelection);
NSString *filepath = info.filePath().toNSString();
+ NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
- || [self panel:nil shouldShowFilename:filepath];
+ || [self panel:nil shouldEnableURL:url];
[mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]];
[mSavePanel setNameFieldStringValue:selectable ? info.fileName().toNSString() : @""];
@@ -272,8 +274,9 @@ static QString strippedText(QString s)
{
QFileInfo info(*mCurrentSelection);
NSString *filepath = info.filePath().toNSString();
+ NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
- || [self panel:nil shouldShowFilename:filepath];
+ || [self panel:nil shouldEnableURL:url];
[self updateProperties];
QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
@@ -289,26 +292,24 @@ static QString strippedText(QString s)
}];
}
-- (BOOL)isHiddenFile:(NSString *)filename isDir:(BOOL)isDir
+- (BOOL)isHiddenFileAtURL:(NSURL *)url
{
- CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)filename, kCFURLPOSIXPathStyle, isDir);
- CFBooleanRef isHidden;
- Boolean errorOrHidden = false;
- if (!CFURLCopyResourcePropertyForKey(url, kCFURLIsHiddenKey, &isHidden, NULL)) {
- errorOrHidden = true;
- } else {
- if (CFBooleanGetValue(isHidden))
- errorOrHidden = true;
- CFRelease(isHidden);
+ BOOL hidden = NO;
+ if (url) {
+ CFBooleanRef isHiddenProperty;
+ if (CFURLCopyResourcePropertyForKey((__bridge CFURLRef)url, kCFURLIsHiddenKey, &isHiddenProperty, NULL)) {
+ hidden = CFBooleanGetValue(isHiddenProperty);
+ CFRelease(isHiddenProperty);
+ }
}
- CFRelease(url);
- return errorOrHidden;
+ return hidden;
}
-- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
+- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url
{
Q_UNUSED(sender);
+ NSString *filename = [url path];
if ([filename length] == 0)
return NO;
@@ -352,7 +353,7 @@ static QString strippedText(QString s)
return NO;
}
if (!(filter & QDir::Hidden)
- && (qtFileName.startsWith(QLatin1Char('.')) || [self isHiddenFile:filename isDir:isDir]))
+ && (qtFileName.startsWith(QLatin1Char('.')) || [self isHiddenFileAtURL:url]))
return NO;
return YES;
@@ -445,11 +446,15 @@ static QString strippedText(QString s)
[mSavePanel setTitle:mOptions->windowTitle().toNSString()];
[mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead?
- QStringList ext = [self acceptableExtensionsForSave];
- const QString defaultSuffix = mOptions->defaultSuffix();
- if (!ext.isEmpty() && !defaultSuffix.isEmpty())
- ext.prepend(defaultSuffix);
- [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)];
+ if (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) {
+ QStringList ext = [self acceptableExtensionsForSave];
+ const QString defaultSuffix = mOptions->defaultSuffix();
+ if (!ext.isEmpty() && !defaultSuffix.isEmpty())
+ ext.prepend(defaultSuffix);
+ [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)];
+ } else {
+ [mOpenPanel setAllowedFileTypes:nil]; // delegate panel:shouldEnableURL: does the file filtering for NSOpenPanel
+ }
if ([mSavePanel respondsToSelector:@selector(isVisible)] && [mSavePanel isVisible]) {
if ([mSavePanel respondsToSelector:@selector(validateVisibleColumns)])
diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
index 33dd4260a5..e4b796dcde 100644
--- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm
@@ -106,7 +106,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
mHelper = 0;
mStolenContentView = 0;
mPanelButtons = 0;
- mResultCode = NSCancelButton;
+ mResultCode = NSModalResponseCancel;
mDialogIsExecuting = false;
mResultSet = false;
@@ -171,7 +171,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
- (void)onOkClicked
{
[mFontPanel close];
- [self finishOffWithCode:NSOKButton];
+ [self finishOffWithCode:NSModalResponseOK];
}
- (void)onCancelClicked
@@ -179,7 +179,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
if (mPanelButtons) {
[mFontPanel close];
mQtFont = QFont();
- [self finishOffWithCode:NSCancelButton];
+ [self finishOffWithCode:NSModalResponseCancel];
}
}
@@ -224,12 +224,12 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
[NSApp runModalForWindow:mFontPanel];
mDialogIsExecuting = false;
- return (mResultCode == NSOKButton);
+ return (mResultCode == NSModalResponseOK);
}
- (QPlatformDialogHelper::DialogCode)dialogResultCode
{
- return (mResultCode == NSOKButton) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
+ return (mResultCode == NSModalResponseOK) ? QPlatformDialogHelper::Accepted : QPlatformDialogHelper::Rejected;
}
- (BOOL)windowShouldClose:(id)window
@@ -238,7 +238,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
if (!mPanelButtons)
[self updateQtFont];
if (mDialogIsExecuting) {
- [self finishOffWithCode:NSCancelButton];
+ [self finishOffWithCode:NSModalResponseCancel];
} else {
mResultSet = true;
if (mHelper)
@@ -264,7 +264,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate);
// This check will prevent any such recursion.
if (!mResultSet) {
mResultSet = true;
- if (mResultCode == NSCancelButton) {
+ if (mResultCode == NSModalResponseCancel) {
emit mHelper->reject();
} else {
emit mHelper->accept();
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index a7cc19b3bf..9e688f4d1b 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -255,7 +255,8 @@ void QCocoaGLContext::setActiveWindow(QWindow *window)
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
cocoaWindow->setCurrentContext(this);
- [(QNSView *) cocoaWindow->view() setQCocoaGLContext:this];
+ Q_ASSERT(!cocoaWindow->isForeignWindow());
+ [qnsview_cast(cocoaWindow->view()) setQCocoaGLContext:this];
}
void QCocoaGLContext::updateSurfaceFormat()
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 3ab6b641fa..232e40769b 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -151,7 +151,8 @@ Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions)
a no-op.
For extra verbosity and clearer code, please consider checking
- that window()->type() != Qt::ForeignWindow before using this cast.
+ that the platform window is not a foreign window before using
+ this cast, via QPlatformWindow::isForeignWindow().
Do not use this method soley to check for foreign windows, as
that will make the code harder to read for people not working
@@ -160,10 +161,8 @@ Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions)
*/
QNSView *qnsview_cast(NSView *view)
{
- if (![view isKindOfClass:[QNSView class]]) {
- qCWarning(lcQpaCocoaWindow) << "NSView is not QNSView, consider checking for Qt::ForeignWindow";
+ if (![view isKindOfClass:[QNSView class]])
return nil;
- }
return static_cast<QNSView *>(view);
}
@@ -235,13 +234,13 @@ QString qt_mac_applicationName()
return appName;
}
-int qt_mac_mainScreenHeight()
+int qt_mac_primaryScreenHeight()
{
QMacAutoReleasePool pool;
NSArray *screens = [NSScreen screens];
if ([screens count] > 0) {
- // The first screen in the screens array is documented
- // to have the (0,0) origin.
+ // The first screen in the screens array is documented to
+ // have the (0,0) origin and is designated the primary screen.
NSRect screenFrame = [[screens objectAtIndex: 0] frame];
return screenFrame.size.height;
}
@@ -250,12 +249,12 @@ int qt_mac_mainScreenHeight()
int qt_mac_flipYCoordinate(int y)
{
- return qt_mac_mainScreenHeight() - y;
+ return qt_mac_primaryScreenHeight() - y;
}
qreal qt_mac_flipYCoordinate(qreal y)
{
- return qt_mac_mainScreenHeight() - y;
+ return qt_mac_primaryScreenHeight() - y;
}
QPointF qt_mac_flipPoint(const NSPoint &p)
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index 32f6fe0af1..ecdd20c4dc 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -84,9 +84,18 @@ public:
// ----------------------------------------------------
// Additional methods
void setVirtualSiblings(const QList<QPlatformScreen *> &siblings) { m_siblings = siblings; }
- NSScreen *osScreen() const;
+ NSScreen *nativeScreen() const;
void updateGeometry();
+ QPointF mapToNative(const QPointF &pos) const { return flipCoordinate(pos); }
+ QRectF mapToNative(const QRectF &rect) const { return flipCoordinate(rect); }
+ QPointF mapFromNative(const QPointF &pos) const { return flipCoordinate(pos); }
+ QRectF mapFromNative(const QRectF &rect) const { return flipCoordinate(rect); }
+
+private:
+ QPointF flipCoordinate(const QPointF &pos) const;
+ QRectF flipCoordinate(const QRectF &rect) const;
+
public:
int m_screenIndex;
QRect m_geometry;
@@ -117,6 +126,7 @@ public:
bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE;
+ QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const Q_DECL_OVERRIDE;
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE;
#endif
@@ -144,7 +154,7 @@ public:
QList<int> possibleKeys(const QKeyEvent *event) const Q_DECL_OVERRIDE;
void updateScreens();
- QCocoaScreen *screenAtIndex(int index);
+ QCocoaScreen *screenForNSScreen(NSScreen *nsScreen);
void setToolbar(QWindow *window, NSToolbar *toolbar);
NSToolbar *toolbar(QWindow *window) const;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index fe4933ed6f..d48ec8c6f7 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -69,8 +69,11 @@ static void initResources()
QT_BEGIN_NAMESPACE
-QCocoaScreen::QCocoaScreen(int screenIndex) :
- QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0)
+class QCoreTextFontEngine;
+class QFontEngineFT;
+
+QCocoaScreen::QCocoaScreen(int screenIndex)
+ : QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0)
{
updateGeometry();
m_cursor = new QCocoaCursor;
@@ -81,41 +84,65 @@ QCocoaScreen::~QCocoaScreen()
delete m_cursor;
}
-NSScreen *QCocoaScreen::osScreen() const
+NSScreen *QCocoaScreen::nativeScreen() const
{
NSArray *screens = [NSScreen screens];
- return ((NSUInteger)m_screenIndex < [screens count]) ? [screens objectAtIndex:m_screenIndex] : nil;
+
+ // Stale reference, screen configuration has changed
+ if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count])
+ return nil;
+
+ return [screens objectAtIndex:m_screenIndex];
+}
+
+/*!
+ Flips the Y coordinate of the point between quadrant I and IV.
+
+ The native coordinate system on macOS uses quadrant I, with origin
+ in bottom left, and Qt uses quadrant IV, with origin in top left.
+
+ By flippig the Y coordinate, we can map the position between the
+ two coordinate systems.
+*/
+QPointF QCocoaScreen::flipCoordinate(const QPointF &pos) const
+{
+ return QPointF(pos.x(), m_geometry.height() - pos.y());
+}
+
+/*!
+ Flips the Y coordinate of the rectangle between quadrant I and IV.
+
+ The native coordinate system on macOS uses quadrant I, with origin
+ in bottom left, and Qt uses quadrant IV, with origin in top left.
+
+ By flippig the Y coordinate, we can map the rectangle between the
+ two coordinate systems.
+*/
+QRectF QCocoaScreen::flipCoordinate(const QRectF &rect) const
+{
+ return QRectF(flipCoordinate(rect.topLeft() + QPoint(0, rect.height())), rect.size());
}
void QCocoaScreen::updateGeometry()
{
- NSScreen *nsScreen = osScreen();
+ NSScreen *nsScreen = nativeScreen();
if (!nsScreen)
return;
- NSRect frameRect = [nsScreen frame];
+ // At this point the geometry is in native coordinates, but the size
+ // is correct, which we take advantage of next when we map the native
+ // coordinates to the Qt coordinate system.
+ m_geometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.frame)).toRect();
+ m_availableGeometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.visibleFrame)).toRect();
- if (m_screenIndex == 0) {
- m_geometry = QRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height);
- // This is the primary screen, the one that contains the menubar. Its origin should be
- // (0, 0), and it's the only one whose available geometry differs from its full geometry.
- NSRect visibleRect = [nsScreen visibleFrame];
- m_availableGeometry = QRect(visibleRect.origin.x,
- frameRect.size.height - (visibleRect.origin.y + visibleRect.size.height), // invert y
- visibleRect.size.width, visibleRect.size.height);
- } else {
- // NSScreen origin is at the bottom-left corner, QScreen is at the top-left corner.
- // When we get the NSScreen frame rect, we need to re-align its origin y coordinate
- // w.r.t. the primary screen, whose origin is (0, 0).
- NSRect r = [[[NSScreen screens] objectAtIndex:0] frame];
- QRect referenceScreenGeometry = QRect(r.origin.x, r.origin.y, r.size.width, r.size.height);
- m_geometry = QRect(frameRect.origin.x,
- referenceScreenGeometry.height() - (frameRect.origin.y + frameRect.size.height),
- frameRect.size.width, frameRect.size.height);
-
- // Not primary screen. See above.
- m_availableGeometry = m_geometry;
- }
+ // The reference screen for the geometry is always the primary screen, but since
+ // we may be in the process of creating and registering the primary screen, we
+ // must special-case that and assign it direcly.
+ QCocoaScreen *primaryScreen = (nsScreen == [[NSScreen screens] firstObject]) ?
+ this : static_cast<QCocoaScreen*>(QGuiApplication::primaryScreen()->handle());
+
+ m_geometry = primaryScreen->mapFromNative(m_geometry).toRect();
+ m_availableGeometry = primaryScreen->mapFromNative(m_availableGeometry).toRect();
m_format = QImage::Format_RGB32;
m_depth = NSBitsPerPixelFromDepth([nsScreen depth]);
@@ -147,8 +174,8 @@ void QCocoaScreen::updateGeometry()
qreal QCocoaScreen::devicePixelRatio() const
{
QMacAutoReleasePool pool;
- NSScreen * screen = osScreen();
- return qreal(screen ? [screen backingScaleFactor] : 1.0);
+ NSScreen *nsScreen = nativeScreen();
+ return qreal(nsScreen ? [nsScreen backingScaleFactor] : 1.0);
}
QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const
@@ -278,7 +305,7 @@ QCocoaIntegration *QCocoaIntegration::mInstance = 0;
QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
: mOptions(parseOptions(paramList))
- , mFontDb(new QCoreTextFontDatabase(mOptions.testFlag(UseFreeTypeFontEngine)))
+ , mFontDb(0)
#ifndef QT_NO_ACCESSIBILITY
, mAccessibility(new QCocoaAccessibility)
#endif
@@ -294,6 +321,13 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
qWarning("Creating multiple Cocoa platform integrations is not supported");
mInstance = this;
+#ifndef QT_NO_FREETYPE
+ if (mOptions.testFlag(UseFreeTypeFontEngine))
+ mFontDb.reset(new QCoreTextFontDatabaseEngineFactory<QFontEngineFT>);
+ else
+#endif
+ mFontDb.reset(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>);
+
QString icStr = QPlatformInputContextFactory::requested();
icStr.isNull() ? mInputContext.reset(new QCocoaInputContext)
: mInputContext.reset(QPlatformInputContextFactory::create(icStr));
@@ -427,7 +461,7 @@ void QCocoaIntegration::updateScreens()
// NSScreen documentation says do not cache the array returned from [NSScreen screens].
// However in practice, we can identify a screen by its pointer: if resolution changes,
// the NSScreen object will be the same instance, just with different values.
- if (existingScr->osScreen() == scr) {
+ if (existingScr->nativeScreen() == scr) {
screen = existingScr;
break;
}
@@ -451,20 +485,27 @@ void QCocoaIntegration::updateScreens()
// Now the leftovers in remainingScreens are no longer current, so we can delete them.
foreach (QCocoaScreen* screen, remainingScreens) {
mScreens.removeOne(screen);
+ // Prevent stale references to NSScreen during destroy
+ screen->m_screenIndex = -1;
destroyScreen(screen);
}
}
-QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
+QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen)
{
- if (index >= mScreens.count())
+ NSUInteger index = [[NSScreen screens] indexOfObject:nsScreen];
+ if (index == NSNotFound)
+ return 0;
+
+ if (index >= unsigned(mScreens.count()))
updateScreens();
- // It is possible that the screen got removed while updateScreens was called
- // so we do a sanity check to be certain
- if (index >= mScreens.count())
- return 0;
- return mScreens.at(index);
+ for (QCocoaScreen *screen : mScreens) {
+ if (screen->nativeScreen() == nsScreen)
+ return screen;
+ }
+
+ return 0;
}
bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -493,6 +534,11 @@ QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWindow *window) const
return new QCocoaWindow(window);
}
+QPlatformWindow *QCocoaIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
+{
+ return new QCocoaWindow(window, nativeHandle);
+}
+
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index e177a24e73..8e47974d12 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -581,8 +581,8 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
// The calls above block, and also swallow any mouse release event,
// so we need to clear any mouse button that triggered the menu popup.
- if ([view isKindOfClass:[QNSView class]])
- [(QNSView *)view resetMouseButtons];
+ if (!cocoaWindow->isForeignWindow())
+ [qnsview_cast(view) resetMouseButtons];
}
void QCocoaMenu::dismiss()
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
index 972230349b..26ab07ffaf 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
@@ -172,11 +172,12 @@ void *QCocoaNativeInterface::NSPrintInfoForPrintEngine(QPrintEngine *printEngine
QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard()
{
- QCFType<CFURLRef> url;
const int ExpectedImageWidth = 242;
const int ExpectedImageHeight = 414;
- if (LSFindApplicationForInfo(kLSUnknownCreator, CFSTR("com.apple.KeyboardSetupAssistant"),
- 0, 0, &url) == noErr) {
+ QCFType<CFArrayRef> urls = LSCopyApplicationURLsForBundleIdentifier(
+ CFSTR("com.apple.KeyboardSetupAssistant"), nullptr);
+ if (urls && CFArrayGetCount(urls) > 0) {
+ CFURLRef url = (CFURLRef)CFArrayGetValueAtIndex(urls, 0);
QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, url);
if (bundle) {
url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("png"), 0);
diff --git a/src/plugins/platforms/cocoa/qcocoaresources.qrc b/src/plugins/platforms/cocoa/qcocoaresources.qrc
index 4255bfba9d..1c4b941b9b 100644
--- a/src/plugins/platforms/cocoa/qcocoaresources.qrc
+++ b/src/plugins/platforms/cocoa/qcocoaresources.qrc
@@ -1,12 +1,7 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource prefix="/qt-project.org/mac/cursors">
-<file>images/copyarrowcursor.png</file>
-<file>images/forbiddencursor.png</file>
-<file>images/spincursor.png</file>
-<file>images/waitcursor.png</file>
-<file>images/sizeallcursor.png</file>
-</qresource>
-<qresource prefix="/qt-project.org/mac/style">
-<file>images/leopard-unified-toolbar-on.png</file>
-</qresource>
+<RCC>
+ <qresource prefix="/qt-project.org/mac/cursors">
+ <file>images/spincursor.png</file>
+ <file>images/waitcursor.png</file>
+ <file>images/sizeallcursor.png</file>
+ </qresource>
</RCC>
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h
index d47e620fbb..27c071a8cd 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.h
+++ b/src/plugins/platforms/cocoa/qcocoatheme.h
@@ -74,6 +74,7 @@ public:
QVariant themeHint(ThemeHint hint) const Q_DECL_OVERRIDE;
QString standardButtonText(int button) const Q_DECL_OVERRIDE;
+ QKeySequence standardButtonShortcut(int button) const Q_DECL_OVERRIDE;
static const char *name;
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index 4d74c11581..d2345f9abc 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -344,6 +344,12 @@ QString QCocoaTheme::standardButtonText(int button) const
return button == QPlatformDialogHelper::Discard ? msgDialogButtonDiscard() : QPlatformTheme::standardButtonText(button);
}
+QKeySequence QCocoaTheme::standardButtonShortcut(int button) const
+{
+ return button == QPlatformDialogHelper::Discard ? QKeySequence(Qt::CTRL | Qt::Key_Delete)
+ : QPlatformTheme::standardButtonShortcut(button);
+}
+
QPlatformMenuItem *QCocoaTheme::createPlatformMenuItem() const
{
return new QCocoaMenuItem();
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index 16639fd8b1..567eb7438b 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -96,6 +96,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindowHelper);
@property (nonatomic, readonly) QNSWindowHelper *helper;
- (id)initWithContentRect:(NSRect)contentRect
+ screen:(NSScreen*)screen
styleMask:(NSUInteger)windowStyle
qPlatformWindow:(QCocoaWindow *)qpw;
@@ -111,6 +112,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindow);
@property (nonatomic, readonly) QNSWindowHelper *helper;
- (id)initWithContentRect:(NSRect)contentRect
+ screen:(NSScreen*)screen
styleMask:(NSUInteger)windowStyle
qPlatformWindow:(QCocoaWindow *)qpw;
@@ -141,13 +143,20 @@ QT_BEGIN_NAMESPACE
// See the qt_on_cocoa manual tests for a working example, located
// in tests/manual/cocoa at the time of writing.
+#ifdef Q_MOC_RUN
+#define Q_NOTIFICATION_HANDLER(notification) Q_INVOKABLE Q_COCOA_NOTIFICATION_##notification
+#else
+#define Q_NOTIFICATION_HANDLER(notification)
+#define Q_NOTIFICATION_PREFIX QT_STRINGIFY2(Q_COCOA_NOTIFICATION_)
+#endif
+
class QCocoaMenuBar;
class QCocoaWindow : public QObject, public QPlatformWindow
{
Q_OBJECT
public:
- QCocoaWindow(QWindow *tlw);
+ QCocoaWindow(QWindow *tlw, WId nativeHandle = 0);
~QCocoaWindow();
void setGeometry(const QRect &rect) Q_DECL_OVERRIDE;
@@ -177,6 +186,8 @@ public:
QMargins frameMargins() const Q_DECL_OVERRIDE;
QSurfaceFormat format() const Q_DECL_OVERRIDE;
+ bool isForeignWindow() const Q_DECL_OVERRIDE;
+
void requestActivateWindow() Q_DECL_OVERRIDE;
WId winId() const Q_DECL_OVERRIDE;
@@ -187,15 +198,30 @@ public:
void setEmbeddedInForeignView(bool subwindow);
- void windowWillMove();
- void windowDidMove();
- void windowDidResize();
- void windowDidEndLiveResize();
+ Q_NOTIFICATION_HANDLER(NSWindowWillMoveNotification) void windowWillMove();
+ Q_NOTIFICATION_HANDLER(NSWindowDidMoveNotification) void windowDidMove();
+ Q_NOTIFICATION_HANDLER(NSWindowDidResizeNotification) void windowDidResize();
+ Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame();
+ Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame();
+ Q_NOTIFICATION_HANDLER(NSWindowDidEndLiveResizeNotification) void windowDidEndLiveResize();
+ Q_NOTIFICATION_HANDLER(NSWindowDidBecomeKeyNotification) void windowDidBecomeKey();
+ Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey();
+ Q_NOTIFICATION_HANDLER(NSWindowDidMiniaturizeNotification) void windowDidMiniaturize();
+ Q_NOTIFICATION_HANDLER(NSWindowDidDeminiaturizeNotification) void windowDidDeminiaturize();
+ Q_NOTIFICATION_HANDLER(NSWindowWillEnterFullScreenNotification) void windowWillEnterFullScreen();
+ Q_NOTIFICATION_HANDLER(NSWindowDidEnterFullScreenNotification) void windowDidEnterFullScreen();
+ Q_NOTIFICATION_HANDLER(NSWindowWillExitFullScreenNotification) void windowWillExitFullScreen();
+ Q_NOTIFICATION_HANDLER(NSWindowDidExitFullScreenNotification) void windowDidExitFullScreen();
+ Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen();
+ Q_NOTIFICATION_HANDLER(NSWindowDidOrderOnScreenAndFinishAnimatingNotification) void windowDidOrderOnScreen();
+ Q_NOTIFICATION_HANDLER(NSWindowDidChangeOcclusionStateNotification) void windowDidChangeOcclusionState();
+ Q_NOTIFICATION_HANDLER(NSWindowDidChangeScreenNotification) void windowDidChangeScreen();
+ Q_NOTIFICATION_HANDLER(NSWindowWillCloseNotification) void windowWillClose();
+
bool windowShouldClose();
- void windowWillClose();
bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
- void setSynchedWindowStateFromWindow();
+ void reportCurrentWindowState(bool unconditionally = false);
NSInteger windowLevel(Qt::WindowFlags flags);
NSUInteger windowStyleMask(Qt::WindowFlags flags);
@@ -239,19 +265,37 @@ public:
static QPoint bottomLeftClippedByNSWindowOffsetStatic(QWindow *window);
QPoint bottomLeftClippedByNSWindowOffset() const;
+
+ enum RecreationReason {
+ RecreationNotNeeded = 0,
+ ParentChanged = 0x1,
+ MissingWindow = 0x2,
+ WindowModalityChanged = 0x4,
+ ChildNSWindowChanged = 0x8,
+ ContentViewChanged = 0x10,
+ PanelChanged = 0x20,
+ };
+ Q_DECLARE_FLAGS(RecreationReasons, RecreationReason)
+ Q_FLAG(RecreationReasons)
+
protected:
- void recreateWindow(const QPlatformWindow *parentWindow);
- QCocoaNSWindow *createNSWindow();
- void setNSWindow(QCocoaNSWindow *window);
+ bool isChildNSWindow() const;
+ bool isContentView() const;
+
+ void foreachChildNSWindow(void (^block)(QCocoaWindow *));
- bool shouldUseNSPanel();
+ void recreateWindowIfNeeded();
+ QCocoaNSWindow *createNSWindow(bool shouldBeChildNSWindow, bool shouldBePanel);
QRect nativeWindowGeometry() const;
- QCocoaWindow *parentCocoaWindow() const;
- void syncWindowState(Qt::WindowState newState);
void reinsertChildWindow(QCocoaWindow *child);
void removeChildWindow(QCocoaWindow *child);
- bool isNativeWindowTypeInconsistent();
+
+ Qt::WindowState windowState() const;
+ void applyWindowState(Qt::WindowState newState);
+ void toggleMaximized();
+ void toggleFullScreen();
+ bool isTransitioningToFullScreen() const;
// private:
public: // for QNSView
@@ -268,13 +312,8 @@ public: // for QNSView
bool m_viewIsEmbedded; // true if the m_view is actually embedded in a "foreign" NSView hiearchy
bool m_viewIsToBeEmbedded; // true if the m_view is intended to be embedded in a "foreign" NSView hiearchy
- QCocoaWindow *m_parentCocoaWindow;
- bool m_isNSWindowChild; // this window is a non-top level QWindow with a NSWindow.
- QList<QCocoaWindow *> m_childWindows;
-
Qt::WindowFlags m_windowFlags;
- bool m_effectivelyMaximized;
- Qt::WindowState m_synchedWindowState;
+ Qt::WindowState m_lastReportedWindowState;
Qt::WindowModality m_windowModality;
QPointer<QWindow> m_enterLeaveTargetWindow;
bool m_windowUnderMouse;
@@ -308,11 +347,6 @@ public: // for QNSView
int m_topContentBorderThickness;
int m_bottomContentBorderThickness;
- // used by showFullScreen in fake mode
- QRect m_normalGeometry;
- Qt::WindowFlags m_oldWindowFlags;
- NSApplicationPresentationOptions m_presentationOptions;
-
struct BorderRange {
BorderRange(quintptr i, int u, int l) : identifier(i), upper(u), lower(l) { }
quintptr identifier;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 40666772c5..e9bcaa8f41 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -58,6 +58,8 @@
#include <QDebug>
+#include <vector>
+
enum {
defaultWindowWidth = 160,
defaultWindowHeight = 160
@@ -87,6 +89,36 @@ static void qt_closePopups()
}
}
+@interface NSWindow (FullScreenProperty)
+@property(readonly) BOOL qt_fullScreen;
+@end
+
+@implementation NSWindow (FullScreenProperty)
+
++ (void)load
+{
+ NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+ [center addObserverForName:NSWindowDidEnterFullScreenNotification object:nil queue:nil
+ usingBlock:^(NSNotification *notification) {
+ objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
+ [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN);
+ }
+ ];
+ [center addObserverForName:NSWindowDidExitFullScreenNotification object:nil queue:nil
+ usingBlock:^(NSNotification *notification) {
+ objc_setAssociatedObject(notification.object, @selector(qt_fullScreen),
+ nil, OBJC_ASSOCIATION_RETAIN);
+ }
+ ];
+}
+
+- (BOOL)qt_fullScreen
+{
+ NSNumber *number = objc_getAssociatedObject(self, @selector(qt_fullScreen));
+ return [number boolValue];
+}
+@end
+
@implementation QNSWindowHelper
@synthesize window = _window;
@@ -130,8 +162,7 @@ static void qt_closePopups()
[forwardView mouseDragged:theEvent];
}
}
-
- if (!pw->m_isNSWindowChild && theEvent.type == NSLeftMouseDown) {
+ if (pw->window()->isTopLevel() && theEvent.type == NSLeftMouseDown) {
pw->m_forwardWindow.clear();
}
}
@@ -202,13 +233,14 @@ static void qt_closePopups()
@synthesize helper = _helper;
- (id)initWithContentRect:(NSRect)contentRect
+ screen:(NSScreen*)screen
styleMask:(NSUInteger)windowStyle
qPlatformWindow:(QCocoaWindow *)qpw
{
self = [super initWithContentRect:contentRect
styleMask:windowStyle
backing:NSBackingStoreBuffered
- defer:NO]; // Deferring window creation breaks OpenGL (the GL context is
+ defer:NO screen:screen]; // Deferring window creation breaks OpenGL (the GL context is
// set up before the window is shown and needs a proper window)
if (self) {
@@ -222,7 +254,7 @@ static void qt_closePopups()
// Prevent child NSWindows from becoming the key window in
// order keep the active apperance of the top-level window.
QCocoaWindow *pw = self.helper.platformWindow;
- if (!pw || pw->m_isNSWindowChild)
+ if (!pw || !pw->window()->isTopLevel())
return NO;
if (pw->shouldRefuseKeyWindowAndFirstResponder())
@@ -241,7 +273,7 @@ static void qt_closePopups()
// Windows with a transient parent (such as combobox popup windows)
// cannot become the main window:
QCocoaWindow *pw = self.helper.platformWindow;
- if (!pw || pw->m_isNSWindowChild || pw->window()->transientParent())
+ if (!pw || !pw->window()->isTopLevel() || pw->window()->transientParent())
canBecomeMain = NO;
return canBecomeMain;
@@ -284,13 +316,14 @@ static void qt_closePopups()
@synthesize helper = _helper;
- (id)initWithContentRect:(NSRect)contentRect
+ screen:(NSScreen*)screen
styleMask:(NSUInteger)windowStyle
qPlatformWindow:(QCocoaWindow *)qpw
{
self = [super initWithContentRect:contentRect
styleMask:windowStyle
backing:NSBackingStoreBuffered
- defer:NO]; // Deferring window creation breaks OpenGL (the GL context is
+ defer:NO screen:screen]; // Deferring window creation breaks OpenGL (the GL context is
// set up before the window is shown and needs a proper window)
if (self) {
@@ -343,18 +376,72 @@ static void qt_closePopups()
@end
+static void qRegisterNotificationCallbacks()
+{
+ static const QLatin1String notificationHandlerPrefix(Q_NOTIFICATION_PREFIX);
+
+ NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+
+ const QMetaObject *metaObject = QMetaType::metaObjectForType(qRegisterMetaType<QCocoaWindow*>());
+ Q_ASSERT(metaObject);
+
+ for (int i = 0; i < metaObject->methodCount(); ++i) {
+ QMetaMethod method = metaObject->method(i);
+ const QString methodTag = QString::fromLatin1(method.tag());
+ if (!methodTag.startsWith(notificationHandlerPrefix))
+ continue;
+
+ const QString notificationName = methodTag.mid(notificationHandlerPrefix.size());
+ [center addObserverForName:notificationName.toNSString() object:nil queue:nil
+ usingBlock:^(NSNotification *notification) {
+
+ NSView *view = nullptr;
+ if ([notification.object isKindOfClass:[NSWindow class]]) {
+ NSWindow *window = notification.object;
+ // Only top level NSWindows should notify their QNSViews
+ if (window.parentWindow)
+ return;
+
+ if (!window.contentView)
+ return;
+
+ view = window.contentView;
+ } else if ([notification.object isKindOfClass:[NSView class]]) {
+ view = notification.object;
+ } else {
+ qCWarning(lcQpaCocoaWindow) << "Unhandled notifcation"
+ << notification.name << "for" << notification.object;
+ return;
+ }
+ Q_ASSERT(view);
+
+ QCocoaWindow *cocoaWindow = nullptr;
+ if (QNSView *qnsView = qnsview_cast(view))
+ cocoaWindow = qnsView.platformWindow;
+
+ // FIXME: Could be a foreign window, look up by iterating top level QWindows
+
+ if (!cocoaWindow)
+ return;
+
+ if (!method.invoke(cocoaWindow, Qt::DirectConnection)) {
+ qCWarning(lcQpaCocoaWindow) << "Failed to invoke NSNotification callback for"
+ << notification.name << "on" << cocoaWindow;
+ }
+ }];
+ }
+}
+Q_CONSTRUCTOR_FUNCTION(qRegisterNotificationCallbacks)
+
const int QCocoaWindow::NoAlertRequest = -1;
-QCocoaWindow::QCocoaWindow(QWindow *tlw)
+QCocoaWindow::QCocoaWindow(QWindow *tlw, WId nativeHandle)
: QPlatformWindow(tlw)
, m_view(nil)
, m_nsWindow(0)
, m_viewIsEmbedded(false)
, m_viewIsToBeEmbedded(false)
- , m_parentCocoaWindow(0)
- , m_isNSWindowChild(false)
- , m_effectivelyMaximized(false)
- , m_synchedWindowState(Qt::WindowActive)
+ , m_lastReportedWindowState(Qt::WindowNoState)
, m_windowModality(Qt::NonModal)
, m_windowUnderMouse(false)
, m_inConstructor(true)
@@ -379,15 +466,15 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_drawContentBorderGradient(false)
, m_topContentBorderThickness(0)
, m_bottomContentBorderThickness(0)
- , m_normalGeometry(QRect(0,0,-1,-1))
, m_hasWindowFilePath(false)
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window();
QMacAutoReleasePool pool;
- if (tlw->type() == Qt::ForeignWindow) {
- m_view = (NSView *)WId(tlw->property("_q_foreignWinId").value<WId>());
+ if (nativeHandle) {
+ m_view = reinterpret_cast<NSView *>(nativeHandle);
+ [m_view retain];
} else {
m_view = [[QNSView alloc] initWithCocoaWindow:this];
// Enable high-dpi OpenGL for retina displays. Enabling has the side
@@ -405,7 +492,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
[m_view setWantsLayer:enable];
}
setGeometry(tlw->geometry());
- recreateWindow(QPlatformWindow::parent());
+ recreateWindowIfNeeded();
tlw->setGeometry(geometry());
if (tlw->isTopLevel())
setWindowIcon(tlw->icon());
@@ -420,18 +507,16 @@ QCocoaWindow::~QCocoaWindow()
[m_nsWindow makeFirstResponder:nil];
[m_nsWindow setContentView:nil];
[m_nsWindow.helper detachFromPlatformWindow];
- if (m_isNSWindowChild) {
- if (m_parentCocoaWindow)
- m_parentCocoaWindow->removeChildWindow(this);
- } else if ([m_view superview]) {
+ if (m_view.window.parentWindow)
+ [m_view.window.parentWindow removeChildWindow:m_view.window];
+ else if ([m_view superview])
[m_view removeFromSuperview];
- }
removeMonitor();
// Make sure to disconnect observer in all case if view is valid
// to avoid notifications received when deleting when using Qt::AA_NativeWindows attribute
- if (window()->type() != Qt::ForeignWindow)
+ if (!isForeignWindow())
[[NSNotificationCenter defaultCenter] removeObserver:m_view];
// While it is unlikely that this window will be in the popup stack
@@ -440,10 +525,9 @@ QCocoaWindow::~QCocoaWindow()
QCocoaIntegration::instance()->popupWindowStack()->removeAll(this);
}
- foreach (QCocoaWindow *child, m_childWindows) {
- [m_nsWindow removeChildWindow:child->m_nsWindow];
- child->m_parentCocoaWindow = 0;
- }
+ foreachChildNSWindow(^(QCocoaWindow *childWindow) {
+ [m_nsWindow removeChildWindow:childWindow->m_nsWindow];
+ });
[m_view release];
[m_nsWindow release];
@@ -481,6 +565,11 @@ void QCocoaWindow::setGeometry(const QRect &rectIn)
setCocoaGeometry(rect);
}
+bool QCocoaWindow::isForeignWindow() const
+{
+ return ![m_view isKindOfClass:[QNSView class]];
+}
+
QRect QCocoaWindow::geometry() const
{
// QWindows that are embedded in a NSView hiearchy may be considered
@@ -491,7 +580,7 @@ QRect QCocoaWindow::geometry() const
NSRect screenRect = [[m_view window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)];
NSPoint screenPoint = screenRect.origin;
QPoint position = qt_mac_flipPoint(screenPoint).toPoint();
- QSize size = QRectF::fromCGRect([m_view bounds]).toRect().size();
+ QSize size = QRectF::fromCGRect(NSRectToCGRect([m_view bounds])).toRect().size();
return QRect(position, size);
}
@@ -504,7 +593,7 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
QMacAutoReleasePool pool;
if (m_viewIsEmbedded) {
- if (window()->type() != Qt::ForeignWindow) {
+ if (!isForeignWindow()) {
[m_view setFrame:NSMakeRect(0, 0, rect.width(), rect.height())];
} else {
QPlatformWindow::setGeometry(rect);
@@ -512,9 +601,9 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
return;
}
- if (m_isNSWindowChild) {
+ if (isChildNSWindow()) {
QPlatformWindow::setGeometry(rect);
- NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow;
+ NSWindow *parentNSWindow = m_view.window.parentWindow;
NSRect parentWindowFrame = [parentNSWindow contentRectForFrameRect:parentNSWindow.frame];
clipWindow(parentWindowFrame);
@@ -528,7 +617,7 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
[m_view setFrame:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
}
- if (window()->type() == Qt::ForeignWindow)
+ if (isForeignWindow())
QPlatformWindow::setGeometry(rect);
// will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm)
@@ -536,14 +625,14 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
void QCocoaWindow::clipChildWindows()
{
- foreach (QCocoaWindow *childWindow, m_childWindows) {
+ foreachChildNSWindow(^(QCocoaWindow *childWindow) {
childWindow->clipWindow(m_nsWindow.frame);
- }
+ });
}
void QCocoaWindow::clipWindow(const NSRect &clipRect)
{
- if (!m_isNSWindowChild)
+ if (!isChildNSWindow())
return;
NSRect clippedWindowRect = NSZeroRect;
@@ -568,15 +657,15 @@ void QCocoaWindow::clipWindow(const NSRect &clipRect)
m_hiddenByClipping = false;
if (!m_hiddenByAncestor) {
[m_nsWindow orderFront:nil];
- m_parentCocoaWindow->reinsertChildWindow(this);
+ static_cast<QCocoaWindow *>(QPlatformWindow::parent())->reinsertChildWindow(this);
}
}
}
// recurse
- foreach (QCocoaWindow *childWindow, m_childWindows) {
+ foreachChildNSWindow(^(QCocoaWindow *childWindow) {
childWindow->clipWindow(clippedWindowRect);
- }
+ });
}
void QCocoaWindow::hide(bool becauseOfAncestor)
@@ -593,8 +682,9 @@ void QCocoaWindow::hide(bool becauseOfAncestor)
if (!visible) // Could have been clipped before
return;
- foreach (QCocoaWindow *childWindow, m_childWindows)
+ foreachChildNSWindow(^(QCocoaWindow *childWindow) {
childWindow->hide(true);
+ });
[m_nsWindow orderOut:nil];
}
@@ -604,20 +694,21 @@ void QCocoaWindow::show(bool becauseOfAncestor)
if ([m_nsWindow isVisible])
return;
- if (m_parentCocoaWindow && ![m_parentCocoaWindow->m_nsWindow isVisible]) {
+ if (m_view.window.parentWindow && !m_view.window.parentWindow.visible) {
m_hiddenByAncestor = true; // Parent still hidden, don't show now
} else if ((becauseOfAncestor == m_hiddenByAncestor) // Was NEITHER explicitly hidden
&& !m_hiddenByClipping) { // ... NOR clipped
- if (m_isNSWindowChild) {
+ if (isChildNSWindow()) {
m_hiddenByAncestor = false;
setCocoaGeometry(windowGeometry());
}
if (!m_hiddenByClipping) { // setCocoaGeometry() can change the clipping status
[m_nsWindow orderFront:nil];
- if (m_isNSWindowChild)
- m_parentCocoaWindow->reinsertChildWindow(this);
- foreach (QCocoaWindow *childWindow, m_childWindows)
+ if (isChildNSWindow())
+ static_cast<QCocoaWindow *>(QPlatformWindow::parent())->reinsertChildWindow(this);
+ foreachChildNSWindow(^(QCocoaWindow *childWindow) {
childWindow->show(true);
+ });
}
}
}
@@ -626,7 +717,7 @@ void QCocoaWindow::setVisible(bool visible)
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setVisible" << window() << visible;
- if (m_isNSWindowChild && m_hiddenByClipping)
+ if (isChildNSWindow() && m_hiddenByClipping)
return;
m_inSetVisible = true;
@@ -638,8 +729,7 @@ void QCocoaWindow::setVisible(bool visible)
if (visible) {
// We need to recreate if the modality has changed as the style mask will need updating
- if (m_windowModality != window()->modality() || isNativeWindowTypeInconsistent())
- recreateWindow(QPlatformWindow::parent());
+ recreateWindowIfNeeded();
// Register popup windows. The Cocoa platform plugin will forward mouse events
// to them and close them when needed.
@@ -674,14 +764,14 @@ void QCocoaWindow::setVisible(bool visible)
// setWindowState might have been called while the window was hidden and
// will not change the NSWindow state in that case. Sync up here:
- syncWindowState(window()->windowState());
+ applyWindowState(window()->windowState());
if (window()->windowState() != Qt::WindowMinimized) {
if ((window()->modality() == Qt::WindowModal
|| window()->type() == Qt::Sheet)
&& parentCocoaWindow) {
// show the window as a sheet
- [NSApp beginSheet:m_nsWindow modalForWindow:parentCocoaWindow->m_nsWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
+ [parentCocoaWindow->m_nsWindow beginSheet:m_nsWindow completionHandler:nil];
} else if (window()->modality() != Qt::NonModal) {
// show the window as application modal
QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
@@ -700,8 +790,9 @@ void QCocoaWindow::setVisible(bool visible)
else
[m_nsWindow orderFront:nil];
- foreach (QCocoaWindow *childWindow, m_childWindows)
+ foreachChildNSWindow(^(QCocoaWindow *childWindow) {
childWindow->show(true);
+ });
} else {
show();
}
@@ -742,8 +833,10 @@ void QCocoaWindow::setVisible(bool visible)
cocoaEventDispatcherPrivate->endModalSession(window());
m_hasModalSession = false;
} else {
- if ([m_nsWindow isSheet])
- [NSApp endSheet:m_nsWindow];
+ if ([m_nsWindow isSheet]) {
+ Q_ASSERT_X(parentCocoaWindow, "QCocoaWindow", "Window modal dialog has no transient parent.");
+ [parentCocoaWindow->m_nsWindow endSheet:m_nsWindow];
+ }
}
hide();
@@ -856,6 +949,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
if (m_drawContentBorderGradient)
styleMask |= NSTexturedBackgroundWindowMask;
+ // Don't wipe fullscreen state
+ if (m_nsWindow.styleMask & NSFullScreenWindowMask)
+ styleMask |= NSFullScreenWindowMask;
+
return styleMask;
}
@@ -873,13 +970,14 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags)
// in line with the platform style guidelines.
bool fixedSizeNoZoom = (windowMinimumSize().isValid() && windowMaximumSize().isValid()
&& windowMinimumSize() == windowMaximumSize());
- bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint) && !(flags & Qt::WindowMaximizeButtonHint));
+ bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint)
+ && !(flags & (Qt::WindowMaximizeButtonHint | Qt::WindowFullscreenButtonHint)));
[[m_nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:!(fixedSizeNoZoom || customizeNoZoom)];
}
void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
{
- if (m_nsWindow && !m_isNSWindowChild) {
+ if (m_nsWindow && !isChildNSWindow()) {
NSUInteger styleMask = windowStyleMask(flags);
NSInteger level = this->windowLevel(flags);
// While setting style mask we can have -updateGeometry calls on a content
@@ -908,13 +1006,16 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
setWindowZoomButton(flags);
}
+ if (m_nsWindow)
+ m_nsWindow.ignoresMouseEvents = flags & Qt::WindowTransparentForInput;
+
m_windowFlags = flags;
}
void QCocoaWindow::setWindowState(Qt::WindowState state)
{
if (window()->isVisible())
- syncWindowState(state); // Window state set for hidden windows take effect when show() is called.
+ applyWindowState(state); // Window state set for hidden windows take effect when show() is called
}
void QCocoaWindow::setWindowTitle(const QString &title)
@@ -983,19 +1084,16 @@ void QCocoaWindow::raise()
// ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm)
if (!m_nsWindow)
return;
- if (m_isNSWindowChild) {
- QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows;
- siblings.removeOne(this);
- siblings.append(this);
+ if (isChildNSWindow()) {
if (m_hiddenByClipping)
return;
}
if ([m_nsWindow isVisible]) {
- if (m_isNSWindowChild) {
+ if (isChildNSWindow()) {
// -[NSWindow orderFront:] doesn't work with attached windows.
// The only solution is to remove and add the child window.
// This will place it on top of all the other NSWindows.
- NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow;
+ NSWindow *parentNSWindow = m_view.window.parentWindow;
[parentNSWindow removeChildWindow:m_nsWindow];
[parentNSWindow addChildWindow:m_nsWindow ordered:NSWindowAbove];
} else {
@@ -1021,20 +1119,17 @@ void QCocoaWindow::lower()
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::lower" << window();
if (!m_nsWindow)
return;
- if (m_isNSWindowChild) {
- QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows;
- siblings.removeOne(this);
- siblings.prepend(this);
+ if (isChildNSWindow()) {
if (m_hiddenByClipping)
return;
}
if ([m_nsWindow isVisible]) {
- if (m_isNSWindowChild) {
+ if (isChildNSWindow()) {
// -[NSWindow orderBack:] doesn't work with attached windows.
// The only solution is to remove and add all the child windows except this one.
// This will keep the current window at the bottom while adding the others on top of it,
// hopefully in the same order (this is not documented anywhere in the Cocoa documentation).
- NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow;
+ NSWindow *parentNSWindow = m_view.window.parentWindow;
NSArray *children = [parentNSWindow.childWindows copy];
for (NSWindow *child in children)
if (m_nsWindow != child) {
@@ -1095,7 +1190,7 @@ void QCocoaWindow::propagateSizeHints()
QSize sizeIncrement = windowSizeIncrement();
if (sizeIncrement.isEmpty())
sizeIncrement = QSize(1, 1);
- [m_nsWindow setResizeIncrements:sizeIncrement.toCGSize()];
+ [m_nsWindow setResizeIncrements:NSSizeFromCGSize(sizeIncrement.toCGSize())];
QRect rect = geometry();
QSize baseSize = windowBaseSize();
@@ -1158,7 +1253,7 @@ void QCocoaWindow::setParent(const QPlatformWindow *parentWindow)
// recreate the window for compatibility
bool unhideAfterRecreate = parentWindow && !m_viewIsToBeEmbedded && ![m_view isHidden];
- recreateWindow(parentWindow);
+ recreateWindowIfNeeded();
if (unhideAfterRecreate)
[m_view setHidden:NO];
setCocoaGeometry(geometry());
@@ -1182,6 +1277,8 @@ void QCocoaWindow::setEmbeddedInForeignView(bool embedded)
m_nsWindow = 0;
}
+// ----------------------- NSWindow notifications -----------------------
+
void QCocoaWindow::windowWillMove()
{
// Close any open popups on window move
@@ -1190,10 +1287,13 @@ void QCocoaWindow::windowWillMove()
void QCocoaWindow::windowDidMove()
{
- if (m_isNSWindowChild)
+ if (isChildNSWindow())
return;
[qnsview_cast(m_view) updateGeometry];
+
+ // Moving a window might bring it out of maximized state
+ reportCurrentWindowState();
}
void QCocoaWindow::windowDidResize()
@@ -1201,21 +1301,172 @@ void QCocoaWindow::windowDidResize()
if (!m_nsWindow)
return;
- if (m_isNSWindowChild)
+ if (isChildNSWindow())
return;
clipChildWindows();
[qnsview_cast(m_view) updateGeometry];
+
+ if (!m_view.inLiveResize)
+ reportCurrentWindowState();
+}
+
+void QCocoaWindow::viewDidChangeFrame()
+{
+ [qnsview_cast(m_view) updateGeometry];
+}
+
+/*!
+ Callback for NSViewGlobalFrameDidChangeNotification.
+
+ Posted whenever an NSView object that has attached surfaces (that is,
+ NSOpenGLContext objects) moves to a different screen, or other cases
+ where the NSOpenGLContext object needs to be updated.
+*/
+void QCocoaWindow::viewDidChangeGlobalFrame()
+{
+ updateExposedGeometry();
}
void QCocoaWindow::windowDidEndLiveResize()
{
- if (m_synchedWindowState == Qt::WindowMaximized && ![m_nsWindow isZoomed]) {
- m_effectivelyMaximized = false;
- [qnsview_cast(m_view) notifyWindowStateChanged:Qt::WindowNoState];
+ reportCurrentWindowState();
+}
+
+void QCocoaWindow::windowDidBecomeKey()
+{
+ if (isForeignWindow())
+ return;
+
+ if (m_windowUnderMouse) {
+ QPointF windowPoint;
+ QPointF screenPoint;
+ [qnsview_cast(m_view) convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
+ QWindowSystemInterface::handleEnterEvent(m_enterLeaveTargetWindow, windowPoint, screenPoint);
+ }
+
+ if (!windowIsPopupType() && !qnsview_cast(m_view).isMenuView)
+ QWindowSystemInterface::handleWindowActivated(window());
+}
+
+void QCocoaWindow::windowDidResignKey()
+{
+ if (isForeignWindow())
+ return;
+
+ // Key window will be non-nil if another window became key, so do not
+ // set the active window to zero here -- the new key window's
+ // NSWindowDidBecomeKeyNotification hander will change the active window.
+ NSWindow *keyWindow = [NSApp keyWindow];
+ if (!keyWindow || keyWindow == m_view.window) {
+ // No new key window, go ahead and set the active window to zero
+ if (!windowIsPopupType() && !qnsview_cast(m_view).isMenuView)
+ QWindowSystemInterface::handleWindowActivated(0);
+ }
+}
+
+void QCocoaWindow::windowDidMiniaturize()
+{
+ reportCurrentWindowState();
+}
+
+void QCocoaWindow::windowDidDeminiaturize()
+{
+ reportCurrentWindowState();
+}
+
+void QCocoaWindow::windowWillEnterFullScreen()
+{
+ // The NSWindow needs to be resizable, otherwise we'll end up with
+ // the normal window geometry, centered in the middle of the screen
+ // on a black background. The styleMask will be reset below.
+ m_nsWindow.styleMask |= NSResizableWindowMask;
+}
+
+void QCocoaWindow::windowDidEnterFullScreen()
+{
+ Q_ASSERT_X(m_nsWindow.qt_fullScreen, "QCocoaWindow",
+ "FullScreen category processes window notifications first");
+
+ // Reset to original styleMask
+ setWindowFlags(m_windowFlags);
+
+ reportCurrentWindowState();
+}
+
+void QCocoaWindow::windowWillExitFullScreen()
+{
+ // The NSWindow needs to be resizable, otherwise we'll end up with
+ // a weird zoom animation. The styleMask will be reset below.
+ m_nsWindow.styleMask |= NSResizableWindowMask;
+}
+
+void QCocoaWindow::windowDidExitFullScreen()
+{
+ Q_ASSERT_X(!m_nsWindow.qt_fullScreen, "QCocoaWindow",
+ "FullScreen category processes window notifications first");
+
+ // Reset to original styleMask
+ setWindowFlags(m_windowFlags);
+
+ Qt::WindowState requestedState = window()->windowState();
+
+ // Deliver update of QWindow state
+ reportCurrentWindowState();
+
+ if (requestedState != windowState() && requestedState != Qt::WindowFullScreen) {
+ // We were only going out of full screen as an intermediate step before
+ // progressing into the final step, so re-sync the desired state.
+ applyWindowState(requestedState);
+ }
+}
+
+void QCocoaWindow::windowDidOrderOffScreen()
+{
+ obscureWindow();
+}
+
+void QCocoaWindow::windowDidOrderOnScreen()
+{
+ exposeWindow();
+}
+
+void QCocoaWindow::windowDidChangeOcclusionState()
+{
+ // Several unit tests expect paint and/or expose events for windows that are
+ // sometimes (unpredictably) occluded and some unit tests depend on QWindow::isExposed.
+ // Don't send Expose/Obscure events when running under QTestLib.
+ static const bool onTestLib = qt_mac_resolveOption(false, "QT_QTESTLIB_RUNNING");
+ if (!onTestLib) {
+ if ((NSUInteger)[m_view.window occlusionState] & NSWindowOcclusionStateVisible) {
+ exposeWindow();
+ } else {
+ // Send Obscure events on window occlusion to stop animations.
+ obscureWindow();
+ }
}
}
+void QCocoaWindow::windowDidChangeScreen()
+{
+ if (!window())
+ return;
+
+ if (QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenForNSScreen(m_view.window.screen))
+ QWindowSystemInterface::handleWindowScreenChanged(window(), cocoaScreen->screen());
+
+ updateExposedGeometry();
+}
+
+void QCocoaWindow::windowWillClose()
+{
+ // Close any open popups on window closing.
+ if (window() && !windowIsPopupType(window()->type()))
+ qt_closePopups();
+}
+
+// ----------------------- NSWindowDelegate callbacks -----------------------
+
bool QCocoaWindow::windowShouldClose()
{
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::windowShouldClose" << window();
@@ -1229,18 +1480,7 @@ bool QCocoaWindow::windowShouldClose()
return accepted;
}
-void QCocoaWindow::windowWillClose()
-{
- // Close any open popups on window closing.
- if (window() && !windowIsPopupType(window()->type()))
- qt_closePopups();
-}
-
-void QCocoaWindow::setSynchedWindowStateFromWindow()
-{
- if (QWindow *w = window())
- m_synchedWindowState = w->windowState();
-}
+// --------------------------------------------------------------------------
bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const
{
@@ -1264,62 +1504,148 @@ QCocoaGLContext *QCocoaWindow::currentContext() const
}
#endif
-void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
+/*!
+ Checks if the window is a non-top level QWindow with a NSWindow.
+
+ \sa _q_platform_MacUseNSWindow, QT_MAC_USE_NSWINDOW
+*/
+bool QCocoaWindow::isChildNSWindow() const
+{
+ return m_view.window.parentWindow != nil;
+}
+
+/*!
+ Checks if the window is the content view of its immediate NSWindow.
+
+ Being the content view of a NSWindow means the QWindow is
+ the highest accessible NSView object in the window's view
+ hierarchy.
+
+ This can only happen in two cases, either if the QWindow is
+ itself a top level window, or if it's a child NSWindow.
+
+ \sa isChildNSWindow
+*/
+bool QCocoaWindow::isContentView() const
+{
+ return m_view.window.contentView == m_view;
+}
+
+/*!
+ Iterates child NSWindows that have a corresponding QCocoaWindow.
+*/
+void QCocoaWindow::foreachChildNSWindow(void (^block)(QCocoaWindow *))
{
- qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::recreateWindow" << window()
+ NSArray *windows = m_view.window.childWindows;
+ [windows enumerateObjectsUsingBlock:^(NSWindow *window, NSUInteger index, BOOL *stop) {
+ Q_UNUSED(index);
+ Q_UNUSED(stop);
+ if (QNSView *view = qnsview_cast(window.contentView))
+ block(view.platformWindow);
+ }];
+}
+
+/*!
+ Recreates (or removes) the NSWindow for this QWindow, if needed.
+
+ A QWindow may need a corresponding NSWindow, depending on whether
+ or not it's a top level or not (or explicitly set to be a child
+ NSWindow), whether it is a NSPanel or not, etc.
+*/
+void QCocoaWindow::recreateWindowIfNeeded()
+{
+ QPlatformWindow *parentWindow = QPlatformWindow::parent();
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::recreateWindowIfNeeded" << window()
<< "parent" << (parentWindow ? parentWindow->window() : 0);
- bool wasNSWindowChild = m_isNSWindowChild;
- BOOL requestNSWindowChild = qt_mac_resolveOption(NO, window(), "_q_platform_MacUseNSWindow",
- "QT_MAC_USE_NSWINDOW");
- m_isNSWindowChild = parentWindow && requestNSWindowChild;
- bool needsNSWindow = m_isNSWindowChild || !parentWindow;
+ RecreationReasons recreateReason = RecreationNotNeeded;
+
+ QCocoaWindow *oldParentCocoaWindow = nullptr;
+ if (QNSView *qnsView = qnsview_cast(m_view.superview))
+ oldParentCocoaWindow = qnsView.platformWindow;
+
+ if (parentWindow != oldParentCocoaWindow)
+ recreateReason |= ParentChanged;
+
+ if (!m_view.window)
+ recreateReason |= MissingWindow;
+
+ // If the modality has changed the style mask will need updating
+ if (m_windowModality != window()->modality())
+ recreateReason |= WindowModalityChanged;
+
+ const bool shouldBeChildNSWindow = parentWindow && qt_mac_resolveOption(NO,
+ window(), "_q_platform_MacUseNSWindow", "QT_MAC_USE_NSWINDOW");
+
+ if (isChildNSWindow() != shouldBeChildNSWindow)
+ recreateReason |= ChildNSWindowChanged;
+
+ const bool shouldBeContentView = !parentWindow || shouldBeChildNSWindow;
+ if (isContentView() != shouldBeContentView)
+ recreateReason |= ContentViewChanged;
+
+ Qt::WindowType type = window()->type();
+ const bool isPanel = isContentView() && [m_view.window isKindOfClass:[QNSPanel class]];
+ const bool shouldBePanel = shouldBeContentView && !shouldBeChildNSWindow &&
+ ((type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog);
+
+ if (isPanel != shouldBePanel)
+ recreateReason |= PanelChanged;
+
+ if (recreateReason == RecreationNotNeeded) {
+ qCDebug(lcQpaCocoaWindow) << "No need to recreate NSWindow";
+ return;
+ }
+
+ qCDebug(lcQpaCocoaWindow) << "Recreating NSWindow due to" << recreateReason;
+
+ QCocoaWindow *parentCocoaWindow = static_cast<QCocoaWindow *>(parentWindow);
- QCocoaWindow *oldParentCocoaWindow = m_parentCocoaWindow;
- m_parentCocoaWindow = const_cast<QCocoaWindow *>(static_cast<const QCocoaWindow *>(parentWindow));
- if (m_parentCocoaWindow && m_isNSWindowChild) {
- QWindow *parentQWindow = m_parentCocoaWindow->window();
+ if (shouldBeChildNSWindow) {
+ QWindow *parentQWindow = parentWindow->window();
+ // Ensure that all parents in the hierarchy are also child NSWindows
if (!parentQWindow->property("_q_platform_MacUseNSWindow").toBool()) {
parentQWindow->setProperty("_q_platform_MacUseNSWindow", QVariant(true));
- m_parentCocoaWindow->recreateWindow(m_parentCocoaWindow->m_parentCocoaWindow);
+ parentCocoaWindow->recreateWindowIfNeeded();
}
}
- bool usesNSPanel = [m_nsWindow isKindOfClass:[QNSPanel class]];
-
- // No child QNSWindow should notify its QNSView
- if (m_nsWindow && (window()->type() != Qt::ForeignWindow) && m_parentCocoaWindow && !oldParentCocoaWindow)
- [[NSNotificationCenter defaultCenter] removeObserver:m_view
- name:nil object:m_nsWindow];
-
// Remove current window (if any)
- if ((m_nsWindow && !needsNSWindow) || (usesNSPanel != shouldUseNSPanel())) {
+ if ((isContentView() && !shouldBeContentView) || (recreateReason & PanelChanged)) {
[m_nsWindow closeAndRelease];
- if (wasNSWindowChild && oldParentCocoaWindow)
- oldParentCocoaWindow->removeChildWindow(this);
+ if (isChildNSWindow())
+ [m_view.window.parentWindow removeChildWindow:m_view.window];
+ if (isContentView()) {
+ // We explicitly disassociate m_view from the window's contentView,
+ // as AppKit does not automatically do this in response to removing
+ // the view from the NSThemeFrame subview list, so we might end up
+ // with a NSWindow contentView pointing to a deallocated NSView.
+ m_view.window.contentView = nil;
+ }
m_nsWindow = 0;
}
- if (needsNSWindow) {
+ if (shouldBeContentView) {
bool noPreviousWindow = m_nsWindow == 0;
if (noPreviousWindow)
- m_nsWindow = createNSWindow();
-
- // Only non-child QNSWindows should notify their QNSViews
- // (but don't register more than once).
- if ((window()->type() != Qt::ForeignWindow) && (noPreviousWindow || (wasNSWindowChild && !m_isNSWindowChild)))
- [[NSNotificationCenter defaultCenter] addObserver:m_view
- selector:@selector(windowNotification:)
- name:nil // Get all notifications
- object:m_nsWindow];
-
- if (oldParentCocoaWindow) {
- if (!m_isNSWindowChild || oldParentCocoaWindow != m_parentCocoaWindow)
- oldParentCocoaWindow->removeChildWindow(this);
+ m_nsWindow = createNSWindow(shouldBeChildNSWindow, shouldBePanel);
+
+ if (m_view.window.parentWindow) {
+ if (!shouldBeChildNSWindow || (recreateReason & ParentChanged))
+ [m_view.window.parentWindow removeChildWindow:m_view.window];
m_forwardWindow = oldParentCocoaWindow;
}
- setNSWindow(m_nsWindow);
+ // Move view to new NSWindow if needed
+ if (m_nsWindow.contentView != m_view) {
+ [m_view setPostsFrameChangedNotifications:NO];
+ [m_view retain];
+ if (m_view.superview) // m_view comes from another NSWindow
+ [m_view removeFromSuperview];
+ [m_nsWindow setContentView:m_view];
+ [m_view release];
+ [m_view setPostsFrameChangedNotifications:YES];
+ }
}
if (m_viewIsToBeEmbedded) {
@@ -1330,32 +1656,21 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
setWindowFlags(window()->flags());
setWindowTitle(window()->title());
setWindowState(window()->windowState());
- } else if (m_isNSWindowChild) {
- m_nsWindow.styleMask = NSBorderlessWindowMask;
- m_nsWindow.hasShadow = NO;
- m_nsWindow.level = NSNormalWindowLevel;
- NSWindowCollectionBehavior collectionBehavior =
- NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorIgnoresCycle
- | NSWindowCollectionBehaviorFullScreenAuxiliary;
- m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone;
- m_nsWindow.collectionBehavior = collectionBehavior;
- setCocoaGeometry(windowGeometry());
-
- QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows;
- if (siblings.contains(this)) {
- if (!m_hiddenByClipping)
- m_parentCocoaWindow->reinsertChildWindow(this);
- } else {
- if (!m_hiddenByClipping)
- [m_parentCocoaWindow->m_nsWindow addChildWindow:m_nsWindow ordered:NSWindowAbove];
- siblings.append(this);
+ } else if (shouldBeChildNSWindow) {
+ if (!m_hiddenByClipping) {
+ [parentCocoaWindow->m_nsWindow addChildWindow:m_nsWindow ordered:NSWindowAbove];
+ parentCocoaWindow->reinsertChildWindow(this);
}
+
+ // Set properties after the window has been made a child NSWindow
+ setCocoaGeometry(windowGeometry());
+ setWindowFlags(window()->flags());
} else {
// Child windows have no NSWindow, link the NSViews instead.
if ([m_view superview])
[m_view removeFromSuperview];
- [m_parentCocoaWindow->m_view addSubview:m_view];
+ [parentCocoaWindow->m_view addSubview:m_view];
QRect rect = windowGeometry();
// Prevent setting a (0,0) window size; causes opengl context
// "Invalid Drawable" warnings.
@@ -1366,9 +1681,6 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
[m_view setHidden:!window()->isVisible()];
}
- m_nsWindow.ignoresMouseEvents =
- (window()->flags() & Qt::WindowTransparentForInput) == Qt::WindowTransparentForInput;
-
const qreal opacity = qt_window_private(window())->opacity;
if (!qFuzzyCompare(opacity, qreal(1.0)))
setOpacity(opacity);
@@ -1381,11 +1693,17 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
void QCocoaWindow::reinsertChildWindow(QCocoaWindow *child)
{
- int childIndex = m_childWindows.indexOf(child);
+ const QObjectList &childWindows = window()->children();
+ int childIndex = childWindows.indexOf(child->window());
Q_ASSERT(childIndex != -1);
- for (int i = childIndex; i < m_childWindows.size(); i++) {
- NSWindow *nsChild = m_childWindows[i]->m_nsWindow;
+ for (int i = childIndex; i < childWindows.size(); ++i) {
+ QWindow *window = static_cast<QWindow *>(childWindows.at(i));
+ QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
+ if (!cocoaWindow)
+ continue;
+
+ NSWindow *nsChild = cocoaWindow->m_nsWindow;
if (i != childIndex)
[m_nsWindow removeChildWindow:nsChild];
[m_nsWindow addChildWindow:nsChild ordered:NSWindowAbove];
@@ -1399,114 +1717,80 @@ void QCocoaWindow::requestActivateWindow()
[window makeKeyWindow];
}
-bool QCocoaWindow::shouldUseNSPanel()
-{
- Qt::WindowType type = window()->type();
-
- return !m_isNSWindowChild &&
- ((type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog);
-}
-
-QCocoaNSWindow * QCocoaWindow::createNSWindow()
+QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBeChildNSWindow, bool shouldBePanel)
{
QMacAutoReleasePool pool;
QRect rect = initialGeometry(window(), windowGeometry(), defaultWindowWidth, defaultWindowHeight);
- NSRect frame = qt_mac_flipRect(rect);
- Qt::WindowType type = window()->type();
- Qt::WindowFlags flags = window()->flags();
-
- NSUInteger styleMask;
- if (m_isNSWindowChild) {
- styleMask = NSBorderlessWindowMask;
- } else {
- styleMask = windowStyleMask(flags);
+ QScreen *targetScreen = nullptr;
+ for (QScreen *screen : QGuiApplication::screens()) {
+ if (screen->geometry().contains(rect.topLeft())) {
+ targetScreen = screen;
+ break;
+ }
}
- QCocoaNSWindow *createdWindow = 0;
-
- // Use NSPanel for popup-type windows. (Popup, Tool, ToolTip, SplashScreen)
- // and dialogs
- if (shouldUseNSPanel()) {
- QNSPanel *window;
- window = [[QNSPanel alloc] initWithContentRect:frame
- styleMask: styleMask
- qPlatformWindow:this];
- if ((type & Qt::Popup) == Qt::Popup)
- [window setHasShadow:YES];
-
- // Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set.
- QVariant showWithoutActivating = QPlatformWindow::window()->property("_q_macAlwaysShowToolWindow");
- bool shouldHideOnDeactivate = ((type & Qt::Tool) == Qt::Tool) &&
- !(showWithoutActivating.isValid() && showWithoutActivating.toBool());
- [window setHidesOnDeactivate: shouldHideOnDeactivate];
-
- // Make popup windows show on the same desktop as the parent full-screen window.
- [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
- if ((type & Qt::Popup) == Qt::Popup)
- [window setAnimationBehavior:NSWindowAnimationBehaviorUtilityWindow];
-
- createdWindow = window;
- } else {
- QNSWindow *window;
- window = [[QNSWindow alloc] initWithContentRect:frame
- styleMask: styleMask
- qPlatformWindow:this];
- createdWindow = window;
+
+ if (!targetScreen) {
+ qCWarning(lcQpaCocoaWindow) << "Window position outside any known screen, using primary screen";
+ targetScreen = QGuiApplication::primaryScreen();
}
- if ([createdWindow respondsToSelector:@selector(setRestorable:)])
- [createdWindow setRestorable: NO];
+ rect.translate(-targetScreen->geometry().topLeft());
+ QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen *>(targetScreen->handle());
+ NSRect frame = NSRectFromCGRect(cocoaScreen->mapToNative(rect).toCGRect());
- NSInteger level = windowLevel(flags);
- [createdWindow setLevel:level];
+ // Note: The macOS window manager has a bug, where if a screen is rotated, it will not allow
+ // a window to be created within the area of the screen that has a Y coordinate (I quadrant)
+ // higher than the height of the screen in its non-rotated state, unless the window is
+ // created with the NSWindowStyleMaskBorderless style mask.
- // OpenGL surfaces can be ordered either above(default) or below the NSWindow.
- // When ordering below the window must be tranclucent and have a clear background color.
- static GLint openglSourfaceOrder = qt_mac_resolveOption(1, "QT_MAC_OPENGL_SURFACE_ORDER");
+ Qt::WindowType type = window()->type();
+ Qt::WindowFlags flags = window()->flags();
+
+ // Create NSWindow
+ Class windowClass = shouldBePanel ? [QNSPanel class] : [QNSWindow class];
+ NSUInteger styleMask = shouldBeChildNSWindow ? NSBorderlessWindowMask : windowStyleMask(flags);
+ QCocoaNSWindow *window = [[windowClass alloc] initWithContentRect:frame
+ screen:cocoaScreen->nativeScreen() styleMask:styleMask qPlatformWindow:this];
- bool isTranslucent = window()->format().alphaBufferSize() > 0
- || (surface()->supportsOpenGL() && openglSourfaceOrder == -1);
- if (isTranslucent) {
- [createdWindow setBackgroundColor:[NSColor clearColor]];
- [createdWindow setOpaque:NO];
+ window.restorable = NO;
+ window.level = shouldBeChildNSWindow ? NSNormalWindowLevel : windowLevel(flags);
+
+ if (!isOpaque()) {
+ window.backgroundColor = [NSColor clearColor];
+ window.opaque = NO;
}
- m_windowModality = window()->modality();
+ Q_ASSERT(!(shouldBePanel && shouldBeChildNSWindow));
- applyContentBorderThickness(createdWindow);
+ if (shouldBePanel) {
+ // Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set
+ window.hidesOnDeactivate = ((type & Qt::Tool) == Qt::Tool) &&
+ !qt_mac_resolveOption(false, QPlatformWindow::window(), "_q_macAlwaysShowToolWindow", "");
- return createdWindow;
-}
+ // Make popup windows show on the same desktop as the parent full-screen window
+ window.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
-void QCocoaWindow::setNSWindow(QCocoaNSWindow *window)
-{
- if (window.contentView != m_view) {
- [m_view setPostsFrameChangedNotifications:NO];
- [m_view retain];
- if (m_view.superview) // m_view comes from another NSWindow
- [m_view removeFromSuperview];
- [window setContentView:m_view];
- [m_view release];
- [m_view setPostsFrameChangedNotifications:YES];
+ if ((type & Qt::Popup) == Qt::Popup) {
+ window.hasShadow = YES;
+ window.animationBehavior = NSWindowAnimationBehaviorUtilityWindow;
+ }
+ } else if (shouldBeChildNSWindow) {
+ window.collectionBehavior =
+ NSWindowCollectionBehaviorManaged
+ | NSWindowCollectionBehaviorIgnoresCycle
+ | NSWindowCollectionBehaviorFullScreenAuxiliary;
+ window.hasShadow = NO;
+ window.animationBehavior = NSWindowAnimationBehaviorNone;
}
-}
-void QCocoaWindow::removeChildWindow(QCocoaWindow *child)
-{
- m_childWindows.removeOne(child);
- [m_nsWindow removeChildWindow:child->m_nsWindow];
-}
+ // Persist modality so we can detect changes later on
+ m_windowModality = QPlatformWindow::window()->modality();
-bool QCocoaWindow::isNativeWindowTypeInconsistent()
-{
- if (!m_nsWindow)
- return false;
+ applyContentBorderThickness(window);
- const bool isPanel = [m_nsWindow isKindOfClass:[QNSPanel class]];
- const bool usePanel = shouldUseNSPanel();
-
- return isPanel != usePanel;
+ return window;
}
void QCocoaWindow::removeMonitor()
@@ -1520,7 +1804,7 @@ void QCocoaWindow::removeMonitor()
// Returns the current global screen geometry for the nswindow associated with this window.
QRect QCocoaWindow::nativeWindowGeometry() const
{
- if (!m_nsWindow || m_isNSWindowChild)
+ if (!m_nsWindow || isChildNSWindow())
return geometry();
NSRect rect = [m_nsWindow frame];
@@ -1530,94 +1814,139 @@ QRect QCocoaWindow::nativeWindowGeometry() const
return qRect;
}
-// Returns a pointer to the parent QCocoaWindow for this window, or 0 if there is none.
-QCocoaWindow *QCocoaWindow::parentCocoaWindow() const
-{
- if (window() && window()->transientParent()) {
- return static_cast<QCocoaWindow*>(window()->transientParent()->handle());
- }
- return 0;
-}
+/*!
+ Applies the given state to the NSWindow, going in/out of minimize/zoomed/fullscreen
-// Syncs the NSWindow minimize/maximize/fullscreen state with the current QWindow state
-void QCocoaWindow::syncWindowState(Qt::WindowState newState)
+ When this is called from QWindow::setWindowState(), the QWindow state has not been
+ updated yet, so window()->windowState() will reflect the previous state that was
+ reported to QtGui.
+*/
+void QCocoaWindow::applyWindowState(Qt::WindowState newState)
{
+ const Qt::WindowState currentState = windowState();
+ if (newState == currentState)
+ return;
+
if (!m_nsWindow)
return;
- // if content view width or height is 0 then the window animations will crash so
- // do nothing except set the new state
- NSRect contentRect = m_view.frame;
- if (contentRect.size.width <= 0 || contentRect.size.height <= 0) {
+
+ const NSSize contentSize = m_view.frame.size;
+ if (contentSize.width <= 0 || contentSize.height <= 0) {
+ // If content view width or height is 0 then the window animations will crash so
+ // do nothing. We report the current state back to reflect the failed operation.
qWarning("invalid window content view size, check your window geometry");
- m_synchedWindowState = newState;
+ reportCurrentWindowState(true);
return;
}
- Qt::WindowState predictedState = newState;
- if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) {
- const int styleMask = [m_nsWindow styleMask];
- const bool usePerform = styleMask & NSResizableWindowMask;
- [m_nsWindow setStyleMask:styleMask | NSResizableWindowMask];
- if (usePerform)
- [m_nsWindow performZoom : m_nsWindow]; // toggles
- else
- [m_nsWindow zoom : m_nsWindow]; // toggles
- [m_nsWindow setStyleMask:styleMask];
+ if (m_nsWindow.styleMask & NSUtilityWindowMask) {
+ // Utility panels cannot be fullscreen
+ qWarning() << window()->type() << "windows can not be made full screen";
+ reportCurrentWindowState(true);
+ return;
}
- if ((m_synchedWindowState & Qt::WindowMinimized) != (newState & Qt::WindowMinimized)) {
- if (newState & Qt::WindowMinimized) {
- if ([m_nsWindow styleMask] & NSMiniaturizableWindowMask)
- [m_nsWindow performMiniaturize : m_nsWindow];
- else
- [m_nsWindow miniaturize : m_nsWindow];
- } else {
- [m_nsWindow deminiaturize : m_nsWindow];
- }
+ const id sender = m_nsWindow;
+
+ // First we need to exit states that can't transition directly to other states
+ switch (currentState) {
+ case Qt::WindowMinimized:
+ [m_nsWindow deminiaturize:sender];
+ Q_ASSERT_X(windowState() != Qt::WindowMinimized, "QCocoaWindow",
+ "[NSWindow deminiaturize:] is synchronous");
+ break;
+ case Qt::WindowFullScreen: {
+ toggleFullScreen();
+ // Exiting fullscreen is not synchronous, so we need to wait for the
+ // NSWindowDidExitFullScreenNotification before continuing to apply
+ // the new state.
+ return;
}
-
- const bool effMax = m_effectivelyMaximized;
- if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized) || (m_effectivelyMaximized && newState == Qt::WindowNoState)) {
- if ((m_synchedWindowState & Qt::WindowFullScreen) == (newState & Qt::WindowFullScreen)) {
- [m_nsWindow zoom : m_nsWindow]; // toggles
- m_effectivelyMaximized = !effMax;
- } else if (!(newState & Qt::WindowMaximized)) {
- // it would be nice to change the target geometry that toggleFullScreen will animate toward
- // but there is no known way, so the maximized state is not possible at this time
- predictedState = static_cast<Qt::WindowState>(static_cast<int>(newState) | Qt::WindowMaximized);
- m_effectivelyMaximized = true;
- }
+ default:;
}
- if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) {
- if (window()->flags() & Qt::WindowFullscreenButtonHint) {
- if (m_effectivelyMaximized && m_synchedWindowState == Qt::WindowFullScreen)
- predictedState = Qt::WindowMaximized;
- [m_nsWindow toggleFullScreen : m_nsWindow];
- } else {
- if (newState & Qt::WindowFullScreen) {
- QScreen *screen = window()->screen();
- if (screen) {
- if (m_normalGeometry.width() < 0) {
- m_oldWindowFlags = m_windowFlags;
- window()->setFlags(window()->flags() | Qt::FramelessWindowHint);
- m_normalGeometry = nativeWindowGeometry();
- setGeometry(screen->geometry());
- m_presentationOptions = [NSApp presentationOptions];
- [NSApp setPresentationOptions : m_presentationOptions | NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock];
- }
- }
- } else {
- window()->setFlags(m_oldWindowFlags);
- setGeometry(m_normalGeometry);
- m_normalGeometry.setRect(0, 0, -1, -1);
- [NSApp setPresentationOptions : m_presentationOptions];
- }
- }
+ // Then we apply the new state if needed
+ if (newState == windowState())
+ return;
+
+ switch (newState) {
+ case Qt::WindowFullScreen:
+ toggleFullScreen();
+ break;
+ case Qt::WindowMaximized:
+ toggleMaximized();
+ break;
+ case Qt::WindowMinimized:
+ [m_nsWindow miniaturize:sender];
+ break;
+ case Qt::WindowNoState:
+ if (windowState() == Qt::WindowMaximized)
+ toggleMaximized();
+ break;
+ default:
+ Q_UNREACHABLE();
}
+}
+
+void QCocoaWindow::toggleMaximized()
+{
+ // The NSWindow needs to be resizable, otherwise the window will
+ // not be possible to zoom back to non-zoomed state.
+ const bool wasResizable = m_nsWindow.styleMask & NSResizableWindowMask;
+ m_nsWindow.styleMask |= NSResizableWindowMask;
+
+ const id sender = m_nsWindow;
+ [m_nsWindow zoom:sender];
+
+ if (!wasResizable)
+ m_nsWindow.styleMask &= ~NSResizableWindowMask;
+}
+
+void QCocoaWindow::toggleFullScreen()
+{
+ // The window needs to have the correct collection behavior for the
+ // toggleFullScreen call to have an effect. The collection behavior
+ // will be reset in windowDidEnterFullScreen/windowDidLeaveFullScreen.
+ m_nsWindow.collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
+
+ const id sender = m_nsWindow;
+ [m_nsWindow toggleFullScreen:sender];
+}
+
+bool QCocoaWindow::isTransitioningToFullScreen() const
+{
+ NSWindow *window = m_view.window;
+ return window.styleMask & NSFullScreenWindowMask && !window.qt_fullScreen;
+}
+
+Qt::WindowState QCocoaWindow::windowState() const
+{
+ // FIXME: Support compound states (Qt::WindowStates)
+
+ NSWindow *window = m_view.window;
+ if (window.miniaturized)
+ return Qt::WindowMinimized;
+ if (window.qt_fullScreen)
+ return Qt::WindowFullScreen;
+ if ((window.zoomed && !isTransitioningToFullScreen())
+ || (m_lastReportedWindowState == Qt::WindowMaximized && isTransitioningToFullScreen()))
+ return Qt::WindowMaximized;
+
+ // Note: We do not report Qt::WindowActive, even if isActive()
+ // is true, as QtGui does not expect this window state to be set.
+
+ return Qt::WindowNoState;
+}
+
+void QCocoaWindow::reportCurrentWindowState(bool unconditionally)
+{
+ Qt::WindowState currentState = windowState();
+ if (!unconditionally && currentState == m_lastReportedWindowState)
+ return;
- // New state is now the current synched state
- m_synchedWindowState = predictedState;
+ QWindowSystemInterface::handleWindowStateChanged<QWindowSystemInterface::SynchronousDelivery>(
+ window(), currentState, m_lastReportedWindowState);
+ m_lastReportedWindowState = currentState;
}
bool QCocoaWindow::setWindowModified(bool modified)
@@ -1671,7 +2000,7 @@ void QCocoaWindow::setWindowCursor(NSCursor *cursor)
return;
// Setting a cursor in a foregin view is not supported.
- if (window()->type() == Qt::ForeignWindow)
+ if (isForeignWindow())
return;
[m_windowCursor release];
@@ -1734,10 +2063,10 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
}
// Find consecutive registered border areas, starting from the top.
- QList<BorderRange> ranges = m_contentBorderAreas.values();
+ std::vector<BorderRange> ranges(m_contentBorderAreas.cbegin(), m_contentBorderAreas.cend());
std::sort(ranges.begin(), ranges.end());
int effectiveTopContentBorderThickness = m_topContentBorderThickness;
- foreach (BorderRange range, ranges) {
+ for (BorderRange range : ranges) {
// Skip disiabled ranges (typically hidden tool bars)
if (!m_enabledContentBorderAreas.value(range.identifier, false))
continue;
@@ -1814,15 +2143,13 @@ void QCocoaWindow::exposeWindow()
if (!isWindowExposable())
return;
- // Update the QWindow's screen property. This property is set
- // to QGuiApplication::primaryScreen() at QWindow construciton
- // time, and we won't get a NSWindowDidChangeScreenNotification
- // on show. The case where the window is initially displayed
- // on a non-primary screen needs special handling here.
- NSUInteger screenIndex = [[NSScreen screens] indexOfObject:m_nsWindow.screen];
- if (screenIndex != NSNotFound) {
- QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex);
- if (cocoaScreen)
+ if (window()->isTopLevel()) {
+ // Update the QWindow's screen property. This property is set
+ // to QGuiApplication::primaryScreen() at QWindow construciton
+ // time, and we won't get a NSWindowDidChangeScreenNotification
+ // on show. The case where the window is initially displayed
+ // on a non-primary screen needs special handling here.
+ if (QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenForNSScreen(m_nsWindow.screen))
window()->setScreen(cocoaScreen->screen());
}
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm
index e09bb1e362..f3467fdc73 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.mm
+++ b/src/plugins/platforms/cocoa/qmacclipboard.mm
@@ -139,10 +139,22 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
const long promise_id = (long)id;
// Find the kept promise
+ QList<QMacInternalPasteboardMime*> availableConverters
+ = QMacInternalPasteboardMime::all(QMacInternalPasteboardMime::MIME_ALL);
const QString flavorAsQString = QString::fromCFString(flavor);
QMacPasteboard::Promise promise;
for (int i = 0; i < qpaste->promises.size(); i++){
QMacPasteboard::Promise tmp = qpaste->promises[i];
+ if (!availableConverters.contains(tmp.convertor)) {
+ // promise.converter is a pointer initialized by the value found
+ // in QMacInternalPasteboardMime's global list of QMacInternalPasteboardMimes.
+ // We add pointers to this list in QMacInternalPasteboardMime's ctor;
+ // we remove these pointers in QMacInternalPasteboardMime's dtor.
+ // If tmp.converter was not found in this list, we probably have a
+ // dangling pointer so let's skip it.
+ continue;
+ }
+
if (tmp.itemId == promise_id && tmp.convertor->canConvert(tmp.mime, flavorAsQString)){
promise = tmp;
break;
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index f226547b90..75a508370f 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -74,7 +74,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
QStringList *currentCustomDragTypes;
bool m_sendUpAsRightButton;
Qt::KeyboardModifiers currentWheelModifiers;
- bool m_subscribesForGlobalFrameNotifications;
#ifndef QT_NO_OPENGL
QCocoaGLContext *m_glContext;
bool m_shouldSetGLContextinDrawRect;
@@ -101,9 +100,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
- (void)drawRect:(NSRect)dirtyRect;
- (void)drawBackingStoreUsingCoreGraphics:(NSRect)dirtyRect;
- (void)updateGeometry;
-- (void)notifyWindowStateChanged:(Qt::WindowState)newState;
-- (void)windowNotification : (NSNotification *) windowNotification;
-- (void)notifyWindowWillZoom:(BOOL)willZoom;
- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification;
- (void)viewDidHide;
- (void)viewDidUnhide;
@@ -152,6 +148,11 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
@end
+@interface QT_MANGLE_NAMESPACE(QNSView) (QtExtras)
+@property (nonatomic, readonly) QCocoaWindow *platformWindow;
+@property (nonatomic, readonly) BOOL isMenuView;
+@end
+
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSView);
#endif //QNSVIEW_H
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 970ce9e785..296b6a28cc 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -140,8 +140,7 @@ static bool _q_dontOverrideCtrlLMB = false;
- (id) init
{
- self = [super initWithFrame : NSMakeRect(0,0, 300,300)];
- if (self) {
+ if (self = [super initWithFrame:NSZeroRect]) {
m_backingStore = 0;
m_maskImage = 0;
m_shouldInvalidateWindowShadow = false;
@@ -149,7 +148,6 @@ static bool _q_dontOverrideCtrlLMB = false;
m_acceptedMouseDowns = Qt::NoButton;
m_frameStrutButtons = Qt::NoButton;
m_sendKeyEvent = false;
- m_subscribesForGlobalFrameNotifications = false;
#ifndef QT_NO_OPENGL
m_glContext = 0;
m_shouldSetGLContextinDrawRect = false;
@@ -181,7 +179,6 @@ static bool _q_dontOverrideCtrlLMB = false;
CGImageRelease(m_maskImage);
[m_trackingArea release];
m_maskImage = 0;
- m_subscribesForGlobalFrameNotifications = false;
[m_inputSource release];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[m_mouseMoveHelper release];
@@ -217,11 +214,6 @@ static bool _q_dontOverrideCtrlLMB = false;
#endif
[self registerDragTypes];
- [self setPostsFrameChangedNotifications : YES];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(updateGeometry)
- name:NSViewFrameDidChangeNotification
- object:self];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(textInputContextKeyboardSelectionDidChangeNotification:)
@@ -240,29 +232,14 @@ static bool _q_dontOverrideCtrlLMB = false;
//was unable to set view
m_shouldSetGLContextinDrawRect = true;
}
-
- if (!m_subscribesForGlobalFrameNotifications) {
- // NSOpenGLContext expects us to repaint (or update) the view when
- // it changes position on screen. Since this happens unnoticed for
- // the view when the parent view moves, we need to register a special
- // notification that lets us handle this case:
- m_subscribesForGlobalFrameNotifications = true;
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(globalFrameChanged:)
- name:NSViewGlobalFrameDidChangeNotification
- object:self];
- }
}
#endif
-- (void) globalFrameChanged:(NSNotification*)notification
-{
- Q_UNUSED(notification);
- m_platformWindow->updateExposedGeometry();
-}
-
- (void)viewDidMoveToSuperview
{
+ if (m_platformWindow.isNull())
+ return;
+
if (!(m_platformWindow->m_viewIsToBeEmbedded))
return;
@@ -281,24 +258,11 @@ static bool _q_dontOverrideCtrlLMB = false;
m_backingStore = Q_NULLPTR;
}
-- (void)viewWillMoveToWindow:(NSWindow *)newWindow
-{
- // ### Merge "normal" window code path with this one for 5.1.
- if (!(m_platformWindow->window()->type() & Qt::SubWindow))
- return;
-
- if (newWindow) {
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(windowNotification:)
- name:nil // Get all notifications
- object:newWindow];
- }
- if ([self window])
- [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:[self window]];
-}
-
- (QWindow *)topLevelWindow
{
+ if (m_platformWindow.isNull())
+ return nullptr;
+
QWindow *focusWindow = m_platformWindow->window();
// For widgets we need to do a bit of trickery as the window
@@ -314,9 +278,12 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)updateGeometry
{
+ if (m_platformWindow.isNull())
+ return;
+
QRect geometry;
- if (m_platformWindow->m_isNSWindowChild) {
+ if (self.window.parentWindow) {
return;
#if 0
//geometry = QRectF::fromCGRect([self frame]).toRect();
@@ -336,10 +303,10 @@ static bool _q_dontOverrideCtrlLMB = false;
geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height);
} else if (m_platformWindow->m_viewIsToBeEmbedded) {
// embedded child window, use the frame rect ### merge with case below
- geometry = QRectF::fromCGRect([self bounds]).toRect();
+ geometry = QRectF::fromCGRect(NSRectToCGRect([self bounds])).toRect();
} else {
// child window, use the frame rect
- geometry = QRectF::fromCGRect([self frame]).toRect();
+ geometry = QRectF::fromCGRect(NSRectToCGRect([self frame])).toRect();
}
if (m_platformWindow->m_nsWindow && geometry == m_platformWindow->geometry())
@@ -380,79 +347,6 @@ static bool _q_dontOverrideCtrlLMB = false;
}
}
-- (void)notifyWindowStateChanged:(Qt::WindowState)newState
-{
- // If the window was maximized, then fullscreen, then tried to go directly to "normal" state,
- // this notification will say that it is "normal", but it will still look maximized, and
- // if you called performZoom it would actually take it back to "normal".
- // So we should say that it is maximized because it actually is.
- if (newState == Qt::WindowNoState && m_platformWindow->m_effectivelyMaximized)
- newState = Qt::WindowMaximized;
- QWindowSystemInterface::handleWindowStateChanged(m_platformWindow->window(), newState);
- // We want to read the window state back from the window,
- // but the event we just sent may be asynchronous.
- QWindowSystemInterface::flushWindowSystemEvents();
- m_platformWindow->setSynchedWindowStateFromWindow();
-}
-
-- (void)windowNotification : (NSNotification *) windowNotification
-{
- //qDebug() << "windowNotification" << QString::fromNSString([windowNotification name]);
-
- NSString *notificationName = [windowNotification name];
- if (notificationName == NSWindowDidBecomeKeyNotification) {
- if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
- QWindowSystemInterface::handleWindowActivated(m_platformWindow->window());
- } else if (notificationName == NSWindowDidResignKeyNotification) {
- // key window will be non-nil if another window became key... do not
- // set the active window to zero here, the new key window's
- // NSWindowDidBecomeKeyNotification hander will change the active window
- NSWindow *keyWindow = [NSApp keyWindow];
- if (!keyWindow || keyWindow == windowNotification.object) {
- // no new key window, go ahead and set the active window to zero
- if (!m_platformWindow->windowIsPopupType() && !m_isMenuView)
- QWindowSystemInterface::handleWindowActivated(0);
- }
- } else if (notificationName == NSWindowDidMiniaturizeNotification
- || notificationName == NSWindowDidDeminiaturizeNotification) {
- Qt::WindowState newState = notificationName == NSWindowDidMiniaturizeNotification ?
- Qt::WindowMinimized : Qt::WindowNoState;
- [self notifyWindowStateChanged:newState];
- } else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) {
- m_platformWindow->obscureWindow();
- } else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) {
- m_platformWindow->exposeWindow();
- } else if ([notificationName isEqualToString:NSWindowDidChangeOcclusionStateNotification]) {
- // Several unit tests expect paint and/or expose events for windows that are
- // sometimes (unpredictably) occluded and some unit tests depend on QWindow::isExposed -
- // don't send Expose/Obscure events when running under QTestLib.
- static const bool onTestLib = qt_mac_resolveOption(false, "QT_QTESTLIB_RUNNING");
- if (!onTestLib) {
- if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) {
- m_platformWindow->exposeWindow();
- } else {
- // Send Obscure events on window occlusion to stop animations.
- m_platformWindow->obscureWindow();
- }
- }
- } else if (notificationName == NSWindowDidChangeScreenNotification) {
- if (m_platformWindow->window()) {
- NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen];
- if (screenIndex != NSNotFound) {
- QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex);
- if (cocoaScreen)
- QWindowSystemInterface::handleWindowScreenChanged(m_platformWindow->window(), cocoaScreen->screen());
- m_platformWindow->updateExposedGeometry();
- }
- }
- } else if (notificationName == NSWindowDidEnterFullScreenNotification
- || notificationName == NSWindowDidExitFullScreenNotification) {
- Qt::WindowState newState = notificationName == NSWindowDidEnterFullScreenNotification ?
- Qt::WindowFullScreen : Qt::WindowNoState;
- [self notifyWindowStateChanged:newState];
- }
-}
-
- (void)textInputContextKeyboardSelectionDidChangeNotification : (NSNotification *) textInputContextKeyboardSelectionDidChangeNotification
{
Q_UNUSED(textInputContextKeyboardSelectionDidChangeNotification)
@@ -462,14 +356,6 @@ static bool _q_dontOverrideCtrlLMB = false;
}
}
-- (void)notifyWindowWillZoom:(BOOL)willZoom
-{
- Qt::WindowState newState = willZoom ? Qt::WindowMaximized : Qt::WindowNoState;
- if (!willZoom)
- m_platformWindow->m_effectivelyMaximized = false;
- [self notifyWindowStateChanged:newState];
-}
-
- (void)viewDidHide
{
m_platformWindow->obscureWindow();
@@ -553,7 +439,7 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void) drawRect:(NSRect)dirtyRect
{
- qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_platformWindow->window() << QRectF::fromCGRect(dirtyRect);
+ qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_platformWindow->window() << QRectF::fromCGRect(NSRectToCGRect(dirtyRect));
#ifndef QT_NO_OPENGL
if (m_glContext && m_shouldSetGLContextinDrawRect) {
@@ -741,6 +627,9 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)handleMouseEvent:(NSEvent *)theEvent
{
+ if (m_platformWindow.isNull())
+ return;
+
// Tablet events may come in via the mouse event handlers,
// check if this is a valid tablet event first.
if ([self handleTabletEvent: theEvent])
@@ -755,6 +644,8 @@ static bool _q_dontOverrideCtrlLMB = false;
else
m_platformWindow->m_forwardWindow.clear();
}
+ if (targetView->m_platformWindow.isNull())
+ return;
// Popups implicitly grap mouse events; forward to the active popup if there is one
if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) {
@@ -779,6 +670,9 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent
{
+ if (m_platformWindow.isNull())
+ return;
+
// get m_buttons in sync
// Don't send frme strut events if we are in the middle of a mouse drag.
if (m_buttons != Qt::NoButton)
@@ -1058,6 +952,9 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)mouseMovedImpl:(NSEvent *)theEvent
{
+ if (m_platformWindow.isNull())
+ return;
+
if ([self isTransparentForUserInput])
return;
@@ -1089,6 +986,9 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)mouseEnteredImpl:(NSEvent *)theEvent
{
Q_UNUSED(theEvent)
+ if (m_platformWindow.isNull())
+ return;
+
m_platformWindow->m_windowUnderMouse = true;
if ([self isTransparentForUserInput])
@@ -1108,6 +1008,9 @@ static bool _q_dontOverrideCtrlLMB = false;
- (void)mouseExitedImpl:(NSEvent *)theEvent
{
Q_UNUSED(theEvent);
+ if (m_platformWindow.isNull())
+ return;
+
m_platformWindow->m_windowUnderMouse = false;
if ([self isTransparentForUserInput])
@@ -1134,6 +1037,9 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash)
- (bool)handleTabletEvent: (NSEvent *)theEvent
{
+ if (m_platformWindow.isNull())
+ return false;
+
NSEventType eventType = [theEvent type];
if (eventType != NSTabletPoint && [theEvent subtype] != NSTabletPointEventSubtype)
return false; // Not a tablet event.
@@ -1292,6 +1198,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (bool)shouldSendSingleTouch
{
+ if (m_platformWindow.isNull())
+ return true;
+
// QtWidgets expects single-point touch events, QtDeclarative does not.
// Until there is an API we solve this by looking at the window class type.
return m_platformWindow->window()->inherits("QWidgetWindow");
@@ -1299,6 +1208,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)touchesBeganWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points;
@@ -1307,6 +1219,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)touchesMovedWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points;
@@ -1315,6 +1230,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)touchesEndedWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points;
@@ -1323,6 +1241,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)touchesCancelledWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points;
@@ -1333,7 +1254,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (bool)handleGestureAsBeginEnd:(NSEvent *)event
{
- if (QSysInfo::QSysInfo::MacintoshVersion < QSysInfo::MV_10_11)
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::OSXElCapitan)
return false;
if ([event phase] == NSEventPhaseBegan) {
@@ -1350,6 +1271,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
}
- (void)magnifyWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
if ([self handleGestureAsBeginEnd:event])
return;
@@ -1364,6 +1288,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)smartMagnifyWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
static bool zoomIn = true;
qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn;
const NSTimeInterval timestamp = [event timestamp];
@@ -1377,6 +1304,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)rotateWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
if ([self handleGestureAsBeginEnd:event])
return;
@@ -1390,6 +1320,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)swipeWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
@@ -1412,6 +1345,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)beginGestureWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
@@ -1423,6 +1359,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)endGestureWithEvent:(NSEvent *)event
{
+ if (m_platformWindow.isNull())
+ return;
+
qCDebug(lcQpaGestures) << "endGestureWithEvent";
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
@@ -1436,6 +1375,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
#ifndef QT_NO_WHEELEVENT
- (void)scrollWheel:(NSEvent *)theEvent
{
+ if (m_platformWindow.isNull())
+ return;
+
if ([self isTransparentForUserInput])
return [super scrollWheel:theEvent];
@@ -2106,6 +2048,9 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
// Sends drag update to Qt, return the action
- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender
{
+ if (m_platformWindow.isNull())
+ return NSDragOperationNone;
+
NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
@@ -2133,6 +2078,9 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
- (void)draggingExited:(id <NSDraggingInfo>)sender
{
+ if (m_platformWindow.isNull())
+ return;
+
QWindow *target = findEventTargetWindow(m_platformWindow->window());
if (!target)
return;
@@ -2147,6 +2095,9 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
// called on drop, send the drop to Qt and return if it was accepted.
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
+ if (m_platformWindow.isNull())
+ return false;
+
QWindow *target = findEventTargetWindow(m_platformWindow->window());
if (!target)
return false;
@@ -2177,6 +2128,10 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
{
Q_UNUSED(session);
Q_UNUSED(operation);
+
+ if (m_platformWindow.isNull())
+ return;
+
QWindow *target = findEventTargetWindow(m_platformWindow->window());
if (!target)
return;
@@ -2199,3 +2154,17 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
}
@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSView) (QtExtras)
+
+- (QCocoaWindow*)platformWindow
+{
+ return m_platformWindow.data();;
+}
+
+- (BOOL)isMenuView
+{
+ return m_isMenuView;
+}
+
+@end
diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
index 73e1f41dd5..645a93edf7 100644
--- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
@@ -53,6 +53,9 @@
@implementation QNSView (QNSViewAccessibility)
- (id)childAccessibleElement {
+ if (m_platformWindow.isNull())
+ return nil;
+
if (!m_platformWindow->window()->accessibleRoot())
return nil;
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h
index f29aa97b68..d2078b5786 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.h
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h
@@ -49,15 +49,9 @@
QCocoaWindow *m_cocoaWindow;
}
-- (id)initWithQCocoaWindow: (QCocoaWindow *) cocoaWindow;
+- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow;
-- (void)windowDidBecomeKey:(NSNotification *)notification;
-- (void)windowDidResize:(NSNotification *)notification;
-- (void)windowDidMove:(NSNotification *)notification;
-- (void)windowWillMove:(NSNotification *)notification;
- (BOOL)windowShouldClose:(NSNotification *)notification;
-- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame;
-- (void)windowWillClose:(NSNotification *)notification;
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu;
- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard;
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index 7f988ac963..ce74aa9973 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -41,61 +41,17 @@
#include "qcocoahelpers.h"
#include <QDebug>
+#include <qpa/qplatformscreen.h>
#include <qpa/qwindowsysteminterface.h>
@implementation QNSWindowDelegate
-- (id) initWithQCocoaWindow: (QCocoaWindow *) cocoaWindow
+- (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow
{
- self = [super init];
-
- if (self) {
+ if (self = [super init])
m_cocoaWindow = cocoaWindow;
- }
- return self;
-}
-
-- (void)windowDidBecomeKey:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- if (m_cocoaWindow->m_windowUnderMouse) {
- QPointF windowPoint;
- QPointF screenPoint;
- [qnsview_cast(m_cocoaWindow->view()) convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- QWindowSystemInterface::handleEnterEvent(m_cocoaWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
- }
-}
-- (void)windowDidResize:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- if (m_cocoaWindow) {
- m_cocoaWindow->windowDidResize();
- }
-}
-
-- (void)windowDidEndLiveResize:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- if (m_cocoaWindow) {
- m_cocoaWindow->windowDidEndLiveResize();
- }
-}
-
-- (void)windowWillMove:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- if (m_cocoaWindow) {
- m_cocoaWindow->windowWillMove();
- }
-}
-
-- (void)windowDidMove:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- if (m_cocoaWindow) {
- m_cocoaWindow->windowDidMove();
- }
+ return self;
}
- (BOOL)windowShouldClose:(NSNotification *)notification
@@ -107,20 +63,19 @@
return YES;
}
-
-- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
+/*!
+ Overridden to ensure that the zoomed state always results in a maximized
+ window, which would otherwise not be the case for borderless windows.
+*/
+- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)newFrame
{
Q_UNUSED(newFrame);
- if (m_cocoaWindow && m_cocoaWindow->window()->type() != Qt::ForeignWindow)
- [qnsview_cast(m_cocoaWindow->view()) notifyWindowWillZoom:![window isZoomed]];
- return YES;
-}
-- (void)windowWillClose:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- if (m_cocoaWindow)
- m_cocoaWindow->windowWillClose();
+ // We explicitly go through the QScreen API here instead of just using
+ // window.screen.visibleFrame directly, as that ensures we have the same
+ // behavior for both use-cases/APIs.
+ Q_ASSERT(window == m_cocoaWindow->nativeWindow());
+ return m_cocoaWindow->screen()->availableGeometry().toCGRect();
}
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp
index b5065ba380..38425f8fa1 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbitmap.cpp
@@ -55,8 +55,9 @@ class QWindowsDirect2DBitmapPrivate
{
public:
QWindowsDirect2DBitmapPrivate(ID2D1DeviceContext *dc = 0, ID2D1Bitmap1 *bm = 0)
- : bitmap(bm)
- , deviceContext(new QWindowsDirect2DDeviceContext(dc))
+ : deviceContext(new QWindowsDirect2DDeviceContext(dc))
+ , bitmap(bm)
+
{
deviceContext->get()->SetTarget(bm);
}
@@ -83,13 +84,13 @@ public:
UINT32(width), UINT32(height)
};
- HRESULT hr = deviceContext->get()->CreateBitmap(size, data, pitch,
+ HRESULT hr = deviceContext->get()->CreateBitmap(size, data, UINT32(pitch),
bitmapProperties(),
bitmap.ReleaseAndGetAddressOf());
if (SUCCEEDED(hr))
deviceContext->get()->SetTarget(bitmap.Get());
else
- qWarning("%s: Could not create bitmap: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create bitmap: %#lx", __FUNCTION__, hr);
return SUCCEEDED(hr);
}
@@ -107,28 +108,28 @@ public:
D2D1_BITMAP_PROPERTIES1 properties = bitmapProperties();
properties.bitmapOptions = D2D1_BITMAP_OPTIONS_CANNOT_DRAW | D2D1_BITMAP_OPTIONS_CPU_READ;
- hr = deviceContext->get()->CreateBitmap(size, NULL, NULL,
+ hr = deviceContext->get()->CreateBitmap(size, NULL, 0,
properties, &mappingCopy);
if (FAILED(hr)) {
- qWarning("%s: Could not create bitmap: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create bitmap: %#lx", __FUNCTION__, hr);
return QImage();
}
hr = mappingCopy->CopyFromBitmap(NULL, bitmap.Get(), NULL);
if (FAILED(hr)) {
- qWarning("%s: Could not copy from bitmap: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not copy from bitmap: %#lx", __FUNCTION__, hr);
return QImage();
}
D2D1_MAPPED_RECT mappedRect;
hr = mappingCopy->Map(D2D1_MAP_OPTIONS_READ, &mappedRect);
if (FAILED(hr)) {
- qWarning("%s: Could not map: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not map: %#lx", __FUNCTION__, hr);
return QImage();
}
return QImage(static_cast<const uchar *>(mappedRect.bits),
- size.width, size.height, mappedRect.pitch,
+ int(size.width), int(size.height), int(mappedRect.pitch),
QImage::Format_ARGB32_Premultiplied).copy(rect);
}
@@ -197,7 +198,7 @@ QSize QWindowsDirect2DBitmap::size() const
Q_D(const QWindowsDirect2DBitmap);
D2D1_SIZE_U size = d->bitmap->GetPixelSize();
- return QSize(size.width, size.height);
+ return QSize(int(size.width), int(size.height));
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp
index fb5bb43d17..a5817016e6 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.cpp
@@ -84,7 +84,7 @@ public:
}
if (FAILED(hr)) {
- qWarning("%s: Could not create Direct3D Device: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create Direct3D Device: %#lx", __FUNCTION__, hr);
return false;
}
@@ -93,7 +93,7 @@ public:
hr = d3dDevice.As(&dxgiDevice);
if (FAILED(hr)) {
- qWarning("%s: DXGI Device interface query failed on D3D Device: %#x", __FUNCTION__, hr);
+ qWarning("%s: DXGI Device interface query failed on D3D Device: %#lx", __FUNCTION__, hr);
return false;
}
@@ -102,13 +102,13 @@ public:
hr = dxgiDevice->GetAdapter(&dxgiAdapter);
if (FAILED(hr)) {
- qWarning("%s: Failed to probe DXGI Device for parent DXGI Adapter: %#x", __FUNCTION__, hr);
+ qWarning("%s: Failed to probe DXGI Device for parent DXGI Adapter: %#lx", __FUNCTION__, hr);
return false;
}
hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory));
if (FAILED(hr)) {
- qWarning("%s: Failed to probe DXGI Adapter for parent DXGI Factory: %#x", __FUNCTION__, hr);
+ qWarning("%s: Failed to probe DXGI Adapter for parent DXGI Factory: %#lx", __FUNCTION__, hr);
return false;
}
@@ -121,26 +121,26 @@ public:
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, options, d2dFactory.GetAddressOf());
if (FAILED(hr)) {
- qWarning("%s: Could not create Direct2D Factory: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create Direct2D Factory: %#lx", __FUNCTION__, hr);
return false;
}
hr = d2dFactory->CreateDevice(dxgiDevice.Get(), &d2dDevice);
if (FAILED(hr)) {
- qWarning("%s: Could not create D2D Device: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create D2D Device: %#lx", __FUNCTION__, hr);
return false;
}
hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
static_cast<IUnknown **>(&directWriteFactory));
if (FAILED(hr)) {
- qWarning("%s: Could not create DirectWrite factory: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create DirectWrite factory: %#lx", __FUNCTION__, hr);
return false;
}
hr = directWriteFactory->GetGdiInterop(&directWriteGdiInterop);
if (FAILED(hr)) {
- qWarning("%s: Could not create DirectWrite GDI Interop: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create DirectWrite GDI Interop: %#lx", __FUNCTION__, hr);
return false;
}
@@ -161,7 +161,7 @@ QWindowsDirect2DContext::QWindowsDirect2DContext()
{
}
-QWindowsDirect2DContext::~QWindowsDirect2DContext() {}
+QWindowsDirect2DContext::~QWindowsDirect2DContext() = default;
bool QWindowsDirect2DContext::init()
{
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h
index a3478d2d4e..0d42c65964 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dcontext.h
@@ -59,7 +59,7 @@ class QWindowsDirect2DContext
public:
QWindowsDirect2DContext();
- virtual ~QWindowsDirect2DContext();
+ ~QWindowsDirect2DContext();
bool init();
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp
index 30238217dd..8a34f6974f 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp
@@ -51,14 +51,13 @@ class QWindowsDirect2DDeviceContextPrivate {
public:
QWindowsDirect2DDeviceContextPrivate(ID2D1DeviceContext *dc)
: deviceContext(dc)
- , refCount(0)
{
if (!dc) {
HRESULT hr = QWindowsDirect2DContext::instance()->d2dDevice()->CreateDeviceContext(
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
&deviceContext);
if (Q_UNLIKELY(FAILED(hr)))
- qFatal("%s: Couldn't create Direct2D Device Context: %#x", __FUNCTION__, hr);
+ qFatal("%s: Couldn't create Direct2D Device Context: %#lx", __FUNCTION__, hr);
}
Q_ASSERT(deviceContext);
@@ -98,7 +97,7 @@ public:
}
ComPtr<ID2D1DeviceContext> deviceContext;
- int refCount;
+ int refCount = 0;
};
QWindowsDirect2DDeviceContext::QWindowsDirect2DDeviceContext(ID2D1DeviceContext *dc)
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp
index da4a4e6ce6..ea51135583 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp
@@ -76,12 +76,7 @@ public:
class Direct2DVersion
{
private:
- Direct2DVersion()
- : partOne(0)
- , partTwo(0)
- , partThree(0)
- , partFour(0)
- {}
+ Direct2DVersion() = default;
Direct2DVersion(int one, int two, int three, int four)
: partOne(one)
@@ -108,13 +103,14 @@ public:
if (_tcscat_s(filename, bufSize, __TEXT("\\d2d1.dll")) == 0) {
DWORD versionInfoSize = GetFileVersionInfoSize(filename, NULL);
if (versionInfoSize) {
- QVarLengthArray<BYTE> info(versionInfoSize);
- if (GetFileVersionInfo(filename, NULL, versionInfoSize, info.data())) {
+ QVarLengthArray<BYTE> info(static_cast<int>(versionInfoSize));
+ if (GetFileVersionInfo(filename, 0, versionInfoSize, info.data())) {
UINT size;
DWORD *fi;
- if (VerQueryValue(info.constData(), __TEXT("\\"), (LPVOID *) &fi, &size) && size) {
- VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *) fi;
+ if (VerQueryValue(info.constData(), __TEXT("\\"),
+ reinterpret_cast<void **>(&fi), &size) && size) {
+ const VS_FIXEDFILEINFO *verInfo = reinterpret_cast<const VS_FIXEDFILEINFO *>(fi);
return Direct2DVersion(HIWORD(verInfo->dwFileVersionMS),
LOWORD(verInfo->dwFileVersionMS),
HIWORD(verInfo->dwFileVersionLS),
@@ -171,7 +167,10 @@ public:
return a - b;
}
- int partOne, partTwo, partThree, partFour;
+ int partOne = 0;
+ int partTwo = 0;
+ int partThree = 0;
+ int partFour = 0;
};
QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::create(const QStringList &paramList)
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp
index 29b01391e2..3c86168a74 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp
@@ -93,42 +93,33 @@ int QWindowsDirect2DPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric)
switch (metric) {
case QPaintDevice::PdmWidth:
- return d->bitmap->bitmap()->GetPixelSize().width;
- break;
+ return int(d->bitmap->bitmap()->GetPixelSize().width);
case QPaintDevice::PdmHeight:
- return d->bitmap->bitmap()->GetPixelSize().height;
- break;
+ return int(d->bitmap->bitmap()->GetPixelSize().height);
case QPaintDevice::PdmNumColors:
return INT_MAX;
- break;
case QPaintDevice::PdmDepth:
return 32;
- break;
case QPaintDevice::PdmDpiX:
case QPaintDevice::PdmPhysicalDpiX:
{
FLOAT x, y;
QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y);
- return x;
+ return qRound(x);
}
- break;
case QPaintDevice::PdmDpiY:
case QPaintDevice::PdmPhysicalDpiY:
{
FLOAT x, y;
QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&x, &y);
- return y;
+ return qRound(y);
}
- break;
case QPaintDevice::PdmDevicePixelRatio:
return 1;
- break;
case QPaintDevice::PdmDevicePixelRatioScaled:
- return 1 * devicePixelRatioFScale();
- break;
+ return qRound(devicePixelRatioFScale());
case QPaintDevice::PdmWidthMM:
case QPaintDevice::PdmHeightMM:
- return -1;
break;
}
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
index c4ff937a0b..164429ba30 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp
@@ -87,7 +87,7 @@ enum {
};
//Clipping flags
-enum {
+enum : unsigned {
SimpleSystemClip = 0x1
};
@@ -125,28 +125,30 @@ static inline D2D1_MATRIX_3X2_F transformFromLine(const QLineF &line, qreal penW
static void adjustLine(QPointF *p1, QPointF *p2);
static bool isLinePositivelySloped(const QPointF &p1, const QPointF &p2);
-class Direct2DPathGeometryWriter
+static QVector<D2D1_GRADIENT_STOP> qGradientStopsToD2DStops(const QGradientStops &qstops)
{
-public:
- Direct2DPathGeometryWriter()
- : m_inFigure(false)
- , m_roundCoordinates(false)
- , m_adjustPositivelySlopedLines(false)
- {
-
+ QVector<D2D1_GRADIENT_STOP> stops(qstops.count());
+ for (int i = 0, count = stops.size(); i < count; ++i) {
+ stops[i].position = FLOAT(qstops.at(i).first);
+ stops[i].color = to_d2d_color_f(qstops.at(i).second);
}
+ return stops;
+}
+class Direct2DPathGeometryWriter
+{
+public:
bool begin()
{
HRESULT hr = factory()->CreatePathGeometry(&m_geometry);
if (FAILED(hr)) {
- qWarning("%s: Could not create path geometry: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create path geometry: %#lx", __FUNCTION__, hr);
return false;
}
hr = m_geometry->Open(&m_sink);
if (FAILED(hr)) {
- qWarning("%s: Could not create geometry sink: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create geometry sink: %#lx", __FUNCTION__, hr);
return false;
}
@@ -239,9 +241,9 @@ private:
ComPtr<ID2D1PathGeometry1> m_geometry;
ComPtr<ID2D1GeometrySink> m_sink;
- bool m_inFigure;
- bool m_roundCoordinates;
- bool m_adjustPositivelySlopedLines;
+ bool m_inFigure = false;
+ bool m_roundCoordinates = false;
+ bool m_adjustPositivelySlopedLines = false;
QPointF m_previousPoint;
};
@@ -262,7 +264,6 @@ class QWindowsDirect2DPaintEnginePrivate : public QPaintEngineExPrivate
public:
QWindowsDirect2DPaintEnginePrivate(QWindowsDirect2DBitmap *bm, QWindowsDirect2DPaintEngine::Flags flags)
: bitmap(bm)
- , clipFlags(0)
, flags(flags)
{
pen.reset();
@@ -274,7 +275,7 @@ public:
QWindowsDirect2DBitmap *bitmap;
QImage fallbackImage;
- unsigned int clipFlags;
+ unsigned int clipFlags = 0;
QStack<ClipType> pushedClips;
QWindowsDirect2DPaintEngine::Flags flags;
@@ -348,9 +349,9 @@ public:
void updateOpacity(qreal opacity)
{
if (brush.brush)
- brush.brush->SetOpacity(opacity);
+ brush.brush->SetOpacity(FLOAT(opacity));
if (pen.brush)
- pen.brush->SetOpacity(opacity);
+ pen.brush->SetOpacity(FLOAT(opacity));
}
void pushClip(const QVectorPath &path)
@@ -459,7 +460,7 @@ public:
brush.qbrush = newBrush;
if (brush.brush) {
- brush.brush->SetOpacity(q->state()->opacity);
+ brush.brush->SetOpacity(FLOAT(q->state()->opacity));
applyBrushOrigin(currentBrushOrigin);
}
}
@@ -477,8 +478,8 @@ public:
brush.brush->GetTransform(&transform);
brush.brush->SetTransform(*(D2D1::Matrix3x2F::ReinterpretBaseType(&transform))
- * D2D1::Matrix3x2F::Translation(-currentBrushOrigin.x(),
- -currentBrushOrigin.y()));
+ * D2D1::Matrix3x2F::Translation(FLOAT(-currentBrushOrigin.x()),
+ FLOAT(-currentBrushOrigin.y())));
}
}
@@ -489,7 +490,7 @@ public:
brush.brush->GetTransform(&transform);
brush.brush->SetTransform(*(D2D1::Matrix3x2F::ReinterpretBaseType(&transform))
- * D2D1::Matrix3x2F::Translation(origin.x(), origin.y()));
+ * D2D1::Matrix3x2F::Translation(FLOAT(origin.x()), FLOAT(origin.y())));
}
currentBrushOrigin = origin;
@@ -511,7 +512,7 @@ public:
if (!pen.brush)
return;
- pen.brush->SetOpacity(q->state()->opacity);
+ pen.brush->SetOpacity(FLOAT(q->state()->opacity));
D2D1_STROKE_STYLE_PROPERTIES1 props = {};
@@ -541,8 +542,8 @@ public:
break;
}
- props.miterLimit = newPen.miterLimit() * qreal(2.0); // D2D and Qt miter specs differ
- props.dashOffset = newPen.dashOffset();
+ props.miterLimit = FLOAT(newPen.miterLimit() * qreal(2.0)); // D2D and Qt miter specs differ
+ props.dashOffset = FLOAT(newPen.dashOffset());
if (newPen.widthF() == 0)
props.transformType = D2D1_STROKE_TRANSFORM_TYPE_HAIRLINE;
@@ -577,24 +578,24 @@ public:
qreal penWidth = pen.qpen.widthF();
qreal brushWidth = 0;
for (int i = 0; i < dashes.size(); i++) {
- converted[i] = dashes[i];
+ converted[i] = FLOAT(dashes[i]);
brushWidth += penWidth * dashes[i];
}
- hr = factory()->CreateStrokeStyle(props, converted.constData(), converted.size(), &pen.strokeStyle);
+ hr = factory()->CreateStrokeStyle(props, converted.constData(), UINT32(converted.size()), &pen.strokeStyle);
// Create a combined brush/dash pattern for optimized line drawing
QWindowsDirect2DBitmap bitmap;
- bitmap.resize(ceil(brushWidth), ceil(penWidth));
+ bitmap.resize(int(ceil(brushWidth)), int(ceil(penWidth)));
bitmap.deviceContext()->begin();
bitmap.deviceContext()->get()->SetAntialiasMode(antialiasMode());
bitmap.deviceContext()->get()->SetTransform(D2D1::IdentityMatrix());
bitmap.deviceContext()->get()->Clear();
const qreal offsetX = (qreal(bitmap.size().width()) - brushWidth) / 2;
const qreal offsetY = qreal(bitmap.size().height()) / 2;
- bitmap.deviceContext()->get()->DrawLine(D2D1::Point2F(offsetX, offsetY),
- D2D1::Point2F(brushWidth, offsetY),
- pen.brush.Get(), penWidth, pen.strokeStyle.Get());
+ bitmap.deviceContext()->get()->DrawLine(D2D1::Point2F(FLOAT(offsetX), FLOAT(offsetY)),
+ D2D1::Point2F(FLOAT(brushWidth), FLOAT(offsetY)),
+ pen.brush.Get(), FLOAT(penWidth), pen.strokeStyle.Get());
bitmap.deviceContext()->end();
D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrushProperties = D2D1::BitmapBrushProperties1(
D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_CLAMP, D2D1_INTERPOLATION_MODE_LINEAR);
@@ -605,7 +606,7 @@ public:
}
if (FAILED(hr))
- qWarning("%s: Could not create stroke style: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create stroke style: %#lx", __FUNCTION__, hr);
}
ComPtr<ID2D1Brush> to_d2d_brush(const QBrush &newBrush, bool *needsEmulation)
@@ -627,13 +628,13 @@ public:
hr = dc()->CreateSolidColorBrush(to_d2d_color_f(newBrush.color()), &solid);
if (FAILED(hr)) {
- qWarning("%s: Could not create solid color brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create solid color brush: %#lx", __FUNCTION__, hr);
break;
}
hr = solid.As(&result);
if (FAILED(hr))
- qWarning("%s: Could not convert solid color brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not convert solid color brush: %#lx", __FUNCTION__, hr);
}
break;
@@ -673,13 +674,13 @@ public:
bitmapBrushProperties,
&bitmapBrush);
if (FAILED(hr)) {
- qWarning("%s: Could not create Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create Direct2D bitmap brush for Qt pattern brush: %#lx", __FUNCTION__, hr);
break;
}
hr = bitmapBrush.As(&result);
if (FAILED(hr))
- qWarning("%s: Could not convert Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not convert Direct2D bitmap brush for Qt pattern brush: %#lx", __FUNCTION__, hr);
}
break;
@@ -693,33 +694,29 @@ public:
D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES linearGradientBrushProperties;
ComPtr<ID2D1GradientStopCollection> gradientStopCollection;
- const QGradientStops &qstops = qlinear->stops();
- QVector<D2D1_GRADIENT_STOP> stops(qstops.count());
-
linearGradientBrushProperties.startPoint = to_d2d_point_2f(qlinear->start());
linearGradientBrushProperties.endPoint = to_d2d_point_2f(qlinear->finalStop());
- for (int i = 0; i < stops.size(); i++) {
- stops[i].position = qstops[i].first;
- stops[i].color = to_d2d_color_f(qstops[i].second);
- }
+ const QVector<D2D1_GRADIENT_STOP> stops = qGradientStopsToD2DStops(qlinear->stops());
- hr = dc()->CreateGradientStopCollection(stops.constData(), stops.size(), &gradientStopCollection);
+ hr = dc()->CreateGradientStopCollection(stops.constData(),
+ UINT32(stops.size()),
+ &gradientStopCollection);
if (FAILED(hr)) {
- qWarning("%s: Could not create gradient stop collection for linear gradient: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create gradient stop collection for linear gradient: %#lx", __FUNCTION__, hr);
break;
}
hr = dc()->CreateLinearGradientBrush(linearGradientBrushProperties, gradientStopCollection.Get(),
&linear);
if (FAILED(hr)) {
- qWarning("%s: Could not create Direct2D linear gradient brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create Direct2D linear gradient brush: %#lx", __FUNCTION__, hr);
break;
}
hr = linear.As(&result);
if (FAILED(hr)) {
- qWarning("%s: Could not convert Direct2D linear gradient brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not convert Direct2D linear gradient brush: %#lx", __FUNCTION__, hr);
break;
}
}
@@ -735,35 +732,29 @@ public:
D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES radialGradientBrushProperties;
ComPtr<ID2D1GradientStopCollection> gradientStopCollection;
- const QGradientStops &qstops = qradial->stops();
- QVector<D2D1_GRADIENT_STOP> stops(qstops.count());
-
radialGradientBrushProperties.center = to_d2d_point_2f(qradial->center());
radialGradientBrushProperties.gradientOriginOffset = to_d2d_point_2f(qradial->focalPoint() - qradial->center());
- radialGradientBrushProperties.radiusX = qradial->radius();
- radialGradientBrushProperties.radiusY = qradial->radius();
+ radialGradientBrushProperties.radiusX = FLOAT(qradial->radius());
+ radialGradientBrushProperties.radiusY = FLOAT(qradial->radius());
- for (int i = 0; i < stops.size(); i++) {
- stops[i].position = qstops[i].first;
- stops[i].color = to_d2d_color_f(qstops[i].second);
- }
+ const QVector<D2D1_GRADIENT_STOP> stops = qGradientStopsToD2DStops(qradial->stops());
hr = dc()->CreateGradientStopCollection(stops.constData(), stops.size(), &gradientStopCollection);
if (FAILED(hr)) {
- qWarning("%s: Could not create gradient stop collection for radial gradient: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create gradient stop collection for radial gradient: %#lx", __FUNCTION__, hr);
break;
}
hr = dc()->CreateRadialGradientBrush(radialGradientBrushProperties, gradientStopCollection.Get(),
&radial);
if (FAILED(hr)) {
- qWarning("%s: Could not create Direct2D radial gradient brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create Direct2D radial gradient brush: %#lx", __FUNCTION__, hr);
break;
}
radial.As(&result);
if (FAILED(hr)) {
- qWarning("%s: Could not convert Direct2D radial gradient brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not convert Direct2D radial gradient brush: %#lx", __FUNCTION__, hr);
break;
}
}
@@ -789,13 +780,13 @@ public:
&bitmapBrush);
if (FAILED(hr)) {
- qWarning("%s: Could not create texture brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create texture brush: %#lx", __FUNCTION__, hr);
break;
}
hr = bitmapBrush.As(&result);
if (FAILED(hr))
- qWarning("%s: Could not convert texture brush: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not convert texture brush: %#lx", __FUNCTION__, hr);
}
break;
}
@@ -958,7 +949,8 @@ public:
qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__);
return;
}
- dc()->DrawGeometry(geometry.Get(), pen.brush.Get(), pen.qpen.widthF(), pen.strokeStyle.Get());
+ dc()->DrawGeometry(geometry.Get(), pen.brush.Get(),
+ FLOAT(pen.qpen.widthF()), pen.strokeStyle.Get());
return;
}
@@ -998,7 +990,7 @@ public:
dashOffset = pen.dashLength - fmod(lineLength - dashOffset, pen.dashLength);
}
dc()->DrawLine(to_d2d_point_2f(p1), to_d2d_point_2f(p2),
- brush, pen.qpen.widthF(), NULL);
+ brush, FLOAT(pen.qpen.widthF()), NULL);
if (skipJoin)
continue;
@@ -1013,7 +1005,8 @@ public:
writer.lineTo(p1);
writer.lineTo(line.pointAt(patchSegment));
writer.close();
- dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(), pen.qpen.widthF(), pen.strokeStyle.Get());
+ dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(),
+ FLOAT(pen.qpen.widthF()), pen.strokeStyle.Get());
}
// Record the start position of the next joint
jointStart = line.pointAt(1 - patchSegment);
@@ -1025,7 +1018,8 @@ public:
writer.lineTo(p2);
writer.lineTo(QLineF(p2, QPointF(points[2], points[3])).pointAt(patchSegment));
writer.close();
- dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(), pen.qpen.widthF(), pen.strokeStyle.Get());
+ dc()->DrawGeometry(writer.geometry().Get(), pen.brush.Get(),
+ FLOAT(pen.qpen.widthF()), pen.strokeStyle.Get());
}
}
}
@@ -1045,20 +1039,20 @@ public:
const QString nameSubstitute = QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString();
if (nameSubstitute != familyName) {
const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1);
- memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t));
+ memcpy(lf.lfFaceName, nameSubstitute.utf16(), size_t(nameSubstituteLength) * sizeof(wchar_t));
lf.lfFaceName[nameSubstituteLength] = 0;
}
ComPtr<IDWriteFont> dwriteFont;
HRESULT hr = QWindowsDirect2DContext::instance()->dwriteGdiInterop()->CreateFontFromLOGFONT(&lf, &dwriteFont);
if (FAILED(hr)) {
- qDebug("%s: CreateFontFromLOGFONT failed: %#x", __FUNCTION__, hr);
+ qDebug("%s: CreateFontFromLOGFONT failed: %#lx", __FUNCTION__, hr);
return fontFace;
}
hr = dwriteFont->CreateFontFace(&fontFace);
if (FAILED(hr)) {
- qDebug("%s: CreateFontFace failed: %#x", __FUNCTION__, hr);
+ qDebug("%s: CreateFontFace failed: %#lx", __FUNCTION__, hr);
return fontFace;
}
@@ -1332,7 +1326,8 @@ void QWindowsDirect2DPaintEngine::drawRects(const QRect *rects, int rectCount)
d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get());
if (d->pen.brush)
- d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(),
+ FLOAT(d->pen.qpen.widthF()), d->pen.strokeStyle.Get());
}
}
}
@@ -1359,7 +1354,8 @@ void QWindowsDirect2DPaintEngine::drawRects(const QRectF *rects, int rectCount)
d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get());
if (d->pen.brush)
- d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(),
+ FLOAT(d->pen.qpen.widthF()), d->pen.strokeStyle.Get());
}
}
}
@@ -1407,7 +1403,9 @@ void QWindowsDirect2DPaintEngine::drawEllipse(const QRectF &r)
d->dc()->FillEllipse(ellipse, d->brush.brush.Get());
if (d->pen.brush)
- d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(),
+ FLOAT(d->pen.qpen.widthF()),
+ d->pen.strokeStyle.Get());
}
}
@@ -1435,7 +1433,9 @@ void QWindowsDirect2DPaintEngine::drawEllipse(const QRect &r)
d->dc()->FillEllipse(ellipse, d->brush.brush.Get());
if (d->pen.brush)
- d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get());
+ d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(),
+ FLOAT(d->pen.qpen.widthF()),
+ d->pen.strokeStyle.Get());
}
}
@@ -1490,12 +1490,12 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r,
// Good, src bitmap != dst bitmap
if (sr.isValid())
d->dc()->DrawBitmap(bitmap->bitmap(),
- to_d2d_rect_f(r), state()->opacity,
+ to_d2d_rect_f(r), FLOAT(state()->opacity),
d->interpolationMode(),
to_d2d_rect_f(sr));
else
d->dc()->DrawBitmap(bitmap->bitmap(),
- to_d2d_rect_f(r), state()->opacity,
+ to_d2d_rect_f(r), FLOAT(state()->opacity),
d->interpolationMode());
} else {
// Ok, so the source pixmap and destination pixmap is the same.
@@ -1504,7 +1504,7 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r,
QWindowsDirect2DBitmap intermediate;
if (sr.isValid()) {
- bool r = intermediate.resize(sr.width(), sr.height());
+ bool r = intermediate.resize(int(sr.width()), int(sr.height()));
if (!r) {
qWarning("%s: Could not resize intermediate bitmap to source rect size", __FUNCTION__);
return;
@@ -1515,7 +1515,7 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r,
bitmap->bitmap(),
&d2d_sr);
if (FAILED(hr)) {
- qWarning("%s: Could not copy source rect area from source bitmap to intermediate bitmap: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not copy source rect area from source bitmap to intermediate bitmap: %#lx", __FUNCTION__, hr);
return;
}
} else {
@@ -1530,13 +1530,13 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r,
bitmap->bitmap(),
NULL);
if (FAILED(hr)) {
- qWarning("%s: Could not copy source bitmap to intermediate bitmap: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not copy source bitmap to intermediate bitmap: %#lx", __FUNCTION__, hr);
return;
}
}
d->dc()->DrawBitmap(intermediate.bitmap(),
- to_d2d_rect_f(r), state()->opacity,
+ to_d2d_rect_f(r), FLOAT(state()->opacity),
d->interpolationMode());
}
}
@@ -1573,9 +1573,9 @@ void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticText
// This looks a little funky because the positions are precalculated
glyphAdvances[i] = 0;
- glyphOffsets[i].advanceOffset = staticTextItem->glyphPositions[i].x.toReal();
+ glyphOffsets[i].advanceOffset = FLOAT(staticTextItem->glyphPositions[i].x.toReal());
// Qt and Direct2D seem to disagree on the direction of the ascender offset...
- glyphOffsets[i].ascenderOffset = staticTextItem->glyphPositions[i].y.toReal() * -1;
+ glyphOffsets[i].ascenderOffset = FLOAT(staticTextItem->glyphPositions[i].y.toReal() * -1);
}
d->drawGlyphRun(D2D1::Point2F(0, 0),
@@ -1618,11 +1618,11 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem
for (int i = 0; i < ti.glyphs.numGlyphs; i++) {
glyphIndices[i] = UINT16(ti.glyphs.glyphs[i]); // Imperfect conversion here
- glyphAdvances[i] = ti.glyphs.effectiveAdvance(i).toReal();
- glyphOffsets[i].advanceOffset = ti.glyphs.offsets[i].x.toReal();
+ glyphAdvances[i] = FLOAT(ti.glyphs.effectiveAdvance(i).toReal());
+ glyphOffsets[i].advanceOffset = FLOAT(ti.glyphs.offsets[i].x.toReal());
// XXX Should we negate the y value like for static text items?
- glyphOffsets[i].ascenderOffset = ti.glyphs.offsets[i].y.toReal();
+ glyphOffsets[i].ascenderOffset = FLOAT(ti.glyphs.offsets[i].y.toReal());
}
const bool rtl = (ti.flags & QTextItem::RightToLeft);
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp
index e7e2fa4ff7..65e056d312 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp
@@ -57,15 +57,12 @@ public:
: owns_bitmap(true)
, bitmap(new QWindowsDirect2DBitmap)
, device(new QWindowsDirect2DPaintDevice(bitmap, QInternal::Pixmap))
- , devicePixelRatio(1.0)
{}
QWindowsDirect2DPlatformPixmapPrivate(QWindowsDirect2DBitmap *bitmap,
QWindowsDirect2DPaintEngine::Flags flags)
- : owns_bitmap(false)
- , bitmap(bitmap)
+ : bitmap(bitmap)
, device(new QWindowsDirect2DPaintDevice(bitmap, QInternal::Pixmap, flags))
- , devicePixelRatio(1.0)
{}
~QWindowsDirect2DPlatformPixmapPrivate()
@@ -74,10 +71,10 @@ public:
delete bitmap;
}
- bool owns_bitmap;
+ bool owns_bitmap = false;
QWindowsDirect2DBitmap *bitmap;
QScopedPointer<QWindowsDirect2DPaintDevice> device;
- qreal devicePixelRatio;
+ qreal devicePixelRatio = 1.0;
};
static int qt_d2dpixmap_serno = 0;
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
index c750b02078..21294cfb15 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp
@@ -54,7 +54,6 @@ QT_BEGIN_NAMESPACE
QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWindowData &data)
: QWindowsWindow(window, data)
- , m_needsFullFlush(true)
, m_directRendering(!(data.flags & Qt::FramelessWindowHint && window->format().hasAlpha()))
{
if (window->type() == Qt::Desktop)
@@ -67,7 +66,7 @@ QWindowsDirect2DWindow::QWindowsDirect2DWindow(QWindow *window, const QWindowsWi
D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
m_deviceContext.GetAddressOf());
if (FAILED(hr))
- qWarning("%s: Couldn't create Direct2D Device context: %#x", __FUNCTION__, hr);
+ qWarning("%s: Couldn't create Direct2D Device context: %#lx", __FUNCTION__, hr);
}
QWindowsDirect2DWindow::~QWindowsDirect2DWindow()
@@ -100,12 +99,12 @@ void QWindowsDirect2DWindow::flush(QWindowsDirect2DBitmap *bitmap, const QRegion
HRESULT hr = m_swapChain->GetDesc1(&desc);
QRect geom = geometry();
- if ((FAILED(hr) || (desc.Width != geom.width()) || (desc.Height != geom.height()))) {
+ if (FAILED(hr) || (desc.Width != UINT(geom.width()) || (desc.Height != UINT(geom.height())))) {
resizeSwapChain(geom.size());
m_swapChain->GetDesc1(&desc);
}
- size.setWidth(desc.Width);
- size.setHeight(desc.Height);
+ size.setWidth(int(desc.Width));
+ size.setHeight(int(desc.Height));
} else {
size = geometry().size();
}
@@ -175,7 +174,7 @@ void QWindowsDirect2DWindow::present(const QRegion &region)
UPDATELAYEREDWINDOWINFO info = { sizeof(UPDATELAYEREDWINDOWINFO), NULL,
&ptDst, &size, hdc, &ptSrc, 0, &blend, ULW_ALPHA, &dirty };
if (!UpdateLayeredWindowIndirect(handle(), &info))
- qErrnoWarning(GetLastError(), "Failed to update the layered window");
+ qErrnoWarning(int(GetLastError()), "Failed to update the layered window");
hr = dxgiSurface->ReleaseDC(NULL);
if (FAILED(hr))
@@ -201,7 +200,7 @@ void QWindowsDirect2DWindow::setupSwapChain()
m_swapChain.ReleaseAndGetAddressOf()); // [out] IDXGISwapChain1 **ppSwapChain
if (FAILED(hr))
- qWarning("%s: Could not create swap chain: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create swap chain: %#lx", __FUNCTION__, hr);
m_needsFullFlush = true;
}
@@ -217,11 +216,11 @@ void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size)
return;
HRESULT hr = m_swapChain->ResizeBuffers(0,
- size.width(), size.height(),
+ UINT(size.width()), UINT(size.height()),
DXGI_FORMAT_UNKNOWN,
0);
if (FAILED(hr))
- qWarning("%s: Could not resize swap chain: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not resize swap chain: %#lx", __FUNCTION__, hr);
}
QSharedPointer<QWindowsDirect2DBitmap> QWindowsDirect2DWindow::copyBackBuffer() const
@@ -248,13 +247,13 @@ QSharedPointer<QWindowsDirect2DBitmap> QWindowsDirect2DWindow::copyBackBuffer()
HRESULT hr = m_deviceContext.Get()->CreateBitmap(size, NULL, 0, properties, &copy);
if (FAILED(hr)) {
- qWarning("%s: Could not create staging bitmap: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create staging bitmap: %#lx", __FUNCTION__, hr);
return null_result;
}
hr = copy.Get()->CopyFromBitmap(NULL, m_bitmap->bitmap(), NULL);
if (FAILED(hr)) {
- qWarning("%s: Could not copy from bitmap! %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not copy from bitmap! %#lx", __FUNCTION__, hr);
return null_result;
}
@@ -277,12 +276,12 @@ void QWindowsDirect2DWindow::setupBitmap()
if (m_directRendering) {
hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBufferSurface));
if (FAILED(hr)) {
- qWarning("%s: Could not query backbuffer for DXGI Surface: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not query backbuffer for DXGI Surface: %#lx", __FUNCTION__, hr);
return;
}
} else {
const QRect rect = geometry();
- CD3D11_TEXTURE2D_DESC backBufferDesc(DXGI_FORMAT_B8G8R8A8_UNORM, rect.width(), rect.height(), 1, 1);
+ CD3D11_TEXTURE2D_DESC backBufferDesc(DXGI_FORMAT_B8G8R8A8_UNORM, UINT(rect.width()), UINT(rect.height()), 1, 1);
backBufferDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
backBufferDesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
ComPtr<ID3D11Texture2D> backBufferTexture;
@@ -302,7 +301,7 @@ void QWindowsDirect2DWindow::setupBitmap()
ComPtr<ID2D1Bitmap1> backBufferBitmap;
hr = m_deviceContext->CreateBitmapFromDxgiSurface(backBufferSurface.Get(), NULL, backBufferBitmap.GetAddressOf());
if (FAILED(hr)) {
- qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#x", __FUNCTION__, hr);
+ qWarning("%s: Could not create Direct2D Bitmap from DXGI Surface: %#lx", __FUNCTION__, hr);
return;
}
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h
index 2da0e5f507..156d4660d1 100644
--- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h
+++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.h
@@ -74,8 +74,8 @@ private:
Microsoft::WRL::ComPtr<ID2D1DeviceContext> m_deviceContext;
QScopedPointer<QWindowsDirect2DBitmap> m_bitmap;
QScopedPointer<QPixmap> m_pixmap;
- bool m_needsFullFlush;
- bool m_directRendering;
+ bool m_needsFullFlush = true;
+ bool m_directRendering = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/api.pri b/src/plugins/platforms/eglfs/api/api.pri
index 0ea65bd1ff..a6d81016b6 100644
--- a/src/plugins/platforms/eglfs/api/api.pri
+++ b/src/plugins/platforms/eglfs/api/api.pri
@@ -1,21 +1,26 @@
SOURCES += $$PWD/qeglfswindow.cpp \
$$PWD/qeglfsscreen.cpp \
- $$PWD/qeglfscursor.cpp \
$$PWD/qeglfshooks.cpp \
$$PWD/qeglfsdeviceintegration.cpp \
$$PWD/qeglfsintegration.cpp \
- $$PWD/qeglfscontext.cpp \
$$PWD/qeglfsoffscreenwindow.cpp
HEADERS += $$PWD/qeglfswindow_p.h \
$$PWD/qeglfsscreen_p.h \
- $$PWD/qeglfscursor_p.h \
$$PWD/qeglfshooks_p.h \
$$PWD/qeglfsdeviceintegration_p.h \
$$PWD/qeglfsintegration_p.h \
- $$PWD/qeglfscontext_p.h \
$$PWD/qeglfsoffscreenwindow_p.h \
$$PWD/qeglfsglobal_p.h
+qtConfig(opengl) {
+ SOURCES += \
+ $$PWD/qeglfscursor.cpp \
+ $$PWD/qeglfscontext.cpp
+ HEADERS += \
+ $$PWD/qeglfscursor_p.h \
+ $$PWD/qeglfscontext_p.h
+}
+
INCLUDEPATH += $$PWD
diff --git a/src/plugins/platforms/eglfs/api/qeglfscontext_p.h b/src/plugins/platforms/eglfs/api/qeglfscontext_p.h
index ab5bf99c3c..96f7f01381 100644
--- a/src/plugins/platforms/eglfs/api/qeglfscontext_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfscontext_p.h
@@ -62,11 +62,11 @@ class Q_EGLFS_EXPORT QEglFSContext : public QEGLPlatformContext
public:
QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display,
EGLConfig *config, const QVariant &nativeHandle);
- EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) Q_DECL_OVERRIDE;
- EGLSurface createTemporaryOffscreenSurface() Q_DECL_OVERRIDE;
- void destroyTemporaryOffscreenSurface(EGLSurface surface) Q_DECL_OVERRIDE;
- void runGLChecks() Q_DECL_OVERRIDE;
- void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE;
+ EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override;
+ EGLSurface createTemporaryOffscreenSurface() override;
+ void destroyTemporaryOffscreenSurface(EGLSurface surface) override;
+ void runGLChecks() override;
+ void swapBuffers(QPlatformSurface *surface) override;
private:
EGLNativeWindowType m_tempWindow;
diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
index 2b54251a06..19a0e03212 100644
--- a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
@@ -146,8 +146,8 @@ void QEglFSCursor::createShaderPrograms()
GraphicsContextData &gfx(m_gfx[QOpenGLContext::currentContext()]);
gfx.program = new QOpenGLShaderProgram;
- gfx.program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
- gfx.program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
+ gfx.program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
+ gfx.program->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
gfx.program->bindAttributeLocation("vertexCoordEntry", 0);
gfx.program->bindAttributeLocation("textureCoordEntry", 1);
gfx.program->link();
diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
index bf6dbc8a21..aaeb83cb99 100644
--- a/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfscursor_p.h
@@ -79,7 +79,10 @@ private:
QEglFSCursor *m_cursor;
};
-class Q_EGLFS_EXPORT QEglFSCursor : public QPlatformCursor, protected QOpenGLFunctions
+#if QT_CONFIG(opengl)
+
+class Q_EGLFS_EXPORT QEglFSCursor : public QPlatformCursor
+ , protected QOpenGLFunctions
{
Q_OBJECT
public:
@@ -87,11 +90,11 @@ public:
~QEglFSCursor();
#ifndef QT_NO_CURSOR
- void changeCursor(QCursor *cursor, QWindow *widget) Q_DECL_OVERRIDE;
+ void changeCursor(QCursor *cursor, QWindow *widget) override;
#endif
- void pointerEvent(const QMouseEvent &event) Q_DECL_OVERRIDE;
- QPoint pos() const Q_DECL_OVERRIDE;
- void setPos(const QPoint &pos) Q_DECL_OVERRIDE;
+ void pointerEvent(const QMouseEvent &event) override;
+ QPoint pos() const override;
+ void setPos(const QPoint &pos) override;
QRect cursorRect() const;
void paintOnScreen();
@@ -100,7 +103,7 @@ public:
void updateMouseStatus();
private:
- bool event(QEvent *e) Q_DECL_OVERRIDE;
+ bool event(QEvent *e) override;
#ifndef QT_NO_CURSOR
bool setCurrentCursor(QCursor *cursor);
#endif
@@ -153,6 +156,7 @@ private:
};
QHash<QOpenGLContext *, GraphicsContextData> m_gfx;
};
+#endif // QT_CONFIG(opengl)
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
index 3558b929fa..e411ea55e9 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
@@ -39,7 +39,9 @@
#include "qeglfsdeviceintegration_p.h"
#include "qeglfsintegration_p.h"
-#include "qeglfscursor_p.h"
+#ifndef QT_NO_OPENGL
+# include "qeglfscursor_p.h"
+#endif
#include "qeglfswindow_p.h"
#include "qeglfsscreen_p.h"
#include "qeglfshooks_p.h"
@@ -312,7 +314,12 @@ bool QEglFSDeviceIntegration::hasCapability(QPlatformIntegration::Capability cap
QPlatformCursor *QEglFSDeviceIntegration::createCursor(QPlatformScreen *screen) const
{
+#ifndef QT_NO_OPENGL
return new QEglFSCursor(static_cast<QEglFSScreen *>(screen));
+#else
+ Q_UNUSED(screen);
+ return nullptr;
+#endif
}
void QEglFSDeviceIntegration::waitForVSync(QPlatformSurface *surface) const
@@ -355,7 +362,7 @@ EGLConfig QEglFSDeviceIntegration::chooseConfig(EGLDisplay display, const QSurfa
public:
Chooser(EGLDisplay display)
: QEglConfigChooser(display) { }
- bool filterConfig(EGLConfig config) const Q_DECL_OVERRIDE {
+ bool filterConfig(EGLConfig config) const override {
return qt_egl_device_integration()->filterConfig(display(), config)
&& QEglConfigChooser::filterConfig(config);
}
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
index 8cf6660c44..73110dba61 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
@@ -42,9 +42,11 @@
#include <qpa/qplatformwindow.h>
#include <QtGui/QSurfaceFormat>
-#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
-#include <QtGui/QOffscreenSurface>
+#ifndef QT_NO_OPENGL
+# include <QtGui/QOpenGLContext>
+# include <QtGui/QOffscreenSurface>
+#endif
#include <QtGui/QWindow>
#include <QtCore/QLoggingCategory>
#include <qpa/qwindowsysteminterface.h>
@@ -53,20 +55,26 @@
#include "qeglfsintegration_p.h"
#include "qeglfswindow_p.h"
#include "qeglfshooks_p.h"
-#include "qeglfscontext_p.h"
+#ifndef QT_NO_OPENGL
+# include "qeglfscontext_p.h"
+# include "qeglfscursor_p.h"
+#endif
#include "qeglfsoffscreenwindow_p.h"
-#include "qeglfscursor_p.h"
#include <QtEglSupport/private/qeglconvenience_p.h>
-#include <QtEglSupport/private/qeglplatformcontext_p.h>
-#include <QtEglSupport/private/qeglpbuffer_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtEglSupport/private/qeglplatformcontext_p.h>
+# include <QtEglSupport/private/qeglpbuffer_p.h>
+#endif
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
#include <QtServiceSupport/private/qgenericunixservices_p.h>
#include <QtThemeSupport/private/qgenericunixthemes_p.h>
#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
#include <QtFbSupport/private/qfbvthandler_p.h>
-#include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h>
+#endif
#include <QtPlatformHeaders/QEGLNativeContext>
@@ -108,9 +116,9 @@ QEglFSIntegration::QEglFSIntegration()
initResources();
}
-void QEglFSIntegration::addScreen(QPlatformScreen *screen)
+void QEglFSIntegration::addScreen(QPlatformScreen *screen, bool isPrimary)
{
- screenAdded(screen);
+ screenAdded(screen, isPrimary);
}
void QEglFSIntegration::removeScreen(QPlatformScreen *screen)
@@ -179,11 +187,15 @@ QPlatformTheme *QEglFSIntegration::createPlatformTheme(const QString &name) cons
QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *window) const
{
+#ifndef QT_NO_OPENGL
QOpenGLCompositorBackingStore *bs = new QOpenGLCompositorBackingStore(window);
if (!window->handle())
window->create();
static_cast<QEglFSWindow *>(window->handle())->setBackingStore(bs);
return bs;
+#else
+ return nullptr;
+#endif
}
QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
@@ -191,11 +203,15 @@ QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
QEglFSWindow *w = qt_egl_device_integration()->createWindow(window);
w->create();
- if (window->type() != Qt::ToolTip)
+
+ // Activate only the window for the primary screen to make input work
+ if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen())
w->requestActivateWindow();
+
return w;
}
+#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
EGLDisplay dpy = context->screen() ? static_cast<QEglFSScreen *>(context->screen()->handle())->display() : display();
@@ -230,6 +246,7 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf
}
// Never return null. Multiple QWindows are not supported by this plugin.
}
+#endif // QT_NO_OPENGL
bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
@@ -239,10 +256,16 @@ bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) cons
switch (cap) {
case ThreadedPixmaps: return true;
+#ifndef QT_NO_OPENGL
case OpenGL: return true;
case ThreadedOpenGL: return true;
- case WindowManagement: return false;
case RasterGLSurface: return true;
+#else
+ case OpenGL: return false;
+ case ThreadedOpenGL: return false;
+ case RasterGLSurface: return false;
+#endif
+ case WindowManagement: return false;
default: return QPlatformIntegration::hasCapability(cap);
}
}
@@ -259,7 +282,8 @@ enum ResourceType {
EglConfig,
NativeDisplay,
XlibDisplay,
- WaylandDisplay
+ WaylandDisplay,
+ EglSurface
};
static int resourceType(const QByteArray &key)
@@ -271,7 +295,8 @@ static int resourceType(const QByteArray &key)
QByteArrayLiteral("eglconfig"),
QByteArrayLiteral("nativedisplay"),
QByteArrayLiteral("display"),
- QByteArrayLiteral("server_wl_display")
+ QByteArrayLiteral("server_wl_display"),
+ QByteArrayLiteral("eglsurface")
};
const QByteArray *end = names + sizeof(names) / sizeof(names[0]);
const QByteArray *result = std::find(names, end, key);
@@ -333,6 +358,10 @@ void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWi
if (window && window->handle())
result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->eglWindow());
break;
+ case EglSurface:
+ if (window && window->handle())
+ result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->surface());
+ break;
default:
break;
}
@@ -340,6 +369,7 @@ void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWi
return result;
}
+#ifndef QT_NO_OPENGL
void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
{
void *result = 0;
@@ -374,13 +404,17 @@ static void *eglContextForContext(QOpenGLContext *context)
return handle->eglContext();
}
+#endif
QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource)
{
+#ifndef QT_NO_OPENGL
QByteArray lowerCaseResource = resource.toLower();
if (lowerCaseResource == "get_egl_context")
return NativeResourceForContextFunction(eglContextForContext);
-
+#else
+ Q_UNUSED(resource);
+#endif
return 0;
}
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
index 1a3a44d441..c288876678 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
@@ -69,38 +69,41 @@ class Q_EGLFS_EXPORT QEglFSIntegration : public QPlatformIntegration, public QPl
public:
QEglFSIntegration();
- void initialize() Q_DECL_OVERRIDE;
- void destroy() Q_DECL_OVERRIDE;
+ void initialize() override;
+ void destroy() override;
EGLDisplay display() const { return m_display; }
- QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE;
- QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE;
- QPlatformServices *services() const Q_DECL_OVERRIDE;
- QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE { return m_inputContext; }
- QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE;
+ QAbstractEventDispatcher *createEventDispatcher() const override;
+ QPlatformFontDatabase *fontDatabase() const override;
+ QPlatformServices *services() const override;
+ QPlatformInputContext *inputContext() const override { return m_inputContext; }
+ QPlatformTheme *createPlatformTheme(const QString &name) const override;
- QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE;
- QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE;
- QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE;
- QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const Q_DECL_OVERRIDE;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
+#ifndef QT_NO_OPENGL
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+ QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
+#endif
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
- bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
-
- QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE;
+ QPlatformNativeInterface *nativeInterface() const override;
// QPlatformNativeInterface
- void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE;
- void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) Q_DECL_OVERRIDE;
- void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE;
- void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE;
- NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE;
+ void *nativeResourceForIntegration(const QByteArray &resource) override;
+ void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override;
+ void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override;
+#ifndef QT_NO_OPENGL
+ void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override;
+#endif
+ NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) override;
- QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE;
+ QFunctionPointer platformFunction(const QByteArray &function) const override;
QFbVtHandler *vtHandler() { return m_vtHandler.data(); }
- void addScreen(QPlatformScreen *screen);
+ void addScreen(QPlatformScreen *screen, bool isPrimary = false);
void removeScreen(QPlatformScreen *screen);
private:
diff --git a/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h b/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h
index ec483c64e2..9fdb81efdd 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsoffscreenwindow_p.h
@@ -62,8 +62,8 @@ public:
QEglFSOffscreenWindow(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface);
~QEglFSOffscreenWindow();
- QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; }
- bool isValid() const Q_DECL_OVERRIDE { return m_surface != EGL_NO_SURFACE; }
+ QSurfaceFormat format() const override { return m_format; }
+ bool isValid() const override { return m_surface != EGL_NO_SURFACE; }
private:
QSurfaceFormat m_format;
diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
index 5613179041..d5c22b3d37 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
@@ -41,7 +41,9 @@
#include <QtGui/qwindow.h>
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformcursor.h>
-#include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h>
+#endif
#include "qeglfsscreen_p.h"
#include "qeglfswindow_p.h"
@@ -60,7 +62,9 @@ QEglFSScreen::QEglFSScreen(EGLDisplay dpy)
QEglFSScreen::~QEglFSScreen()
{
delete m_cursor;
+#ifndef QT_NO_OPENGL
QOpenGLCompositor::destroy();
+#endif
}
QRect QEglFSScreen::geometry() const
@@ -145,6 +149,7 @@ void QEglFSScreen::setPrimarySurface(EGLSurface surface)
void QEglFSScreen::handleCursorMove(const QPoint &pos)
{
+#ifndef QT_NO_OPENGL
const QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
const QList<QOpenGLCompositorWindow *> windows = compositor->windows();
@@ -178,10 +183,12 @@ void QEglFSScreen::handleCursorMove(const QPoint &pos)
if (enter && leave)
QWindowSystemInterface::handleEnterLeaveEvent(enter, leave, enter->mapFromGlobal(pos), pos);
+#endif
}
QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) const
{
+#ifndef QT_NO_OPENGL
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
const QList<QOpenGLCompositorWindow *> windows = compositor->windows();
Q_ASSERT(!windows.isEmpty());
@@ -224,7 +231,7 @@ QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) c
return QPixmap::fromImage(img).copy(rect);
}
}
-
+#endif // QT_NO_OPENGL
return QPixmap();
}
diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
index 131e619e06..bea7b4c8ef 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen_p.h
@@ -67,22 +67,22 @@ public:
QEglFSScreen(EGLDisplay display);
~QEglFSScreen();
- QRect geometry() const Q_DECL_OVERRIDE;
+ QRect geometry() const override;
virtual QRect rawGeometry() const;
- int depth() const Q_DECL_OVERRIDE;
- QImage::Format format() const Q_DECL_OVERRIDE;
+ int depth() const override;
+ QImage::Format format() const override;
- QSizeF physicalSize() const Q_DECL_OVERRIDE;
- QDpi logicalDpi() const Q_DECL_OVERRIDE;
- qreal pixelDensity() const Q_DECL_OVERRIDE;
- Qt::ScreenOrientation nativeOrientation() const Q_DECL_OVERRIDE;
- Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE;
+ QSizeF physicalSize() const override;
+ QDpi logicalDpi() const override;
+ qreal pixelDensity() const override;
+ Qt::ScreenOrientation nativeOrientation() const override;
+ Qt::ScreenOrientation orientation() const override;
- QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
+ QPlatformCursor *cursor() const override;
- qreal refreshRate() const Q_DECL_OVERRIDE;
+ qreal refreshRate() const override;
- QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE;
+ QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override;
EGLSurface primarySurface() const { return m_surface; }
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
index 639fc56d2b..9b4732eab4 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
@@ -41,13 +41,17 @@
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
-#include <QtGui/private/qopenglcontext_p.h>
-#include <QtGui/QOpenGLContext>
+#ifndef QT_NO_OPENGL
+# include <QtGui/private/qopenglcontext_p.h>
+# include <QtGui/QOpenGLContext>
+# include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h>
+#endif
#include <QtEglSupport/private/qeglconvenience_p.h>
-#include <QtPlatformCompositorSupport/private/qopenglcompositorbackingstore_p.h>
#include "qeglfswindow_p.h"
-#include "qeglfscursor_p.h"
+#ifndef QT_NO_OPENGL
+# include "qeglfscursor_p.h"
+#endif
#include "qeglfshooks_p.h"
#include "qeglfsdeviceintegration_p.h"
@@ -55,7 +59,9 @@ QT_BEGIN_NAMESPACE
QEglFSWindow::QEglFSWindow(QWindow *w)
: QPlatformWindow(w),
+#ifndef QT_NO_OPENGL
m_backingStore(0),
+#endif
m_raster(false),
m_winId(0),
m_surface(EGL_NO_SURFACE),
@@ -107,6 +113,7 @@ void QEglFSWindow::create()
// raster windows will not have their own native window, surface and context. Instead,
// they will be composited onto the root window's surface.
QEglFSScreen *screen = this->screen();
+#ifndef QT_NO_OPENGL
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
if (screen->primarySurface() != EGL_NO_SURFACE) {
if (Q_UNLIKELY(!isRaster() || !compositor->targetWindow())) {
@@ -120,10 +127,10 @@ void QEglFSWindow::create()
m_format = compositor->targetWindow()->format();
return;
}
+#endif // QT_NO_OPENGL
m_flags |= HasNativeWindow;
setGeometry(QRect()); // will become fullscreen
- QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
resetSurface();
@@ -135,6 +142,7 @@ void QEglFSWindow::create()
screen->setPrimarySurface(m_surface);
+#ifndef QT_NO_OPENGL
if (isRaster()) {
QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance());
context->setShareContext(qt_gl_global_share_context());
@@ -153,16 +161,18 @@ void QEglFSWindow::create()
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
}
}
+#endif // QT_NO_OPENGL
}
void QEglFSWindow::destroy()
{
QEglFSScreen *screen = this->screen();
if (m_flags.testFlag(HasNativeWindow)) {
+#ifndef QT_NO_OPENGL
QEglFSCursor *cursor = qobject_cast<QEglFSCursor *>(screen->cursor());
if (cursor)
cursor->resetResources();
-
+#endif
if (screen->primarySurface() == m_surface)
screen->setPrimarySurface(EGL_NO_SURFACE);
@@ -170,7 +180,9 @@ void QEglFSWindow::destroy()
}
m_flags = 0;
+#ifndef QT_NO_OPENGL
QOpenGLCompositor::instance()->removeWindow(this);
+#endif
}
void QEglFSWindow::invalidateSurface()
@@ -197,6 +209,7 @@ void QEglFSWindow::resetSurface()
void QEglFSWindow::setVisible(bool visible)
{
+#ifndef QT_NO_OPENGL
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
QList<QOpenGLCompositorWindow *> windows = compositor->windows();
QWindow *wnd = window();
@@ -211,7 +224,9 @@ void QEglFSWindow::setVisible(bool visible)
windows.last()->sourceWindow()->requestActivate();
}
}
-
+#else
+ QWindow *wnd = window();
+#endif
QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size()));
if (visible)
@@ -227,11 +242,15 @@ void QEglFSWindow::setGeometry(const QRect &r)
else
rect = r;
+ const bool changed = rect != QPlatformWindow::geometry();
QPlatformWindow::setGeometry(rect);
// if we corrected the size, trigger a resize event
if (rect != r)
QWindowSystemInterface::handleGeometryChange(window(), rect, r);
+
+ if (changed)
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
}
QRect QEglFSWindow::geometry() const
@@ -247,9 +266,10 @@ QRect QEglFSWindow::geometry() const
void QEglFSWindow::requestActivateWindow()
{
+#ifndef QT_NO_OPENGL
if (window()->type() != Qt::Desktop)
QOpenGLCompositor::instance()->moveToTop(this);
-
+#endif
QWindow *wnd = window();
QWindowSystemInterface::handleWindowActivated(wnd);
QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size()));
@@ -259,13 +279,16 @@ void QEglFSWindow::raise()
{
QWindow *wnd = window();
if (wnd->type() != Qt::Desktop) {
+#ifndef QT_NO_OPENGL
QOpenGLCompositor::instance()->moveToTop(this);
+#endif
QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size()));
}
}
void QEglFSWindow::lower()
{
+#ifndef QT_NO_OPENGL
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
QList<QOpenGLCompositorWindow *> windows = compositor->windows();
if (window()->type() != Qt::Desktop && windows.count() > 1) {
@@ -276,6 +299,7 @@ void QEglFSWindow::lower()
QRect(QPoint(0, 0), windows.last()->sourceWindow()->geometry().size()));
}
}
+#endif
}
EGLSurface QEglFSWindow::surface() const
@@ -303,6 +327,7 @@ bool QEglFSWindow::isRaster() const
return m_raster || window()->surfaceType() == QSurface::RasterGLSurface;
}
+#ifndef QT_NO_OPENGL
QWindow *QEglFSWindow::sourceWindow() const
{
return window();
@@ -321,6 +346,7 @@ void QEglFSWindow::endCompositing()
if (m_backingStore)
m_backingStore->notifyComposited();
}
+#endif
WId QEglFSWindow::winId() const
{
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
index 0889f27ae3..6bda262523 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
@@ -56,14 +56,19 @@
#include "qeglfsscreen_p.h"
#include <qpa/qplatformwindow.h>
-#include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtPlatformCompositorSupport/private/qopenglcompositor_p.h>
+#endif
QT_BEGIN_NAMESPACE
class QOpenGLCompositorBackingStore;
class QPlatformTextureList;
-
+#ifndef QT_NO_OPENGL
class Q_EGLFS_EXPORT QEglFSWindow : public QPlatformWindow, public QOpenGLCompositorWindow
+#else
+class Q_EGLFS_EXPORT QEglFSWindow : public QPlatformWindow
+#endif
{
public:
QEglFSWindow(QWindow *w);
@@ -72,21 +77,21 @@ public:
void create();
void destroy();
- void setGeometry(const QRect &) Q_DECL_OVERRIDE;
- QRect geometry() const Q_DECL_OVERRIDE;
- void setVisible(bool visible) Q_DECL_OVERRIDE;
- void requestActivateWindow() Q_DECL_OVERRIDE;
- void raise() Q_DECL_OVERRIDE;
- void lower() Q_DECL_OVERRIDE;
+ void setGeometry(const QRect &) override;
+ QRect geometry() const override;
+ void setVisible(bool visible) override;
+ void requestActivateWindow() override;
+ void raise() override;
+ void lower() override;
- void propagateSizeHints() Q_DECL_OVERRIDE { }
- void setMask(const QRegion &) Q_DECL_OVERRIDE { }
- bool setKeyboardGrabEnabled(bool) Q_DECL_OVERRIDE { return false; }
- bool setMouseGrabEnabled(bool) Q_DECL_OVERRIDE { return false; }
- void setOpacity(qreal) Q_DECL_OVERRIDE;
- WId winId() const Q_DECL_OVERRIDE;
+ void propagateSizeHints() override { }
+ void setMask(const QRegion &) override { }
+ bool setKeyboardGrabEnabled(bool) override { return false; }
+ bool setMouseGrabEnabled(bool) override { return false; }
+ void setOpacity(qreal) override;
+ WId winId() const override;
- QSurfaceFormat format() const Q_DECL_OVERRIDE;
+ QSurfaceFormat format() const override;
EGLNativeWindowType eglWindow() const;
EGLSurface surface() const;
@@ -94,19 +99,24 @@ public:
bool hasNativeWindow() const { return m_flags.testFlag(HasNativeWindow); }
- virtual void invalidateSurface() Q_DECL_OVERRIDE;
+ void invalidateSurface() override;
virtual void resetSurface();
+#ifndef QT_NO_OPENGL
QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; }
void setBackingStore(QOpenGLCompositorBackingStore *backingStore) { m_backingStore = backingStore; }
+#endif
bool isRaster() const;
-
- QWindow *sourceWindow() const Q_DECL_OVERRIDE;
- const QPlatformTextureList *textures() const Q_DECL_OVERRIDE;
- void endCompositing() Q_DECL_OVERRIDE;
+#ifndef QT_NO_OPENGL
+ QWindow *sourceWindow() const override;
+ const QPlatformTextureList *textures() const override;
+ void endCompositing() override;
+#endif
protected:
+#ifndef QT_NO_OPENGL
QOpenGLCompositorBackingStore *m_backingStore;
+#endif
bool m_raster;
WId m_winId;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
index f936d05927..6d759938b5 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
@@ -9,5 +9,7 @@ qtConfig(eglfs_mali): SUBDIRS += eglfs_mali
qtConfig(eglfs_viv): SUBDIRS += eglfs_viv
qtConfig(eglfs_viv_wl): SUBDIRS += eglfs_viv_wl
+qtConfig(opengl): SUBDIRS += eglfs_emu
+
eglfs_kms_egldevice.depends = eglfs_kms_support
eglfs_kms.depends = eglfs_kms_support
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h
index 5af628dedd..83bcc487af 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.h
@@ -47,13 +47,13 @@ QT_BEGIN_NAMESPACE
class QEglFSBrcmIntegration : public QEglFSDeviceIntegration
{
public:
- void platformInit() Q_DECL_OVERRIDE;
- void platformDestroy() Q_DECL_OVERRIDE;
- EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE;
- QSize screenSize() const Q_DECL_OVERRIDE;
- EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) Q_DECL_OVERRIDE;
- void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
- bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
+ void platformInit() override;
+ void platformDestroy() override;
+ EGLNativeDisplayType platformDisplay() const override;
+ QSize screenSize() const override;
+ EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override;
+ void destroyNativeWindow(EGLNativeWindowType window) override;
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp
index 80d7631931..fd6665e560 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmmain.cpp
@@ -48,7 +48,7 @@ class QEglFSBrcmIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_brcm.json")
public:
- QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSBrcmIntegration; }
+ QEglFSDeviceIntegration *create() override { return new QEglFSBrcmIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.json b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.json
new file mode 100644
index 0000000000..3aa38abd7a
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "eglfs_emu" ]
+}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro
new file mode 100644
index 0000000000..609f04e8a9
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/eglfs_emu.pro
@@ -0,0 +1,27 @@
+TARGET = qeglfs-emu-integration
+
+QT += core-private gui-private eglfsdeviceintegration-private
+
+INCLUDEPATH += $$PWD/../../api
+CONFIG += egl
+
+# Avoid X11 header collision
+DEFINES += QT_EGL_NO_X11
+
+OTHER_FILES += $$PWD/eglfs_emu.json
+
+PLUGIN_TYPE = egldeviceintegrations
+PLUGIN_CLASS_NAME = QEglFSEmulatorIntegrationPlugin
+load(qt_plugin)
+
+DISTFILES += \
+ eglfs_emu.json
+
+SOURCES += \
+ qeglfsemumain.cpp \
+ qeglfsemulatorintegration.cpp \
+ qeglfsemulatorscreen.cpp
+
+HEADERS += \
+ qeglfsemulatorintegration.h \
+ qeglfsemulatorscreen.h
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
new file mode 100644
index 0000000000..5e2708e958
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeglfsemulatorintegration.h"
+#include "qeglfsemulatorscreen.h"
+#include "private/qeglfsintegration_p.h"
+
+#include <private/qguiapplication_p.h>
+#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtEglSupport/private/qeglplatformcontext_p.h>
+
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonArray>
+#include <QtCore/QJsonParseError>
+
+QT_BEGIN_NAMESPACE
+
+QEglFSEmulatorIntegration::QEglFSEmulatorIntegration()
+{
+ // The Qt Emulator provides the ability to render to multiple displays
+ // In addition to the usual EGL and OpenGLESv2 API's, there are also a
+ // few additional API's that enable the client (this plugin) to query
+ // the available screens and their properties, as well as the ability
+ // to select which screen is the active render target (as this is
+ // usually handled in a platform specific way and not by EGL itself).
+
+ getDisplays = reinterpret_cast<PFNQGSGETDISPLAYSPROC>(eglGetProcAddress("qgsGetDisplays"));
+ setDisplay = reinterpret_cast<PFNQGSSETDISPLAYPROC>(eglGetProcAddress("qgsSetDisplay"));
+}
+
+void QEglFSEmulatorIntegration::platformInit()
+{
+}
+
+void QEglFSEmulatorIntegration::platformDestroy()
+{
+}
+
+bool QEglFSEmulatorIntegration::usesDefaultScreen()
+{
+ // This makes it possible to remotely query and then register our own set of screens
+ return false;
+}
+
+void QEglFSEmulatorIntegration::screenInit()
+{
+ QEglFSIntegration *integration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
+
+ // Use qgsGetDisplays() call to retrieve the available screens from the Emulator
+ if (getDisplays) {
+ QByteArray displaysInfo = getDisplays();
+ QJsonParseError error;
+ QJsonDocument displaysDocument = QJsonDocument::fromJson(displaysInfo, &error);
+ if (error.error == QJsonParseError::NoError) {
+ // Document should be an array of screen objects
+ if (displaysDocument.isArray()){
+ QJsonArray screenArray = displaysDocument.array();
+ for (auto screenValue : screenArray) {
+ if (screenValue.isObject())
+ integration->addScreen(new QEglFSEmulatorScreen(screenValue.toObject()));
+ }
+ }
+ } else {
+ qWarning() << "eglfs_emu: Failed to parse display info JSON with error: " << error.errorString()
+ << " at offset " << error.offset << " : " << displaysInfo;
+
+ }
+ } else {
+ qFatal("EGL library doesn't support Emulator extensions");
+ }
+}
+
+bool QEglFSEmulatorIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case QPlatformIntegration::ThreadedPixmaps:
+ case QPlatformIntegration::OpenGL:
+ case QPlatformIntegration::ThreadedOpenGL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+EGLNativeWindowType QEglFSEmulatorIntegration::createNativeWindow(QPlatformWindow *platformWindow,
+ const QSize &size,
+ const QSurfaceFormat &format)
+{
+ Q_UNUSED(size);
+ Q_UNUSED(format);
+ QEglFSEmulatorScreen *screen = static_cast<QEglFSEmulatorScreen *>(platformWindow->screen());
+ if (screen && setDisplay) {
+ // Let the emulator know which screen the window surface is attached to
+ setDisplay(screen->id());
+ }
+ static QBasicAtomicInt uniqueWindowId = Q_BASIC_ATOMIC_INITIALIZER(0);
+ return EGLNativeWindowType(qintptr(1 + uniqueWindowId.fetchAndAddRelaxed(1)));
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h
new file mode 100644
index 0000000000..513a5063fb
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorintegration.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEGLFSEMULATORINTEGRATION_H
+#define QEGLFSEMULATORINTEGRATION_H
+
+#include "private/qeglfsdeviceintegration_p.h"
+
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QFunctionPointer>
+
+typedef const char *(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC) ();
+typedef void (EGLAPIENTRYP PFNQGSSETDISPLAYPROC) (uint screen);
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(qLcEglfsEmuDebug)
+
+class QEglFSEmulatorIntegration : public QEglFSDeviceIntegration
+{
+public:
+ QEglFSEmulatorIntegration();
+
+ void platformInit() override;
+ void platformDestroy() override;
+ bool usesDefaultScreen() override;
+ void screenInit() override;
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
+
+ PFNQGSGETDISPLAYSPROC getDisplays;
+ PFNQGSSETDISPLAYPROC setDisplay;
+
+ EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow, const QSize &size, const QSurfaceFormat &format) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSEMULATORINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp
new file mode 100644
index 0000000000..4546088327
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.cpp
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeglfsemulatorscreen.h"
+
+QT_BEGIN_NAMESPACE
+
+QEglFSEmulatorScreen::QEglFSEmulatorScreen(const QJsonObject &screenDescription)
+ : QEglFSScreen(eglGetDisplay(EGL_DEFAULT_DISPLAY))
+ , m_id(0)
+{
+ initFromJsonObject(screenDescription);
+}
+
+QRect QEglFSEmulatorScreen::geometry() const
+{
+ return m_geometry;
+}
+
+QRect QEglFSEmulatorScreen::rawGeometry() const
+{
+ return QRect(QPoint(0, 0), m_geometry.size());
+}
+
+int QEglFSEmulatorScreen::depth() const
+{
+ return m_depth;
+}
+
+QImage::Format QEglFSEmulatorScreen::format() const
+{
+ return m_format;
+}
+
+QSizeF QEglFSEmulatorScreen::physicalSize() const
+{
+ return m_physicalSize;
+}
+
+QDpi QEglFSEmulatorScreen::logicalDpi() const
+{
+ const QSizeF ps = m_physicalSize;
+ const QSize s = m_geometry.size();
+
+ if (!ps.isEmpty() && !s.isEmpty())
+ return QDpi(25.4 * s.width() / ps.width(),
+ 25.4 * s.height() / ps.height());
+ else
+ return QDpi(100, 100);
+}
+
+qreal QEglFSEmulatorScreen::pixelDensity() const
+{
+ return m_pixelDensity;
+}
+
+qreal QEglFSEmulatorScreen::refreshRate() const
+{
+ return m_refreshRate;
+}
+
+Qt::ScreenOrientation QEglFSEmulatorScreen::nativeOrientation() const
+{
+ return m_nativeOrientation;
+}
+
+Qt::ScreenOrientation QEglFSEmulatorScreen::orientation() const
+{
+ return m_orientation;
+}
+
+uint QEglFSEmulatorScreen::id() const
+{
+ return m_id;
+}
+
+void QEglFSEmulatorScreen::initFromJsonObject(const QJsonObject &description)
+{
+ QJsonValue value;
+
+ value = description.value(QLatin1String("id"));
+ if (!value.isUndefined() && value.isDouble())
+ m_id = value.toInt();
+
+ value = description.value(QLatin1String("description"));
+ if (!value.isUndefined() && value.isString())
+ m_description = value.toString();
+
+ value = description.value(QLatin1String("geometry"));
+ if (!value.isUndefined() && value.isObject()) {
+ QJsonObject geometryObject = value.toObject();
+ value = geometryObject.value(QLatin1String("x"));
+ if (!value.isUndefined() && value.isDouble())
+ m_geometry.setX(value.toInt());
+ value = geometryObject.value(QLatin1String("y"));
+ if (!value.isUndefined() && value.isDouble())
+ m_geometry.setY(value.toInt());
+ value = geometryObject.value(QLatin1String("width"));
+ if (!value.isUndefined() && value.isDouble())
+ m_geometry.setWidth(value.toInt());
+ value = geometryObject.value(QLatin1String("height"));
+ if (!value.isUndefined() && value.isDouble())
+ m_geometry.setHeight(value.toInt());
+ }
+
+ value = description.value(QLatin1String("depth"));
+ if (!value.isUndefined() && value.isDouble())
+ m_depth = value.toInt();
+
+ value = description.value(QLatin1String("format"));
+ if (!value.isUndefined() && value.isDouble())
+ m_format = static_cast<QImage::Format>(value.toInt());
+
+ value = description.value(QLatin1String("physicalSize"));
+ if (!value.isUndefined() && value.isObject()) {
+ QJsonObject physicalSizeObject = value.toObject();
+ value = physicalSizeObject.value(QLatin1String("width"));
+ if (!value.isUndefined() && value.isDouble())
+ m_physicalSize.setWidth(value.toInt());
+ value = physicalSizeObject.value(QLatin1String("height"));
+ if (!value.isUndefined() && value.isDouble())
+ m_physicalSize.setHeight(value.toInt());
+ }
+
+ value = description.value(QLatin1String("pixelDensity"));
+ if (!value.isUndefined() && value.isDouble())
+ m_pixelDensity = value.toDouble();
+
+ value = description.value(QLatin1String("refreshRate"));
+ if (!value.isUndefined() && value.isDouble())
+ m_refreshRate = value.toDouble();
+
+ value = description.value(QLatin1String("nativeOrientation"));
+ if (!value.isUndefined() && value.isDouble())
+ m_nativeOrientation = static_cast<Qt::ScreenOrientation>(value.toInt());
+
+ value = description.value(QLatin1String("orientation"));
+ if (!value.isUndefined() && value.isDouble())
+ m_orientation = static_cast<Qt::ScreenOrientation>(value.toInt());
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h
new file mode 100644
index 0000000000..3e5113c9c2
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemulatorscreen.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEGLFSEMULATORSCREEN_H
+#define QEGLFSEMULATORSCREEN_H
+
+#include <QtCore/QJsonObject>
+
+#include "qeglfsemulatorintegration.h"
+#include "private/qeglfsscreen_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSEmulatorScreen : public QEglFSScreen
+{
+public:
+ QEglFSEmulatorScreen(const QJsonObject &screenDescription);
+
+ QRect geometry() const override;
+ QRect rawGeometry() const override;
+ int depth() const override;
+ QImage::Format format() const override;
+ QSizeF physicalSize() const override;
+ QDpi logicalDpi() const override;
+ qreal pixelDensity() const override;
+ qreal refreshRate() const override;
+ Qt::ScreenOrientation nativeOrientation() const override;
+ Qt::ScreenOrientation orientation() const override;
+
+ uint id() const;
+
+private:
+ void initFromJsonObject(const QJsonObject &description);
+
+ QString m_description;
+ QRect m_geometry;
+ int m_depth;
+ QImage::Format m_format;
+ QSizeF m_physicalSize;
+ float m_pixelDensity;
+ float m_refreshRate;
+ Qt::ScreenOrientation m_nativeOrientation;
+ Qt::ScreenOrientation m_orientation;
+ uint m_id;
+};
+
+QT_END_NAMESPACE
+
+#endif // QEGLFSEMULATORSCREEN_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp
new file mode 100644
index 0000000000..a9923851ef
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_emu/qeglfsemumain.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qeglfsdeviceintegration_p.h"
+#include "qeglfsemulatorintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSEmulatorIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_emu.json")
+
+public:
+ QEglFSDeviceIntegration *create() override { return new QEglFSEmulatorIntegration; }
+};
+
+QT_END_NAMESPACE
+
+#include "qeglfsemumain.moc"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
index 255db824b7..e522c0ee1b 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/eglfs_kms.pro
@@ -4,7 +4,7 @@ PLUGIN_TYPE = egldeviceintegrations
PLUGIN_CLASS_NAME = QEglFSKmsGbmIntegrationPlugin
load(qt_plugin)
-QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private
+QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private kms_support-private
INCLUDEPATH += $$PWD/../../api $$PWD/../eglfs_kms_support
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h
index de13a058cf..c96dd585d3 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.h
@@ -76,12 +76,12 @@ public:
~QEglFSKmsGbmCursor();
// input methods
- void pointerEvent(const QMouseEvent & event) Q_DECL_OVERRIDE;
+ void pointerEvent(const QMouseEvent & event) override;
#ifndef QT_NO_CURSOR
- void changeCursor(QCursor * windowCursor, QWindow * window) Q_DECL_OVERRIDE;
+ void changeCursor(QCursor * windowCursor, QWindow * window) override;
#endif
- QPoint pos() const Q_DECL_OVERRIDE;
- void setPos(const QPoint &pos) Q_DECL_OVERRIDE;
+ QPoint pos() const override;
+ void setPos(const QPoint &pos) override;
void updateMouseStatus();
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
index 3a220ec942..2040d6bc0e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
@@ -46,7 +46,6 @@
#include <QtCore/QLoggingCategory>
#include <QtCore/private/qcore_unix_p.h>
-#include <QtGui/private/qguiapplication_p.h>
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
@@ -65,8 +64,8 @@ void QEglFSKmsGbmDevice::pageFlipHandler(int fd, unsigned int sequence, unsigned
screen->flipFinished();
}
-QEglFSKmsGbmDevice::QEglFSKmsGbmDevice(QEglFSKmsIntegration *integration, const QString &path)
- : QEglFSKmsDevice(integration, path)
+QEglFSKmsGbmDevice::QEglFSKmsGbmDevice(QKmsScreenConfig *screenConfig, const QString &path)
+ : QEglFSKmsDevice(screenConfig, path)
, m_gbm_device(Q_NULLPTR)
, m_globalCursor(Q_NULLPTR)
{
@@ -77,7 +76,6 @@ bool QEglFSKmsGbmDevice::open()
Q_ASSERT(fd() == -1);
Q_ASSERT(m_gbm_device == Q_NULLPTR);
- qCDebug(qLcEglfsKmsDebug) << "Opening device" << devicePath();
int fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
if (fd == -1) {
qErrnoWarning("Could not open DRM device %s", qPrintable(devicePath()));
@@ -101,6 +99,8 @@ bool QEglFSKmsGbmDevice::open()
void QEglFSKmsGbmDevice::close()
{
+ // Note: screens are gone at this stage.
+
if (m_gbm_device) {
gbm_device_destroy(m_gbm_device);
m_gbm_device = Q_NULLPTR;
@@ -110,15 +110,11 @@ void QEglFSKmsGbmDevice::close()
qt_safe_close(fd());
setFd(-1);
}
-
- if (m_globalCursor)
- m_globalCursor->deleteLater();
- m_globalCursor = Q_NULLPTR;
}
-EGLNativeDisplayType QEglFSKmsGbmDevice::nativeDisplay() const
+void *QEglFSKmsGbmDevice::nativeDisplay() const
{
- return reinterpret_cast<EGLNativeDisplayType>(m_gbm_device);
+ return m_gbm_device;
}
gbm_device * QEglFSKmsGbmDevice::gbmDevice() const
@@ -131,6 +127,17 @@ QPlatformCursor *QEglFSKmsGbmDevice::globalCursor() const
return m_globalCursor;
}
+// Cannot do this from close(), it may be too late.
+// Call this from the last screen dtor instead.
+void QEglFSKmsGbmDevice::destroyGlobalCursor()
+{
+ if (m_globalCursor) {
+ qCDebug(qLcEglfsKmsDebug, "Destroying global GBM mouse cursor");
+ delete m_globalCursor;
+ m_globalCursor = Q_NULLPTR;
+ }
+}
+
void QEglFSKmsGbmDevice::handleDrmEvent()
{
drmEventContext drmEvent = {
@@ -142,14 +149,13 @@ void QEglFSKmsGbmDevice::handleDrmEvent()
drmHandleEvent(fd(), &drmEvent);
}
-QEglFSKmsScreen *QEglFSKmsGbmDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output)
+QPlatformScreen *QEglFSKmsGbmDevice::createScreen(const QKmsOutput &output)
{
- static bool firstScreen = true;
- QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(integration, device, output);
+ QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(this, output);
- if (firstScreen && integration->hwCursor()) {
+ if (!m_globalCursor && screenConfig()->hwCursor()) {
+ qCDebug(qLcEglfsKmsDebug, "Creating new global GBM mouse cursor");
m_globalCursor = new QEglFSKmsGbmCursor(screen);
- firstScreen = false;
}
return screen;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h
index 7c0af84422..08ca28d48e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.h
@@ -43,7 +43,7 @@
#define QEGLFSKMSGBMDEVICE_H
#include "qeglfskmsgbmcursor.h"
-#include "qeglfskmsdevice.h"
+#include <qeglfskmsdevice.h>
#include <gbm.h>
@@ -54,21 +54,20 @@ class QEglFSKmsScreen;
class QEglFSKmsGbmDevice: public QEglFSKmsDevice
{
public:
- QEglFSKmsGbmDevice(QEglFSKmsIntegration *integration, const QString &path);
+ QEglFSKmsGbmDevice(QKmsScreenConfig *screenConfig, const QString &path);
- bool open() Q_DECL_OVERRIDE;
- void close() Q_DECL_OVERRIDE;
+ bool open() override;
+ void close() override;
- EGLNativeDisplayType nativeDisplay() const Q_DECL_OVERRIDE;
+ void *nativeDisplay() const override;
gbm_device *gbmDevice() const;
QPlatformCursor *globalCursor() const;
+ void destroyGlobalCursor();
void handleDrmEvent();
- virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
- QEglFSKmsDevice *device,
- QEglFSKmsOutput output) Q_DECL_OVERRIDE;
+ QPlatformScreen *createScreen(const QKmsOutput &output) override;
private:
Q_DISABLE_COPY(QEglFSKmsGbmDevice)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
index 38419a55c8..b6cdcf92b6 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
@@ -63,8 +63,9 @@ QT_BEGIN_NAMESPACE
QMutex QEglFSKmsGbmScreen::m_waitForFlipMutex;
QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration()
- : QEglFSKmsIntegration()
-{}
+{
+ qCDebug(qLcEglfsKmsDebug, "New DRM/KMS via GBM integration created");
+}
EGLNativeWindowType QEglFSKmsGbmIntegration::createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
@@ -104,10 +105,13 @@ void QEglFSKmsGbmIntegration::destroyNativeWindow(EGLNativeWindowType window)
QPlatformCursor *QEglFSKmsGbmIntegration::createCursor(QPlatformScreen *screen) const
{
- if (hwCursor())
- return Q_NULLPTR;
- else
+#if QT_CONFIG(opengl)
+ if (!screenConfig()->hwCursor()) {
+ qCDebug(qLcEglfsKmsDebug, "Using plain OpenGL mouse cursor");
return new QEglFSCursor(screen);
+ }
+#endif
+ return nullptr;
}
void QEglFSKmsGbmIntegration::presentBuffer(QPlatformSurface *surface)
@@ -118,13 +122,12 @@ void QEglFSKmsGbmIntegration::presentBuffer(QPlatformSurface *surface)
screen->flip();
}
-QEglFSKmsDevice *QEglFSKmsGbmIntegration::createDevice(const QString &devicePath)
+QKmsDevice *QEglFSKmsGbmIntegration::createDevice()
{
- QString path = devicePath;
- if (!devicePath.isEmpty()) {
- qCDebug(qLcEglfsKmsDebug) << "Using DRM device" << path << "specified in config file";
+ QString path = screenConfig()->devicePath();
+ if (!path.isEmpty()) {
+ qCDebug(qLcEglfsKmsDebug) << "GBM: Using DRM device" << path << "specified in config file";
} else {
-
QDeviceDiscovery *d = QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask);
const QStringList devices = d->scanConnectedDevices();
qCDebug(qLcEglfsKmsDebug) << "Found the following video devices:" << devices;
@@ -137,7 +140,7 @@ QEglFSKmsDevice *QEglFSKmsGbmIntegration::createDevice(const QString &devicePath
qCDebug(qLcEglfsKmsDebug) << "Using" << path;
}
- return new QEglFSKmsGbmDevice(this, path);
+ return new QEglFSKmsGbmDevice(screenConfig(), path);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h
index 727571d3e3..38f132d72e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.h
@@ -57,15 +57,15 @@ public:
EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
- const QSurfaceFormat &format) Q_DECL_OVERRIDE;
- EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) Q_DECL_OVERRIDE;
- void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
+ const QSurfaceFormat &format) override;
+ EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) override;
+ void destroyNativeWindow(EGLNativeWindowType window) override;
- QPlatformCursor *createCursor(QPlatformScreen *screen) const Q_DECL_OVERRIDE;
- void presentBuffer(QPlatformSurface *surface) Q_DECL_OVERRIDE;
+ QPlatformCursor *createCursor(QPlatformScreen *screen) const override;
+ void presentBuffer(QPlatformSurface *surface) override;
protected:
- QEglFSKmsDevice *createDevice(const QString &devicePath) Q_DECL_OVERRIDE;
+ QKmsDevice *createDevice() override;
private:
};
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp
index f34e4859c6..945c8b4255 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmmain.cpp
@@ -49,7 +49,7 @@ class QEglFSKmsGbmIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms.json")
public:
- QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsGbmIntegration; }
+ QEglFSDeviceIntegration *create() override { return new QEglFSKmsGbmIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index d4df0dc66e..87fb3146c7 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -49,6 +49,8 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtFbSupport/private/qfbvthandler_p.h>
+#include <errno.h>
+
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
@@ -92,10 +94,8 @@ QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(
return fb.take();
}
-QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration,
- QEglFSKmsDevice *device,
- QEglFSKmsOutput output)
- : QEglFSKmsScreen(integration, device, output)
+QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QKmsDevice *device, const QKmsOutput &output)
+ : QEglFSKmsScreen(device, output)
, m_gbm_surface(Q_NULLPTR)
, m_gbm_bo_current(Q_NULLPTR)
, m_gbm_bo_next(Q_NULLPTR)
@@ -105,12 +105,17 @@ QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration,
QEglFSKmsGbmScreen::~QEglFSKmsGbmScreen()
{
+ const int remainingScreenCount = qGuiApp->screens().count();
+ qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount);
+ if (!remainingScreenCount && !device()->screenConfig()->separateScreens())
+ static_cast<QEglFSKmsGbmDevice *>(device())->destroyGlobalCursor();
}
QPlatformCursor *QEglFSKmsGbmScreen::cursor() const
{
- if (integration()->hwCursor()) {
- if (!integration()->separateScreens())
+ QKmsScreenConfig *config = device()->screenConfig();
+ if (config->hwCursor()) {
+ if (!config->separateScreens())
return static_cast<QEglFSKmsGbmDevice *>(device())->globalCursor();
if (m_cursor.isNull()) {
@@ -181,7 +186,7 @@ void QEglFSKmsGbmScreen::flip()
FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next);
- QEglFSKmsOutput &op(output());
+ QKmsOutput &op(output());
const int fd = device()->fd();
const uint32_t w = op.modes[op.mode].hdisplay;
const uint32_t h = op.modes[op.mode].vdisplay;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h
index d7ad348291..341cc95bbe 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.h
@@ -54,20 +54,18 @@ class QEglFSKmsGbmCursor;
class QEglFSKmsGbmScreen : public QEglFSKmsScreen
{
public:
- QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration,
- QEglFSKmsDevice *device,
- QEglFSKmsOutput output);
+ QEglFSKmsGbmScreen(QKmsDevice *device, const QKmsOutput &output);
~QEglFSKmsGbmScreen();
- QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
+ QPlatformCursor *cursor() const override;
gbm_surface *surface() const { return m_gbm_surface; }
gbm_surface *createSurface();
void destroySurface();
- void waitForFlip() Q_DECL_OVERRIDE;
- void flip() Q_DECL_OVERRIDE;
- void flipFinished() Q_DECL_OVERRIDE;
+ void waitForFlip() override;
+ void flip() override;
+ void flipFinished() override;
private:
gbm_surface *m_gbm_surface;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
index a625021aba..a2dc9c4a50 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
@@ -1,6 +1,6 @@
TARGET = qeglfs-kms-egldevice-integration
-QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private
+QT += core-private gui-private eglfsdeviceintegration-private eglfs_kms_support-private kms_support-private
INCLUDEPATH += $$PWD/../../api $$PWD/../eglfs_kms_support
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp
index 60989e2bd0..0a66a897a1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp
@@ -40,14 +40,16 @@
#include "qeglfskmsegldevice.h"
#include "qeglfskmsegldevicescreen.h"
#include "qeglfskmsegldeviceintegration.h"
+#include "private/qeglfsintegration_p.h"
#include "private/qeglfscursor_p.h"
#include <QtCore/private/qcore_unix_p.h>
QT_BEGIN_NAMESPACE
-QEglFSKmsEglDevice::QEglFSKmsEglDevice(QEglFSKmsIntegration *integration, const QString &path)
- : QEglFSKmsDevice(integration, path),
+QEglFSKmsEglDevice::QEglFSKmsEglDevice(QEglFSKmsEglDeviceIntegration *devInt, QKmsScreenConfig *screenConfig, const QString &path)
+ : QEglFSKmsDevice(screenConfig, path),
+ m_devInt(devInt),
m_globalCursor(nullptr)
{
}
@@ -56,11 +58,9 @@ bool QEglFSKmsEglDevice::open()
{
Q_ASSERT(fd() == -1);
- qCDebug(qLcEglfsKmsDebug, "Opening DRM device %s", qPrintable(devicePath()));
-
int fd = drmOpen(devicePath().toLocal8Bit().constData(), Q_NULLPTR);
if (Q_UNLIKELY(fd < 0))
- qFatal("Could not open DRM device");
+ qFatal("Could not open DRM (NV) device");
setFd(fd);
@@ -69,29 +69,28 @@ bool QEglFSKmsEglDevice::open()
void QEglFSKmsEglDevice::close()
{
- qCDebug(qLcEglfsKmsDebug, "Closing DRM device");
+ // Note: screens are gone at this stage.
if (qt_safe_close(fd()) == -1)
- qErrnoWarning("Could not close DRM device");
+ qErrnoWarning("Could not close DRM (NV) device");
setFd(-1);
}
EGLNativeDisplayType QEglFSKmsEglDevice::nativeDisplay() const
{
- return reinterpret_cast<EGLNativeDisplayType>(static_cast<QEglFSKmsEglDeviceIntegration *>(m_integration)->eglDevice());
+ return reinterpret_cast<EGLNativeDisplayType>(m_devInt->eglDevice());
}
-QEglFSKmsScreen *QEglFSKmsEglDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device,
- QEglFSKmsOutput output)
+QPlatformScreen *QEglFSKmsEglDevice::createScreen(const QKmsOutput &output)
{
- QEglFSKmsScreen *screen = new QEglFSKmsEglDeviceScreen(integration, device, output);
-
- if (!m_globalCursor && !integration->separateScreens()) {
+ QEglFSKmsScreen *screen = new QEglFSKmsEglDeviceScreen(this, output);
+#if QT_CONFIG(opengl)
+ if (!m_globalCursor && !screenConfig()->separateScreens()) {
qCDebug(qLcEglfsKmsDebug, "Creating new global mouse cursor");
m_globalCursor = new QEglFSCursor(screen);
}
-
+#endif
return screen;
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h
index 8c8f79f70c..8d469879ab 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.h
@@ -45,25 +45,25 @@
QT_BEGIN_NAMESPACE
class QPlatformCursor;
+class QEglFSKmsEglDeviceIntegration;
class QEglFSKmsEglDevice: public QEglFSKmsDevice
{
public:
- QEglFSKmsEglDevice(QEglFSKmsIntegration *integration, const QString &path);
+ QEglFSKmsEglDevice(QEglFSKmsEglDeviceIntegration *devInt, QKmsScreenConfig *screenConfig, const QString &path);
- virtual bool open() Q_DECL_OVERRIDE;
- virtual void close() Q_DECL_OVERRIDE;
+ bool open() override;
+ void close() override;
- virtual EGLNativeDisplayType nativeDisplay() const Q_DECL_OVERRIDE;
+ void *nativeDisplay() const override;
- virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
- QEglFSKmsDevice *device,
- QEglFSKmsOutput output) Q_DECL_OVERRIDE;
+ QPlatformScreen *createScreen(const QKmsOutput &output) override;
QPlatformCursor *globalCursor() { return m_globalCursor; }
void destroyGlobalCursor();
private:
+ QEglFSKmsEglDeviceIntegration *m_devInt;
QPlatformCursor *m_globalCursor;
};
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
index cf1de71831..43bdb77a18 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
@@ -50,8 +50,7 @@
QT_BEGIN_NAMESPACE
QEglFSKmsEglDeviceIntegration::QEglFSKmsEglDeviceIntegration()
- : QEglFSKmsIntegration()
- , m_egl_device(EGL_NO_DEVICE_EXT)
+ : m_egl_device(EGL_NO_DEVICE_EXT)
, m_funcs(Q_NULLPTR)
{
qCDebug(qLcEglfsKmsDebug, "New DRM/KMS on EGLDevice integration created");
@@ -101,30 +100,30 @@ bool QEglFSKmsEglDeviceIntegration::supportsPBuffers() const
return true;
}
-class QEglJetsonTK1Window : public QEglFSWindow
+class QEglFSKmsEglDeviceWindow : public QEglFSWindow
{
public:
- QEglJetsonTK1Window(QWindow *w, const QEglFSKmsEglDeviceIntegration *integration)
+ QEglFSKmsEglDeviceWindow(QWindow *w, const QEglFSKmsEglDeviceIntegration *integration)
: QEglFSWindow(w)
, m_integration(integration)
, m_egl_stream(EGL_NO_STREAM_KHR)
{ }
- void invalidateSurface() Q_DECL_OVERRIDE;
- void resetSurface() Q_DECL_OVERRIDE;
+ void invalidateSurface() override;
+ void resetSurface() override;
const QEglFSKmsEglDeviceIntegration *m_integration;
EGLStreamKHR m_egl_stream;
EGLint m_latency;
};
-void QEglJetsonTK1Window::invalidateSurface()
+void QEglFSKmsEglDeviceWindow::invalidateSurface()
{
QEglFSWindow::invalidateSurface();
m_integration->m_funcs->destroy_stream(screen()->display(), m_egl_stream);
}
-void QEglJetsonTK1Window::resetSurface()
+void QEglFSKmsEglDeviceWindow::resetSurface()
{
qCDebug(qLcEglfsKmsDebug, "Creating stream");
@@ -173,7 +172,7 @@ void QEglJetsonTK1Window::resetSurface()
QEglFSKmsEglDeviceScreen *cur_screen = static_cast<QEglFSKmsEglDeviceScreen *>(screen());
Q_ASSERT(cur_screen);
- QEglFSKmsOutput &output(cur_screen->output());
+ QKmsOutput &output(cur_screen->output());
const uint32_t wantedId = !output.wants_plane ? output.crtc_id : output.plane_id;
qCDebug(qLcEglfsKmsDebug, "Searching for id: %d", wantedId);
@@ -235,7 +234,7 @@ void QEglJetsonTK1Window::resetSurface()
QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const
{
- QEglJetsonTK1Window *eglWindow = new QEglJetsonTK1Window(window, this);
+ QEglFSKmsEglDeviceWindow *eglWindow = new QEglFSKmsEglDeviceWindow(window, this);
m_funcs->initialize(eglWindow->screen()->display());
if (Q_UNLIKELY(!(m_funcs->has_egl_output_base && m_funcs->has_egl_output_drm && m_funcs->has_egl_stream &&
@@ -245,10 +244,8 @@ QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const
return eglWindow;
}
-QEglFSKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice(const QString &devicePath)
+QKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice()
{
- Q_UNUSED(devicePath)
-
if (Q_UNLIKELY(!query_egl_device()))
qFatal("Could not set up EGL device!");
@@ -256,7 +253,7 @@ QEglFSKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice(const QString &devi
if (Q_UNLIKELY(!deviceName))
qFatal("Failed to query device name from EGLDevice");
- return new QEglFSKmsEglDevice(this, deviceName);
+ return new QEglFSKmsEglDevice(this, screenConfig(), deviceName);
}
bool QEglFSKmsEglDeviceIntegration::query_egl_device()
@@ -283,7 +280,11 @@ bool QEglFSKmsEglDeviceIntegration::query_egl_device()
QPlatformCursor *QEglFSKmsEglDeviceIntegration::createCursor(QPlatformScreen *screen) const
{
- return separateScreens() ? new QEglFSCursor(screen) : nullptr;
+#if QT_CONFIG(opengl)
+ if (screenConfig()->separateScreens())
+ return new QEglFSCursor(screen);
+#endif
+ return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
index cddfdbd5c6..62404cfcd1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
@@ -55,27 +55,26 @@ class QEglFSKmsEglDeviceIntegration : public QEglFSKmsIntegration
public:
QEglFSKmsEglDeviceIntegration();
- EGLint surfaceType() const Q_DECL_OVERRIDE;
- EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) Q_DECL_OVERRIDE;
- bool supportsSurfacelessContexts() const Q_DECL_OVERRIDE;
- bool supportsPBuffers() const Q_DECL_OVERRIDE;
- QEglFSWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE;
+ EGLint surfaceType() const override;
+ EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) override;
+ bool supportsSurfacelessContexts() const override;
+ bool supportsPBuffers() const override;
+ QEglFSWindow *createWindow(QWindow *window) const override;
EGLDeviceEXT eglDevice() const { return m_egl_device; }
protected:
- QEglFSKmsDevice *createDevice(const QString &devicePath) Q_DECL_OVERRIDE;
- QPlatformCursor *createCursor(QPlatformScreen *screen) const Q_DECL_OVERRIDE;
+ QKmsDevice *createDevice() override;
+ QPlatformCursor *createCursor(QPlatformScreen *screen) const override;
private:
bool setup_kms();
bool query_egl_device();
EGLDeviceEXT m_egl_device;
-
- friend class QEglJetsonTK1Window;
- // EGLStream infrastructure
QEGLStreamConvenience *m_funcs;
+
+ friend class QEglFSKmsEglDeviceWindow;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
index 42fec073f1..5763ab45cc 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
@@ -47,7 +47,7 @@ class QEglFSKmsEglDeviceIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms_egldevice.json")
public:
- QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsEglDeviceIntegration; }
+ QEglFSDeviceIntegration *create() override { return new QEglFSKmsEglDeviceIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
index 3935c99b9e..a27c89faab 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
@@ -40,11 +40,15 @@
#include "qeglfskmsegldevicescreen.h"
#include "qeglfskmsegldevice.h"
#include <QGuiApplication>
+#include <QLoggingCategory>
+#include <errno.h>
QT_BEGIN_NAMESPACE
-QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output)
- : QEglFSKmsScreen(integration, device, output)
+Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
+
+QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QKmsDevice *device, const QKmsOutput &output)
+ : QEglFSKmsScreen(device, output)
{
}
@@ -52,7 +56,7 @@ QEglFSKmsEglDeviceScreen::~QEglFSKmsEglDeviceScreen()
{
const int remainingScreenCount = qGuiApp->screens().count();
qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount);
- if (!remainingScreenCount && !m_integration->separateScreens())
+ if (!remainingScreenCount && !device()->screenConfig()->separateScreens())
static_cast<QEglFSKmsEglDevice *>(device())->destroyGlobalCursor();
}
@@ -62,12 +66,15 @@ QPlatformCursor *QEglFSKmsEglDeviceScreen::cursor() const
// in its ctor. With separateScreens just use that. Otherwise
// there's a virtual desktop and the device has a global cursor
// and the base class has no dedicated cursor at all.
- return m_integration->separateScreens() ? QEglFSScreen::cursor() : static_cast<QEglFSKmsEglDevice *>(device())->globalCursor();
+ // config->hwCursor() is ignored for now, just use the standard OpenGL cursor.
+ return device()->screenConfig()->separateScreens()
+ ? QEglFSScreen::cursor()
+ : static_cast<QEglFSKmsEglDevice *>(device())->globalCursor();
}
void QEglFSKmsEglDeviceScreen::waitForFlip()
{
- QEglFSKmsOutput &op(output());
+ QKmsOutput &op(output());
const int fd = device()->fd();
const uint32_t w = op.modes[op.mode].hdisplay;
const uint32_t h = op.modes[op.mode].vdisplay;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
index c57f52c6b7..5efe35f8b3 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
@@ -47,14 +47,12 @@ QT_BEGIN_NAMESPACE
class QEglFSKmsEglDeviceScreen : public QEglFSKmsScreen
{
public:
- QEglFSKmsEglDeviceScreen(QEglFSKmsIntegration *integration,
- QEglFSKmsDevice *device,
- QEglFSKmsOutput output);
+ QEglFSKmsEglDeviceScreen(QKmsDevice *device, const QKmsOutput &output);
~QEglFSKmsEglDeviceScreen();
- QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
+ QPlatformCursor *cursor() const override;
- void waitForFlip() Q_DECL_OVERRIDE;
+ void waitForFlip() override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
index 487edb569e..3c0a0ce30f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/eglfs_kms_support.pro
@@ -2,7 +2,7 @@ TARGET = QtEglFsKmsSupport
CONFIG += no_module_headers internal_module
load(qt_module)
-QT += core-private gui-private eglfsdeviceintegration-private
+QT += core-private gui-private eglfsdeviceintegration-private kms_support-private
INCLUDEPATH += $$PWD/../../api
@@ -15,8 +15,8 @@ QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfskmsintegration.cpp \
$$PWD/qeglfskmsdevice.cpp \
- $$PWD/qeglfskmsscreen.cpp \
+ $$PWD/qeglfskmsscreen.cpp
HEADERS += $$PWD/qeglfskmsintegration.h \
$$PWD/qeglfskmsdevice.h \
- $$PWD/qeglfskmsscreen.h \
+ $$PWD/qeglfskmsscreen.h
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
index f372b9d156..b073577797 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.cpp
@@ -1,6 +1,5 @@
/****************************************************************************
**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -41,464 +40,25 @@
#include "qeglfskmsdevice.h"
#include "qeglfskmsscreen.h"
-
-#include "qeglfsintegration_p.h"
-
-#include <QtCore/QLoggingCategory>
-#include <QtCore/private/qcore_unix_p.h>
+#include "private/qeglfsintegration_p.h"
#include <QtGui/private/qguiapplication_p.h>
-#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
-
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
-
-enum OutputConfiguration {
- OutputConfigOff,
- OutputConfigPreferred,
- OutputConfigCurrent,
- OutputConfigMode,
- OutputConfigModeline
-};
-
-int QEglFSKmsDevice::crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector)
-{
- for (int i = 0; i < connector->count_encoders; i++) {
- drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->encoders[i]);
- if (!encoder) {
- qWarning("Failed to get encoder");
- continue;
- }
-
- quint32 possibleCrtcs = encoder->possible_crtcs;
- drmModeFreeEncoder(encoder);
-
- for (int j = 0; j < resources->count_crtcs; j++) {
- bool isPossible = possibleCrtcs & (1 << j);
- bool isAvailable = !(m_crtc_allocator & 1 << resources->crtcs[j]);
-
- if (isPossible && isAvailable)
- return j;
- }
- }
-
- return -1;
-}
-
-static const char * const connector_type_names[] = { // must match DRM_MODE_CONNECTOR_*
- "None",
- "VGA",
- "DVI",
- "DVI",
- "DVI",
- "Composite",
- "TV",
- "LVDS",
- "CTV",
- "DIN",
- "DP",
- "HDMI",
- "HDMI",
- "TV",
- "eDP",
- "Virtual",
- "DSI"
-};
-
-static QByteArray nameForConnector(const drmModeConnectorPtr connector)
-{
- const QByteArray id = QByteArray::number(connector->connector_type_id);
- if (connector->connector_type < ARRAY_LENGTH(connector_type_names))
- return connector_type_names[connector->connector_type] + id;
- return "UNKNOWN" + id;
-}
-
-static bool parseModeline(const QByteArray &text, drmModeModeInfoPtr mode)
-{
- char hsync[16];
- char vsync[16];
- float fclock;
-
- mode->type = DRM_MODE_TYPE_USERDEF;
- mode->hskew = 0;
- mode->vscan = 0;
- mode->vrefresh = 0;
- mode->flags = 0;
-
- if (sscanf(text.constData(), "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
- &fclock,
- &mode->hdisplay,
- &mode->hsync_start,
- &mode->hsync_end,
- &mode->htotal,
- &mode->vdisplay,
- &mode->vsync_start,
- &mode->vsync_end,
- &mode->vtotal, hsync, vsync) != 11)
- return false;
-
- mode->clock = fclock * 1000;
-
- if (strcmp(hsync, "+hsync") == 0)
- mode->flags |= DRM_MODE_FLAG_PHSYNC;
- else if (strcmp(hsync, "-hsync") == 0)
- mode->flags |= DRM_MODE_FLAG_NHSYNC;
- else
- return false;
-
- if (strcmp(vsync, "+vsync") == 0)
- mode->flags |= DRM_MODE_FLAG_PVSYNC;
- else if (strcmp(vsync, "-vsync") == 0)
- mode->flags |= DRM_MODE_FLAG_NVSYNC;
- else
- return false;
-
- return true;
-}
-
-QEglFSKmsScreen *QEglFSKmsDevice::createScreenForConnector(drmModeResPtr resources,
- drmModeConnectorPtr connector,
- VirtualDesktopInfo *vinfo)
-{
- const QByteArray connectorName = nameForConnector(connector);
-
- const int crtc = crtcForConnector(resources, connector);
- if (crtc < 0) {
- qWarning() << "No usable crtc/encoder pair for connector" << connectorName;
- return Q_NULLPTR;
- }
-
- OutputConfiguration configuration;
- QSize configurationSize;
- drmModeModeInfo configurationModeline;
-
- auto userConfig = m_integration->outputSettings();
- auto userConnectorConfig = userConfig.value(QString::fromUtf8(connectorName));
- // default to the preferred mode unless overridden in the config
- const QByteArray mode = userConnectorConfig.value(QStringLiteral("mode"), QStringLiteral("preferred"))
- .toByteArray().toLower();
- if (mode == "off") {
- configuration = OutputConfigOff;
- } else if (mode == "preferred") {
- configuration = OutputConfigPreferred;
- } else if (mode == "current") {
- configuration = OutputConfigCurrent;
- } else if (sscanf(mode.constData(), "%dx%d", &configurationSize.rwidth(), &configurationSize.rheight()) == 2) {
- configuration = OutputConfigMode;
- } else if (parseModeline(mode, &configurationModeline)) {
- configuration = OutputConfigModeline;
- } else {
- qWarning("Invalid mode \"%s\" for output %s", mode.constData(), connectorName.constData());
- configuration = OutputConfigPreferred;
- }
- if (vinfo) {
- *vinfo = VirtualDesktopInfo();
- vinfo->virtualIndex = userConnectorConfig.value(QStringLiteral("virtualIndex"), INT_MAX).toInt();
- if (userConnectorConfig.contains(QStringLiteral("virtualPos"))) {
- const QByteArray vpos = userConnectorConfig.value(QStringLiteral("virtualPos")).toByteArray();
- const QByteArrayList vposComp = vpos.split(',');
- if (vposComp.count() == 2)
- vinfo->virtualPos = QPoint(vposComp[0].trimmed().toInt(), vposComp[1].trimmed().toInt());
- }
- }
-
- const uint32_t crtc_id = resources->crtcs[crtc];
-
- if (configuration == OutputConfigOff) {
- qCDebug(qLcEglfsKmsDebug) << "Turning off output" << connectorName;
- drmModeSetCrtc(m_dri_fd, crtc_id, 0, 0, 0, 0, 0, Q_NULLPTR);
- return Q_NULLPTR;
- }
-
- // Skip disconnected output
- if (configuration == OutputConfigPreferred && connector->connection == DRM_MODE_DISCONNECTED) {
- qCDebug(qLcEglfsKmsDebug) << "Skipping disconnected output" << connectorName;
- return Q_NULLPTR;
- }
-
- // Get the current mode on the current crtc
- drmModeModeInfo crtc_mode;
- memset(&crtc_mode, 0, sizeof crtc_mode);
- if (drmModeEncoderPtr encoder = drmModeGetEncoder(m_dri_fd, connector->connector_id)) {
- drmModeCrtcPtr crtc = drmModeGetCrtc(m_dri_fd, encoder->crtc_id);
- drmModeFreeEncoder(encoder);
-
- if (!crtc)
- return Q_NULLPTR;
-
- if (crtc->mode_valid)
- crtc_mode = crtc->mode;
-
- drmModeFreeCrtc(crtc);
- }
-
- QList<drmModeModeInfo> modes;
- modes.reserve(connector->count_modes);
- qCDebug(qLcEglfsKmsDebug) << connectorName << "mode count:" << connector->count_modes;
- for (int i = 0; i < connector->count_modes; i++) {
- const drmModeModeInfo &mode = connector->modes[i];
- qCDebug(qLcEglfsKmsDebug) << "mode" << i << mode.hdisplay << "x" << mode.vdisplay
- << '@' << mode.vrefresh << "hz";
- modes << connector->modes[i];
- }
-
- int preferred = -1;
- int current = -1;
- int configured = -1;
- int best = -1;
-
- for (int i = modes.size() - 1; i >= 0; i--) {
- const drmModeModeInfo &m = modes.at(i);
-
- if (configuration == OutputConfigMode &&
- m.hdisplay == configurationSize.width() &&
- m.vdisplay == configurationSize.height()) {
- configured = i;
- }
-
- if (!memcmp(&crtc_mode, &m, sizeof m))
- current = i;
-
- if (m.type & DRM_MODE_TYPE_PREFERRED)
- preferred = i;
-
- best = i;
- }
-
- if (configuration == OutputConfigModeline) {
- modes << configurationModeline;
- configured = modes.size() - 1;
- }
-
- if (current < 0 && crtc_mode.clock != 0) {
- modes << crtc_mode;
- current = mode.size() - 1;
- }
-
- if (configuration == OutputConfigCurrent)
- configured = current;
-
- int selected_mode = -1;
-
- if (configured >= 0)
- selected_mode = configured;
- else if (preferred >= 0)
- selected_mode = preferred;
- else if (current >= 0)
- selected_mode = current;
- else if (best >= 0)
- selected_mode = best;
-
- if (selected_mode < 0) {
- qWarning() << "No modes available for output" << connectorName;
- return Q_NULLPTR;
- } else {
- int width = modes[selected_mode].hdisplay;
- int height = modes[selected_mode].vdisplay;
- int refresh = modes[selected_mode].vrefresh;
- qCDebug(qLcEglfsKmsDebug) << "Selected mode" << selected_mode << ":" << width << "x" << height
- << '@' << refresh << "hz for output" << connectorName;
- }
-
- // physical size from connector < config values < env vars
- static const int width = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_WIDTH");
- static const int height = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_HEIGHT");
- QSizeF physSize(width, height);
- if (physSize.isEmpty()) {
- physSize = QSize(userConnectorConfig.value(QStringLiteral("physicalWidth")).toInt(),
- userConnectorConfig.value(QStringLiteral("physicalHeight")).toInt());
- if (physSize.isEmpty()) {
- physSize.setWidth(connector->mmWidth);
- physSize.setHeight(connector->mmHeight);
- }
- }
- qCDebug(qLcEglfsKmsDebug) << "Physical size is" << physSize << "mm" << "for output" << connectorName;
-
- QEglFSKmsOutput output = {
- QString::fromUtf8(connectorName),
- connector->connector_id,
- crtc_id,
- physSize,
- selected_mode,
- false,
- drmModeGetCrtc(m_dri_fd, crtc_id),
- modes,
- connector->subpixel,
- connectorProperty(connector, QByteArrayLiteral("DPMS")),
- false,
- 0,
- false
- };
-
- bool ok;
- int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_PLANE_INDEX", &ok);
- if (ok) {
- drmModePlaneRes *planeResources = drmModeGetPlaneResources(m_dri_fd);
- if (planeResources) {
- if (idx >= 0 && idx < int(planeResources->count_planes)) {
- drmModePlane *plane = drmModeGetPlane(m_dri_fd, planeResources->planes[idx]);
- if (plane) {
- output.wants_plane = true;
- output.plane_id = plane->plane_id;
- qCDebug(qLcEglfsKmsDebug, "Forcing plane index %d, plane id %u (belongs to crtc id %u)",
- idx, plane->plane_id, plane->crtc_id);
- drmModeFreePlane(plane);
- }
- } else {
- qWarning("Invalid plane index %d, must be between 0 and %u", idx, planeResources->count_planes - 1);
- }
- }
- }
-
- m_crtc_allocator |= (1 << output.crtc_id);
- m_connector_allocator |= (1 << output.connector_id);
-
- return createScreen(m_integration, this, output);
-}
-
-drmModePropertyPtr QEglFSKmsDevice::connectorProperty(drmModeConnectorPtr connector, const QByteArray &name)
-{
- drmModePropertyPtr prop;
-
- for (int i = 0; i < connector->count_props; i++) {
- prop = drmModeGetProperty(m_dri_fd, connector->props[i]);
- if (!prop)
- continue;
- if (strcmp(prop->name, name.constData()) == 0)
- return prop;
- drmModeFreeProperty(prop);
- }
-
- return Q_NULLPTR;
-}
-
-QEglFSKmsDevice::QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QString &path)
- : m_integration(integration)
- , m_path(path)
- , m_dri_fd(-1)
- , m_crtc_allocator(0)
- , m_connector_allocator(0)
-{
-}
-
-QEglFSKmsDevice::~QEglFSKmsDevice()
-{
-}
-
-struct OrderedScreen
-{
- OrderedScreen() : screen(nullptr) { }
- OrderedScreen(QEglFSKmsScreen *screen, const QEglFSKmsDevice::VirtualDesktopInfo &vinfo)
- : screen(screen), vinfo(vinfo) { }
- QEglFSKmsScreen *screen;
- QEglFSKmsDevice::VirtualDesktopInfo vinfo;
-};
-
-QDebug operator<<(QDebug dbg, const OrderedScreen &s)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << "OrderedScreen(" << s.screen << " : " << s.vinfo.virtualIndex
- << " / " << s.vinfo.virtualPos << ")";
- return dbg;
-}
-
-static bool orderedScreenLessThan(const OrderedScreen &a, const OrderedScreen &b)
-{
- return a.vinfo.virtualIndex < b.vinfo.virtualIndex;
-}
-
-void QEglFSKmsDevice::createScreens()
-{
- drmModeResPtr resources = drmModeGetResources(m_dri_fd);
- if (!resources) {
- qWarning("drmModeGetResources failed");
- return;
- }
-
- QVector<OrderedScreen> screens;
-
- int wantedConnectorIndex = -1;
- bool ok;
- int idx = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_CONNECTOR_INDEX", &ok);
- if (ok) {
- if (idx >= 0 && idx < resources->count_connectors)
- wantedConnectorIndex = idx;
- else
- qWarning("Invalid connector index %d, must be between 0 and %u", idx, resources->count_connectors - 1);
- }
-
- for (int i = 0; i < resources->count_connectors; i++) {
- if (wantedConnectorIndex >= 0 && i != wantedConnectorIndex)
- continue;
-
- drmModeConnectorPtr connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
- if (!connector)
- continue;
-
- VirtualDesktopInfo vinfo;
- QEglFSKmsScreen *screen = createScreenForConnector(resources, connector, &vinfo);
- if (screen)
- screens.append(OrderedScreen(screen, vinfo));
-
- drmModeFreeConnector(connector);
- }
-
- drmModeFreeResources(resources);
-
- // Use stable sort to preserve the original order for outputs with unspecified indices.
- std::stable_sort(screens.begin(), screens.end(), orderedScreenLessThan);
- qCDebug(qLcEglfsKmsDebug) << "Sorted screen list:" << screens;
-
- QPoint pos(0, 0);
- QList<QPlatformScreen *> siblings;
- QEglFSIntegration *qpaIntegration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
-
- for (const OrderedScreen &orderedScreen : screens) {
- QEglFSKmsScreen *s = orderedScreen.screen;
- // set up a horizontal or vertical virtual desktop
- if (orderedScreen.vinfo.virtualPos.isNull()) {
- s->setVirtualPosition(pos);
- if (m_integration->virtualDesktopLayout() == QEglFSKmsIntegration::VirtualDesktopLayoutVertical)
- pos.ry() += s->geometry().height();
- else
- pos.rx() += s->geometry().width();
- } else {
- s->setVirtualPosition(orderedScreen.vinfo.virtualPos);
- }
- qCDebug(qLcEglfsKmsDebug) << "Adding screen" << s << "to QPA with geometry" << s->geometry();
- // The order in qguiapp's screens list will match the order set by
- // virtualIndex. This is not only handy but also required since for instance
- // evdevtouch relies on it when performing touch device - screen mapping.
- qpaIntegration->addScreen(s);
- siblings << s;
- }
-
- if (!m_integration->separateScreens()) {
- // enable the virtual desktop
- Q_FOREACH (QPlatformScreen *screen, siblings)
- static_cast<QEglFSKmsScreen *>(screen)->setVirtualSiblings(siblings);
- }
-}
-
-int QEglFSKmsDevice::fd() const
-{
- return m_dri_fd;
-}
-
-QString QEglFSKmsDevice::devicePath() const
-{
- return m_path;
-}
-
-QEglFSKmsScreen *QEglFSKmsDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output)
+QEglFSKmsDevice::QEglFSKmsDevice(QKmsScreenConfig *screenConfig, const QString &path)
+ : QKmsDevice(screenConfig, path)
{
- return new QEglFSKmsScreen(integration, device, output);
}
-void QEglFSKmsDevice::setFd(int fd)
+void QEglFSKmsDevice::registerScreen(QPlatformScreen *screen,
+ bool isPrimary,
+ const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings)
{
- m_dri_fd = fd;
+ QEglFSKmsScreen *s = static_cast<QEglFSKmsScreen *>(screen);
+ s->setVirtualPosition(virtualPos);
+ s->setVirtualSiblings(virtualSiblings);
+ static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->addScreen(s, isPrimary);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
index 3e7ac7e3f0..fc83a620d9 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsdevice.h
@@ -1,6 +1,5 @@
/****************************************************************************
**
-** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -42,64 +41,22 @@
#ifndef QEGLFSKMSDEVICE_H
#define QEGLFSKMSDEVICE_H
-#include "qeglfskmsintegration.h"
-#include "qeglfskmsscreen.h"
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
+#include "private/qeglfsglobal_p.h"
+#include <QtKmsSupport/private/qkmsdevice_p.h>
QT_BEGIN_NAMESPACE
-class Q_EGLFS_EXPORT QEglFSKmsDevice
+class Q_EGLFS_EXPORT QEglFSKmsDevice : public QKmsDevice
{
public:
- struct VirtualDesktopInfo {
- VirtualDesktopInfo() : virtualIndex(0) { }
- int virtualIndex;
- QPoint virtualPos;
- };
-
- QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QString &path);
- virtual ~QEglFSKmsDevice();
-
- virtual bool open() = 0;
- virtual void close() = 0;
-
- virtual void createScreens();
-
- virtual EGLNativeDisplayType nativeDisplay() const = 0;
- int fd() const;
- QString devicePath() const;
-
-protected:
- virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
- QEglFSKmsDevice *device,
- QEglFSKmsOutput output);
- void setFd(int fd);
-
- QEglFSKmsIntegration *m_integration;
- QString m_path;
- int m_dri_fd;
-
- quint32 m_crtc_allocator;
- quint32 m_connector_allocator;
-
- int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector);
- QEglFSKmsScreen *createScreenForConnector(drmModeResPtr resources,
- drmModeConnectorPtr connector,
- VirtualDesktopInfo *vinfo);
- drmModePropertyPtr connectorProperty(drmModeConnectorPtr connector, const QByteArray &name);
-
- static void pageFlipHandler(int fd,
- unsigned int sequence,
- unsigned int tv_sec,
- unsigned int tv_usec,
- void *user_data);
+ QEglFSKmsDevice(QKmsScreenConfig *screenConfig, const QString &path);
-private:
- Q_DISABLE_COPY(QEglFSKmsDevice)
+ void registerScreen(QPlatformScreen *screen,
+ bool isPrimary,
+ const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings) override;
};
QT_END_NAMESPACE
-#endif
+#endif // QEGLFSKMSDEVICE_H
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
index 5368a6d031..c77151181e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.cpp
@@ -40,13 +40,10 @@
****************************************************************************/
#include "qeglfskmsintegration.h"
-#include "qeglfskmsdevice.h"
#include "qeglfskmsscreen.h"
-#include <QtCore/QJsonDocument>
-#include <QtCore/QJsonObject>
-#include <QtCore/QJsonArray>
-#include <QtCore/QFile>
+#include <QtKmsSupport/private/qkmsdevice_p.h>
+
#include <QtGui/qpa/qplatformwindow.h>
#include <QtGui/QScreen>
@@ -58,28 +55,27 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcEglfsKmsDebug, "qt.qpa.eglfs.kms")
QEglFSKmsIntegration::QEglFSKmsIntegration()
- : m_device(Q_NULLPTR)
- , m_hwCursor(false)
- , m_pbuffers(false)
- , m_separateScreens(false)
- , m_virtualDesktopLayout(VirtualDesktopLayoutHorizontal)
-{}
-
-void QEglFSKmsIntegration::platformInit()
+ : m_device(Q_NULLPTR),
+ m_screenConfig(new QKmsScreenConfig)
{
- loadConfig();
+}
- if (!m_devicePath.isEmpty()) {
- qCDebug(qLcEglfsKmsDebug) << "Using DRM device" << m_devicePath << "specified in config file";
- }
+QEglFSKmsIntegration::~QEglFSKmsIntegration()
+{
+ delete m_screenConfig;
+}
- m_device = createDevice(m_devicePath);
+void QEglFSKmsIntegration::platformInit()
+{
+ qCDebug(qLcEglfsKmsDebug, "platformInit: Opening DRM device");
+ m_device = createDevice();
if (Q_UNLIKELY(!m_device->open()))
- qFatal("Could not open device %s - aborting!", qPrintable(m_devicePath));
+ qFatal("Could not open DRM device");
}
void QEglFSKmsIntegration::platformDestroy()
{
+ qCDebug(qLcEglfsKmsDebug, "platformDestroy: Closing DRM device");
m_device->close();
delete m_device;
m_device = Q_NULLPTR;
@@ -88,7 +84,7 @@ void QEglFSKmsIntegration::platformDestroy()
EGLNativeDisplayType QEglFSKmsIntegration::platformDisplay() const
{
Q_ASSERT(m_device);
- return m_device->nativeDisplay();
+ return (EGLNativeDisplayType) m_device->nativeDisplay();
}
bool QEglFSKmsIntegration::usesDefaultScreen()
@@ -134,94 +130,17 @@ void QEglFSKmsIntegration::waitForVSync(QPlatformSurface *surface) const
bool QEglFSKmsIntegration::supportsPBuffers() const
{
- return m_pbuffers;
-}
-
-bool QEglFSKmsIntegration::hwCursor() const
-{
- return m_hwCursor;
-}
-
-bool QEglFSKmsIntegration::separateScreens() const
-{
- return m_separateScreens;
-}
-
-QEglFSKmsIntegration::VirtualDesktopLayout QEglFSKmsIntegration::virtualDesktopLayout() const
-{
- return m_virtualDesktopLayout;
+ return m_screenConfig->supportsPBuffers();
}
-QMap<QString, QVariantMap> QEglFSKmsIntegration::outputSettings() const
-{
- return m_outputSettings;
-}
-
-QEglFSKmsDevice *QEglFSKmsIntegration::device() const
+QKmsDevice *QEglFSKmsIntegration::device() const
{
return m_device;
}
-void QEglFSKmsIntegration::loadConfig()
+QKmsScreenConfig *QEglFSKmsIntegration::screenConfig() const
{
- static QByteArray json = qgetenv("QT_QPA_EGLFS_KMS_CONFIG");
- if (json.isEmpty())
- return;
-
- qCDebug(qLcEglfsKmsDebug) << "Loading KMS setup from" << json;
-
- QFile file(QString::fromUtf8(json));
- if (!file.open(QFile::ReadOnly)) {
- qCWarning(qLcEglfsKmsDebug) << "Could not open config file"
- << json << "for reading";
- return;
- }
-
- const QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
- if (!doc.isObject()) {
- qCWarning(qLcEglfsKmsDebug) << "Invalid config file" << json
- << "- no top-level JSON object";
- return;
- }
-
- const QJsonObject object = doc.object();
-
- m_hwCursor = object.value(QLatin1String("hwcursor")).toBool(m_hwCursor);
- m_pbuffers = object.value(QLatin1String("pbuffers")).toBool(m_pbuffers);
- m_devicePath = object.value(QLatin1String("device")).toString();
- m_separateScreens = object.value(QLatin1String("separateScreens")).toBool(m_separateScreens);
-
- const QString vdOriString = object.value(QLatin1String("virtualDesktopLayout")).toString();
- if (!vdOriString.isEmpty()) {
- if (vdOriString == QLatin1String("horizontal"))
- m_virtualDesktopLayout = VirtualDesktopLayoutHorizontal;
- else if (vdOriString == QLatin1String("vertical"))
- m_virtualDesktopLayout = VirtualDesktopLayoutVertical;
- else
- qCWarning(qLcEglfsKmsDebug) << "Unknown virtualDesktopOrientation value" << vdOriString;
- }
-
- const QJsonArray outputs = object.value(QLatin1String("outputs")).toArray();
- for (int i = 0; i < outputs.size(); i++) {
- const QVariantMap outputSettings = outputs.at(i).toObject().toVariantMap();
-
- if (outputSettings.contains(QStringLiteral("name"))) {
- const QString name = outputSettings.value(QStringLiteral("name")).toString();
-
- if (m_outputSettings.contains(name)) {
- qCDebug(qLcEglfsKmsDebug) << "Output" << name << "configured multiple times!";
- }
-
- m_outputSettings.insert(name, outputSettings);
- }
- }
-
- qCDebug(qLcEglfsKmsDebug) << "Configuration:\n"
- << "\thwcursor:" << m_hwCursor << "\n"
- << "\tpbuffers:" << m_pbuffers << "\n"
- << "\tseparateScreens:" << m_separateScreens << "\n"
- << "\tvirtualDesktopLayout:" << m_virtualDesktopLayout << "\n"
- << "\toutputs:" << m_outputSettings;
+ return m_screenConfig;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
index ba49945715..9955616919 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsintegration.h
@@ -49,49 +49,35 @@
QT_BEGIN_NAMESPACE
-class QEglFSKmsDevice;
+class QKmsDevice;
+class QKmsScreenConfig;
Q_EGLFS_EXPORT Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
class Q_EGLFS_EXPORT QEglFSKmsIntegration : public QEglFSDeviceIntegration
{
public:
- enum VirtualDesktopLayout {
- VirtualDesktopLayoutHorizontal,
- VirtualDesktopLayoutVertical
- };
-
QEglFSKmsIntegration();
+ ~QEglFSKmsIntegration();
- void platformInit() Q_DECL_OVERRIDE;
- void platformDestroy() Q_DECL_OVERRIDE;
- EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE;
- bool usesDefaultScreen() Q_DECL_OVERRIDE;
- void screenInit() Q_DECL_OVERRIDE;
- QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const Q_DECL_OVERRIDE;
- bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
- void waitForVSync(QPlatformSurface *surface) const Q_DECL_OVERRIDE;
- bool supportsPBuffers() const Q_DECL_OVERRIDE;
-
- virtual bool hwCursor() const;
- virtual bool separateScreens() const;
- virtual VirtualDesktopLayout virtualDesktopLayout() const;
- QMap<QString, QVariantMap> outputSettings() const;
+ void platformInit() override;
+ void platformDestroy() override;
+ EGLNativeDisplayType platformDisplay() const override;
+ bool usesDefaultScreen() override;
+ void screenInit() override;
+ QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const override;
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
+ void waitForVSync(QPlatformSurface *surface) const override;
+ bool supportsPBuffers() const override;
- QEglFSKmsDevice *device() const;
+ QKmsDevice *device() const;
+ QKmsScreenConfig *screenConfig() const;
protected:
- virtual QEglFSKmsDevice *createDevice(const QString &devicePath) = 0;
-
- void loadConfig();
+ virtual QKmsDevice *createDevice() = 0;
- QEglFSKmsDevice *m_device;
- bool m_hwCursor;
- bool m_pbuffers;
- bool m_separateScreens;
- VirtualDesktopLayout m_virtualDesktopLayout;
- QString m_devicePath;
- QMap<QString, QVariantMap> m_outputSettings;
+ QKmsDevice *m_device;
+ QKmsScreenConfig *m_screenConfig;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
index 4021609407..3951f46a82 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.cpp
@@ -40,7 +40,6 @@
****************************************************************************/
#include "qeglfskmsscreen.h"
-#include "qeglfskmsdevice.h"
#include "qeglfsintegration_p.h"
#include <QtCore/QLoggingCategory>
@@ -69,30 +68,19 @@ private:
QEglFSKmsScreen *m_screen;
};
-QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration,
- QEglFSKmsDevice *device,
- QEglFSKmsOutput output)
- : QEglFSScreen(eglGetDisplay(device->nativeDisplay()))
- , m_integration(integration)
+QEglFSKmsScreen::QEglFSKmsScreen(QKmsDevice *device, const QKmsOutput &output)
+ : QEglFSScreen(eglGetDisplay((EGLNativeDisplayType) device->nativeDisplay()))
, m_device(device)
, m_output(output)
, m_powerState(PowerStateOn)
, m_interruptHandler(new QEglFSKmsInterruptHandler(this))
{
- m_siblings << this; // gets overridden by QEglFSKmsDevice later if !separateScreens
+ m_siblings << this; // gets overridden later
}
QEglFSKmsScreen::~QEglFSKmsScreen()
{
- if (m_output.dpms_prop) {
- drmModeFreeProperty(m_output.dpms_prop);
- m_output.dpms_prop = Q_NULLPTR;
- }
- restoreMode();
- if (m_output.saved_crtc) {
- drmModeFreeCrtc(m_output.saved_crtc);
- m_output.saved_crtc = Q_NULLPTR;
- }
+ m_output.cleanup(m_device);
delete m_interruptHandler;
}
@@ -123,7 +111,12 @@ QImage::Format QEglFSKmsScreen::format() const
QSizeF QEglFSKmsScreen::physicalSize() const
{
- return m_output.physical_size;
+ if (!m_output.physical_size.isEmpty()) {
+ return m_output.physical_size;
+ } else {
+ const QSize s = geometry().size();
+ return QSizeF(0.254 * s.width(), 0.254 * s.height());
+ }
}
QDpi QEglFSKmsScreen::logicalDpi() const
@@ -171,16 +164,7 @@ void QEglFSKmsScreen::flipFinished()
void QEglFSKmsScreen::restoreMode()
{
- if (m_output.mode_set && m_output.saved_crtc) {
- drmModeSetCrtc(m_device->fd(),
- m_output.saved_crtc->crtc_id,
- m_output.saved_crtc->buffer_id,
- 0, 0,
- &m_output.connector_id, 1,
- &m_output.saved_crtc->mode);
-
- m_output.mode_set = false;
- }
+ m_output.restoreMode(m_device);
}
qreal QEglFSKmsScreen::refreshRate() const
@@ -191,20 +175,7 @@ qreal QEglFSKmsScreen::refreshRate() const
QPlatformScreen::SubpixelAntialiasingType QEglFSKmsScreen::subpixelAntialiasingTypeHint() const
{
- switch (m_output.subpixel) {
- default:
- case DRM_MODE_SUBPIXEL_UNKNOWN:
- case DRM_MODE_SUBPIXEL_NONE:
- return Subpixel_None;
- case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
- return Subpixel_RGB;
- case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
- return Subpixel_BGR;
- case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
- return Subpixel_VRGB;
- case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
- return Subpixel_VBGR;
- }
+ return m_output.subpixelAntialiasingTypeHint();
}
QPlatformScreen::PowerState QEglFSKmsScreen::powerState() const
@@ -214,11 +185,7 @@ QPlatformScreen::PowerState QEglFSKmsScreen::powerState() const
void QEglFSKmsScreen::setPowerState(QPlatformScreen::PowerState state)
{
- if (!m_output.dpms_prop)
- return;
-
- drmModeConnectorSetProperty(m_device->fd(), m_output.connector_id,
- m_output.dpms_prop->prop_id, (int)state);
+ m_output.setPowerState(m_device, state);
m_powerState = state;
}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
index fa331f0931..80bbb0c7f1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/qeglfskmsscreen.h
@@ -42,65 +42,42 @@
#ifndef QEGLFSKMSSCREEN_H
#define QEGLFSKMSSCREEN_H
-#include "qeglfskmsintegration.h"
#include "private/qeglfsscreen_p.h"
#include <QtCore/QList>
#include <QtCore/QMutex>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
+#include <QtKmsSupport/private/qkmsdevice_p.h>
QT_BEGIN_NAMESPACE
-class QEglFSKmsDevice;
class QEglFSKmsInterruptHandler;
-struct QEglFSKmsOutput
-{
- QString name;
- uint32_t connector_id;
- uint32_t crtc_id;
- QSizeF physical_size;
- int mode; // index of selected mode in list below
- bool mode_set;
- drmModeCrtcPtr saved_crtc;
- QList<drmModeModeInfo> modes;
- int subpixel;
- drmModePropertyPtr dpms_prop;
- bool wants_plane;
- uint32_t plane_id;
- bool plane_set;
-};
-
class Q_EGLFS_EXPORT QEglFSKmsScreen : public QEglFSScreen
{
public:
- QEglFSKmsScreen(QEglFSKmsIntegration *integration,
- QEglFSKmsDevice *device,
- QEglFSKmsOutput output);
+ QEglFSKmsScreen(QKmsDevice *device, const QKmsOutput &output);
~QEglFSKmsScreen();
void setVirtualPosition(const QPoint &pos);
- QRect rawGeometry() const Q_DECL_OVERRIDE;
+ QRect rawGeometry() const override;
- int depth() const Q_DECL_OVERRIDE;
- QImage::Format format() const Q_DECL_OVERRIDE;
+ int depth() const override;
+ QImage::Format format() const override;
- QSizeF physicalSize() const Q_DECL_OVERRIDE;
- QDpi logicalDpi() const Q_DECL_OVERRIDE;
- Qt::ScreenOrientation nativeOrientation() const Q_DECL_OVERRIDE;
- Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE;
+ QSizeF physicalSize() const override;
+ QDpi logicalDpi() const override;
+ Qt::ScreenOrientation nativeOrientation() const override;
+ Qt::ScreenOrientation orientation() const override;
- QString name() const Q_DECL_OVERRIDE;
+ QString name() const override;
- qreal refreshRate() const Q_DECL_OVERRIDE;
+ qreal refreshRate() const override;
- QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE { return m_siblings; }
+ QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; }
void setVirtualSiblings(QList<QPlatformScreen *> sl) { m_siblings = sl; }
- QEglFSKmsIntegration *integration() const { return m_integration; }
- QEglFSKmsDevice *device() const { return m_device; }
+ QKmsDevice *device() const { return m_device; }
void destroySurface();
@@ -108,19 +85,18 @@ public:
virtual void flip();
virtual void flipFinished();
- QEglFSKmsOutput &output() { return m_output; }
+ QKmsOutput &output() { return m_output; }
void restoreMode();
- SubpixelAntialiasingType subpixelAntialiasingTypeHint() const Q_DECL_OVERRIDE;
+ SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override;
- QPlatformScreen::PowerState powerState() const Q_DECL_OVERRIDE;
- void setPowerState(QPlatformScreen::PowerState state) Q_DECL_OVERRIDE;
+ QPlatformScreen::PowerState powerState() const override;
+ void setPowerState(QPlatformScreen::PowerState state) override;
protected:
- QEglFSKmsIntegration *m_integration;
- QEglFSKmsDevice *m_device;
+ QKmsDevice *m_device;
- QEglFSKmsOutput m_output;
+ QKmsOutput m_output;
QPoint m_pos;
QList<QPlatformScreen *> m_siblings;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h
index 56883a3676..85eda4889f 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmaliintegration.h
@@ -47,9 +47,9 @@ QT_BEGIN_NAMESPACE
class QEglFSMaliIntegration : public QEglFSDeviceIntegration
{
public:
- void platformInit() Q_DECL_OVERRIDE;
- EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) Q_DECL_OVERRIDE;
- void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
+ void platformInit() override;
+ EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override;
+ void destroyNativeWindow(EGLNativeWindowType window) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp
index a3c804f54d..4f87dab967 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_mali/qeglfsmalimain.cpp
@@ -48,7 +48,7 @@ class QEglFSMaliIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_mali.json")
public:
- QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSMaliIntegration; }
+ QEglFSDeviceIntegration *create() override { return new QEglFSMaliIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp
index f2fcc0d3ff..763a4a462b 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp
@@ -63,9 +63,11 @@ void QEglFSVivIntegration::platformInit()
#ifdef Q_OS_INTEGRITY
VivanteInit();
+ mNativeDisplay = fbGetDisplay();
+#else
+ mNativeDisplay = fbGetDisplayByIndex(framebufferIndex());
#endif
- mNativeDisplay = fbGetDisplayByIndex(framebufferIndex());
fbGetDisplayGeometry(mNativeDisplay, &width, &height);
mScreenSize.setHeight(height);
mScreenSize.setWidth(width);
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h
index 2e98c2b4b1..4d1718afcf 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h
@@ -47,11 +47,11 @@ QT_BEGIN_NAMESPACE
class QEglFSVivIntegration : public QEglFSDeviceIntegration
{
public:
- void platformInit() Q_DECL_OVERRIDE;
- QSize screenSize() const Q_DECL_OVERRIDE;
- EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) Q_DECL_OVERRIDE;
- void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
- EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE;
+ void platformInit() override;
+ QSize screenSize() const override;
+ EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override;
+ void destroyNativeWindow(EGLNativeWindowType window) override;
+ EGLNativeDisplayType platformDisplay() const override;
private:
QSize mScreenSize;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp
index ebe2091b1e..0736637b6b 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivmain.cpp
@@ -48,7 +48,7 @@ class QEglFSVivIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_viv.json")
public:
- QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSVivIntegration; }
+ QEglFSDeviceIntegration *create() override { return new QEglFSVivIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h
index 9abbe817a6..2c49eb6440 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlintegration.h
@@ -48,13 +48,13 @@ QT_BEGIN_NAMESPACE
class QEglFSVivWaylandIntegration : public QEglFSDeviceIntegration
{
public:
- void platformInit() Q_DECL_OVERRIDE;
- QSize screenSize() const Q_DECL_OVERRIDE;
- EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) Q_DECL_OVERRIDE;
- void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
- EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE;
+ void platformInit() override;
+ QSize screenSize() const override;
+ EGLNativeWindowType createNativeWindow(QPlatformWindow *window, const QSize &size, const QSurfaceFormat &format) override;
+ void destroyNativeWindow(EGLNativeWindowType window) override;
+ EGLNativeDisplayType platformDisplay() const override;
- void *wlDisplay() const Q_DECL_OVERRIDE;
+ void *wlDisplay() const override;
private:
QSize mScreenSize;
EGLNativeDisplayType mNativeDisplay;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp
index 3b26feda07..6cdc9346c0 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv_wl/qeglfsvivwlmain.cpp
@@ -48,7 +48,7 @@ class QEglFSVivWaylandIntegrationPlugin : public QEglFSDeviceIntegrationPlugin
Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_viv_wl.json")
public:
- QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSVivWaylandIntegration; }
+ QEglFSDeviceIntegration *create() override { return new QEglFSVivWaylandIntegration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
index 0a547b832f..64d0d9b515 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp
@@ -114,7 +114,7 @@ void EventReader::run()
{
Qt::MouseButtons buttons;
- xcb_generic_event_t *event;
+ xcb_generic_event_t *event = nullptr;
while (running.load() && (event = xcb_wait_for_event(m_integration->connection()))) {
uint response_type = event->response_type & ~0x80;
switch (response_type) {
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
index c0f0ee5f22..bf431caaac 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.h
@@ -69,15 +69,15 @@ class QEglFSX11Integration : public QEglFSDeviceIntegration
public:
QEglFSX11Integration() : m_connection(0), m_window(0), m_eventReader(0) {}
- void platformInit() Q_DECL_OVERRIDE;
- void platformDestroy() Q_DECL_OVERRIDE;
- EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE;
- QSize screenSize() const Q_DECL_OVERRIDE;
+ void platformInit() override;
+ void platformDestroy() override;
+ EGLNativeDisplayType platformDisplay() const override;
+ QSize screenSize() const override;
EGLNativeWindowType createNativeWindow(QPlatformWindow *window,
const QSize &size,
- const QSurfaceFormat &format) Q_DECL_OVERRIDE;
- void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
- bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
+ const QSurfaceFormat &format) override;
+ void destroyNativeWindow(EGLNativeWindowType window) override;
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
xcb_connection_t *connection() { return m_connection; }
const xcb_atom_t *atoms() const { return m_atoms; }
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
index c15e05b657..39ab54ae5a 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11main.cpp
@@ -48,7 +48,7 @@ class QEglFSX11IntegrationPlugin : public QEglFSDeviceIntegrationPlugin
Q_PLUGIN_METADATA(IID QEglFSDeviceIntegrationFactoryInterface_iid FILE "eglfs_x11.json")
public:
- QEglFSDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSX11Integration; }
+ QEglFSDeviceIntegration *create() override { return new QEglFSX11Integration; }
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
index 2593df937b..187cbc025f 100644
--- a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
+++ b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro
@@ -12,11 +12,14 @@ QT += \
core-private gui-private \
devicediscovery_support-private eventdispatcher_support-private \
service_support-private theme_support-private fontdatabase_support-private \
- fb_support-private egl_support-private platformcompositor_support-private
+ fb_support-private egl_support-private
qtHaveModule(input_support-private): \
QT += input_support-private
+qtHaveModule(platformcompositor_support-private): \
+ QT += platformcompositor_support-private
+
# Avoid X11 header collision, use generic EGL native types
DEFINES += QT_EGL_NO_X11
diff --git a/src/plugins/platforms/eglfs/qeglfsmain.cpp b/src/plugins/platforms/eglfs/qeglfsmain.cpp
index 2885d397c6..4f77b7cd17 100644
--- a/src/plugins/platforms/eglfs/qeglfsmain.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsmain.cpp
@@ -47,7 +47,7 @@ class QEglFSIntegrationPlugin : public QPlatformIntegrationPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "eglfs.json")
public:
- QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE;
+ QPlatformIntegration *create(const QString&, const QStringList&) override;
};
QPlatformIntegration* QEglFSIntegrationPlugin::create(const QString& system, const QStringList& paramList)
diff --git a/src/plugins/platforms/integrity/main.cpp b/src/plugins/platforms/integrity/main.cpp
index 3330ddc5ae..f75e227335 100644
--- a/src/plugins/platforms/integrity/main.cpp
+++ b/src/plugins/platforms/integrity/main.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp
index a88c85e30d..ae802bb1fa 100644
--- a/src/plugins/platforms/integrity/qintegrityfbintegration.cpp
+++ b/src/plugins/platforms/integrity/qintegrityfbintegration.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/integrity/qintegrityfbintegration.h b/src/plugins/platforms/integrity/qintegrityfbintegration.h
index 3210cc9369..a954dc2356 100644
--- a/src/plugins/platforms/integrity/qintegrityfbintegration.h
+++ b/src/plugins/platforms/integrity/qintegrityfbintegration.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/integrity/qintegrityfbscreen.cpp b/src/plugins/platforms/integrity/qintegrityfbscreen.cpp
index 256cc117a2..3979937955 100644
--- a/src/plugins/platforms/integrity/qintegrityfbscreen.cpp
+++ b/src/plugins/platforms/integrity/qintegrityfbscreen.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -206,7 +212,7 @@ QRegion QIntegrityFbScreen::doRedraw()
(uint32_t)rects[i].width(),
(uint32_t)rects[i].height()
};
- mBlitter->drawImage(rects[i], *mScreenImage, rects[i]);
+ mBlitter->drawImage(rects[i], mScreenImage, rects[i]);
gh_FB_expose(mFbh, &fbrect, NULL);
}
return touched;
diff --git a/src/plugins/platforms/integrity/qintegrityfbscreen.h b/src/plugins/platforms/integrity/qintegrityfbscreen.h
index 5b4d900a4b..6bc78913c9 100644
--- a/src/plugins/platforms/integrity/qintegrityfbscreen.h
+++ b/src/plugins/platforms/integrity/qintegrityfbscreen.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/integrity/qintegrityhidmanager.cpp b/src/plugins/platforms/integrity/qintegrityhidmanager.cpp
index 64eda98e2a..49583735f5 100644
--- a/src/plugins/platforms/integrity/qintegrityhidmanager.cpp
+++ b/src/plugins/platforms/integrity/qintegrityhidmanager.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2015 Green Hills Software
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/integrity/qintegrityhidmanager.h b/src/plugins/platforms/integrity/qintegrityhidmanager.h
index 9a0f27d833..c8780b2dc2 100644
--- a/src/plugins/platforms/integrity/qintegrityhidmanager.h
+++ b/src/plugins/platforms/integrity/qintegrityhidmanager.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
** Copyright (C) 2015 Green Hills Software
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro
index caafe89730..6eb9f2c534 100644
--- a/src/plugins/platforms/ios/kernel.pro
+++ b/src/plugins/platforms/ios/kernel.pro
@@ -1,5 +1,12 @@
TARGET = qios
+# QTBUG-42937: Work around linker errors caused by circular
+# dependencies between the iOS platform plugin and the user
+# application's main() when the plugin is a shared library.
+qtConfig(shared): CONFIG += static
+
+CONFIG += no_app_extension_api_only
+
QT += \
core-private gui-private \
clipboard_support-private fontdatabase_support-private graphics_support-private
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro
index f4588dda03..7379765599 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro
@@ -1,7 +1,11 @@
TARGET = qiosnsphotolibrarysupport
+# QTBUG-42937: Since the iOS plugin (kernel) is
+# static, this plugin needs to be static as well.
+qtConfig(shared): CONFIG += static
+
QT += core gui gui-private
-LIBS += -framework UIKit -framework AssetsLibrary
+LIBS += -framework Foundation -framework UIKit -framework AssetsLibrary
HEADERS = \
qiosfileengineassetslibrary.h \
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm
index 2ec0d33a41..8b372b8749 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
index df3f6b9fa3..c52d498cd4 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
index f9662b964a..78e0f00ab4 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm
index 076e34c1a5..96be28af81 100644
--- a/src/plugins/platforms/ios/qiosbackingstore.mm
+++ b/src/plugins/platforms/ios/qiosbackingstore.mm
@@ -122,7 +122,17 @@ QIOSBackingStore::QIOSBackingStore(QWindow *window)
QIOSBackingStore::~QIOSBackingStore()
{
- delete m_context;
+ if (window()->surfaceType() == QSurface::RasterGLSurface) {
+ // We're using composeAndFlush from QPlatformBackingStore, which
+ // need to clean up any textures in its destructor, so make the
+ // context current and keep it alive until QPlatformBackingStore
+ // has cleaned up everything.
+ makeCurrent();
+ m_context->deleteLater();
+ } else {
+ delete m_context;
+ }
+
delete m_glDevice;
}
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index 68088540c6..237077400b 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -498,15 +498,32 @@ void QIOSInputContext::scrollToCursor()
return;
}
- const int margin = 20;
- QRectF translatedCursorPos = qApp->inputMethod()->cursorRectangle();
- translatedCursorPos.translate(focusView().qwindow->geometry().topLeft());
-
- qreal keyboardY = [rootView convertRect:m_keyboardState.keyboardEndRect fromView:nil].origin.y;
- int statusBarY = qGuiApp->primaryScreen()->availableGeometry().y();
+ QWindow *focusWindow = qApp->focusWindow();
+ QRect cursorRect = qApp->inputMethod()->cursorRectangle().translated(focusWindow->geometry().topLeft()).toRect();
+ if (cursorRect.isNull()) {
+ scroll(0);
+ return;
+ }
- scroll((translatedCursorPos.bottomLeft().y() < keyboardY - margin) ? 0
- : qMin(rootView.bounds.size.height - keyboardY, translatedCursorPos.y() - statusBarY - margin));
+ // Add some padding so that the cusor does not end up directly above the keyboard
+ static const int kCursorRectPadding = 20;
+ cursorRect.adjust(0, -kCursorRectPadding, 0, kCursorRectPadding);
+
+ // We explicitly ask for the geometry of the screen instead of the availableGeometry,
+ // as we hide the statusbar when scrolling the screen, so the available geometry will
+ // include the space taken by the status bar at the moment.
+ QRect screenGeometry = focusWindow->screen()->geometry();
+ QRect keyboardGeometry = QRectF::fromCGRect(m_keyboardState.keyboardEndRect).toRect();
+ QRect availableGeometry = (QRegion(screenGeometry) - keyboardGeometry).boundingRect();
+
+ if (!availableGeometry.contains(cursorRect, true)) {
+ qImDebug() << "cursor rect" << cursorRect << "not fully within" << availableGeometry;
+ int scrollToCenter = -(availableGeometry.center() - cursorRect.center()).y();
+ int scrollToBottom = focusWindow->screen()->geometry().bottom() - availableGeometry.bottom();
+ scroll(qMin(scrollToCenter, scrollToBottom));
+ } else {
+ scroll(0);
+ }
}
void QIOSInputContext::scroll(int y)
@@ -519,6 +536,8 @@ void QIOSInputContext::scroll(int y)
if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform))
return;
+ qImDebug() << "scrolling root view to y =" << -y;
+
QPointer<QIOSInputContext> self = this;
[UIView animateWithDuration:m_keyboardState.animationDuration delay:0
options:(m_keyboardState.animationCurve << 16) | UIViewAnimationOptionBeginFromCurrentState
@@ -631,11 +650,21 @@ void QIOSInputContext::focusWindowChanged(QWindow *focusWindow)
*/
void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties)
{
+ qImDebug() << "fw =" << qApp->focusWindow() << "fo =" << qApp->focusObject();
+
+ // Changes to the focus object should always result in a call to setFocusObject(),
+ // triggering a reset() which will update all the properties based on the new
+ // focus object. We try to detect code paths that fail this assertion and smooth
+ // over the situation by doing a manual update of the focus object.
+ if (qApp->focusObject() != m_imeState.focusObject && updatedProperties != Qt::ImQueryAll) {
+ qWarning() << "stale focus object" << m_imeState.focusObject << ", doing manual update";
+ setFocusObject(qApp->focusObject());
+ return;
+ }
+
// Mask for properties that we are interested in and see if any of them changed
updatedProperties &= (Qt::ImEnabled | Qt::ImHints | Qt::ImQueryInput | Qt::ImEnterKeyType | Qt::ImPlatformData);
- qImDebug() << "fw =" << qApp->focusWindow() << "fo =" << qApp->focusObject();
-
// Perform update first, so we can trust the value of inputMethodAccepted()
Qt::InputMethodQueries changedProperties = m_imeState.update(updatedProperties);
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index e5b4d6da85..5c42828885 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -61,6 +61,7 @@
#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
#include <QtClipboardSupport/private/qmacmime_p.h>
#include <QDir>
+#include <QOperatingSystemVersion>
#import <AudioToolbox/AudioServices.h>
@@ -68,13 +69,15 @@
QT_BEGIN_NAMESPACE
+class QCoreTextFontEngine;
+
QIOSIntegration *QIOSIntegration::instance()
{
return static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
}
QIOSIntegration::QIOSIntegration()
- : m_fontDatabase(new QCoreTextFontDatabase)
+ : m_fontDatabase(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>)
#if !defined(Q_OS_TVOS) && !defined(QT_NO_CLIPBOARD)
, m_clipboard(new QIOSClipboard)
#endif
@@ -119,7 +122,7 @@ QIOSIntegration::QIOSIntegration()
m_touchDevice = new QTouchDevice;
m_touchDevice->setType(QTouchDevice::TouchScreen);
QTouchDevice::Capabilities touchCapabilities = QTouchDevice::Position | QTouchDevice::NormalizedPosition;
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_9_0) {
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)) {
if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
touchCapabilities |= QTouchDevice::Pressure;
}
diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm
index 50d5442f17..4f0c667861 100644
--- a/src/plugins/platforms/ios/qiosmessagedialog.mm
+++ b/src/plugins/platforms/ios/qiosmessagedialog.mm
@@ -39,6 +39,7 @@
#import <UIKit/UIKit.h>
+#include <QtCore/qoperatingsystemversion.h>
#include <QtGui/qwindow.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformtheme.h>
@@ -109,7 +110,7 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win
if (m_alertController // Ensure that the dialog is not showing already
|| !options() // Some message dialogs don't have options (QErrorMessage)
|| windowModality == Qt::NonModal // We can only do modal dialogs
- || QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_8_0) // API limitation
+ || QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) // API limitation
return false;
m_alertController = [[UIAlertController
diff --git a/src/plugins/platforms/ios/qiosoptionalplugininterface.h b/src/plugins/platforms/ios/qiosoptionalplugininterface.h
index bcb8978e02..3f74e41c83 100644
--- a/src/plugins/platforms/ios/qiosoptionalplugininterface.h
+++ b/src/plugins/platforms/ios/qiosoptionalplugininterface.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index c518f9111d..3514bf63bb 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -45,6 +45,7 @@
#include "qiosapplicationdelegate.h"
#include "qiosviewcontroller.h"
#include "quiview.h"
+#include <QtCore/qoperatingsystemversion.h>
#include <QtGui/private/qwindow_p.h>
#include <private/qcoregraphics_p.h>
@@ -274,7 +275,7 @@ void QIOSScreen::updateProperties()
if (m_uiScreen == [UIScreen mainScreen]) {
Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation));
- if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_8_0) {
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) {
// On iOS < 8.0 the UIScreen geometry is always in portait, and the system applies
// the screen rotation to the root view-controller's view instead of directly to the
// screen, like iOS 8 and above does.
@@ -302,7 +303,7 @@ void QIOSScreen::updateProperties()
if (m_geometry != previousGeometry) {
QRectF physicalGeometry;
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) {
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) {
// We can't use the primaryOrientation of screen(), as we haven't reported the new geometry yet
Qt::ScreenOrientation primaryOrientation = m_geometry.width() >= m_geometry.height() ?
Qt::LandscapeOrientation : Qt::PortraitOrientation;
@@ -406,10 +407,11 @@ qreal QIOSScreen::devicePixelRatio() const
Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
{
CGRect nativeBounds =
-#if !defined(Q_OS_TVOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
- QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0 ? m_uiScreen.nativeBounds :
-#endif
+#if defined(Q_OS_IOS)
+ m_uiScreen.nativeBounds;
+#else
m_uiScreen.bounds;
+#endif
// All known iOS devices have a native orientation of portrait, but to
// be on the safe side we compare the width and height of the bounds.
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.h b/src/plugins/platforms/ios/qiostextinputoverlay.h
index 2f01993b19..9ed3a9b271 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.h
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
index 238d7addf6..9b97ce17bb 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.mm
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -110,6 +116,11 @@ static void executeBlockWithoutAnimation(Block block)
dispatch_async(dispatch_get_main_queue (), ^{ self.visible = YES; });
}
}];
+ [center addObserverForName:UIKeyboardDidHideNotification object:nil queue:nil
+ usingBlock:^(NSNotification *) {
+ self.visible = NO;
+ }];
+
}
return self;
@@ -219,7 +230,7 @@ static void executeBlockWithoutAnimation(Block block)
borderLayer.borderColor = [[UIColor lightGrayColor] CGColor];
[self addSublayer:borderLayer];
- if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0) {
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 7)) {
// [UIView snapshotViewAfterScreenUpdates:] is available since iOS 7.0.
// Just silently ignore showing the loupe for older versions.
self.hidden = YES;
@@ -267,7 +278,7 @@ static void executeBlockWithoutAnimation(Block block)
- (void)display
{
- if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0)
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 7))
return;
// Take a snapshow of the target view, magnify the area around the focal
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index 2a1444e9e5..9966bd50a3 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -48,6 +48,7 @@
#include "qiosmenu.h"
#endif
+#include <QtCore/qoperatingsystemversion.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qwindow_p.h>
#include <qpa/qwindowsysteminterface_p.h>
@@ -208,18 +209,23 @@
- (BOOL)becomeFirstResponder
{
- FirstResponderCandidate firstResponderCandidate(self);
+ {
+ // Scope for the duration of becoming first responder only, as the window
+ // activation event may trigger new responders, which we don't want to be
+ // blocked by this guard.
+ FirstResponderCandidate firstResponderCandidate(self);
- qImDebug() << "win:" << m_qioswindow->window() << "self:" << self
- << "first:" << [UIResponder currentFirstResponder];
+ qImDebug() << "win:" << m_qioswindow->window() << "self:" << self
+ << "first:" << [UIResponder currentFirstResponder];
- if (![super becomeFirstResponder]) {
- qImDebug() << m_qioswindow->window()
- << "was not allowed to become first responder";
- return NO;
- }
+ if (![super becomeFirstResponder]) {
+ qImDebug() << m_qioswindow->window()
+ << "was not allowed to become first responder";
+ return NO;
+ }
- qImDebug() << m_qioswindow->window() << "became first responder";
+ qImDebug() << m_qioswindow->window() << "became first responder";
+ }
if (qGuiApp->focusWindow() != m_qioswindow->window())
QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(m_qioswindow->window());
@@ -291,7 +297,7 @@
QTouchDevice *touchDevice = QIOSIntegration::instance()->touchDevice();
QTouchDevice::Capabilities touchCapabilities = touchDevice->capabilities();
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_9_0) {
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)) {
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
touchCapabilities |= QTouchDevice::Pressure;
else
diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro
index e2fa31211d..d3a4476f80 100644
--- a/src/plugins/platforms/linuxfb/linuxfb.pro
+++ b/src/plugins/platforms/linuxfb/linuxfb.pro
@@ -10,8 +10,18 @@ QT += \
qtHaveModule(input_support-private): \
QT += input_support-private
-SOURCES = main.cpp qlinuxfbintegration.cpp qlinuxfbscreen.cpp
-HEADERS = qlinuxfbintegration.h qlinuxfbscreen.h
+SOURCES = main.cpp \
+ qlinuxfbintegration.cpp \
+ qlinuxfbscreen.cpp
+
+HEADERS = qlinuxfbintegration.h \
+ qlinuxfbscreen.h
+
+qtHaveModule(kms_support-private) {
+ QT += kms_support-private
+ SOURCES += qlinuxfbdrmscreen.cpp
+ HEADERS += qlinuxfbdrmscreen.h
+}
OTHER_FILES += linuxfb.json
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp
new file mode 100644
index 0000000000..2ca251c4af
--- /dev/null
+++ b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.cpp
@@ -0,0 +1,412 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Experimental DRM dumb buffer backend.
+//
+// TODO:
+// Multiscreen: QWindow-QScreen(-output) association. Needs some reorg (device cannot be owned by screen)
+// Find card via devicediscovery like in eglfs_kms.
+// Mode restore like QEglFSKmsInterruptHandler.
+// Formats other then 32 bpp?
+// grabWindow
+
+#include "qlinuxfbdrmscreen.h"
+#include <QLoggingCategory>
+#include <QGuiApplication>
+#include <QPainter>
+#include <QtFbSupport/private/qfbcursor_p.h>
+#include <QtFbSupport/private/qfbwindow_p.h>
+#include <QtKmsSupport/private/qkmsdevice_p.h>
+#include <QtCore/private/qcore_unix_p.h>
+#include <sys/mman.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcFbDrm, "qt.qpa.fb")
+
+static const int BUFFER_COUNT = 2;
+
+class QLinuxFbDevice : public QKmsDevice
+{
+public:
+ struct Framebuffer {
+ Framebuffer() : handle(0), pitch(0), size(0), fb(0), p(MAP_FAILED) { }
+ uint32_t handle;
+ uint32_t pitch;
+ uint64_t size;
+ uint32_t fb;
+ void *p;
+ QImage wrapper;
+ };
+
+ struct Output {
+ Output() : backFb(0), flipped(false) { }
+ QKmsOutput kmsOutput;
+ Framebuffer fb[BUFFER_COUNT];
+ QRegion dirty[BUFFER_COUNT];
+ int backFb;
+ bool flipped;
+ QSize currentRes() const {
+ const drmModeModeInfo &modeInfo(kmsOutput.modes[kmsOutput.mode]);
+ return QSize(modeInfo.hdisplay, modeInfo.vdisplay);
+ }
+ };
+
+ QLinuxFbDevice(QKmsScreenConfig *screenConfig);
+
+ bool open() override;
+ void close() override;
+
+ void createFramebuffers();
+ void destroyFramebuffers();
+ void setMode();
+
+ void swapBuffers(Output *output);
+
+ int outputCount() const { return m_outputs.count(); }
+ Output *output(int idx) { return &m_outputs[idx]; }
+
+private:
+ void *nativeDisplay() const override;
+ QPlatformScreen *createScreen(const QKmsOutput &output) override;
+ void registerScreen(QPlatformScreen *screen,
+ bool isPrimary,
+ const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings) override;
+
+ bool createFramebuffer(Output *output, int bufferIdx);
+ void destroyFramebuffer(Output *output, int bufferIdx);
+
+ static void pageFlipHandler(int fd, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data);
+
+ QVector<Output> m_outputs;
+};
+
+QLinuxFbDevice::QLinuxFbDevice(QKmsScreenConfig *screenConfig)
+ : QKmsDevice(screenConfig, QStringLiteral("/dev/dri/card0"))
+{
+}
+
+bool QLinuxFbDevice::open()
+{
+ int fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
+ if (fd == -1) {
+ qErrnoWarning("Could not open DRM device %s", qPrintable(devicePath()));
+ return false;
+ }
+
+ uint64_t hasDumbBuf = 0;
+ if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &hasDumbBuf) == -1 || !hasDumbBuf) {
+ qWarning("Dumb buffers not supported");
+ qt_safe_close(fd);
+ return false;
+ }
+
+ setFd(fd);
+
+ qCDebug(qLcFbDrm, "DRM device %s opened", qPrintable(devicePath()));
+
+ return true;
+}
+
+void QLinuxFbDevice::close()
+{
+ for (Output &output : m_outputs)
+ output.kmsOutput.cleanup(this); // restore mode
+
+ m_outputs.clear();
+
+ if (fd() != -1) {
+ qCDebug(qLcFbDrm, "Closing DRM device");
+ qt_safe_close(fd());
+ setFd(-1);
+ }
+}
+
+void *QLinuxFbDevice::nativeDisplay() const
+{
+ Q_UNREACHABLE();
+ return nullptr;
+}
+
+QPlatformScreen *QLinuxFbDevice::createScreen(const QKmsOutput &output)
+{
+ qCDebug(qLcFbDrm, "Got a new output: %s", qPrintable(output.name));
+ Output o;
+ o.kmsOutput = output;
+ m_outputs.append(o);
+ return nullptr; // no platformscreen, we are not a platform plugin
+}
+
+void QLinuxFbDevice::registerScreen(QPlatformScreen *screen,
+ bool isPrimary,
+ const QPoint &virtualPos,
+ const QList<QPlatformScreen *> &virtualSiblings)
+{
+ Q_UNUSED(screen);
+ Q_UNUSED(isPrimary);
+ Q_UNUSED(virtualPos);
+ Q_UNUSED(virtualSiblings);
+ Q_UNREACHABLE();
+}
+
+bool QLinuxFbDevice::createFramebuffer(QLinuxFbDevice::Output *output, int bufferIdx)
+{
+ const QSize size = output->currentRes();
+ const uint32_t w = size.width();
+ const uint32_t h = size.height();
+ drm_mode_create_dumb creq = {
+ h,
+ w,
+ 32,
+ 0, 0, 0, 0
+ };
+ if (drmIoctl(fd(), DRM_IOCTL_MODE_CREATE_DUMB, &creq) == -1) {
+ qErrnoWarning(errno, "Failed to create dumb buffer");
+ return false;
+ }
+
+ Framebuffer &fb(output->fb[bufferIdx]);
+ fb.handle = creq.handle;
+ fb.pitch = creq.pitch;
+ fb.size = creq.size;
+ qCDebug(qLcFbDrm, "Got a dumb buffer for size %dx%d, handle %u, pitch %u, size %u",
+ w, h, fb.handle, fb.pitch, (uint) fb.size);
+
+ if (drmModeAddFB(fd(), w, h, 24, 32, fb.pitch, fb.handle, &fb.fb) == -1) {
+ qErrnoWarning(errno, "Failed to add FB");
+ return false;
+ }
+
+ drm_mode_map_dumb mreq = {
+ fb.handle,
+ 0, 0
+ };
+ if (drmIoctl(fd(), DRM_IOCTL_MODE_MAP_DUMB, &mreq) == -1) {
+ qErrnoWarning(errno, "Failed to map dumb buffer");
+ return false;
+ }
+ fb.p = mmap(0, fb.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd(), mreq.offset);
+ if (fb.p == MAP_FAILED) {
+ qErrnoWarning(errno, "Failed to mmap dumb buffer");
+ return false;
+ }
+
+ qCDebug(qLcFbDrm, "FB is %u, mapped at %p", fb.fb, fb.p);
+ memset(fb.p, 0, fb.size);
+
+ fb.wrapper = QImage(static_cast<uchar *>(fb.p), w, h, fb.pitch, QImage::Format_ARGB32);
+
+ return true;
+}
+
+void QLinuxFbDevice::createFramebuffers()
+{
+ for (Output &output : m_outputs) {
+ for (int i = 0; i < BUFFER_COUNT; ++i) {
+ if (!createFramebuffer(&output, i))
+ return;
+ }
+ output.backFb = 0;
+ output.flipped = false;
+ }
+}
+
+void QLinuxFbDevice::destroyFramebuffer(QLinuxFbDevice::Output *output, int bufferIdx)
+{
+ Framebuffer &fb(output->fb[bufferIdx]);
+ if (fb.p != MAP_FAILED)
+ munmap(fb.p, fb.size);
+ if (fb.fb) {
+ if (drmModeRmFB(fd(), fb.fb) == -1)
+ qErrnoWarning("Failed to remove fb");
+ }
+ if (fb.handle) {
+ drm_mode_destroy_dumb dreq = { fb.handle };
+ if (drmIoctl(fd(), DRM_IOCTL_MODE_DESTROY_DUMB, &dreq) == -1)
+ qErrnoWarning(errno, "Failed to destroy dumb buffer %u", fb.handle);
+ }
+ fb = Framebuffer();
+}
+
+void QLinuxFbDevice::destroyFramebuffers()
+{
+ for (Output &output : m_outputs) {
+ for (int i = 0; i < BUFFER_COUNT; ++i)
+ destroyFramebuffer(&output, i);
+ }
+}
+
+void QLinuxFbDevice::setMode()
+{
+ for (Output &output : m_outputs) {
+ drmModeModeInfo &modeInfo(output.kmsOutput.modes[output.kmsOutput.mode]);
+ if (drmModeSetCrtc(fd(), output.kmsOutput.crtc_id, output.fb[0].fb, 0, 0,
+ &output.kmsOutput.connector_id, 1, &modeInfo) == -1) {
+ qErrnoWarning(errno, "Failed to set mode");
+ return;
+ }
+
+ output.kmsOutput.mode_set = true; // have cleanup() to restore the mode
+ output.kmsOutput.setPowerState(this, QPlatformScreen::PowerStateOn);
+ }
+}
+
+void QLinuxFbDevice::pageFlipHandler(int fd, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec,
+ void *user_data)
+{
+ Q_UNUSED(fd);
+ Q_UNUSED(sequence);
+ Q_UNUSED(tv_sec);
+ Q_UNUSED(tv_usec);
+
+ Output *output = static_cast<Output *>(user_data);
+ output->backFb = (output->backFb + 1) % BUFFER_COUNT;
+}
+
+void QLinuxFbDevice::swapBuffers(Output *output)
+{
+ Framebuffer &fb(output->fb[output->backFb]);
+ if (drmModePageFlip(fd(), output->kmsOutput.crtc_id, fb.fb, DRM_MODE_PAGE_FLIP_EVENT, output) == -1) {
+ qErrnoWarning(errno, "Page flip failed");
+ return;
+ }
+
+ const int fbIdx = output->backFb;
+ while (output->backFb == fbIdx) {
+ drmEventContext drmEvent = {
+ DRM_EVENT_CONTEXT_VERSION,
+ nullptr,
+ pageFlipHandler
+ };
+ // Blocks until there is something to read on the drm fd
+ // and calls back pageFlipHandler once the flip completes.
+ drmHandleEvent(fd(), &drmEvent);
+ }
+}
+
+QLinuxFbDrmScreen::QLinuxFbDrmScreen(const QStringList &args)
+ : m_screenConfig(nullptr),
+ m_device(nullptr)
+{
+ Q_UNUSED(args);
+}
+
+QLinuxFbDrmScreen::~QLinuxFbDrmScreen()
+{
+ if (m_device) {
+ m_device->destroyFramebuffers();
+ m_device->close();
+ delete m_device;
+ }
+ delete m_screenConfig;
+}
+
+bool QLinuxFbDrmScreen::initialize()
+{
+ m_screenConfig = new QKmsScreenConfig;
+ m_device = new QLinuxFbDevice(m_screenConfig);
+ if (!m_device->open())
+ return false;
+
+ // Discover outputs. Calls back Device::createScreen().
+ m_device->createScreens();
+ // Now off to dumb buffer specifics.
+ m_device->createFramebuffers();
+ // Do the modesetting.
+ m_device->setMode();
+
+ QLinuxFbDevice::Output *output(m_device->output(0));
+
+ mGeometry = QRect(QPoint(0, 0), output->currentRes());
+ mDepth = 32;
+ mFormat = QImage::Format_ARGB32;
+ mPhysicalSize = output->kmsOutput.physical_size;
+ qCDebug(qLcFbDrm) << mGeometry << mPhysicalSize;
+
+ QFbScreen::initializeCompositor();
+
+ mCursor = new QFbCursor(this);
+
+ return true;
+}
+
+QRegion QLinuxFbDrmScreen::doRedraw()
+{
+ const QRegion dirty = QFbScreen::doRedraw();
+ if (dirty.isEmpty())
+ return dirty;
+
+ QLinuxFbDevice::Output *output(m_device->output(0));
+
+ for (int i = 0; i < BUFFER_COUNT; ++i)
+ output->dirty[i] += dirty;
+
+ if (output->fb[output->backFb].wrapper.isNull())
+ return dirty;
+
+ QPainter pntr(&output->fb[output->backFb].wrapper);
+ // Image has alpha but no need for blending at this stage.
+ // Do not waste time with the default SourceOver.
+ pntr.setCompositionMode(QPainter::CompositionMode_Source);
+ for (const QRect &rect : qAsConst(output->dirty[output->backFb]))
+ pntr.drawImage(rect, mScreenImage, rect);
+ pntr.end();
+
+ output->dirty[output->backFb] = QRegion();
+
+ m_device->swapBuffers(output);
+
+ return dirty;
+}
+
+QPixmap QLinuxFbDrmScreen::grabWindow(WId wid, int x, int y, int width, int height) const
+{
+ Q_UNUSED(wid);
+ Q_UNUSED(x);
+ Q_UNUSED(y);
+ Q_UNUSED(width);
+ Q_UNUSED(height);
+
+ return QPixmap();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h
new file mode 100644
index 0000000000..50a9576798
--- /dev/null
+++ b/src/plugins/platforms/linuxfb/qlinuxfbdrmscreen.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QLINUXFBDRMSCREEN_H
+#define QLINUXFBDRMSCREEN_H
+
+#include <QtFbSupport/private/qfbscreen_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QKmsScreenConfig;
+class QLinuxFbDevice;
+
+class QLinuxFbDrmScreen : public QFbScreen
+{
+ Q_OBJECT
+public:
+ QLinuxFbDrmScreen(const QStringList &args);
+ ~QLinuxFbDrmScreen();
+
+ bool initialize() override;
+ QRegion doRedraw() override;
+ QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override;
+
+private:
+ QKmsScreenConfig *m_screenConfig;
+ QLinuxFbDevice *m_device;
+};
+
+QT_END_NAMESPACE
+
+#endif // QLINUXFBDRMSCREEN_H
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
index c1c235588e..ce193bdf90 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp
@@ -39,6 +39,9 @@
#include "qlinuxfbintegration.h"
#include "qlinuxfbscreen.h"
+#if QT_CONFIG(kms)
+#include "qlinuxfbdrmscreen.h"
+#endif
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
#include <QtServiceSupport/private/qgenericunixservices_p.h>
@@ -69,10 +72,16 @@
QT_BEGIN_NAMESPACE
QLinuxFbIntegration::QLinuxFbIntegration(const QStringList &paramList)
- : m_fontDb(new QGenericUnixFontDatabase),
+ : m_primaryScreen(nullptr),
+ m_fontDb(new QGenericUnixFontDatabase),
m_services(new QGenericUnixServices)
{
- m_primaryScreen = new QLinuxFbScreen(paramList);
+#if QT_CONFIG(kms)
+ if (qEnvironmentVariableIntValue("QT_QPA_FB_DRM") != 0)
+ m_primaryScreen = new QLinuxFbDrmScreen(paramList);
+#endif
+ if (!m_primaryScreen)
+ m_primaryScreen = new QLinuxFbScreen(paramList);
}
QLinuxFbIntegration::~QLinuxFbIntegration()
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
index e48a1bae28..9934a8cd54 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
+++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
class QAbstractEventDispatcher;
-class QLinuxFbScreen;
+class QFbScreen;
class QFbVtHandler;
class QLinuxFbIntegration : public QPlatformIntegration, public QPlatformNativeInterface
@@ -74,7 +74,7 @@ public:
private:
void createInputHandlers();
- QLinuxFbScreen *m_primaryScreen;
+ QFbScreen *m_primaryScreen;
QPlatformInputContext *m_inputContext;
QScopedPointer<QPlatformFontDatabase> m_fontDb;
QScopedPointer<QPlatformServices> m_services;
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
index 246c959fd3..dc7ea08dc5 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
@@ -414,7 +414,7 @@ QRegion QLinuxFbScreen::doRedraw()
mBlitter->setCompositionMode(QPainter::CompositionMode_Source);
for (const QRect &rect : touched)
- mBlitter->drawImage(rect, *mScreenImage, rect);
+ mBlitter->drawImage(rect, mScreenImage, rect);
return touched;
}
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h
index 1e98191569..c7ce455e6a 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h
@@ -54,11 +54,11 @@ public:
QLinuxFbScreen(const QStringList &args);
~QLinuxFbScreen();
- bool initialize();
+ bool initialize() override;
- QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE;
+ QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override;
- QRegion doRedraw() Q_DECL_OVERRIDE;
+ QRegion doRedraw() override;
private:
QStringList mArgs;
diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp
index 03c72502cb..ca33689cd7 100644
--- a/src/plugins/platforms/minimal/qminimalintegration.cpp
+++ b/src/plugins/platforms/minimal/qminimalintegration.cpp
@@ -44,12 +44,19 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformwindow.h>
-#if defined(Q_OS_WIN)
-#include <QtFontDatabaseSupport/private/qbasicfontdatabase_p.h>
+#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
+#if defined(Q_OS_WINRT)
+# include <QtFontDatabaseSupport/private/qwinrtfontdatabase_p.h>
+#elif defined(Q_OS_WIN)
+# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
+# if QT_CONFIG(freetype)
+# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_ft_p.h>
+# endif
+#elif defined(Q_OS_DARWIN)
+# include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
#elif QT_CONFIG(fontconfig)
-#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
-#else
-#include <qpa/qplatformfontdatabase.h>
+# include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
+# include <qpa/qplatformfontdatabase.h>
#endif
#if !defined(Q_OS_WIN)
@@ -62,6 +69,8 @@
QT_BEGIN_NAMESPACE
+class QCoreTextFontEngine;
+
static const char debugBackingStoreEnvironmentVariable[] = "QT_DEBUG_BACKINGSTORE";
static inline unsigned parseOptions(const QStringList &paramList)
@@ -70,6 +79,8 @@ static inline unsigned parseOptions(const QStringList &paramList)
for (const QString &param : paramList) {
if (param == QLatin1String("enable_fonts"))
options |= QMinimalIntegration::EnableFonts;
+ else if (param == QLatin1String("freetype"))
+ options |= QMinimalIntegration::FreeTypeFontDatabase;
}
return options;
}
@@ -117,12 +128,23 @@ public:
QPlatformFontDatabase *QMinimalIntegration::fontDatabase() const
{
- if (m_options & EnableFonts) {
+ if (!m_fontDatabase && (m_options & EnableFonts)) {
#if QT_CONFIG(fontconfig)
- if (!m_fontDatabase)
- m_fontDatabase = new QGenericUnixFontDatabase;
+ m_fontDatabase = new QGenericUnixFontDatabase;
+#elif defined(Q_OS_WINRT)
+ m_fontDatabase = new QWinRTFontDatabase;
+#elif defined(Q_OS_WIN)
+ if (m_options & FreeTypeFontDatabase) {
+# if QT_CONFIG(freetype)
+ m_fontDatabase = new QWindowsFontDatabaseFT;
+# endif // freetype
+ } else {
+ m_fontDatabase = new QWindowsFontDatabase;
+ }
+#elif defined(Q_OS_DARWIN)
+ m_fontDatabase = new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>;
#else
- return QPlatformIntegration::fontDatabase();
+ m_fontDatabase = QPlatformIntegration::fontDatabase();
#endif
}
if (!m_fontDatabase)
diff --git a/src/plugins/platforms/minimal/qminimalintegration.h b/src/plugins/platforms/minimal/qminimalintegration.h
index 755664d14d..eaa2f228c5 100644
--- a/src/plugins/platforms/minimal/qminimalintegration.h
+++ b/src/plugins/platforms/minimal/qminimalintegration.h
@@ -67,7 +67,8 @@ class QMinimalIntegration : public QPlatformIntegration
public:
enum Options { // Options to be passed on command line or determined from environment
DebugBackingStore = 0x1,
- EnableFonts = 0x2
+ EnableFonts = 0x2,
+ FreeTypeFontDatabase = 0x4
};
explicit QMinimalIntegration(const QStringList &parameters);
diff --git a/src/plugins/platforms/minimalegl/minimalegl.pro b/src/plugins/platforms/minimalegl/minimalegl.pro
index 88466e7f36..b7dde9069f 100644
--- a/src/plugins/platforms/minimalegl/minimalegl.pro
+++ b/src/plugins/platforms/minimalegl/minimalegl.pro
@@ -14,14 +14,17 @@ DEFINES += QT_EGL_NO_X11
SOURCES = main.cpp \
qminimaleglintegration.cpp \
qminimaleglwindow.cpp \
- qminimaleglbackingstore.cpp \
qminimaleglscreen.cpp
HEADERS = qminimaleglintegration.h \
qminimaleglwindow.h \
- qminimaleglbackingstore.h \
qminimaleglscreen.h
+qtConfig(opengl) {
+ SOURCES += qminimaleglbackingstore.cpp
+ HEADERS += qminimaleglbackingstore.h
+}
+
CONFIG += egl
OTHER_FILES += \
diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
index c564e1e431..81512b1561 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp
@@ -40,8 +40,9 @@
#include "qminimaleglintegration.h"
#include "qminimaleglwindow.h"
-#include "qminimaleglbackingstore.h"
-
+#ifndef QT_NO_OPENGL
+# include "qminimaleglbackingstore.h"
+#endif
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
#if defined(Q_OS_UNIX)
@@ -127,13 +128,18 @@ QPlatformBackingStore *QMinimalEglIntegration::createPlatformBackingStore(QWindo
#ifdef QEGL_EXTRA_DEBUG
qWarning("QMinimalEglIntegration::createWindowSurface %p\n", window);
#endif
+#ifndef QT_NO_OPENGL
return new QMinimalEglBackingStore(window);
+#else
+ return nullptr;
+#endif
}
-
+#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QMinimalEglIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
return static_cast<QMinimalEglScreen *>(context->screen()->handle())->platformContext();
}
+#endif
QPlatformFontDatabase *QMinimalEglIntegration::fontDatabase() const
{
diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.h b/src/plugins/platforms/minimalegl/qminimaleglintegration.h
index 529e89f85a..d0ab75bd3c 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglintegration.h
+++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.h
@@ -55,8 +55,9 @@ public:
QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE;
+#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE;
-
+#endif
QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE;
QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp b/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp
index d3d091fab7..0175d2dbdd 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglscreen.cpp
@@ -41,7 +41,9 @@
#include "qminimaleglwindow.h"
#include <QtEglSupport/private/qeglconvenience_p.h>
-#include <QtEglSupport/private/qeglplatformcontext_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtEglSupport/private/qeglplatformcontext_p.h>
+#endif
#ifdef Q_OPENKODE
#include <KD/kd.h>
@@ -52,6 +54,8 @@ QT_BEGIN_NAMESPACE
// #define QEGL_EXTRA_DEBUG
+#ifndef QT_NO_OPENGL
+
class QMinimalEglContext : public QEGLPlatformContext
{
public:
@@ -68,6 +72,8 @@ public:
}
};
+#endif
+
QMinimalEglScreen::QMinimalEglScreen(EGLNativeDisplayType display)
: m_depth(32)
, m_format(QImage::Format_Invalid)
@@ -161,9 +167,10 @@ void QMinimalEglScreen::createAndSetPlatformContext()
}
// qWarning("Created surface %dx%d\n", w, h);
+#ifndef QT_NO_OPENGL
QEGLPlatformContext *platformContext = new QMinimalEglContext(platformFormat, 0, m_dpy);
m_platformContext = platformContext;
-
+#endif
EGLint w,h; // screen size detection
eglQuerySurface(m_dpy, m_surface, EGL_WIDTH, &w);
eglQuerySurface(m_dpy, m_surface, EGL_HEIGHT, &h);
@@ -191,6 +198,7 @@ QImage::Format QMinimalEglScreen::format() const
createAndSetPlatformContext();
return m_format;
}
+#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QMinimalEglScreen::platformContext() const
{
if (!m_platformContext) {
@@ -199,5 +207,5 @@ QPlatformOpenGLContext *QMinimalEglScreen::platformContext() const
}
return m_platformContext;
}
-
+#endif
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/minimalegl/qminimaleglscreen.h b/src/plugins/platforms/minimalegl/qminimaleglscreen.h
index ba605835a8..24098b8127 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglscreen.h
+++ b/src/plugins/platforms/minimalegl/qminimaleglscreen.h
@@ -59,9 +59,9 @@ public:
QRect geometry() const Q_DECL_OVERRIDE;
int depth() const Q_DECL_OVERRIDE;
QImage::Format format() const Q_DECL_OVERRIDE;
-
+#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *platformContext() const;
-
+#endif
EGLSurface surface() const { return m_surface; }
private:
diff --git a/src/plugins/platforms/mirclient/mirclient.pro b/src/plugins/platforms/mirclient/mirclient.pro
index 0ba63601a9..d2da7e6ca0 100644
--- a/src/plugins/platforms/mirclient/mirclient.pro
+++ b/src/plugins/platforms/mirclient/mirclient.pro
@@ -5,6 +5,9 @@ QT += \
theme_support-private eventdispatcher_support-private \
fontdatabase_support-private egl_support-private
+qtHaveModule(linuxaccessibility_support-private): \
+ QT += linuxaccessibility_support-private
+
DEFINES += MESA_EGL_NO_X11_HEADERS
# CONFIG += c++11 # only enables C++0x
QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall
@@ -13,9 +16,12 @@ QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined
QMAKE_USE_PRIVATE += mirclient
SOURCES = \
+ qmirclientappstatecontroller.cpp \
qmirclientbackingstore.cpp \
qmirclientclipboard.cpp \
qmirclientcursor.cpp \
+ qmirclientdebugextension.cpp \
+ qmirclientdesktopwindow.cpp \
qmirclientglcontext.cpp \
qmirclientinput.cpp \
qmirclientintegration.cpp \
@@ -23,13 +29,17 @@ SOURCES = \
qmirclientplatformservices.cpp \
qmirclientplugin.cpp \
qmirclientscreen.cpp \
+ qmirclientscreenobserver.cpp \
qmirclienttheme.cpp \
qmirclientwindow.cpp
HEADERS = \
+ qmirclientappstatecontroller.h \
qmirclientbackingstore.h \
qmirclientclipboard.h \
qmirclientcursor.h \
+ qmirclientdebugextension.h \
+ qmirclientdesktopwindow.h \
qmirclientglcontext.h \
qmirclientinput.h \
qmirclientintegration.h \
@@ -39,9 +49,17 @@ HEADERS = \
qmirclientplatformservices.h \
qmirclientplugin.h \
qmirclientscreen.h \
+ qmirclientscreenobserver.h \
qmirclienttheme.h \
qmirclientwindow.h
+# libxkbcommon
+!qtConfig(xkbcommon-system) {
+ include(../../../3rdparty/xkbcommon.pri)
+} else {
+ QMAKE_USE += xkbcommon
+}
+
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = MirServerIntegrationPlugin
!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
diff --git a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp
new file mode 100644
index 0000000000..69fc9b7aa7
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical, Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclientappstatecontroller.h"
+
+#include <qpa/qwindowsysteminterface.h>
+
+/*
+ * QMirClientAppStateController - updates Qt's QApplication::applicationState property.
+ *
+ * Tries to avoid active-inactive-active invocations using a timer. The rapid state
+ * change can confuse some applications.
+ */
+
+QMirClientAppStateController::QMirClientAppStateController()
+ : m_suspended(false)
+ , m_lastActive(true)
+{
+ m_inactiveTimer.setSingleShot(true);
+ m_inactiveTimer.setInterval(10);
+ QObject::connect(&m_inactiveTimer, &QTimer::timeout, []()
+ {
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
+ });
+}
+
+void QMirClientAppStateController::setSuspended()
+{
+ m_inactiveTimer.stop();
+ if (!m_suspended) {
+ m_suspended = true;
+
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
+ }
+}
+
+void QMirClientAppStateController::setResumed()
+{
+ m_inactiveTimer.stop();
+ if (m_suspended) {
+ m_suspended = false;
+
+ if (m_lastActive) {
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
+ } else {
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
+ }
+ }
+}
+
+void QMirClientAppStateController::setWindowFocused(bool focused)
+{
+ if (m_suspended) {
+ return;
+ }
+
+ if (focused) {
+ m_inactiveTimer.stop();
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
+ } else {
+ m_inactiveTimer.start();
+ }
+
+ m_lastActive = focused;
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h
new file mode 100644
index 0000000000..b3aa0022d9
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientappstatecontroller.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical, Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTAPPSTATECONTROLLER_H
+#define QMIRCLIENTAPPSTATECONTROLLER_H
+
+#include <QTimer>
+
+class QMirClientAppStateController
+{
+public:
+ QMirClientAppStateController();
+
+ void setSuspended();
+ void setResumed();
+
+ void setWindowFocused(bool focused);
+
+private:
+ bool m_suspended;
+ bool m_lastActive;
+ QTimer m_inactiveTimer;
+};
+
+#endif // QMIRCLIENTAPPSTATECONTROLLER_H
diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp
index a4bb8864ab..51363619d9 100644
--- a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp
@@ -61,6 +61,7 @@ QMirClientBackingStore::QMirClientBackingStore(QWindow* window)
QMirClientBackingStore::~QMirClientBackingStore()
{
+ mContext->makeCurrent(window()); // needed as QOpenGLTexture destructor assumes current context
}
void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const QPoint& offset)
@@ -76,7 +77,6 @@ void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const
mBlitter->create();
mBlitter->bind();
- mBlitter->setRedBlueSwizzle(true);
mBlitter->blit(mTexture->textureId(), QMatrix4x4(), QOpenGLTextureBlitter::OriginTopLeft);
mBlitter->release();
@@ -137,7 +137,9 @@ void QMirClientBackingStore::beginPaint(const QRegion& region)
void QMirClientBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/)
{
- mImage = QImage(size, QImage::Format_RGB32);
+ mImage = QImage(size, QImage::Format_RGBA8888);
+
+ mContext->makeCurrent(window());
if (mTexture->isCreated())
mTexture->destroy();
@@ -147,3 +149,9 @@ QPaintDevice* QMirClientBackingStore::paintDevice()
{
return &mImage;
}
+
+QImage QMirClientBackingStore::toImage() const
+{
+ // used by QPlatformBackingStore::composeAndFlush
+ return mImage;
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.h b/src/plugins/platforms/mirclient/qmirclientbackingstore.h
index 0c75e182ff..7644c77df2 100644
--- a/src/plugins/platforms/mirclient/qmirclientbackingstore.h
+++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.h
@@ -58,6 +58,7 @@ public:
void flush(QWindow* window, const QRegion& region, const QPoint& offset) override;
void resize(const QSize& size, const QRegion& staticContents) override;
QPaintDevice* paintDevice() override;
+ QImage toImage() const override;
protected:
void updateTexture();
diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp
index 4dff339f21..b9fc9b3b42 100644
--- a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp
@@ -39,41 +39,36 @@
#include "qmirclientclipboard.h"
+#include "qmirclientlogging.h"
+#include "qmirclientwindow.h"
+#include <QDBusPendingCallWatcher>
+#include <QGuiApplication>
+#include <QSignalBlocker>
#include <QtCore/QMimeData>
#include <QtCore/QStringList>
-#include <QDBusInterface>
-#include <QDBusPendingCallWatcher>
-#include <QDBusPendingReply>
-
-// FIXME(loicm) The clipboard data format is not defined by Ubuntu Platform API
-// which makes it impossible to have non-Qt applications communicate with Qt
-// applications through the clipboard API. The solution would be to have
-// Ubuntu Platform define the data format or propose an API that supports
-// embedding different mime types in the clipboard.
-// Data format:
-// number of mime types (sizeof(int))
-// data layout ((4 * sizeof(int)) * number of mime types)
-// mime type string offset (sizeof(int))
-// mime type string size (sizeof(int))
-// data offset (sizeof(int))
-// data size (sizeof(int))
-// data (n bytes)
+// content-hub
+#include <com/ubuntu/content/hub.h>
-namespace {
-
-const int maxFormatsCount = 16;
-const int maxBufferSize = 4 * 1024 * 1024; // 4 Mb
-
-}
+// get this cumbersome nested namespace out of the way
+using namespace com::ubuntu::content;
QMirClientClipboard::QMirClientClipboard()
: mMimeData(new QMimeData)
- , mIsOutdated(true)
- , mUpdatesDisabled(false)
- , mDBusSetupDone(false)
+ , mContentHub(Hub::Client::instance())
{
+ connect(mContentHub, &Hub::pasteboardChanged, this, [this]() {
+ if (mClipboardState == QMirClientClipboard::SyncedClipboard) {
+ mClipboardState = QMirClientClipboard::OutdatedClipboard;
+ emitChanged(QClipboard::Clipboard);
+ }
+ });
+
+ connect(qGuiApp, &QGuiApplication::applicationStateChanged,
+ this, &QMirClientClipboard::onApplicationStateChanged);
+
+ requestMimeData();
}
QMirClientClipboard::~QMirClientClipboard()
@@ -81,236 +76,106 @@ QMirClientClipboard::~QMirClientClipboard()
delete mMimeData;
}
-void QMirClientClipboard::requestDBusClipboardContents()
+QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode)
{
- if (!mDBusSetupDone) {
- setupDBus();
- }
-
- if (!mPendingGetContentsCall.isNull())
- return;
+ if (mode != QClipboard::Clipboard)
+ return nullptr;
- QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("GetContents"));
+ // Blocks dataChanged() signal from being emitted. Makes no sense to emit it from
+ // inside the data getter.
+ const QSignalBlocker blocker(this);
- mPendingGetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
+ if (mClipboardState == OutdatedClipboard) {
+ updateMimeData();
+ } else if (mClipboardState == SyncingClipboard) {
+ mPasteReply->waitForFinished();
+ }
- QObject::connect(mPendingGetContentsCall.data(), &QDBusPendingCallWatcher::finished,
- this, &QMirClientClipboard::onDBusClipboardGetContentsFinished);
+ return mMimeData;
}
-void QMirClientClipboard::onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher* call)
+void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode)
{
- Q_ASSERT(call == mPendingGetContentsCall.data());
+ QWindow *focusWindow = QGuiApplication::focusWindow();
+ if (focusWindow && mode == QClipboard::Clipboard && mimeData != nullptr) {
+ QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId();
- QDBusPendingReply<QByteArray> reply = *call;
- if (Q_UNLIKELY(reply.isError())) {
- qCritical("QMirClientClipboard - Failed to get system clipboard contents via D-Bus. %s, %s",
- qPrintable(reply.error().name()), qPrintable(reply.error().message()));
- // TODO: Might try again later a number of times...
- } else {
- QByteArray serializedMimeData = reply.argumentAt<0>();
- updateMimeData(serializedMimeData);
- }
- call->deleteLater();
-}
+ QDBusPendingCall reply = mContentHub->createPaste(surfaceId, *mimeData);
-void QMirClientClipboard::onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher *call)
-{
- QDBusPendingReply<void> reply = *call;
- if (Q_UNLIKELY(reply.isError())) {
- qCritical("QMirClientClipboard - Failed to set the system clipboard contents via D-Bus. %s, %s",
- qPrintable(reply.error().name()), qPrintable(reply.error().message()));
- // TODO: Might try again later a number of times...
- }
- call->deleteLater();
-}
-
-void QMirClientClipboard::updateMimeData(const QByteArray &serializedMimeData)
-{
- if (mUpdatesDisabled)
- return;
+ // Don't care whether it succeeded
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
+ connect(watcher, &QDBusPendingCallWatcher::finished,
+ watcher, &QObject::deleteLater);
- QMimeData *newMimeData = deserializeMimeData(serializedMimeData);
- if (newMimeData) {
- delete mMimeData;
- mMimeData = newMimeData;
- mIsOutdated = false;
+ mMimeData = mimeData;
+ mClipboardState = SyncedClipboard;
emitChanged(QClipboard::Clipboard);
- } else {
- qWarning("QMirClientClipboard - Got invalid serialized mime data. Ignoring it.");
}
}
-void QMirClientClipboard::setupDBus()
-{
- QDBusConnection dbusConnection = QDBusConnection::sessionBus();
-
- bool ok = dbusConnection.connect(
- QStringLiteral("com.canonical.QtMir"),
- QStringLiteral("/com/canonical/QtMir/Clipboard"),
- QStringLiteral("com.canonical.QtMir.Clipboard"),
- QStringLiteral("ContentsChanged"),
- this, SLOT(updateMimeData(QByteArray)));
- if (Q_UNLIKELY(!ok))
- qCritical("QMirClientClipboard - Failed to connect to ContentsChanged signal form the D-Bus system clipboard.");
-
- mDBusClipboard = new QDBusInterface(QStringLiteral("com.canonical.QtMir"),
- QStringLiteral("/com/canonical/QtMir/Clipboard"),
- QStringLiteral("com.canonical.QtMir.Clipboard"),
- dbusConnection);
-
- mDBusSetupDone = true;
-}
-
-QByteArray QMirClientClipboard::serializeMimeData(QMimeData *mimeData) const
+bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const
{
- Q_ASSERT(mimeData != nullptr);
-
- const QStringList formats = mimeData->formats();
- const int formatCount = qMin(formats.size(), maxFormatsCount);
- const int headerSize = sizeof(int) + (formatCount * 4 * sizeof(int));
- int bufferSize = headerSize;
-
- for (int i = 0; i < formatCount; i++)
- bufferSize += formats[i].size() + mimeData->data(formats[i]).size();
-
- QByteArray serializedMimeData;
- if (bufferSize <= maxBufferSize) {
- // Serialize data.
- serializedMimeData.resize(bufferSize);
- {
- char *buffer = serializedMimeData.data();
- int* header = reinterpret_cast<int*>(serializedMimeData.data());
- int offset = headerSize;
- header[0] = formatCount;
- for (int i = 0; i < formatCount; i++) {
- const QByteArray data = mimeData->data(formats[i]);
- const int formatOffset = offset;
- const int formatSize = formats[i].size();
- const int dataOffset = offset + formatSize;
- const int dataSize = data.size();
- memcpy(&buffer[formatOffset], formats[i].toLatin1().data(), formatSize);
- memcpy(&buffer[dataOffset], data.data(), dataSize);
- header[i*4+1] = formatOffset;
- header[i*4+2] = formatSize;
- header[i*4+3] = dataOffset;
- header[i*4+4] = dataSize;
- offset += formatSize + dataSize;
- }
- }
- } else {
- qWarning("QMirClientClipboard: Not sending contents (%d bytes) to the global clipboard as it's"
- " bigger than the maximum allowed size of %d bytes", bufferSize, maxBufferSize);
- }
-
- return serializedMimeData;
+ return mode == QClipboard::Clipboard;
}
-QMimeData *QMirClientClipboard::deserializeMimeData(const QByteArray &serializedMimeData) const
+bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const
{
- if (static_cast<std::size_t>(serializedMimeData.size()) < sizeof(int)) {
- // Data is invalid
- return nullptr;
- }
-
- QMimeData *mimeData = new QMimeData;
-
- const char* const buffer = serializedMimeData.constData();
- const int* const header = reinterpret_cast<const int*>(serializedMimeData.constData());
-
- const int count = qMin(header[0], maxFormatsCount);
-
- for (int i = 0; i < count; i++) {
- const int formatOffset = header[i*4+1];
- const int formatSize = header[i*4+2];
- const int dataOffset = header[i*4+3];
- const int dataSize = header[i*4+4];
-
- if (formatOffset + formatSize <= serializedMimeData.size()
- && dataOffset + dataSize <= serializedMimeData.size()) {
-
- QString mimeType = QString::fromLatin1(&buffer[formatOffset], formatSize);
- QByteArray mimeDataBytes(&buffer[dataOffset], dataSize);
-
- mimeData->setData(mimeType, mimeDataBytes);
- }
- }
-
- return mimeData;
+ Q_UNUSED(mode);
+ return false;
}
-QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode)
+void QMirClientClipboard::onApplicationStateChanged(Qt::ApplicationState state)
{
- if (mode != QClipboard::Clipboard)
- return nullptr;
-
- if (mIsOutdated && mPendingGetContentsCall.isNull()) {
- requestDBusClipboardContents();
+ if (state == Qt::ApplicationActive) {
+ // Only focused or active applications might be allowed to paste, so we probably
+ // missed changes in the clipboard while we were hidden, inactive or, more importantly,
+ // suspended.
+ requestMimeData();
}
-
- // Return whatever we have at the moment instead of blocking until we have something.
- //
- // This might be called during app startup just for the sake of checking if some
- // "Paste" UI control should be enabled or not.
- // We will emit QClipboard::changed() once we finally have something.
- return mMimeData;
}
-void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode)
+void QMirClientClipboard::updateMimeData()
{
- if (mode != QClipboard::Clipboard)
+ if (qGuiApp->applicationState() != Qt::ApplicationActive) {
+ // Don't even bother asking as content-hub would probably ignore our request (and should).
return;
-
- if (!mPendingGetContentsCall.isNull()) {
- // Ignore whatever comes from the system clipboard as we are going to change it anyway
- QObject::disconnect(mPendingGetContentsCall.data(), 0, this, 0);
- mUpdatesDisabled = true;
- mPendingGetContentsCall->waitForFinished();
- mUpdatesDisabled = false;
- delete mPendingGetContentsCall.data();
}
- if (mimeData != nullptr) {
- QByteArray serializedMimeData = serializeMimeData(mimeData);
- if (!serializedMimeData.isEmpty()) {
- setDBusClipboardContents(serializedMimeData);
- }
+ delete mMimeData;
- mMimeData = mimeData;
+ QWindow *focusWindow = QGuiApplication::focusWindow();
+ if (focusWindow) {
+ QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId();
+ mMimeData = mContentHub->latestPaste(surfaceId);
+ mClipboardState = SyncedClipboard;
emitChanged(QClipboard::Clipboard);
}
}
-bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const
-{
- return mode == QClipboard::Clipboard;
-}
-
-bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const
+void QMirClientClipboard::requestMimeData()
{
- Q_UNUSED(mode);
- return false;
-}
-
-void QMirClientClipboard::setDBusClipboardContents(const QByteArray &clipboardContents)
-{
- if (!mDBusSetupDone) {
- setupDBus();
+ if (qGuiApp->applicationState() != Qt::ApplicationActive) {
+ // Don't even bother asking as content-hub would probably ignore our request (and should).
+ return;
}
- if (!mPendingSetContentsCall.isNull()) {
- // Ignore any previous set call as we are going to overwrite it anyway
- QObject::disconnect(mPendingSetContentsCall.data(), 0, this, 0);
- mUpdatesDisabled = true;
- mPendingSetContentsCall->waitForFinished();
- mUpdatesDisabled = false;
- delete mPendingSetContentsCall.data();
+ QWindow *focusWindow = QGuiApplication::focusWindow();
+ if (!focusWindow) {
+ return;
}
- QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("SetContents"), clipboardContents);
-
- mPendingSetContentsCall = new QDBusPendingCallWatcher(pendingCall, this);
+ QString surfaceId = static_cast<QMirClientWindow*>(focusWindow->handle())->persistentSurfaceId();
+ QDBusPendingCall reply = mContentHub->requestLatestPaste(surfaceId);
+ mClipboardState = SyncingClipboard;
- QObject::connect(mPendingSetContentsCall.data(), &QDBusPendingCallWatcher::finished,
- this, &QMirClientClipboard::onDBusClipboardSetContentsFinished);
+ mPasteReply = new QDBusPendingCallWatcher(reply, this);
+ connect(mPasteReply, &QDBusPendingCallWatcher::finished,
+ this, [this]() {
+ delete mMimeData;
+ mMimeData = mContentHub->paste(*mPasteReply);
+ mClipboardState = SyncedClipboard;
+ mPasteReply->deleteLater();
+ mPasteReply = nullptr;
+ emitChanged(QClipboard::Clipboard);
+ });
}
diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.h b/src/plugins/platforms/mirclient/qmirclientclipboard.h
index 1394498320..09e9bcdf38 100644
--- a/src/plugins/platforms/mirclient/qmirclientclipboard.h
+++ b/src/plugins/platforms/mirclient/qmirclientclipboard.h
@@ -45,7 +45,15 @@
#include <QMimeData>
#include <QPointer>
-class QDBusInterface;
+
+namespace com {
+ namespace ubuntu {
+ namespace content {
+ class Hub;
+ }
+ }
+}
+
class QDBusPendingCallWatcher;
class QMirClientClipboard : public QObject, public QPlatformClipboard
@@ -61,31 +69,24 @@ public:
bool supportsMode(QClipboard::Mode mode) const override;
bool ownsMode(QClipboard::Mode mode) const override;
- void requestDBusClipboardContents();
-
private Q_SLOTS:
- void onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*);
- void onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*);
- void updateMimeData(const QByteArray &serializedMimeData);
+ void onApplicationStateChanged(Qt::ApplicationState state);
private:
- void setupDBus();
-
- QByteArray serializeMimeData(QMimeData *mimeData) const;
- QMimeData *deserializeMimeData(const QByteArray &serializedMimeData) const;
-
- void setDBusClipboardContents(const QByteArray &clipboardContents);
+ void updateMimeData();
+ void requestMimeData();
QMimeData *mMimeData;
- bool mIsOutdated;
- QPointer<QDBusInterface> mDBusClipboard;
+ enum {
+ OutdatedClipboard, // Our mimeData is outdated, need to fetch latest from ContentHub
+ SyncingClipboard, // Our mimeData is outdated and we are waiting for ContentHub to reply with the latest paste
+ SyncedClipboard // Our mimeData is in sync with what ContentHub has
+ } mClipboardState{OutdatedClipboard};
- QPointer<QDBusPendingCallWatcher> mPendingGetContentsCall;
- QPointer<QDBusPendingCallWatcher> mPendingSetContentsCall;
+ com::ubuntu::content::Hub *mContentHub;
- bool mUpdatesDisabled;
- bool mDBusSetupDone;
+ QDBusPendingCallWatcher *mPasteReply{nullptr};
};
#endif // QMIRCLIENTCLIPBOARD_H
diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.cpp b/src/plugins/platforms/mirclient/qmirclientcursor.cpp
index a0da3fdd77..812cde95c6 100644
--- a/src/plugins/platforms/mirclient/qmirclientcursor.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientcursor.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 Canonical, Ltd.
+** Copyright (C) 2015-2016 Canonical, Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -45,35 +45,41 @@
#include <mir_toolkit/mir_client_library.h>
+Q_LOGGING_CATEGORY(mirclientCursor, "qt.qpa.mirclient.cursor", QtWarningMsg)
+
QMirClientCursor::QMirClientCursor(MirConnection *connection)
: mConnection(connection)
{
- mShapeToCursorName[Qt::ArrowCursor] = "left_ptr";
+ /*
+ * TODO: Add the missing cursors to Mir (LP: #1388987)
+ * Those are the ones without a mir_ prefix, which are X11 cursors
+ * and won't be understood by any shell other than Unity8.
+ */
+ mShapeToCursorName[Qt::ArrowCursor] = mir_arrow_cursor_name;
mShapeToCursorName[Qt::UpArrowCursor] = "up_arrow";
- mShapeToCursorName[Qt::CrossCursor] = "cross";
- mShapeToCursorName[Qt::WaitCursor] = "watch";
- mShapeToCursorName[Qt::IBeamCursor] = "xterm";
- mShapeToCursorName[Qt::SizeVerCursor] = "size_ver";
- mShapeToCursorName[Qt::SizeHorCursor] = "size_hor";
- mShapeToCursorName[Qt::SizeBDiagCursor] = "size_bdiag";
- mShapeToCursorName[Qt::SizeFDiagCursor] = "size_fdiag";
- mShapeToCursorName[Qt::SizeAllCursor] = "size_all";
- mShapeToCursorName[Qt::BlankCursor] = "blank";
- mShapeToCursorName[Qt::SplitVCursor] = "split_v";
- mShapeToCursorName[Qt::SplitHCursor] = "split_h";
- mShapeToCursorName[Qt::PointingHandCursor] = "hand";
+ mShapeToCursorName[Qt::CrossCursor] = mir_crosshair_cursor_name;
+ mShapeToCursorName[Qt::WaitCursor] = mir_busy_cursor_name;
+ mShapeToCursorName[Qt::IBeamCursor] = mir_caret_cursor_name;
+ mShapeToCursorName[Qt::SizeVerCursor] = mir_vertical_resize_cursor_name;
+ mShapeToCursorName[Qt::SizeHorCursor] = mir_horizontal_resize_cursor_name;
+ mShapeToCursorName[Qt::SizeBDiagCursor] = mir_diagonal_resize_bottom_to_top_cursor_name;
+ mShapeToCursorName[Qt::SizeFDiagCursor] = mir_diagonal_resize_top_to_bottom_cursor_name;
+ mShapeToCursorName[Qt::SizeAllCursor] = mir_omnidirectional_resize_cursor_name;
+ mShapeToCursorName[Qt::BlankCursor] = mir_disabled_cursor_name;
+ mShapeToCursorName[Qt::SplitVCursor] = mir_vsplit_resize_cursor_name;
+ mShapeToCursorName[Qt::SplitHCursor] = mir_hsplit_resize_cursor_name;
+ mShapeToCursorName[Qt::PointingHandCursor] = mir_pointing_hand_cursor_name;
mShapeToCursorName[Qt::ForbiddenCursor] = "forbidden";
mShapeToCursorName[Qt::WhatsThisCursor] = "whats_this";
mShapeToCursorName[Qt::BusyCursor] = "left_ptr_watch";
- mShapeToCursorName[Qt::OpenHandCursor] = "openhand";
- mShapeToCursorName[Qt::ClosedHandCursor] = "closedhand";
+ mShapeToCursorName[Qt::OpenHandCursor] = mir_open_hand_cursor_name;
+ mShapeToCursorName[Qt::ClosedHandCursor] = mir_closed_hand_cursor_name;
mShapeToCursorName[Qt::DragCopyCursor] = "dnd-copy";
mShapeToCursorName[Qt::DragMoveCursor] = "dnd-move";
mShapeToCursorName[Qt::DragLinkCursor] = "dnd-link";
}
namespace {
-#if !defined(QT_NO_DEBUG)
const char *qtCursorShapeToStr(Qt::CursorShape shape)
{
switch (shape) {
@@ -127,7 +133,6 @@ const char *qtCursorShapeToStr(Qt::CursorShape shape)
return "???";
}
}
-#endif // !defined(QT_NO_DEBUG)
} // anonymous namespace
void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window)
@@ -144,7 +149,7 @@ void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window)
if (windowCursor) {
- DLOG("[ubuntumirclient QPA] changeCursor shape=%s, window=%p\n", qtCursorShapeToStr(windowCursor->shape()), window);
+ qCDebug(mirclientCursor, "changeCursor shape=%s, window=%p", qtCursorShapeToStr(windowCursor->shape()), window);
if (!windowCursor->pixmap().isNull()) {
configureMirCursorWithPixmapQCursor(surface, *windowCursor);
} else if (windowCursor->shape() == Qt::BitmapCursor) {
diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.h b/src/plugins/platforms/mirclient/qmirclientcursor.h
index 4ecc3d97ee..c5de23b272 100644
--- a/src/plugins/platforms/mirclient/qmirclientcursor.h
+++ b/src/plugins/platforms/mirclient/qmirclientcursor.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2015 Canonical, Ltd.
+** Copyright (C) 2015-2016 Canonical, Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
diff --git a/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp b/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp
new file mode 100644
index 0000000000..9aa934083d
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientdebugextension.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical, Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclientdebugextension.h"
+
+#include "qmirclientlogging.h"
+
+// mir client debug
+#include <mir_toolkit/debug/surface.h>
+
+Q_LOGGING_CATEGORY(mirclientDebug, "qt.qpa.mirclient.debug")
+
+QMirClientDebugExtension::QMirClientDebugExtension()
+ : m_mirclientDebug(QStringLiteral("mirclient-debug-extension"), 1)
+ , m_mapper(nullptr)
+{
+ qCDebug(mirclientDebug) << "NOTICE: Loading mirclient-debug-extension";
+ m_mapper = (MapperPrototype) m_mirclientDebug.resolve("mir_debug_surface_coords_to_screen");
+
+ if (!m_mirclientDebug.isLoaded()) {
+ qCWarning(mirclientDebug) << "ERROR: mirclient-debug-extension failed to load:"
+ << m_mirclientDebug.errorString();
+ } else if (!m_mapper) {
+ qCWarning(mirclientDebug) << "ERROR: unable to find required symbols in mirclient-debug-extension:"
+ << m_mirclientDebug.errorString();
+ }
+}
+
+QPoint QMirClientDebugExtension::mapSurfacePointToScreen(MirSurface *surface, const QPoint &point)
+{
+ if (!m_mapper) {
+ return point;
+ }
+
+ QPoint mappedPoint;
+ bool status = m_mapper(surface, point.x(), point.y(), &mappedPoint.rx(), &mappedPoint.ry());
+ if (status) {
+ return mappedPoint;
+ } else {
+ return point;
+ }
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientdebugextension.h b/src/plugins/platforms/mirclient/qmirclientdebugextension.h
new file mode 100644
index 0000000000..0596561d77
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientdebugextension.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical, Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTDEBUGEXTENSION_H
+#define QMIRCLIENTDEBUGEXTENSION_H
+
+#include <QPoint>
+#include <QLibrary>
+struct MirSurface;
+
+typedef bool (*MapperPrototype)(MirSurface* surface, int x, int y, int* screenX, int* screenY);
+
+
+class QMirClientDebugExtension
+{
+public:
+ QMirClientDebugExtension();
+
+ QPoint mapSurfacePointToScreen(MirSurface *, const QPoint &point);
+
+private:
+ QLibrary m_mirclientDebug;
+ MapperPrototype m_mapper;
+};
+
+#endif // QMIRCLIENTDEBUGEXTENSION_H
diff --git a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp
new file mode 100644
index 0000000000..123f805c25
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical, Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclientdesktopwindow.h"
+
+// local
+#include "qmirclientlogging.h"
+
+QMirClientDesktopWindow::QMirClientDesktopWindow(QWindow *window)
+ : QPlatformWindow(window)
+{
+ qCDebug(mirclient, "QMirClientDesktopWindow(window=%p)", window);
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h
new file mode 100644
index 0000000000..3ba54db826
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientdesktopwindow.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical, Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTDESKTOPWINDOW_H
+#define QMIRCLIENTDESKTOPWINDOW_H
+
+#include <qpa/qplatformwindow.h>
+
+// TODO Implement it. For now it's just an empty, dummy class.
+class QMirClientDesktopWindow : public QPlatformWindow
+{
+public:
+ QMirClientDesktopWindow(QWindow*);
+};
+
+#endif // QMIRCLIENTDESKTOPWINDOW_H
diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp
index 38eb0a4609..fc7d90d5ec 100644
--- a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp
@@ -39,123 +39,94 @@
#include "qmirclientglcontext.h"
-#include "qmirclientwindow.h"
#include "qmirclientlogging.h"
+#include "qmirclientwindow.h"
+
+#include <QOpenGLFramebufferObject>
#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtEglSupport/private/qeglpbuffer_p.h>
#include <QtGui/private/qopenglcontext_p.h>
-#include <dlfcn.h>
-
-#if !defined(QT_NO_DEBUG)
-static void printOpenGLESConfig() {
- static bool once = true;
- if (once) {
- const char* string = (const char*) glGetString(GL_VENDOR);
- LOG("OpenGL ES vendor: %s", string);
- string = (const char*) glGetString(GL_RENDERER);
- LOG("OpenGL ES renderer: %s", string);
- string = (const char*) glGetString(GL_VERSION);
- LOG("OpenGL ES version: %s", string);
- string = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION);
- LOG("OpenGL ES Shading Language version: %s", string);
- string = (const char*) glGetString(GL_EXTENSIONS);
- LOG("OpenGL ES extensions: %s", string);
- once = false;
- }
-}
-#endif
-static EGLenum api_in_use()
+Q_LOGGING_CATEGORY(mirclientGraphics, "qt.qpa.mirclient.graphics", QtWarningMsg)
+
+namespace {
+
+void printEglConfig(EGLDisplay display, EGLConfig config)
{
-#ifdef QTUBUNTU_USE_OPENGL
- return EGL_OPENGL_API;
-#else
- return EGL_OPENGL_ES_API;
-#endif
+ Q_ASSERT(display != EGL_NO_DISPLAY);
+ Q_ASSERT(config != nullptr);
+
+ const char *string = eglQueryString(display, EGL_VENDOR);
+ qCDebug(mirclientGraphics, "EGL vendor: %s", string);
+
+ string = eglQueryString(display, EGL_VERSION);
+ qCDebug(mirclientGraphics, "EGL version: %s", string);
+
+ string = eglQueryString(display, EGL_EXTENSIONS);
+ qCDebug(mirclientGraphics, "EGL extensions: %s", string);
+
+ qCDebug(mirclientGraphics, "EGL configuration attributes:");
+ q_printEglConfig(display, config);
}
-QMirClientOpenGLContext::QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share)
+} // anonymous namespace
+
+QMirClientOpenGLContext::QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share,
+ EGLDisplay display)
+ : QEGLPlatformContext(format, share, display, 0)
{
- ASSERT(screen != NULL);
- mEglDisplay = screen->eglDisplay();
- mScreen = screen;
-
- // Create an OpenGL ES 2 context.
- QVector<EGLint> attribs;
- attribs.append(EGL_CONTEXT_CLIENT_VERSION);
- attribs.append(2);
- attribs.append(EGL_NONE);
- ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
-
- mEglContext = eglCreateContext(mEglDisplay, screen->eglConfig(), share ? share->eglContext() : EGL_NO_CONTEXT,
- attribs.constData());
- DASSERT(mEglContext != EGL_NO_CONTEXT);
+ if (mirclientGraphics().isDebugEnabled()) {
+ printEglConfig(display, eglConfig());
+ }
}
-QMirClientOpenGLContext::~QMirClientOpenGLContext()
+static bool needsFBOReadBackWorkaround()
{
- ASSERT(eglDestroyContext(mEglDisplay, mEglContext) == EGL_TRUE);
+ static bool set = false;
+ static bool needsWorkaround = false;
+
+ if (Q_UNLIKELY(!set)) {
+ const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
+ needsWorkaround = qstrncmp(rendererString, "Mali-400", 8) == 0
+ || qstrncmp(rendererString, "Mali-T7", 7) == 0
+ || qstrncmp(rendererString, "PowerVR Rogue G6200", 19) == 0;
+ set = true;
+ }
+
+ return needsWorkaround;
}
bool QMirClientOpenGLContext::makeCurrent(QPlatformSurface* surface)
{
- DASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
- EGLSurface eglSurface = static_cast<QMirClientWindow*>(surface)->eglSurface();
-#if defined(QT_NO_DEBUG)
- eglBindAPI(api_in_use());
- eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext);
-#else
- ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
- ASSERT(eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext) == EGL_TRUE);
- printOpenGLESConfig();
-#endif
-
- // When running on the emulator, shaders will be compiled using a thin wrapper around the desktop drivers.
- // These wrappers might not support the precision qualifiers, so set the workaround flag to true.
- const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
- if (rendererString != 0 && qstrncmp(rendererString, "Android Emulator", 16) == 0) {
+ const bool ret = QEGLPlatformContext::makeCurrent(surface);
+
+ if (Q_LIKELY(ret)) {
QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(context());
- ctx_d->workaround_missingPrecisionQualifiers = true;
+ if (!ctx_d->workaround_brokenFBOReadBack && needsFBOReadBackWorkaround()) {
+ ctx_d->workaround_brokenFBOReadBack = true;
+ }
}
-
- return true;
+ return ret;
}
-void QMirClientOpenGLContext::doneCurrent()
+// Following method used internally in the base class QEGLPlatformContext to access
+// the egl surface of a QPlatformSurface/QMirClientWindow
+EGLSurface QMirClientOpenGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
-#if defined(QT_NO_DEBUG)
- eglBindAPI(api_in_use());
- eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-#else
- ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
- ASSERT(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_TRUE);
-#endif
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ return static_cast<QMirClientWindow *>(surface)->eglSurface();
+ } else {
+ return static_cast<QEGLPbuffer *>(surface)->pbuffer();
+ }
}
void QMirClientOpenGLContext::swapBuffers(QPlatformSurface* surface)
{
- QMirClientWindow *ubuntuWindow = static_cast<QMirClientWindow*>(surface);
-
- EGLSurface eglSurface = ubuntuWindow->eglSurface();
-#if defined(QT_NO_DEBUG)
- eglBindAPI(api_in_use());
- eglSwapBuffers(mEglDisplay, eglSurface);
-#else
- ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
- ASSERT(eglSwapBuffers(mEglDisplay, eglSurface) == EGL_TRUE);
-#endif
-
- ubuntuWindow->onSwapBuffersDone();
-}
+ QEGLPlatformContext::swapBuffers(surface);
-QFunctionPointer QMirClientOpenGLContext::getProcAddress(const char *procName)
-{
-#if defined(QT_NO_DEBUG)
- eglBindAPI(api_in_use());
-#else
- ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE);
-#endif
- QFunctionPointer proc = (QFunctionPointer) eglGetProcAddress(procName);
- if (!proc)
- proc = (QFunctionPointer) dlsym(RTLD_DEFAULT, procName);
- return proc;
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ // notify window on swap completion
+ auto platformWindow = static_cast<QMirClientWindow *>(surface);
+ platformWindow->onSwapBuffersDone();
+ }
}
diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.h b/src/plugins/platforms/mirclient/qmirclientglcontext.h
index eac0b78c4e..92331a6fb1 100644
--- a/src/plugins/platforms/mirclient/qmirclientglcontext.h
+++ b/src/plugins/platforms/mirclient/qmirclientglcontext.h
@@ -42,28 +42,22 @@
#define QMIRCLIENTGLCONTEXT_H
#include <qpa/qplatformopenglcontext.h>
-#include "qmirclientscreen.h"
+#include <QtEglSupport/private/qeglplatformcontext_p.h>
-class QMirClientOpenGLContext : public QPlatformOpenGLContext
+#include <EGL/egl.h>
+
+class QMirClientOpenGLContext : public QEGLPlatformContext
{
public:
- QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share);
- virtual ~QMirClientOpenGLContext();
-
- // QPlatformOpenGLContext methods.
- QSurfaceFormat format() const override { return mScreen->surfaceFormat(); }
- void swapBuffers(QPlatformSurface* surface) override;
- bool makeCurrent(QPlatformSurface* surface) override;
- void doneCurrent() override;
- bool isValid() const override { return mEglContext != EGL_NO_CONTEXT; }
- QFunctionPointer getProcAddress(const char *procName) override;
+ QMirClientOpenGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share,
+ EGLDisplay display);
- EGLContext eglContext() const { return mEglContext; }
+ // QEGLPlatformContext methods.
+ void swapBuffers(QPlatformSurface *surface) final;
+ bool makeCurrent(QPlatformSurface *surface) final;
-private:
- QMirClientScreen* mScreen;
- EGLContext mEglContext;
- EGLDisplay mEglDisplay;
+protected:
+ EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) final;
};
#endif // QMIRCLIENTGLCONTEXT_H
diff --git a/src/plugins/platforms/mirclient/qmirclientinput.cpp b/src/plugins/platforms/mirclient/qmirclientinput.cpp
index b3b21ae0e3..ea13f3cc17 100644
--- a/src/plugins/platforms/mirclient/qmirclientinput.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientinput.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014-2015 Canonical, Ltd.
+** Copyright (C) 2014-2016 Canonical, Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -48,21 +48,23 @@
#include "qmirclientorientationchangeevent_p.h"
// Qt
-#if !defined(QT_NO_DEBUG)
#include <QtCore/QThread>
-#endif
#include <QtCore/qglobal.h>
#include <QtCore/QCoreApplication>
-#include <private/qguiapplication_p.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatforminputcontext.h>
#include <qpa/qwindowsysteminterface.h>
+#include <QTextCodec>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-keysyms.h>
#include <mir_toolkit/mir_client_library.h>
-#define LOG_EVENTS 0
+Q_LOGGING_CATEGORY(mirclientInput, "qt.qpa.mirclient.input", QtWarningMsg)
+
+namespace
+{
// XKB Keysyms which do not map directly to Qt types (i.e. Unicode points)
static const uint32_t KeyTable[] = {
@@ -134,6 +136,27 @@ static const uint32_t KeyTable[] = {
XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate,
XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate,
+ // dead keys
+ XKB_KEY_dead_grave, Qt::Key_Dead_Grave,
+ XKB_KEY_dead_acute, Qt::Key_Dead_Acute,
+ XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex,
+ XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde,
+ XKB_KEY_dead_macron, Qt::Key_Dead_Macron,
+ XKB_KEY_dead_breve, Qt::Key_Dead_Breve,
+ XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot,
+ XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis,
+ XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering,
+ XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute,
+ XKB_KEY_dead_caron, Qt::Key_Dead_Caron,
+ XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla,
+ XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek,
+ XKB_KEY_dead_iota, Qt::Key_Dead_Iota,
+ XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
+ XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
+ XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot,
+ XKB_KEY_dead_hook, Qt::Key_Dead_Hook,
+ XKB_KEY_dead_horn, Qt::Key_Dead_Horn,
+
XKB_KEY_Mode_switch, Qt::Key_Mode_switch,
XKB_KEY_script_switch, Qt::Key_Mode_switch,
XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp,
@@ -144,14 +167,37 @@ static const uint32_t KeyTable[] = {
0, 0
};
-class QMirClientEvent : public QEvent
+Qt::WindowState mirSurfaceStateToWindowState(MirSurfaceState state)
+{
+ switch (state) {
+ case mir_surface_state_fullscreen:
+ return Qt::WindowFullScreen;
+ case mir_surface_state_maximized:
+ case mir_surface_state_vertmaximized:
+ case mir_surface_state_horizmaximized:
+ return Qt::WindowMaximized;
+ case mir_surface_state_minimized:
+ return Qt::WindowMinimized;
+ case mir_surface_state_hidden:
+ // We should be handling this state separately.
+ Q_ASSERT(false);
+ case mir_surface_state_restored:
+ case mir_surface_state_unknown:
+ default:
+ return Qt::WindowNoState;
+ }
+}
+
+} // namespace
+
+class UbuntuEvent : public QEvent
{
public:
- QMirClientEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type)
+ UbuntuEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type)
: QEvent(type), window(window) {
nativeEvent = mir_event_ref(event);
}
- ~QMirClientEvent()
+ ~UbuntuEvent()
{
mir_event_unref(nativeEvent);
}
@@ -166,7 +212,7 @@ QMirClientInput::QMirClientInput(QMirClientClientIntegration* integration)
, mEventFilterType(static_cast<QMirClientNativeInterface*>(
integration->nativeInterface())->genericEventFilterType())
, mEventType(static_cast<QEvent::Type>(QEvent::registerEventType()))
- , mLastFocusedWindow(nullptr)
+ , mLastInputWindow(nullptr)
{
// Initialize touch device.
mTouchDevice = new QTouchDevice;
@@ -182,42 +228,47 @@ QMirClientInput::~QMirClientInput()
// Qt will take care of deleting mTouchDevice.
}
-#if (LOG_EVENTS != 0)
static const char* nativeEventTypeToStr(MirEventType t)
{
switch (t)
{
case mir_event_type_key:
- return "mir_event_type_key";
+ return "key";
case mir_event_type_motion:
- return "mir_event_type_motion";
+ return "motion";
case mir_event_type_surface:
- return "mir_event_type_surface";
+ return "surface";
case mir_event_type_resize:
- return "mir_event_type_resize";
+ return "resize";
case mir_event_type_prompt_session_state_change:
- return "mir_event_type_prompt_session_state_change";
+ return "prompt_session_state_change";
case mir_event_type_orientation:
- return "mir_event_type_orientation";
+ return "orientation";
case mir_event_type_close_surface:
- return "mir_event_type_close_surface";
+ return "close_surface";
case mir_event_type_input:
- return "mir_event_type_input";
+ return "input";
+ case mir_event_type_keymap:
+ return "keymap";
+ case mir_event_type_input_configuration:
+ return "input_configuration";
+ case mir_event_type_surface_output:
+ return "surface_output";
+ case mir_event_type_input_device_state:
+ return "input_device_state";
default:
- DLOG("Invalid event type %d", t);
- return "invalid";
+ return "unknown";
}
}
-#endif // LOG_EVENTS != 0
void QMirClientInput::customEvent(QEvent* event)
{
- DASSERT(QThread::currentThread() == thread());
- QMirClientEvent* ubuntuEvent = static_cast<QMirClientEvent*>(event);
+ Q_ASSERT(QThread::currentThread() == thread());
+ UbuntuEvent* ubuntuEvent = static_cast<UbuntuEvent*>(event);
const MirEvent *nativeEvent = ubuntuEvent->nativeEvent;
if ((ubuntuEvent->window == nullptr) || (ubuntuEvent->window->window() == nullptr)) {
- qWarning("Attempted to deliver an event to a non-existent window, ignoring.");
+ qCWarning(mirclient) << "Attempted to deliver an event to a non-existent window, ignoring.";
return;
}
@@ -226,13 +277,11 @@ void QMirClientInput::customEvent(QEvent* event)
if (QWindowSystemInterface::handleNativeEvent(
ubuntuEvent->window->window(), mEventFilterType,
const_cast<void *>(static_cast<const void *>(nativeEvent)), &result) == true) {
- DLOG("event filtered out by native interface");
+ qCDebug(mirclient, "event filtered out by native interface");
return;
}
- #if (LOG_EVENTS != 0)
- LOG("QMirClientInput::customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent)));
- #endif
+ qCDebug(mirclientInput, "customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent)));
// Event dispatching.
switch (mir_event_get_type(nativeEvent))
@@ -242,43 +291,30 @@ void QMirClientInput::customEvent(QEvent* event)
break;
case mir_event_type_resize:
{
- Q_ASSERT(ubuntuEvent->window->screen() == mIntegration->screen());
-
auto resizeEvent = mir_event_get_resize_event(nativeEvent);
- mIntegration->screen()->handleWindowSurfaceResize(
- mir_resize_event_get_width(resizeEvent),
- mir_resize_event_get_height(resizeEvent));
+ // Enable workaround for Screen rotation
+ auto const targetWindow = ubuntuEvent->window;
+ if (targetWindow) {
+ auto const screen = static_cast<QMirClientScreen*>(targetWindow->screen());
+ if (screen) {
+ screen->handleWindowSurfaceResize(
+ mir_resize_event_get_width(resizeEvent),
+ mir_resize_event_get_height(resizeEvent));
+ }
- ubuntuEvent->window->handleSurfaceResized(mir_resize_event_get_width(resizeEvent),
- mir_resize_event_get_height(resizeEvent));
+ targetWindow->handleSurfaceResized(
+ mir_resize_event_get_width(resizeEvent),
+ mir_resize_event_get_height(resizeEvent));
+ }
break;
}
case mir_event_type_surface:
- {
- auto surfaceEvent = mir_event_get_surface_event(nativeEvent);
- if (mir_surface_event_get_attribute(surfaceEvent) == mir_surface_attrib_focus) {
- const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
- // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
- // so that we don't deactivate windows prematurely.
- if (focused) {
- mPendingFocusGainedEvents--;
- ubuntuEvent->window->handleSurfaceFocused();
- QWindowSystemInterface::handleWindowActivated(ubuntuEvent->window->window(), Qt::ActiveWindowFocusReason);
-
- // NB: Since processing of system events is queued, never check qGuiApp->applicationState()
- // as it might be outdated. Always call handleApplicationStateChanged() with the latest
- // state regardless.
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
-
- } else if (!mPendingFocusGainedEvents) {
- DLOG("[ubuntumirclient QPA] No windows have focus");
- QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
- }
- }
+ handleSurfaceEvent(ubuntuEvent->window, mir_event_get_surface_event(nativeEvent));
+ break;
+ case mir_event_type_surface_output:
+ handleSurfaceOutputEvent(ubuntuEvent->window, mir_event_get_surface_output_event(nativeEvent));
break;
- }
case mir_event_type_orientation:
dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent));
break;
@@ -286,7 +322,7 @@ void QMirClientInput::customEvent(QEvent* event)
QWindowSystemInterface::handleCloseEvent(ubuntuEvent->window->window());
break;
default:
- DLOG("unhandled event type: %d", static_cast<int>(mir_event_get_type(nativeEvent)));
+ qCDebug(mirclient, "unhandled event type: %d", static_cast<int>(mir_event_get_type(nativeEvent)));
}
}
@@ -294,22 +330,11 @@ void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent
{
QWindow *window = platformWindow->window();
- const auto eventType = mir_event_get_type(event);
- if (mir_event_type_surface == eventType) {
- auto surfaceEvent = mir_event_get_surface_event(event);
- if (mir_surface_attrib_focus == mir_surface_event_get_attribute(surfaceEvent)) {
- const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
- if (focused) {
- mPendingFocusGainedEvents++;
- }
- }
- }
-
- QCoreApplication::postEvent(this, new QMirClientEvent(
+ QCoreApplication::postEvent(this, new UbuntuEvent(
platformWindow, event, mEventType));
if ((window->flags().testFlag(Qt::WindowTransparentForInput)) && window->parent()) {
- QCoreApplication::postEvent(this, new QMirClientEvent(
+ QCoreApplication::postEvent(this, new UbuntuEvent(
static_cast<QMirClientWindow*>(platformWindow->QPlatformWindow::parent()),
event, mEventType));
}
@@ -365,15 +390,17 @@ void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInpu
switch (touch_action)
{
case mir_touch_action_down:
- mLastFocusedWindow = window;
+ mLastInputWindow = window;
touchPoint.state = Qt::TouchPointPressed;
break;
case mir_touch_action_up:
touchPoint.state = Qt::TouchPointReleased;
break;
case mir_touch_action_change:
- default:
touchPoint.state = Qt::TouchPointMoved;
+ break;
+ default:
+ Q_UNREACHABLE();
}
touchPoints.append(touchPoint);
@@ -384,22 +411,26 @@ void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInpu
mTouchDevice, touchPoints);
}
-static uint32_t translateKeysym(uint32_t sym, char *string, size_t size)
-{
- Q_UNUSED(size);
- string[0] = '\0';
+static uint32_t translateKeysym(uint32_t sym, const QString &text) {
+ int code = 0;
- if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35)
+ QTextCodec *systemCodec = QTextCodec::codecForLocale();
+ if (sym < 128 || (sym < 256 && systemCodec->mibEnum() == 4)) {
+ // upper-case key, if known
+ code = isprint((int)sym) ? toupper((int)sym) : 0;
+ } else if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35) {
return Qt::Key_F1 + (int(sym) - XKB_KEY_F1);
-
- for (int i = 0; KeyTable[i]; i += 2) {
- if (sym == KeyTable[i])
- return KeyTable[i + 1];
+ } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f
+ && text.unicode()->unicode() != 0x7f
+ && !(sym >= XKB_KEY_dead_grave && sym <= XKB_KEY_dead_currency)) {
+ code = text.unicode()->toUpper().unicode();
+ } else {
+ for (int i = 0; KeyTable[i]; i += 2)
+ if (sym == KeyTable[i])
+ code = KeyTable[i + 1];
}
- string[0] = sym;
- string[1] = '\0';
- return toupper(sym);
+ return code;
}
namespace
@@ -413,12 +444,15 @@ Qt::KeyboardModifiers qt_modifiers_from_mir(MirInputEventModifiers modifiers)
if (modifiers & mir_input_event_modifier_ctrl) {
q_modifiers |= Qt::ControlModifier;
}
- if (modifiers & mir_input_event_modifier_alt) {
+ if (modifiers & mir_input_event_modifier_alt_left) {
q_modifiers |= Qt::AltModifier;
}
if (modifiers & mir_input_event_modifier_meta) {
q_modifiers |= Qt::MetaModifier;
}
+ if (modifiers & mir_input_event_modifier_alt_right) {
+ q_modifiers |= Qt::GroupSwitchModifier;
+ }
return q_modifiers;
}
}
@@ -429,34 +463,43 @@ void QMirClientInput::dispatchKeyEvent(QMirClientWindow *window, const MirInputE
ulong timestamp = mir_input_event_get_event_time(event) / 1000000;
xkb_keysym_t xk_sym = mir_keyboard_event_key_code(key_event);
+ quint32 scan_code = mir_keyboard_event_scan_code(key_event);
+ quint32 native_modifiers = mir_keyboard_event_modifiers(key_event);
// Key modifier and unicode index mapping.
- auto modifiers = qt_modifiers_from_mir(mir_keyboard_event_modifiers(key_event));
+ auto modifiers = qt_modifiers_from_mir(native_modifiers);
MirKeyboardAction action = mir_keyboard_event_action(key_event);
QEvent::Type keyType = action == mir_keyboard_action_up
? QEvent::KeyRelease : QEvent::KeyPress;
if (action == mir_keyboard_action_down)
- mLastFocusedWindow = window;
+ mLastInputWindow = window;
- char s[2];
- int sym = translateKeysym(xk_sym, s, sizeof(s));
- QString text = QString::fromLatin1(s);
+ QString text;
+ QVarLengthArray<char, 32> chars(32);
+ {
+ int result = xkb_keysym_to_utf8(xk_sym, chars.data(), chars.size());
+
+ if (result > 0) {
+ text = QString::fromUtf8(chars.constData());
+ }
+ }
+ int sym = translateKeysym(xk_sym, text);
bool is_auto_rep = action == mir_keyboard_action_repeat;
QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
if (context) {
- QKeyEvent qKeyEvent(keyType, sym, modifiers, text, is_auto_rep);
+ QKeyEvent qKeyEvent(keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep);
qKeyEvent.setTimestamp(timestamp);
if (context->filterEvent(&qKeyEvent)) {
- DLOG("key event filtered out by input context");
+ qCDebug(mirclient, "key event filtered out by input context");
return;
}
}
- QWindowSystemInterface::handleKeyEvent(window->window(), timestamp, keyType, sym, modifiers, text, is_auto_rep);
+ QWindowSystemInterface::handleExtendedKeyEvent(window->window(), timestamp, keyType, sym, modifiers, scan_code, xk_sym, native_modifiers, text, is_auto_rep);
}
namespace
@@ -481,14 +524,17 @@ Qt::MouseButtons extract_buttons(const MirPointerEvent *pev)
void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, const MirInputEvent *ev)
{
- auto window = platformWindow->window();
- auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
+ const auto window = platformWindow->window();
+ const auto timestamp = mir_input_event_get_event_time(ev) / 1000000;
+
+ const auto pev = mir_input_event_get_pointer_event(ev);
+ const auto action = mir_pointer_event_action(pev);
+
+ const auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));
+ const auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
+ mir_pointer_event_axis_value(pev, mir_pointer_axis_y));
- auto pev = mir_input_event_get_pointer_event(ev);
- auto action = mir_pointer_event_action(pev);
- auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x),
- mir_pointer_event_axis_value(pev, mir_pointer_axis_y));
- auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev));
+ mLastInputWindow = platformWindow;
switch (action) {
case mir_pointer_action_button_up:
@@ -499,7 +545,8 @@ void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, con
const float vDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_vscroll);
if (hDelta != 0 || vDelta != 0) {
- const QPoint angleDelta = QPoint(hDelta * 15, vDelta * 15);
+ // QWheelEvent::DefaultDeltasPerStep = 120 but doesn't exist on vivid
+ const QPoint angleDelta(120 * hDelta, 120 * vDelta);
QWindowSystemInterface::handleWheelEvent(window, timestamp, localPoint, window->position() + localPoint,
QPoint(), angleDelta, modifiers, Qt::ScrollUpdate);
}
@@ -515,42 +562,32 @@ void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, con
QWindowSystemInterface::handleLeaveEvent(window);
break;
default:
- DLOG("Unrecognized pointer event");
+ Q_UNREACHABLE();
}
}
-#if (LOG_EVENTS != 0)
static const char* nativeOrientationDirectionToStr(MirOrientation orientation)
{
switch (orientation) {
case mir_orientation_normal:
return "Normal";
- break;
case mir_orientation_left:
return "Left";
- break;
case mir_orientation_inverted:
return "Inverted";
- break;
case mir_orientation_right:
return "Right";
- break;
- default:
- return "INVALID!";
}
+ Q_UNREACHABLE();
}
-#endif
void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrientationEvent *event)
{
MirOrientation mir_orientation = mir_orientation_event_get_direction(event);
- #if (LOG_EVENTS != 0)
- // Orientation event logging.
- LOG("ORIENTATION direction: %s", nativeOrientationDirectionToStr(mir_orientation));
- #endif
+ qCDebug(mirclientInput, "orientation direction: %s", nativeOrientationDirectionToStr(mir_orientation));
if (!window->screen()) {
- DLOG("Window has no associated screen, dropping orientation event");
+ qCDebug(mirclient, "Window has no associated screen, dropping orientation event");
return;
}
@@ -569,7 +606,7 @@ void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrienta
orientation = OrientationChangeEvent::RightUp;
break;
default:
- DLOG("No such orientation %d", mir_orientation);
+ qCDebug(mirclient, "No such orientation %d", mir_orientation);
return;
}
@@ -581,3 +618,61 @@ void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrienta
new OrientationChangeEvent(OrientationChangeEvent::mType, orientation));
}
+void QMirClientInput::handleSurfaceEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceEvent *event)
+{
+ auto surfaceEventAttribute = mir_surface_event_get_attribute(event);
+
+ switch (surfaceEventAttribute) {
+ case mir_surface_attrib_focus: {
+ window->handleSurfaceFocusChanged(
+ mir_surface_event_get_attribute_value(event) == mir_surface_focused);
+ break;
+ }
+ case mir_surface_attrib_visibility: {
+ window->handleSurfaceExposeChange(
+ mir_surface_event_get_attribute_value(event) == mir_surface_visibility_exposed);
+ break;
+ }
+ // Remaining attributes are ones client sets for server, and server should not override them
+ case mir_surface_attrib_state: {
+ MirSurfaceState state = static_cast<MirSurfaceState>(mir_surface_event_get_attribute_value(event));
+
+ if (state == mir_surface_state_hidden) {
+ window->handleSurfaceVisibilityChanged(false);
+ } else {
+ // it's visible!
+ window->handleSurfaceVisibilityChanged(true);
+ window->handleSurfaceStateChanged(mirSurfaceStateToWindowState(state));
+ }
+ break;
+ }
+ case mir_surface_attrib_type:
+ case mir_surface_attrib_swapinterval:
+ case mir_surface_attrib_dpi:
+ case mir_surface_attrib_preferred_orientation:
+ case mir_surface_attribs:
+ break;
+ }
+}
+
+void QMirClientInput::handleSurfaceOutputEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceOutputEvent *event)
+{
+ const uint32_t outputId = mir_surface_output_event_get_output_id(event);
+ const int dpi = mir_surface_output_event_get_dpi(event);
+ const MirFormFactor formFactor = mir_surface_output_event_get_form_factor(event);
+ const float scale = mir_surface_output_event_get_scale(event);
+
+ const auto screenObserver = mIntegration->screenObserver();
+ QMirClientScreen *screen = screenObserver->findScreenWithId(outputId);
+ if (!screen) {
+ qCWarning(mirclient) << "Mir notified window" << window->window() << "on an unknown screen with id" << outputId;
+ return;
+ }
+
+ screenObserver->handleScreenPropertiesChange(screen, dpi, formFactor, scale);
+ window->handleScreenPropertiesChange(formFactor, scale);
+
+ if (window->screen() != screen) {
+ QWindowSystemInterface::handleWindowScreenChanged(window->window(), screen->screen());
+ }
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientinput.h b/src/plugins/platforms/mirclient/qmirclientinput.h
index 3600ae7ece..263cb5e54e 100644
--- a/src/plugins/platforms/mirclient/qmirclientinput.h
+++ b/src/plugins/platforms/mirclient/qmirclientinput.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014-2015 Canonical, Ltd.
+** Copyright (C) 2014-2016 Canonical, Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -43,7 +43,6 @@
// Qt
#include <qpa/qwindowsysteminterface.h>
-#include <QAtomicInt>
#include <mir_toolkit/mir_client_library.h>
@@ -63,7 +62,7 @@ public:
void postEvent(QMirClientWindow* window, const MirEvent *event);
QMirClientClientIntegration* integration() const { return mIntegration; }
- QMirClientWindow *lastFocusedWindow() const {return mLastFocusedWindow; }
+ QMirClientWindow *lastInputWindow() const {return mLastInputWindow; }
protected:
void dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event);
@@ -72,6 +71,8 @@ protected:
void dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *event);
void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event);
+ void handleSurfaceEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceEvent *event);
+ void handleSurfaceOutputEvent(const QPointer<QMirClientWindow> &window, const MirSurfaceOutputEvent *event);
private:
QMirClientClientIntegration* mIntegration;
@@ -79,8 +80,7 @@ private:
const QByteArray mEventFilterType;
const QEvent::Type mEventType;
- QMirClientWindow *mLastFocusedWindow;
- QAtomicInt mPendingFocusGainedEvents;
+ QMirClientWindow *mLastInputWindow;
};
#endif // QMIRCLIENTINPUT_H
diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.cpp b/src/plugins/platforms/mirclient/qmirclientintegration.cpp
index 2c8740f070..eef96ee3de 100644
--- a/src/plugins/platforms/mirclient/qmirclientintegration.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientintegration.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014-2015 Canonical, Ltd.
+** Copyright (C) 2014-2016 Canonical, Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -42,6 +42,8 @@
#include "qmirclientintegration.h"
#include "qmirclientbackingstore.h"
#include "qmirclientclipboard.h"
+#include "qmirclientdebugextension.h"
+#include "qmirclientdesktopwindow.h"
#include "qmirclientglcontext.h"
#include "qmirclientinput.h"
#include "qmirclientlogging.h"
@@ -51,56 +53,62 @@
#include "qmirclientwindow.h"
// Qt
+#include <QFileInfo>
#include <QGuiApplication>
-#include <private/qguiapplication_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <qpa/qplatforminputcontextfactory_p.h>
#include <qpa/qplatforminputcontext.h>
+#include <QtEglSupport/private/qeglconvenience_p.h>
+#include <QtEglSupport/private/qeglpbuffer_p.h>
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
#include <QtEventDispatcherSupport/private/qgenericunixeventdispatcher_p.h>
+#ifndef QT_NO_ACCESSIBILITY
+#include <qpa/qplatformaccessibility.h>
+#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE
+#include <QtLinuxAccessibilitySupport/private/bridge_p.h>
+#endif
+#endif
+
#include <QOpenGLContext>
+#include <QOffscreenSurface>
// platform-api
#include <ubuntu/application/lifecycle_delegate.h>
#include <ubuntu/application/id.h>
#include <ubuntu/application/options.h>
-static void resumedCallback(const UApplicationOptions *options, void* context)
+static void resumedCallback(const UApplicationOptions */*options*/, void* context)
{
- Q_UNUSED(options)
- Q_UNUSED(context)
- DASSERT(context != NULL);
- if (qGuiApp->focusWindow()) {
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
- } else {
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
- }
+ auto integration = static_cast<QMirClientClientIntegration*>(context);
+ integration->appStateController()->setResumed();
}
-static void aboutToStopCallback(UApplicationArchive *archive, void* context)
+static void aboutToStopCallback(UApplicationArchive */*archive*/, void* context)
{
- Q_UNUSED(archive)
- DASSERT(context != NULL);
- QMirClientClientIntegration* integration = static_cast<QMirClientClientIntegration*>(context);
- QPlatformInputContext *inputContext = integration->inputContext();
+ auto integration = static_cast<QMirClientClientIntegration*>(context);
+ auto inputContext = integration->inputContext();
if (inputContext) {
inputContext->hideInputPanel();
} else {
- qWarning("QMirClientClientIntegration aboutToStopCallback(): no input context");
+ qCWarning(mirclient) << "aboutToStopCallback(): no input context";
}
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
+ integration->appStateController()->setSuspended();
}
-QMirClientClientIntegration::QMirClientClientIntegration()
+QMirClientClientIntegration::QMirClientClientIntegration(int argc, char **argv)
: QPlatformIntegration()
- , mNativeInterface(new QMirClientNativeInterface)
+ , mNativeInterface(new QMirClientNativeInterface(this))
, mFontDb(new QGenericUnixFontDatabase)
, mServices(new QMirClientPlatformServices)
- , mClipboard(new QMirClientClipboard)
+ , mAppStateController(new QMirClientAppStateController)
, mScaleFactor(1.0)
{
- setupOptions();
- setupDescription();
+ {
+ QStringList args = QCoreApplication::arguments();
+ setupOptions(args);
+ QByteArray sessionName = generateSessionName(args);
+ setupDescription(sessionName);
+ }
// Create new application instance
mInstance = u_application_instance_new_from_description_with_options(mDesc, mOptions);
@@ -110,19 +118,48 @@ QMirClientClientIntegration::QMirClientClientIntegration()
"running, and the correct socket is being used and is accessible. The shell may have\n"
"rejected the incoming connection, so check its log file");
- mNativeInterface->setMirConnection(u_application_instance_get_mir_connection(mInstance));
+ mMirConnection = u_application_instance_get_mir_connection(mInstance);
+
+ // Choose the default surface format suited to the Mir platform
+ QSurfaceFormat defaultFormat;
+ defaultFormat.setRedBufferSize(8);
+ defaultFormat.setGreenBufferSize(8);
+ defaultFormat.setBlueBufferSize(8);
+ QSurfaceFormat::setDefaultFormat(defaultFormat);
+
+ // Initialize EGL.
+ mEglNativeDisplay = mir_connection_get_egl_native_display(mMirConnection);
+ ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY);
+ ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE);
+
+ // Has debug mode been requsted, either with "-testability" switch or QT_LOAD_TESTABILITY env var
+ bool testability = qEnvironmentVariableIsSet("QT_LOAD_TESTABILITY");
+ for (int i=1; !testability && i<argc; i++) {
+ if (strcmp(argv[i], "-testability") == 0) {
+ testability = true;
+ }
+ }
+ if (testability) {
+ mDebugExtension.reset(new QMirClientDebugExtension);
+ }
+}
- // Create default screen.
- screenAdded(new QMirClientScreen(u_application_instance_get_mir_connection(mInstance)));
+void QMirClientClientIntegration::initialize()
+{
+ // Init the ScreenObserver
+ mScreenObserver.reset(new QMirClientScreenObserver(mMirConnection));
+ connect(mScreenObserver.data(), &QMirClientScreenObserver::screenAdded,
+ [this](QMirClientScreen *screen) { this->screenAdded(screen); });
+ connect(mScreenObserver.data(), &QMirClientScreenObserver::screenRemoved,
+ this, &QMirClientClientIntegration::destroyScreen);
+
+ Q_FOREACH (auto screen, mScreenObserver->screens()) {
+ screenAdded(screen);
+ }
// Initialize input.
- if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_INPUT")) {
- mInput = new QMirClientInput(this);
- mInputContext = QPlatformInputContextFactory::create();
- } else {
- mInput = nullptr;
- mInputContext = nullptr;
- }
+ mInput = new QMirClientInput(this);
+ mInputContext = QPlatformInputContextFactory::create();
// compute the scale factor
const int defaultGridUnit = 8;
@@ -140,10 +177,9 @@ QMirClientClientIntegration::QMirClientClientIntegration()
QMirClientClientIntegration::~QMirClientClientIntegration()
{
+ eglTerminate(mEglDisplay);
delete mInput;
delete mInputContext;
- for (QScreen *screen : QGuiApplication::screens())
- QPlatformIntegration::destroyScreen(screen->handle());
delete mServices;
}
@@ -152,9 +188,8 @@ QPlatformServices *QMirClientClientIntegration::services() const
return mServices;
}
-void QMirClientClientIntegration::setupOptions()
+void QMirClientClientIntegration::setupOptions(QStringList &args)
{
- QStringList args = QCoreApplication::arguments();
int argc = args.size() + 1;
char **argv = new char*[argc];
for (int i = 0; i < argc - 1; i++)
@@ -168,10 +203,11 @@ void QMirClientClientIntegration::setupOptions()
delete [] argv;
}
-void QMirClientClientIntegration::setupDescription()
+void QMirClientClientIntegration::setupDescription(QByteArray &sessionName)
{
mDesc = u_application_description_new();
- UApplicationId* id = u_application_id_new_from_stringn("QtUbuntu", 8);
+
+ UApplicationId* id = u_application_id_new_from_stringn(sessionName.data(), sessionName.count());
u_application_description_set_application_id(mDesc, id);
UApplicationLifecycleDelegate* delegate = u_application_lifecycle_delegate_new();
@@ -181,43 +217,66 @@ void QMirClientClientIntegration::setupDescription()
u_application_description_set_application_lifecycle_delegate(mDesc, delegate);
}
-QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const
+QByteArray QMirClientClientIntegration::generateSessionName(QStringList &args)
{
- return const_cast<QMirClientClientIntegration*>(this)->createPlatformWindow(window);
+ // Try to come up with some meaningful session name to uniquely identify this session,
+ // helping with shell debugging
+
+ if (args.count() == 0) {
+ return QByteArray("QtUbuntu");
+ } if (args[0].contains("qmlscene")) {
+ return generateSessionNameFromQmlFile(args);
+ } else {
+ // use the executable name
+ QFileInfo fileInfo(args[0]);
+ return fileInfo.fileName().toLocal8Bit();
+ }
}
-QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window)
+QByteArray QMirClientClientIntegration::generateSessionNameFromQmlFile(QStringList &args)
{
- return new QMirClientWindow(window, mClipboard, screen(),
- mInput, u_application_instance_get_mir_connection(mInstance));
+ Q_FOREACH (QString arg, args) {
+ if (arg.endsWith(".qml")) {
+ QFileInfo fileInfo(arg);
+ return fileInfo.fileName().toLocal8Bit();
+ }
+ }
+
+ // give up
+ return "qmlscene";
}
-QMirClientScreen *QMirClientClientIntegration::screen() const
+QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const
{
- return static_cast<QMirClientScreen *>(QGuiApplication::primaryScreen()->handle());
+ if (window->type() == Qt::Desktop) {
+ // Desktop windows should not be backed up by a mir surface as they don't draw anything (nor should).
+ return new QMirClientDesktopWindow(window);
+ } else {
+ return new QMirClientWindow(window, mInput, mNativeInterface, mAppStateController.data(),
+ mEglDisplay, mMirConnection, mDebugExtension.data());
+ }
}
bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
- case ThreadedPixmaps:
- return true;
-
- case OpenGL:
- return true;
-
- case ApplicationState:
- return true;
-
case ThreadedOpenGL:
if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) {
return true;
} else {
- DLOG("ubuntumirclient: disabled threaded OpenGL");
+ qCDebug(mirclient, "disabled threaded OpenGL");
return false;
}
+
+ case ThreadedPixmaps:
+ case OpenGL:
+ case ApplicationState:
case MultipleWindows:
case NonFullScreenWindows:
+#if QT_VERSION > QT_VERSION_CHECK(5, 5, 0)
+ case SwitchableWidgetComposition:
+#endif
+ case RasterGLSurface: // needed for QQuickWidget
return true;
default:
return QPlatformIntegration::hasCapability(cap);
@@ -237,14 +296,25 @@ QPlatformBackingStore* QMirClientClientIntegration::createPlatformBackingStore(Q
QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext(
QOpenGLContext* context) const
{
- return const_cast<QMirClientClientIntegration*>(this)->createPlatformOpenGLContext(context);
-}
-
-QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext(
- QOpenGLContext* context)
-{
- return new QMirClientOpenGLContext(static_cast<QMirClientScreen*>(context->screen()->handle()),
- static_cast<QMirClientOpenGLContext*>(context->shareHandle()));
+ QSurfaceFormat format(context->format());
+
+ auto platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay);
+ if (!platformContext->isValid()) {
+ // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default
+ // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a
+ // 1.4 context, but the XCB EGL backend tries to honor it, and fails. The 1.4 context appears to
+ // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default
+ // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455).
+ static const bool isMesa = QString(eglQueryString(mEglDisplay, EGL_VENDOR)).contains(QStringLiteral("Mesa"));
+ if (isMesa) {
+ qCDebug(mirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa");
+ format.setMajorVersion(1);
+ format.setMinorVersion(4);
+ delete platformContext;
+ platformContext = new QMirClientOpenGLContext(format, context->shareHandle(), mEglDisplay);
+ }
+ }
+ return platformContext;
}
QStringList QMirClientClientIntegration::themeNames() const
@@ -277,10 +347,65 @@ QVariant QMirClientClientIntegration::styleHint(StyleHint hint) const
QPlatformClipboard* QMirClientClientIntegration::clipboard() const
{
- return mClipboard.data();
+ static QPlatformClipboard *clipboard = nullptr;
+ if (!clipboard) {
+ clipboard = new QMirClientClipboard;
+ }
+ return clipboard;
}
QPlatformNativeInterface* QMirClientClientIntegration::nativeInterface() const
{
return mNativeInterface;
}
+
+QPlatformOffscreenSurface *QMirClientClientIntegration::createPlatformOffscreenSurface(
+ QOffscreenSurface *surface) const
+{
+ return new QEGLPbuffer(mEglDisplay, surface->requestedFormat(), surface);
+}
+
+void QMirClientClientIntegration::destroyScreen(QMirClientScreen *screen)
+{
+ // FIXME: on deleting a screen while a Window is on it, Qt will automatically
+ // move the window to the primaryScreen(). This will trigger a screenChanged
+ // signal, causing things like QQuickScreenAttached to re-fetch screen properties
+ // like DPI and physical size. However this is crashing, as Qt is calling virtual
+ // functions on QPlatformScreen, for reasons unclear. As workaround, move window
+ // to primaryScreen() before deleting the screen. Might be QTBUG-38650
+
+ QScreen *primaryScreen = QGuiApplication::primaryScreen();
+ if (screen != primaryScreen->handle()) {
+ uint32_t movedWindowCount = 0;
+ Q_FOREACH (QWindow *w, QGuiApplication::topLevelWindows()) {
+ if (w->screen()->handle() == screen) {
+ QWindowSystemInterface::handleWindowScreenChanged(w, primaryScreen);
+ ++movedWindowCount;
+ }
+ }
+ if (movedWindowCount > 0) {
+ QWindowSystemInterface::flushWindowSystemEvents();
+ }
+ }
+
+ qCDebug(mirclient) << "Removing Screen with id" << screen->mirOutputId() << "and geometry" << screen->geometry();
+#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
+ delete screen;
+#else
+ QPlatformIntegration::destroyScreen(screen);
+#endif
+}
+
+#ifndef QT_NO_ACCESSIBILITY
+QPlatformAccessibility *QMirClientClientIntegration::accessibility() const
+{
+#if !defined(QT_NO_ACCESSIBILITY_ATSPI_BRIDGE)
+ if (!mAccessibility) {
+ Q_ASSERT_X(QCoreApplication::eventDispatcher(), "QMirClientIntegration",
+ "Initializing accessibility without event-dispatcher!");
+ mAccessibility.reset(new QSpiAccessibleBridge());
+ }
+#endif
+ return mAccessibility.data();
+}
+#endif
diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.h b/src/plugins/platforms/mirclient/qmirclientintegration.h
index 97317a310a..035117f4da 100644
--- a/src/plugins/platforms/mirclient/qmirclientintegration.h
+++ b/src/plugins/platforms/mirclient/qmirclientintegration.h
@@ -44,20 +44,28 @@
#include <qpa/qplatformintegration.h>
#include <QSharedPointer>
+#include "qmirclientappstatecontroller.h"
#include "qmirclientplatformservices.h"
+#include "qmirclientscreenobserver.h"
// platform-api
#include <ubuntu/application/description.h>
#include <ubuntu/application/instance.h>
-class QMirClientClipboard;
+#include <EGL/egl.h>
+
+class QMirClientDebugExtension;
class QMirClientInput;
class QMirClientNativeInterface;
class QMirClientScreen;
+class MirConnection;
+
+class QMirClientClientIntegration : public QObject, public QPlatformIntegration
+{
+ Q_OBJECT
-class QMirClientClientIntegration : public QPlatformIntegration {
public:
- QMirClientClientIntegration();
+ QMirClientClientIntegration(int argc, char **argv);
virtual ~QMirClientClientIntegration();
// QPlatformIntegration methods.
@@ -74,14 +82,26 @@ public:
QPlatformWindow* createPlatformWindow(QWindow* window) const override;
QPlatformInputContext* inputContext() const override { return mInputContext; }
QPlatformClipboard* clipboard() const override;
+ void initialize() override;
+ QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
+ QPlatformAccessibility *accessibility() const override;
+
+ // New methods.
+ MirConnection *mirConnection() const { return mMirConnection; }
+ EGLDisplay eglDisplay() const { return mEglDisplay; }
+ EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }
+ QMirClientAppStateController *appStateController() const { return mAppStateController.data(); }
+ QMirClientScreenObserver *screenObserver() const { return mScreenObserver.data(); }
+ QMirClientDebugExtension *debugExtension() const { return mDebugExtension.data(); }
- QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context);
- QPlatformWindow* createPlatformWindow(QWindow* window);
- QMirClientScreen* screen() const;
+private Q_SLOTS:
+ void destroyScreen(QMirClientScreen *screen);
private:
- void setupOptions();
- void setupDescription();
+ void setupOptions(QStringList &args);
+ void setupDescription(QByteArray &sessionName);
+ static QByteArray generateSessionName(QStringList &args);
+ static QByteArray generateSessionNameFromQmlFile(QStringList &args);
QMirClientNativeInterface* mNativeInterface;
QPlatformFontDatabase* mFontDb;
@@ -90,13 +110,22 @@ private:
QMirClientInput* mInput;
QPlatformInputContext* mInputContext;
- QSharedPointer<QMirClientClipboard> mClipboard;
+ mutable QScopedPointer<QPlatformAccessibility> mAccessibility;
+ QScopedPointer<QMirClientDebugExtension> mDebugExtension;
+ QScopedPointer<QMirClientScreenObserver> mScreenObserver;
+ QScopedPointer<QMirClientAppStateController> mAppStateController;
qreal mScaleFactor;
+ MirConnection *mMirConnection;
+
// Platform API stuff
UApplicationOptions* mOptions;
UApplicationDescription* mDesc;
UApplicationInstance* mInstance;
+
+ // EGL related
+ EGLDisplay mEglDisplay{EGL_NO_DISPLAY};
+ EGLNativeDisplayType mEglNativeDisplay;
};
#endif // QMIRCLIENTINTEGRATION_H
diff --git a/src/plugins/platforms/mirclient/qmirclientlogging.h b/src/plugins/platforms/mirclient/qmirclientlogging.h
index 0eb3adbdc7..4921864ced 100644
--- a/src/plugins/platforms/mirclient/qmirclientlogging.h
+++ b/src/plugins/platforms/mirclient/qmirclientlogging.h
@@ -41,23 +41,15 @@
#ifndef QMIRCLIENTLOGGING_H
#define QMIRCLIENTLOGGING_H
-// Logging and assertion macros.
-#define LOG(...) qDebug(__VA_ARGS__)
-#define LOG_IF(cond,...) do { if (cond) qDebug(__VA_ARGS__); } while (0)
+#include <QLoggingCategory>
+
#define ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())
-#define NOT_REACHED() qt_assert("Not reached!",__FILE__,__LINE__)
-// Logging and assertion macros are compiled out for release builds.
-#if !defined(QT_NO_DEBUG)
-#define DLOG(...) LOG(__VA_ARGS__)
-#define DLOG_IF(cond,...) LOG_IF((cond), __VA_ARGS__)
-#define DASSERT(cond) ASSERT((cond))
-#define DNOT_REACHED() NOT_REACHED()
-#else
-#define DLOG(...) qt_noop()
-#define DLOG_IF(cond,...) qt_noop()
-#define DASSERT(cond) qt_noop()
-#define DNOT_REACHED() qt_noop()
-#endif
+Q_DECLARE_LOGGING_CATEGORY(mirclient)
+Q_DECLARE_LOGGING_CATEGORY(mirclientBufferSwap)
+Q_DECLARE_LOGGING_CATEGORY(mirclientInput)
+Q_DECLARE_LOGGING_CATEGORY(mirclientGraphics)
+Q_DECLARE_LOGGING_CATEGORY(mirclientCursor)
+Q_DECLARE_LOGGING_CATEGORY(mirclientDebug)
#endif // QMIRCLIENTLOGGING_H
diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp
index 033df6ba11..b85e6fedfa 100644
--- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp
@@ -42,32 +42,36 @@
#include "qmirclientnativeinterface.h"
#include "qmirclientscreen.h"
#include "qmirclientglcontext.h"
+#include "qmirclientwindow.h"
// Qt
-#include <private/qguiapplication_p.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qopenglcontext.h>
#include <QtGui/qscreen.h>
#include <QtCore/QMap>
-class QMirClientResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType>
+class UbuntuResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType>
{
public:
- QMirClientResourceMap()
+ UbuntuResourceMap()
: QMap<QByteArray, QMirClientNativeInterface::ResourceType>() {
insert("egldisplay", QMirClientNativeInterface::EglDisplay);
insert("eglcontext", QMirClientNativeInterface::EglContext);
insert("nativeorientation", QMirClientNativeInterface::NativeOrientation);
insert("display", QMirClientNativeInterface::Display);
insert("mirconnection", QMirClientNativeInterface::MirConnection);
+ insert("mirsurface", QMirClientNativeInterface::MirSurface);
+ insert("scale", QMirClientNativeInterface::Scale);
+ insert("formfactor", QMirClientNativeInterface::FormFactor);
}
};
-Q_GLOBAL_STATIC(QMirClientResourceMap, ubuntuResourceMap)
+Q_GLOBAL_STATIC(UbuntuResourceMap, ubuntuResourceMap)
-QMirClientNativeInterface::QMirClientNativeInterface()
- : mGenericEventFilterType(QByteArrayLiteral("Event"))
+QMirClientNativeInterface::QMirClientNativeInterface(const QMirClientClientIntegration *integration)
+ : mIntegration(integration)
+ , mGenericEventFilterType(QByteArrayLiteral("Event"))
, mNativeOrientation(nullptr)
- , mMirConnection(nullptr)
{
}
@@ -88,7 +92,7 @@ void* QMirClientNativeInterface::nativeResourceForIntegration(const QByteArray &
const ResourceType resourceType = ubuntuResourceMap()->value(lowerCaseResource);
if (resourceType == QMirClientNativeInterface::MirConnection) {
- return mMirConnection;
+ return mIntegration->mirConnection();
} else {
return nullptr;
}
@@ -119,14 +123,11 @@ void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resou
if (!ubuntuResourceMap()->contains(kLowerCaseResource))
return NULL;
const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);
- if (kResourceType == QMirClientNativeInterface::EglDisplay) {
- if (window) {
- return static_cast<QMirClientScreen*>(window->screen()->handle())->eglDisplay();
- } else {
- return static_cast<QMirClientScreen*>(
- QGuiApplication::primaryScreen()->handle())->eglDisplay();
- }
- } else if (kResourceType == QMirClientNativeInterface::NativeOrientation) {
+
+ switch (kResourceType) {
+ case EglDisplay:
+ return mIntegration->eglDisplay();
+ case NativeOrientation:
// Return the device's native screen orientation.
if (window) {
QMirClientScreen *ubuntuScreen = static_cast<QMirClientScreen*>(window->screen()->handle());
@@ -136,8 +137,19 @@ void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resou
mNativeOrientation = new Qt::ScreenOrientation(platformScreen->nativeOrientation());
}
return mNativeOrientation;
- } else {
- return NULL;
+ case MirSurface:
+ if (window) {
+ auto ubuntuWindow = static_cast<QMirClientWindow*>(window->handle());
+ if (ubuntuWindow) {
+ return ubuntuWindow->mirSurface();
+ } else {
+ return nullptr;
+ }
+ } else {
+ return nullptr;
+ }
+ default:
+ return nullptr;
}
}
@@ -147,10 +159,59 @@ void* QMirClientNativeInterface::nativeResourceForScreen(const QByteArray& resou
if (!ubuntuResourceMap()->contains(kLowerCaseResource))
return NULL;
const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource);
+ if (!screen)
+ screen = QGuiApplication::primaryScreen();
+ auto ubuntuScreen = static_cast<QMirClientScreen*>(screen->handle());
if (kResourceType == QMirClientNativeInterface::Display) {
- if (!screen)
- screen = QGuiApplication::primaryScreen();
- return static_cast<QMirClientScreen*>(screen->handle())->eglNativeDisplay();
+ return mIntegration->eglNativeDisplay();
+ // Changes to the following properties are emitted via the QMirClientNativeInterface::screenPropertyChanged
+ // signal fired by QMirClientScreen. Connect to this signal for these properties updates.
+ // WARNING: code highly thread unsafe!
+ } else if (kResourceType == QMirClientNativeInterface::Scale) {
+ // In application code, read with:
+ // float scale = *reinterpret_cast<float*>(nativeResourceForScreen("scale", screen()));
+ return &ubuntuScreen->mScale;
+ } else if (kResourceType == QMirClientNativeInterface::FormFactor) {
+ return &ubuntuScreen->mFormFactor;
} else
return NULL;
}
+
+// Changes to these properties are emitted via the QMirClientNativeInterface::windowPropertyChanged
+// signal fired by QMirClientWindow. Connect to this signal for these properties updates.
+QVariantMap QMirClientNativeInterface::windowProperties(QPlatformWindow *window) const
+{
+ QVariantMap propertyMap;
+ auto w = static_cast<QMirClientWindow*>(window);
+ if (w) {
+ propertyMap.insert("scale", w->scale());
+ propertyMap.insert("formFactor", w->formFactor());
+ }
+ return propertyMap;
+}
+
+QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const
+{
+ auto w = static_cast<QMirClientWindow*>(window);
+ if (!w) {
+ return QVariant();
+ }
+
+ if (name == QStringLiteral("scale")) {
+ return w->scale();
+ } else if (name == QStringLiteral("formFactor")) {
+ return w->formFactor();
+ } else {
+ return QVariant();
+ }
+}
+
+QVariant QMirClientNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const
+{
+ QVariant returnVal = windowProperty(window, name);
+ if (!returnVal.isValid()) {
+ return defaultValue;
+ } else {
+ return returnVal;
+ }
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h
index 78a440e956..eb601de301 100644
--- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h
+++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h
@@ -43,11 +43,16 @@
#include <qpa/qplatformnativeinterface.h>
+#include "qmirclientintegration.h"
+
+class QPlatformScreen;
+
class QMirClientNativeInterface : public QPlatformNativeInterface {
+ Q_OBJECT
public:
- enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection };
+ enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection, MirSurface, Scale, FormFactor };
- QMirClientNativeInterface();
+ QMirClientNativeInterface(const QMirClientClientIntegration *integration);
~QMirClientNativeInterface();
// QPlatformNativeInterface methods.
@@ -59,14 +64,20 @@ public:
void* nativeResourceForScreen(const QByteArray& resourceString,
QScreen* screen) override;
+ QVariantMap windowProperties(QPlatformWindow *window) const override;
+ QVariant windowProperty(QPlatformWindow *window, const QString &name) const override;
+ QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override;
+
// New methods.
const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; }
- void setMirConnection(void *mirConnection) { mMirConnection = mirConnection; }
+
+Q_SIGNALS: // New signals
+ void screenPropertyChanged(QPlatformScreen *screen, const QString &propertyName);
private:
+ const QMirClientClientIntegration *mIntegration;
const QByteArray mGenericEventFilterType;
Qt::ScreenOrientation* mNativeOrientation;
- void *mMirConnection;
};
#endif // QMIRCLIENTNATIVEINTERFACE_H
diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.cpp b/src/plugins/platforms/mirclient/qmirclientplugin.cpp
index 6899d70f2e..fc44edfe40 100644
--- a/src/plugins/platforms/mirclient/qmirclientplugin.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientplugin.cpp
@@ -40,12 +40,16 @@
#include "qmirclientplugin.h"
#include "qmirclientintegration.h"
+#include "qmirclientlogging.h"
-QPlatformIntegration* QMirClientIntegrationPlugin::create(const QString &system,
- const QStringList &)
+Q_LOGGING_CATEGORY(mirclient, "qt.qpa.mirclient", QtWarningMsg)
+
+QPlatformIntegration *QMirClientIntegrationPlugin::create(const QString &system,
+ const QStringList &/*paramList*/,
+ int &argc, char **argv)
{
if (system.toLower() == QLatin1String("mirclient")) {
- return new QMirClientClientIntegration;
+ return new QMirClientClientIntegration(argc, argv);
} else {
return 0;
}
diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.h b/src/plugins/platforms/mirclient/qmirclientplugin.h
index c91f2d1924..207d97b5af 100644
--- a/src/plugins/platforms/mirclient/qmirclientplugin.h
+++ b/src/plugins/platforms/mirclient/qmirclientplugin.h
@@ -49,7 +49,8 @@ class QMirClientIntegrationPlugin : public QPlatformIntegrationPlugin
Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "mirclient.json")
public:
- QPlatformIntegration* create(const QString&, const QStringList&);
+ QPlatformIntegration *create(const QString &system, const QStringList &paramList,
+ int &argc, char **argv) override;
};
#endif // QMIRCLIENTPLUGIN_H
diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.cpp b/src/plugins/platforms/mirclient/qmirclientscreen.cpp
index 0a2253e9e2..cc8db830aa 100644
--- a/src/plugins/platforms/mirclient/qmirclientscreen.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientscreen.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014-2015 Canonical, Ltd.
+** Copyright (C) 2014-2016 Canonical, Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -42,11 +42,12 @@
#include "qmirclientscreen.h"
#include "qmirclientlogging.h"
#include "qmirclientorientationchangeevent_p.h"
+#include "qmirclientnativeinterface.h"
#include <mir_toolkit/mir_client_library.h>
// Qt
-#include <QCoreApplication>
+#include <QGuiApplication>
#include <QtCore/qmath.h>
#include <QScreen>
#include <QThread>
@@ -55,9 +56,7 @@
#include <memory>
-static const int kSwapInterval = 1;
-
-#if !defined(QT_NO_DEBUG)
+static const int overrideDevicePixelRatio = qgetenv("QT_DEVICE_PIXEL_RATIO").toInt();
static const char *orientationToStr(Qt::ScreenOrientation orientation) {
switch (orientation) {
@@ -71,173 +70,33 @@ static const char *orientationToStr(Qt::ScreenOrientation orientation) {
return "inverted portrait";
case Qt::InvertedLandscapeOrientation:
return "inverted landscape";
- default:
- return "INVALID!";
}
+ Q_UNREACHABLE();
}
-static void printEglConfig(EGLDisplay display, EGLConfig config) {
- DASSERT(display != EGL_NO_DISPLAY);
- DASSERT(config != nullptr);
- static const struct { const EGLint attrib; const char* name; } kAttribs[] = {
- { EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE" },
- { EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE" },
- { EGL_BLUE_SIZE, "EGL_BLUE_SIZE" },
- { EGL_GREEN_SIZE, "EGL_GREEN_SIZE" },
- { EGL_RED_SIZE, "EGL_RED_SIZE" },
- { EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE" },
- { EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE" },
- { EGL_CONFIG_CAVEAT, "EGL_CONFIG_CAVEAT" },
- { EGL_CONFIG_ID, "EGL_CONFIG_ID" },
- { EGL_LEVEL, "EGL_LEVEL" },
- { EGL_MAX_PBUFFER_HEIGHT, "EGL_MAX_PBUFFER_HEIGHT" },
- { EGL_MAX_PBUFFER_PIXELS, "EGL_MAX_PBUFFER_PIXELS" },
- { EGL_MAX_PBUFFER_WIDTH, "EGL_MAX_PBUFFER_WIDTH" },
- { EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE" },
- { EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID" },
- { EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE" },
- { EGL_SAMPLES, "EGL_SAMPLES" },
- { EGL_SAMPLE_BUFFERS, "EGL_SAMPLE_BUFFERS" },
- { EGL_SURFACE_TYPE, "EGL_SURFACE_TYPE" },
- { EGL_TRANSPARENT_TYPE, "EGL_TRANSPARENT_TYPE" },
- { EGL_TRANSPARENT_BLUE_VALUE, "EGL_TRANSPARENT_BLUE_VALUE" },
- { EGL_TRANSPARENT_GREEN_VALUE, "EGL_TRANSPARENT_GREEN_VALUE" },
- { EGL_TRANSPARENT_RED_VALUE, "EGL_TRANSPARENT_RED_VALUE" },
- { EGL_BIND_TO_TEXTURE_RGB, "EGL_BIND_TO_TEXTURE_RGB" },
- { EGL_BIND_TO_TEXTURE_RGBA, "EGL_BIND_TO_TEXTURE_RGBA" },
- { EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL" },
- { EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL" },
- { -1, NULL }
- };
- const char* string = eglQueryString(display, EGL_VENDOR);
- LOG("EGL vendor: %s", string);
- string = eglQueryString(display, EGL_VERSION);
- LOG("EGL version: %s", string);
- string = eglQueryString(display, EGL_EXTENSIONS);
- LOG("EGL extensions: %s", string);
- LOG("EGL configuration attibutes:");
- for (int index = 0; kAttribs[index].attrib != -1; index++) {
- EGLint value;
- if (eglGetConfigAttrib(display, config, kAttribs[index].attrib, &value))
- LOG(" %s: %d", kAttribs[index].name, static_cast<int>(value));
- }
-}
-#endif
-
-
const QEvent::Type OrientationChangeEvent::mType =
static_cast<QEvent::Type>(QEvent::registerEventType());
-static const MirDisplayOutput *find_active_output(
- const MirDisplayConfiguration *conf)
-{
- const MirDisplayOutput *output = NULL;
- for (uint32_t d = 0; d < conf->num_outputs; d++)
- {
- const MirDisplayOutput *out = conf->outputs + d;
-
- if (out->used &&
- out->connected &&
- out->num_modes &&
- out->current_mode < out->num_modes)
- {
- output = out;
- break;
- }
- }
-
- return output;
-}
-QMirClientScreen::QMirClientScreen(MirConnection *connection)
- : mFormat(QImage::Format_RGB32)
+QMirClientScreen::QMirClientScreen(const MirOutput *output, MirConnection *connection)
+ : mDevicePixelRatio(1.0)
+ , mFormat(QImage::Format_RGB32)
, mDepth(32)
+ , mDpi{0}
+ , mFormFactor{mir_form_factor_unknown}
+ , mScale{1.0}
, mOutputId(0)
- , mSurfaceFormat()
- , mEglDisplay(EGL_NO_DISPLAY)
- , mEglConfig(nullptr)
, mCursor(connection)
{
- // Initialize EGL.
- ASSERT(eglBindAPI(EGL_OPENGL_ES_API) == EGL_TRUE);
-
- mEglNativeDisplay = mir_connection_get_egl_native_display(connection);
- ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY);
- ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE);
-
- // Configure EGL buffers format.
- mSurfaceFormat.setRedBufferSize(8);
- mSurfaceFormat.setGreenBufferSize(8);
- mSurfaceFormat.setBlueBufferSize(8);
- mSurfaceFormat.setAlphaBufferSize(8);
- mSurfaceFormat.setDepthBufferSize(24);
- mSurfaceFormat.setStencilBufferSize(8);
- if (!qEnvironmentVariableIsEmpty("QTUBUNTU_MULTISAMPLE")) {
- mSurfaceFormat.setSamples(4);
- DLOG("ubuntumirclient: setting MSAA to 4 samples");
- }
-#ifdef QTUBUNTU_USE_OPENGL
- mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGL);
-#else
- mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES);
-#endif
- mEglConfig = q_configFromGLFormat(mEglDisplay, mSurfaceFormat, true);
-
- #if !defined(QT_NO_DEBUG)
- printEglConfig(mEglDisplay, mEglConfig);
- #endif
-
- // Set vblank swap interval.
- int swapInterval = kSwapInterval;
- QByteArray swapIntervalString = qgetenv("QTUBUNTU_SWAPINTERVAL");
- if (!swapIntervalString.isEmpty()) {
- bool ok;
- swapInterval = swapIntervalString.toInt(&ok);
- if (!ok)
- swapInterval = kSwapInterval;
- }
- DLOG("ubuntumirclient: setting swap interval to %d", swapInterval);
- eglSwapInterval(mEglDisplay, swapInterval);
-
- // Get screen resolution.
- auto configDeleter = [](MirDisplayConfiguration *config) { mir_display_config_destroy(config); };
- using configUp = std::unique_ptr<MirDisplayConfiguration, decltype(configDeleter)>;
- configUp displayConfig(mir_connection_create_display_config(connection), configDeleter);
- ASSERT(displayConfig != nullptr);
-
- auto const displayOutput = find_active_output(displayConfig.get());
- ASSERT(displayOutput != nullptr);
-
- mOutputId = displayOutput->output_id;
-
- mPhysicalSize = QSizeF(displayOutput->physical_width_mm, displayOutput->physical_height_mm);
- DLOG("ubuntumirclient: screen physical size: %.2fx%.2f", mPhysicalSize.width(), mPhysicalSize.height());
-
- const MirDisplayMode *mode = &displayOutput->modes[displayOutput->current_mode];
- const int kScreenWidth = mode->horizontal_resolution;
- const int kScreenHeight = mode->vertical_resolution;
- DASSERT(kScreenWidth > 0 && kScreenHeight > 0);
-
- DLOG("ubuntumirclient: screen resolution: %dx%d", kScreenWidth, kScreenHeight);
-
- mGeometry = QRect(0, 0, kScreenWidth, kScreenHeight);
-
- DLOG("QQMirClientScreen::QQMirClientScreen (this=%p)", this);
-
- // Set the default orientation based on the initial screen dimmensions.
- mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
-
- // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait
- mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
+ setMirOutput(output);
}
QMirClientScreen::~QMirClientScreen()
{
- eglTerminate(mEglDisplay);
}
void QMirClientScreen::customEvent(QEvent* event) {
- DASSERT(QThread::currentThread() == thread());
+ Q_ASSERT(QThread::currentThread() == thread());
OrientationChangeEvent* oReadingEvent = static_cast<OrientationChangeEvent*>(event);
switch (oReadingEvent->mOrientation) {
@@ -261,14 +120,10 @@ void QMirClientScreen::customEvent(QEvent* event) {
Qt::InvertedLandscapeOrientation : Qt::InvertedPortraitOrientation;
break;
}
- default: {
- DLOG("QMirClientScreen::customEvent - Unknown orientation.");
- return;
- }
}
// Raise the event signal so that client apps know the orientation changed
- DLOG("QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation));
+ qCDebug(mirclient, "QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation));
QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation);
}
@@ -289,7 +144,7 @@ void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeig
mGeometry.setWidth(currGeometry.height());
mGeometry.setHeight(currGeometry.width());
- DLOG("QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)",
+ qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)",
mGeometry.width(), mGeometry.height());
QWindowSystemInterface::handleScreenGeometryChange(screen(),
mGeometry /* newGeometry */,
@@ -300,7 +155,108 @@ void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeig
} else {
mCurrentOrientation = Qt::LandscapeOrientation;
}
- DLOG("QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation));
+ qCDebug(mirclient, "QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation));
QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation);
}
}
+
+void QMirClientScreen::setMirOutput(const MirOutput *output)
+{
+ // Physical screen size (in mm)
+ mPhysicalSize.setWidth(mir_output_get_physical_width_mm(output));
+ mPhysicalSize.setHeight(mir_output_get_physical_height_mm(output));
+
+ // Pixel Format
+// mFormat = qImageFormatFromMirPixelFormat(mir_output_get_current_pixel_format(output)); // GERRY: TODO
+
+ // Pixel depth
+ mDepth = 8 * MIR_BYTES_PER_PIXEL(mir_output_get_current_pixel_format(output));
+
+ // Mode = Resolution & refresh rate
+ const MirOutputMode *mode = mir_output_get_current_mode(output);
+ mNativeGeometry.setX(mir_output_get_position_x(output));
+ mNativeGeometry.setY(mir_output_get_position_y(output));
+ mNativeGeometry.setWidth(mir_output_mode_get_width(mode));
+ mNativeGeometry.setHeight(mir_output_mode_get_height(mode));
+
+ mRefreshRate = mir_output_mode_get_refresh_rate(mode);
+
+ // UI scale & DPR
+ mScale = mir_output_get_scale_factor(output);
+ if (overrideDevicePixelRatio > 0) {
+ mDevicePixelRatio = overrideDevicePixelRatio;
+ } else {
+ mDevicePixelRatio = 1.0; // FIXME - need to determine suitable DPR for the specified scale
+ }
+
+ mFormFactor = mir_output_get_form_factor(output);
+
+ mOutputId = mir_output_get_id(output);
+
+ mGeometry.setX(mNativeGeometry.x());
+ mGeometry.setY(mNativeGeometry.y());
+ mGeometry.setWidth(mNativeGeometry.width());
+ mGeometry.setHeight(mNativeGeometry.height());
+
+ // Set the default orientation based on the initial screen dimensions.
+ mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
+
+ // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait
+ mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
+}
+
+void QMirClientScreen::updateMirOutput(const MirOutput *output)
+{
+ auto oldRefreshRate = mRefreshRate;
+ auto oldScale = mScale;
+ auto oldFormFactor = mFormFactor;
+ auto oldGeometry = mGeometry;
+
+ setMirOutput(output);
+
+ // Emit change signals in particular order
+ if (oldGeometry != mGeometry) {
+ QWindowSystemInterface::handleScreenGeometryChange(screen(),
+ mGeometry /* newGeometry */,
+ mGeometry /* newAvailableGeometry */);
+ }
+
+ if (!qFuzzyCompare(mRefreshRate, oldRefreshRate)) {
+ QWindowSystemInterface::handleScreenRefreshRateChange(screen(), mRefreshRate);
+ }
+
+ auto nativeInterface = static_cast<QMirClientNativeInterface *>(qGuiApp->platformNativeInterface());
+ if (!qFuzzyCompare(mScale, oldScale)) {
+ nativeInterface->screenPropertyChanged(this, QStringLiteral("scale"));
+ }
+ if (mFormFactor != oldFormFactor) {
+ nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor"));
+ }
+}
+
+void QMirClientScreen::setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi)
+{
+ if (mDpi != dpi) {
+ mDpi = dpi;
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), dpi, dpi);
+ }
+
+ auto nativeInterface = static_cast<QMirClientNativeInterface *>(qGuiApp->platformNativeInterface());
+ if (!qFuzzyCompare(mScale, scale)) {
+ mScale = scale;
+ nativeInterface->screenPropertyChanged(this, QStringLiteral("scale"));
+ }
+ if (mFormFactor != formFactor) {
+ mFormFactor = formFactor;
+ nativeInterface->screenPropertyChanged(this, QStringLiteral("formFactor"));
+ }
+}
+
+QDpi QMirClientScreen::logicalDpi() const
+{
+ if (mDpi > 0) {
+ return QDpi(mDpi, mDpi);
+ } else {
+ return QPlatformScreen::logicalDpi();
+ }
+}
diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.h b/src/plugins/platforms/mirclient/qmirclientscreen.h
index b050836ada..b31cba1964 100644
--- a/src/plugins/platforms/mirclient/qmirclientscreen.h
+++ b/src/plugins/platforms/mirclient/qmirclientscreen.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014-2015 Canonical, Ltd.
+** Copyright (C) 2014-2016 Canonical, Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -43,17 +43,19 @@
#include <qpa/qplatformscreen.h>
#include <QSurfaceFormat>
-#include <EGL/egl.h>
+
+#include <mir_toolkit/common.h> // just for MirFormFactor enum
#include "qmirclientcursor.h"
struct MirConnection;
+struct MirOutput;
class QMirClientScreen : public QObject, public QPlatformScreen
{
Q_OBJECT
public:
- QMirClientScreen(MirConnection *connection);
+ QMirClientScreen(const MirOutput *output, MirConnection *connection);
virtual ~QMirClientScreen();
// QPlatformScreen methods.
@@ -62,34 +64,43 @@ public:
QRect geometry() const override { return mGeometry; }
QRect availableGeometry() const override { return mGeometry; }
QSizeF physicalSize() const override { return mPhysicalSize; }
+ qreal devicePixelRatio() const override { return mDevicePixelRatio; }
+ QDpi logicalDpi() const override;
Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; }
Qt::ScreenOrientation orientation() const override { return mNativeOrientation; }
QPlatformCursor *cursor() const override { return const_cast<QMirClientCursor*>(&mCursor); }
- // New methods.
- QSurfaceFormat surfaceFormat() const { return mSurfaceFormat; }
- EGLDisplay eglDisplay() const { return mEglDisplay; }
- EGLConfig eglConfig() const { return mEglConfig; }
- EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; }
+ // Additional Screen properties from Mir
+ int mirOutputId() const { return mOutputId; }
+ MirFormFactor formFactor() const { return mFormFactor; }
+ float scale() const { return mScale; }
+
+ // Internally used methods
+ void updateMirOutput(const MirOutput *output);
+ void setAdditionalMirDisplayProperties(float scale, MirFormFactor formFactor, int dpi);
void handleWindowSurfaceResize(int width, int height);
- uint32_t mirOutputId() const { return mOutputId; }
// QObject methods.
void customEvent(QEvent* event) override;
private:
- QRect mGeometry;
+ void setMirOutput(const MirOutput *output);
+
+ QRect mGeometry, mNativeGeometry;
QSizeF mPhysicalSize;
+ qreal mDevicePixelRatio;
Qt::ScreenOrientation mNativeOrientation;
Qt::ScreenOrientation mCurrentOrientation;
QImage::Format mFormat;
int mDepth;
- uint32_t mOutputId;
- QSurfaceFormat mSurfaceFormat;
- EGLDisplay mEglDisplay;
- EGLConfig mEglConfig;
- EGLNativeDisplayType mEglNativeDisplay;
+ int mDpi;
+ qreal mRefreshRate;
+ MirFormFactor mFormFactor;
+ float mScale;
+ int mOutputId;
QMirClientCursor mCursor;
+
+ friend class QMirClientNativeInterface;
};
#endif // QMIRCLIENTSCREEN_H
diff --git a/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp b/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp
new file mode 100644
index 0000000000..792aeca351
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientscreenobserver.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical, Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qmirclientscreenobserver.h"
+#include "qmirclientscreen.h"
+#include "qmirclientwindow.h"
+#include "qmirclientlogging.h"
+
+// Qt
+#include <QMetaObject>
+#include <QPointer>
+
+// Mir
+#include <mirclient/mir_toolkit/mir_connection.h>
+#include <mirclient/mir_toolkit/mir_display_configuration.h>
+
+#include <memory>
+
+namespace {
+ static void displayConfigurationChangedCallback(MirConnection */*connection*/, void* context)
+ {
+ ASSERT(context != NULL);
+ QMirClientScreenObserver *observer = static_cast<QMirClientScreenObserver *>(context);
+ QMetaObject::invokeMethod(observer, "update");
+ }
+
+ const char *mirFormFactorToStr(MirFormFactor formFactor)
+ {
+ switch (formFactor) {
+ case mir_form_factor_unknown: return "unknown";
+ case mir_form_factor_phone: return "phone";
+ case mir_form_factor_tablet: return "tablet";
+ case mir_form_factor_monitor: return "monitor";
+ case mir_form_factor_tv: return "tv";
+ case mir_form_factor_projector: return "projector";
+ }
+ Q_UNREACHABLE();
+ }
+} // anonymous namespace
+
+QMirClientScreenObserver::QMirClientScreenObserver(MirConnection *mirConnection)
+ : mMirConnection(mirConnection)
+{
+ mir_connection_set_display_config_change_callback(mirConnection, ::displayConfigurationChangedCallback, this);
+ update();
+}
+
+void QMirClientScreenObserver::update()
+{
+ // Wrap MirDisplayConfiguration to always delete when out of scope
+ auto configDeleter = [](MirDisplayConfig *config) { mir_display_config_release(config); };
+ using configUp = std::unique_ptr<MirDisplayConfig, decltype(configDeleter)>;
+ configUp displayConfig(mir_connection_create_display_configuration(mMirConnection), configDeleter);
+
+ // Mir only tells us something changed, it is up to us to figure out what.
+ QList<QMirClientScreen*> newScreenList;
+ QList<QMirClientScreen*> oldScreenList = mScreenList;
+ mScreenList.clear();
+
+ for (int i = 0; i < mir_display_config_get_num_outputs(displayConfig.get()); i++) {
+ const MirOutput *output = mir_display_config_get_output(displayConfig.get(), i);
+ if (mir_output_is_enabled(output)) {
+ QMirClientScreen *screen = findScreenWithId(oldScreenList, mir_output_get_id(output));
+ if (screen) { // we've already set up this display before
+ screen->updateMirOutput(output);
+ oldScreenList.removeAll(screen);
+ } else {
+ // new display, so create QMirClientScreen for it
+ screen = new QMirClientScreen(output, mMirConnection);
+ newScreenList.append(screen);
+ qCDebug(mirclient) << "Added Screen with id" << mir_output_get_id(output)
+ << "and geometry" << screen->geometry();
+ }
+ mScreenList.append(screen);
+ }
+ }
+
+ // Announce old & unused Screens, should be deleted by the slot
+ Q_FOREACH (const auto screen, oldScreenList) {
+ Q_EMIT screenRemoved(screen);
+ }
+
+ /*
+ * Mir's MirDisplayOutput does not include formFactor or scale for some reason, but Qt
+ * will want that information on creating the QScreen. Only way we get that info is when
+ * Mir positions a Window on that Screen. See "handleScreenPropertiesChange" method
+ */
+
+ // Announce new Screens
+ Q_FOREACH (const auto screen, newScreenList) {
+ Q_EMIT screenAdded(screen);
+ }
+
+ qCDebug(mirclient) << "=======================================";
+ for (auto screen: mScreenList) {
+ qCDebug(mirclient) << screen << "- id:" << screen->mirOutputId()
+ << "geometry:" << screen->geometry()
+ << "form factor:" << mirFormFactorToStr(screen->formFactor())
+ << "scale:" << screen->scale();
+ }
+ qCDebug(mirclient) << "=======================================";
+}
+
+QMirClientScreen *QMirClientScreenObserver::findScreenWithId(int id)
+{
+ return findScreenWithId(mScreenList, id);
+}
+
+QMirClientScreen *QMirClientScreenObserver::findScreenWithId(const QList<QMirClientScreen *> &list, int id)
+{
+ Q_FOREACH (const auto screen, list) {
+ if (screen->mirOutputId() == id) {
+ return screen;
+ }
+ }
+ return nullptr;
+}
+
+void QMirClientScreenObserver::handleScreenPropertiesChange(QMirClientScreen *screen, int dpi,
+ MirFormFactor formFactor, float scale)
+{
+ screen->setAdditionalMirDisplayProperties(scale, formFactor, dpi);
+}
+
diff --git a/src/plugins/platforms/mirclient/qmirclientscreenobserver.h b/src/plugins/platforms/mirclient/qmirclientscreenobserver.h
new file mode 100644
index 0000000000..ad927319c1
--- /dev/null
+++ b/src/plugins/platforms/mirclient/qmirclientscreenobserver.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Canonical, Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMIRCLIENTSCREENOBSERVER_H
+#define QMIRCLIENTSCREENOBSERVER_H
+
+#include <QObject>
+
+#include <mir_toolkit/mir_connection.h>
+
+class QMirClientScreen;
+
+class QMirClientScreenObserver : public QObject
+{
+ Q_OBJECT
+
+public:
+ QMirClientScreenObserver(MirConnection *connection);
+
+ QList<QMirClientScreen*> screens() const { return mScreenList; }
+ QMirClientScreen *findScreenWithId(int id);
+
+ void handleScreenPropertiesChange(QMirClientScreen *screen, int dpi,
+ MirFormFactor formFactor, float scale);
+
+Q_SIGNALS:
+ void screenAdded(QMirClientScreen *screen);
+ void screenRemoved(QMirClientScreen *screen);
+
+private Q_SLOTS:
+ void update();
+
+private:
+ QMirClientScreen *findScreenWithId(const QList<QMirClientScreen *> &list, int id);
+ void removeScreen(QMirClientScreen *screen);
+
+ MirConnection *mMirConnection;
+ QList<QMirClientScreen*> mScreenList;
+};
+
+#endif // QMIRCLIENTSCREENOBSERVER_H
diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.cpp b/src/plugins/platforms/mirclient/qmirclientwindow.cpp
index 60b9cd7900..adc8ae652a 100644
--- a/src/plugins/platforms/mirclient/qmirclientwindow.cpp
+++ b/src/plugins/platforms/mirclient/qmirclientwindow.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014-2015 Canonical, Ltd.
+** Copyright (C) 2014-2016 Canonical, Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -40,26 +40,33 @@
// Local
#include "qmirclientwindow.h"
-#include "qmirclientclipboard.h"
+#include "qmirclientdebugextension.h"
+#include "qmirclientnativeinterface.h"
#include "qmirclientinput.h"
+#include "qmirclientintegration.h"
#include "qmirclientscreen.h"
#include "qmirclientlogging.h"
#include <mir_toolkit/mir_client_library.h>
+#include <mir_toolkit/version.h>
// Qt
#include <qpa/qwindowsysteminterface.h>
#include <QMutexLocker>
#include <QSize>
#include <QtMath>
+#include <QtEglSupport/private/qeglconvenience_p.h>
// Platform API
#include <ubuntu/application/instance.h>
#include <EGL/egl.h>
+Q_LOGGING_CATEGORY(mirclientBufferSwap, "qt.qpa.mirclient.bufferSwap", QtWarningMsg)
+
namespace
{
+const Qt::WindowType LowChromeWindowHint = (Qt::WindowType)0x00800000;
// FIXME: this used to be defined by platform-api, but it's been removed in v3. Change ubuntu-keyboard to use
// a different enum for window roles.
@@ -87,40 +94,110 @@ EGLNativeWindowType nativeWindowFor(MirSurface *surf)
return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream));
}
-MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
+const char *qtWindowStateToStr(Qt::WindowState state)
{
switch (state) {
case Qt::WindowNoState:
- return mir_surface_state_restored;
+ return "NoState";
case Qt::WindowFullScreen:
- return mir_surface_state_fullscreen;
+ return "FullScreen";
case Qt::WindowMaximized:
- return mir_surface_state_maximized;
+ return "Maximized";
case Qt::WindowMinimized:
- return mir_surface_state_minimized;
- default:
- LOG("Unexpected Qt::WindowState: %d", state);
- return mir_surface_state_restored;
+ return "Minimized";
+ case Qt::WindowActive:
+ return "Active";
}
+ Q_UNREACHABLE();
}
-#if !defined(QT_NO_DEBUG)
-const char *qtWindowStateToStr(Qt::WindowState state)
+const char *mirSurfaceStateToStr(MirSurfaceState surfaceState)
+{
+ switch (surfaceState) {
+ case mir_surface_state_unknown: return "unknown";
+ case mir_surface_state_restored: return "restored";
+ case mir_surface_state_minimized: return "minimized";
+ case mir_surface_state_maximized: return "vertmaximized";
+ case mir_surface_state_vertmaximized: return "vertmaximized";
+ case mir_surface_state_fullscreen: return "fullscreen";
+ case mir_surface_state_horizmaximized: return "horizmaximized";
+ case mir_surface_state_hidden: return "hidden";
+ case mir_surface_states: Q_UNREACHABLE();
+ }
+ Q_UNREACHABLE();
+}
+
+const char *mirPixelFormatToStr(MirPixelFormat pixelFormat)
+{
+ switch (pixelFormat) {
+ case mir_pixel_format_invalid: return "invalid";
+ case mir_pixel_format_abgr_8888: return "ABGR8888";
+ case mir_pixel_format_xbgr_8888: return "XBGR8888";
+ case mir_pixel_format_argb_8888: return "ARGB8888";
+ case mir_pixel_format_xrgb_8888: return "XRGB8888";
+ case mir_pixel_format_bgr_888: return "BGR888";
+ case mir_pixel_format_rgb_888: return "RGB888";
+ case mir_pixel_format_rgb_565: return "RGB565";
+ case mir_pixel_format_rgba_5551: return "RGBA5551";
+ case mir_pixel_format_rgba_4444: return "RGBA4444";
+ case mir_pixel_formats: Q_UNREACHABLE();
+ }
+ Q_UNREACHABLE();
+}
+
+const char *mirSurfaceTypeToStr(MirSurfaceType type)
+{
+ switch (type) {
+ case mir_surface_type_normal: return "Normal"; /**< AKA "regular" */
+ case mir_surface_type_utility: return "Utility"; /**< AKA "floating regular" */
+ case mir_surface_type_dialog: return "Dialog";
+ case mir_surface_type_gloss: return "Gloss";
+ case mir_surface_type_freestyle: return "Freestyle";
+ case mir_surface_type_menu: return "Menu";
+ case mir_surface_type_inputmethod: return "Input Method"; /**< AKA "OSK" or handwriting etc. */
+ case mir_surface_type_satellite: return "Satellite"; /**< AKA "toolbox"/"toolbar" */
+ case mir_surface_type_tip: return "Tip"; /**< AKA "tooltip" */
+ case mir_surface_types: Q_UNREACHABLE();
+ }
+ return "";
+}
+
+MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
{
switch (state) {
case Qt::WindowNoState:
- return "NoState";
+ case Qt::WindowActive:
+ return mir_surface_state_restored;
case Qt::WindowFullScreen:
- return "FullScreen";
+ return mir_surface_state_fullscreen;
case Qt::WindowMaximized:
- return "Maximized";
+ return mir_surface_state_maximized;
case Qt::WindowMinimized:
- return "Minimized";
+ return mir_surface_state_minimized;
+ }
+ return mir_surface_state_unknown; // should never be reached
+}
+
+MirSurfaceType qtWindowTypeToMirSurfaceType(Qt::WindowType type)
+{
+ switch (type & Qt::WindowType_Mask) {
+ case Qt::Dialog:
+ return mir_surface_type_dialog;
+ case Qt::Sheet:
+ case Qt::Drawer:
+ return mir_surface_type_utility;
+ case Qt::Popup:
+ case Qt::Tool:
+ return mir_surface_type_menu;
+ case Qt::ToolTip:
+ return mir_surface_type_tip;
+ case Qt::SplashScreen:
+ return mir_surface_type_freestyle;
+ case Qt::Window:
default:
- return "!?";
+ return mir_surface_type_normal;
}
}
-#endif
WId makeId()
{
@@ -128,14 +205,6 @@ WId makeId()
return id++;
}
-MirPixelFormat defaultPixelFormatFor(MirConnection *connection)
-{
- MirPixelFormat format;
- unsigned int nformats;
- mir_connection_get_available_surface_formats(connection, &format, 1, &nformats);
- return format;
-}
-
UAUiWindowRole roleFor(QWindow *window)
{
QVariant roleVariant = window->property("role");
@@ -155,52 +224,93 @@ QMirClientWindow *transientParentFor(QWindow *window)
return parent ? static_cast<QMirClientWindow *>(parent->handle()) : nullptr;
}
-Spec makeSurfaceSpec(QWindow *window, QMirClientInput *input, MirConnection *connection)
-{
- const auto geom = window->geometry();
- const int width = geom.width() > 0 ? geom.width() : 1;
- const int height = geom.height() > 0 ? geom.height() : 1;
- const auto pixelFormat = defaultPixelFormatFor(connection);
-
- if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
- DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);
- return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
- }
-
- const Qt::WindowType type = window->type();
- if (type == Qt::Popup) {
- auto parent = transientParentFor(window);
- if (parent == nullptr) {
- //NOTE: We cannot have a parentless popup -
- //try using the last surface to receive input as that will most likely be
- //the one that caused this popup to be created
- parent = input->lastFocusedWindow();
- }
- if (parent) {
- auto pos = geom.topLeft();
- pos -= parent->geometry().topLeft();
- MirRectangle location{pos.x(), pos.y(), 0, 0};
- DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);
- return Spec{mir_connection_create_spec_for_menu(
- connection, width, height, pixelFormat, parent->mirSurface(),
- &location, mir_edge_attachment_any)};
- } else {
- DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);
- }
- } else if (type == Qt::Dialog) {
- auto parent = transientParentFor(window);
- if (parent) {
- // Modal dialog
- DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);
- return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};
- } else {
- // TODO: do Qt parentless dialogs have the same semantics as mir?
- DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);
- return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
- }
- }
- DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);
- return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
+bool requiresParent(const MirSurfaceType type)
+{
+ switch (type) {
+ case mir_surface_type_dialog: //FIXME - not quite what the specification dictates, but is what Mir's api dictates
+ case mir_surface_type_utility:
+ case mir_surface_type_gloss:
+ case mir_surface_type_menu:
+ case mir_surface_type_satellite:
+ case mir_surface_type_tip:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool requiresParent(const Qt::WindowType type)
+{
+ return requiresParent(qtWindowTypeToMirSurfaceType(type));
+}
+
+bool isMovable(const Qt::WindowType type)
+{
+ auto mirType = qtWindowTypeToMirSurfaceType(type);
+ switch (mirType) {
+ case mir_surface_type_menu:
+ case mir_surface_type_tip:
+ return true;
+ default:
+ return false;
+ }
+}
+
+Spec makeSurfaceSpec(QWindow *window, MirPixelFormat pixelFormat, QMirClientWindow *parentWindowHandle,
+ MirConnection *connection)
+{
+ const auto geometry = window->geometry();
+ const int width = geometry.width() > 0 ? geometry.width() : 1;
+ const int height = geometry.height() > 0 ? geometry.height() : 1;
+ auto type = qtWindowTypeToMirSurfaceType(window->type());
+
+ if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
+ type = mir_surface_type_inputmethod;
+ }
+
+ MirRectangle location{geometry.x(), geometry.y(), 0, 0};
+ MirSurface *parent = nullptr;
+ if (parentWindowHandle) {
+ parent = parentWindowHandle->mirSurface();
+ // Qt uses absolute positioning, but Mir positions surfaces relative to parent.
+ location.top -= parentWindowHandle->geometry().top();
+ location.left -= parentWindowHandle->geometry().left();
+ }
+
+ Spec spec;
+
+ switch (type) {
+ case mir_surface_type_menu:
+ spec = Spec{mir_connection_create_spec_for_menu(connection, width, height, pixelFormat, parent,
+ &location, mir_edge_attachment_any)};
+ break;
+ case mir_surface_type_dialog:
+ spec = Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent)};
+ break;
+ case mir_surface_type_utility:
+ spec = Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
+ break;
+ case mir_surface_type_tip:
+#if MIR_CLIENT_VERSION < MIR_VERSION_NUMBER(3, 4, 0)
+ spec = Spec{mir_connection_create_spec_for_tooltip(connection, width, height, pixelFormat, parent,
+ &location)};
+#else
+ spec = Spec{mir_connection_create_spec_for_tip(connection, width, height, pixelFormat, parent,
+ &location, mir_edge_attachment_any)};
+#endif
+ break;
+ case mir_surface_type_inputmethod:
+ spec = Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
+ break;
+ default:
+ spec = Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
+ break;
+ }
+
+ qCDebug(mirclient, "makeSurfaceSpec(window=%p): %s spec (type=0x%x, position=(%d, %d)px, size=(%dx%d)px)",
+ window, mirSurfaceTypeToStr(type), window->type(), location.left, location.top, width, height);
+
+ return std::move(spec);
}
void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)
@@ -221,16 +331,30 @@ void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSiz
}
}
-MirSurface *createMirSurface(QWindow *window, QMirClientScreen *screen, QMirClientInput *input, MirConnection *connection)
+MirSurface *createMirSurface(QWindow *window, int mirOutputId, QMirClientWindow *parentWindowHandle,
+ MirPixelFormat pixelFormat, MirConnection *connection,
+ mir_surface_event_callback inputCallback, void *inputContext)
{
- auto spec = makeSurfaceSpec(window, input, connection);
+ auto spec = makeSurfaceSpec(window, pixelFormat, parentWindowHandle, connection);
+
+ // Install event handler as early as possible
+ mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext);
+
const auto title = window->title().toUtf8();
mir_surface_spec_set_name(spec.get(), title.constData());
setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement());
if (window->windowState() == Qt::WindowFullScreen) {
- mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId());
+ mir_surface_spec_set_fullscreen_on_output(spec.get(), mirOutputId);
+ }
+
+ if (window->flags() & LowChromeWindowHint) {
+ mir_surface_spec_set_shell_chrome(spec.get(), mir_shell_chrome_low);
+ }
+
+ if (!window->isVisible()) {
+ mir_surface_spec_set_state(spec.get(), mir_surface_state_hidden);
}
auto surface = mir_surface_create_sync(spec.get());
@@ -238,83 +362,45 @@ MirSurface *createMirSurface(QWindow *window, QMirClientScreen *screen, QMirClie
return surface;
}
-// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633
-// we need to guess the panel height (3GU)
-int panelHeight()
-{
- if (qEnvironmentVariableIsSet("QT_MIRCLIENT_IGNORE_PANEL"))
- return 0;
- const int defaultGridUnit = 8;
- int gridUnit = defaultGridUnit;
- QByteArray gridUnitString = qgetenv("GRID_UNIT_PX");
- if (!gridUnitString.isEmpty()) {
- bool ok;
- gridUnit = gridUnitString.toInt(&ok);
- if (!ok) {
- gridUnit = defaultGridUnit;
+QMirClientWindow *getParentIfNecessary(QWindow *window, QMirClientInput *input)
+{
+ QMirClientWindow *parentWindowHandle = nullptr;
+ if (requiresParent(window->type())) {
+ parentWindowHandle = transientParentFor(window);
+ if (parentWindowHandle == nullptr) {
+ // NOTE: Mir requires this surface have a parent. Try using the last surface to receive input as that will
+ // most likely be the one that caused this surface to be created
+ parentWindowHandle = input->lastInputWindow();
}
}
- return gridUnit * 3;
+ return parentWindowHandle;
}
-} //namespace
-
-class QMirClientSurface
+MirPixelFormat disableAlphaBufferIfPossible(MirPixelFormat pixelFormat)
{
-public:
- QMirClientSurface(QMirClientWindow *platformWindow, QMirClientScreen *screen, QMirClientInput *input, MirConnection *connection)
- : mWindow(platformWindow->window())
- , mPlatformWindow(platformWindow)
- , mInput(input)
- , mConnection(connection)
- , mMirSurface(createMirSurface(mWindow, screen, input, connection))
- , mEglDisplay(screen->eglDisplay())
- , mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr))
- , mVisible(false)
- , mNeedsRepaint(false)
- , mParented(mWindow->transientParent() || mWindow->parent())
- , mWindowState(mWindow->windowState())
-
- {
- mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this);
-
- // Window manager can give us a final size different from what we asked for
- // so let's check what we ended up getting
- MirSurfaceParameters parameters;
- mir_surface_get_parameters(mMirSurface, &parameters);
-
- auto geom = mWindow->geometry();
- geom.setWidth(parameters.width);
- geom.setHeight(parameters.height);
- if (mWindowState == Qt::WindowFullScreen) {
- geom.setY(0);
- } else {
- geom.setY(panelHeight());
- }
+ switch (pixelFormat) {
+ case mir_pixel_format_abgr_8888:
+ return mir_pixel_format_xbgr_8888;
+ case mir_pixel_format_argb_8888:
+ return mir_pixel_format_xrgb_8888;
+ default: // can do nothing, leave it alone
+ return pixelFormat;
+ }
+}
+} //namespace
- // Assume that the buffer size matches the surface size at creation time
- mBufferSize = geom.size();
- platformWindow->QPlatformWindow::setGeometry(geom);
- QWindowSystemInterface::handleGeometryChange(mWindow, geom);
- DLOG("[ubuntumirclient QPA] created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n",
- geom.x(), geom.y(), geom.width(), geom.height(), mWindow->title().toUtf8().constData(), roleFor(mWindow));
- }
- ~QMirClientSurface()
- {
- if (mEglSurface != EGL_NO_SURFACE)
- eglDestroySurface(mEglDisplay, mEglSurface);
- if (mMirSurface)
- mir_surface_release_sync(mMirSurface);
- }
+class UbuntuSurface
+{
+public:
+ UbuntuSurface(QMirClientWindow *platformWindow, EGLDisplay display, QMirClientInput *input, MirConnection *connection);
+ ~UbuntuSurface();
- QMirClientSurface(QMirClientSurface const&) = delete;
- QMirClientSurface& operator=(QMirClientSurface const&) = delete;
+ UbuntuSurface(const UbuntuSurface &) = delete;
+ UbuntuSurface& operator=(const UbuntuSurface &) = delete;
- void resize(const QSize& newSize);
- void setState(Qt::WindowState newState);
- void setVisible(bool state);
+ void updateGeometry(const QRect &newGeometry);
void updateTitle(const QString& title);
void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);
@@ -322,76 +408,151 @@ public:
void handleSurfaceResized(int width, int height);
int needsRepaint() const;
+ MirSurfaceState state() const { return mir_surface_get_state(mMirSurface); }
+ void setState(MirSurfaceState state);
+
+ MirSurfaceType type() const { return mir_surface_get_type(mMirSurface); }
+
+ void setShellChrome(MirShellChrome shellChrome);
+
EGLSurface eglSurface() const { return mEglSurface; }
MirSurface *mirSurface() const { return mMirSurface; }
+ void setSurfaceParent(MirSurface*);
+ bool hasParent() const { return mParented; }
+
+ QSurfaceFormat format() const { return mFormat; }
+
+ bool mNeedsExposeCatchup;
+
+ QString persistentSurfaceId();
+
private:
static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context);
void postEvent(const MirEvent *event);
- void updateSurface();
QWindow * const mWindow;
QMirClientWindow * const mPlatformWindow;
QMirClientInput * const mInput;
MirConnection * const mConnection;
+ QMirClientWindow * mParentWindowHandle{nullptr};
- MirSurface * const mMirSurface;
+ MirSurface* mMirSurface;
const EGLDisplay mEglDisplay;
- const EGLSurface mEglSurface;
+ EGLSurface mEglSurface;
- bool mVisible;
bool mNeedsRepaint;
bool mParented;
- Qt::WindowState mWindowState;
QSize mBufferSize;
+ QSurfaceFormat mFormat;
+ MirPixelFormat mPixelFormat;
QMutex mTargetSizeMutex;
QSize mTargetSize;
+ MirShellChrome mShellChrome;
+ QString mPersistentIdStr;
};
-void QMirClientSurface::resize(const QSize& size)
-{
- DLOG("[ubuntumirclient QPA] resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());
-
- if (mWindowState == Qt::WindowFullScreen || mWindowState == Qt::WindowMaximized) {
- DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
- return;
+UbuntuSurface::UbuntuSurface(QMirClientWindow *platformWindow, EGLDisplay display, QMirClientInput *input, MirConnection *connection)
+ : mWindow(platformWindow->window())
+ , mPlatformWindow(platformWindow)
+ , mInput(input)
+ , mConnection(connection)
+ , mEglDisplay(display)
+ , mNeedsRepaint(false)
+ , mParented(mWindow->transientParent() || mWindow->parent())
+ , mFormat(mWindow->requestedFormat())
+ , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
+{
+ // Have Qt choose most suitable EGLConfig for the requested surface format, and update format to reflect it
+ EGLConfig config = q_configFromGLFormat(display, mFormat, true);
+ if (config == 0) {
+ // Older Intel Atom-based devices only support OpenGL 1.4 compatibility profile but by default
+ // QML asks for at least OpenGL 2.0. The XCB GLX backend ignores this request and returns a
+ // 1.4 context, but the XCB EGL backend tries to honor it, and fails. The 1.4 context appears to
+ // have sufficient capabilities on MESA (i915) to render correctly however. So reduce the default
+ // requested OpenGL version to 1.0 to ensure EGL will give us a working context (lp:1549455).
+ static const bool isMesa = QString(eglQueryString(display, EGL_VENDOR)).contains(QStringLiteral("Mesa"));
+ if (isMesa) {
+ qCDebug(mirclientGraphics, "Attempting to choose OpenGL 1.4 context which may suit Mesa");
+ mFormat.setMajorVersion(1);
+ mFormat.setMinorVersion(4);
+ config = q_configFromGLFormat(display, mFormat, true);
+ }
+ }
+ if (config == 0) {
+ qCritical() << "Qt failed to choose a suitable EGLConfig to suit the surface format" << mFormat;
}
- if (size.isEmpty()) {
- DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, size is empty", mWindow);
- return;
+ mFormat = q_glFormatFromConfig(display, config, mFormat);
+
+ // Have Mir decide the pixel format most suited to the chosen EGLConfig. This is the only way
+ // Mir will know what EGLConfig has been chosen - it cannot deduce it from the buffers.
+ mPixelFormat = mir_connection_get_egl_pixel_format(connection, display, config);
+ // But the chosen EGLConfig might have an alpha buffer enabled, even if not requested by the client.
+ // If that's the case, try to edit the chosen pixel format in order to disable the alpha buffer.
+ // This is an optimization for the compositor, as it can avoid blending this surface.
+ if (mWindow->requestedFormat().alphaBufferSize() < 0) {
+ mPixelFormat = disableAlphaBufferIfPossible(mPixelFormat);
}
- Spec spec{mir_connection_create_spec_for_changes(mConnection)};
- mir_surface_spec_set_width(spec.get(), size.width());
- mir_surface_spec_set_height(spec.get(), size.height());
- mir_surface_apply_spec(mMirSurface, spec.get());
+ const auto outputId = static_cast<QMirClientScreen *>(mWindow->screen()->handle())->mirOutputId();
+
+ mParentWindowHandle = getParentIfNecessary(mWindow, input);
+
+ mMirSurface = createMirSurface(mWindow, outputId, mParentWindowHandle, mPixelFormat, connection, surfaceEventCallback, this);
+ mEglSurface = eglCreateWindowSurface(mEglDisplay, config, nativeWindowFor(mMirSurface), nullptr);
+
+ mNeedsExposeCatchup = mir_surface_get_visibility(mMirSurface) == mir_surface_visibility_occluded;
+
+ // Window manager can give us a final size different from what we asked for
+ // so let's check what we ended up getting
+ MirSurfaceParameters parameters;
+ mir_surface_get_parameters(mMirSurface, &parameters);
+
+ auto geom = mWindow->geometry();
+ geom.setWidth(parameters.width);
+ geom.setHeight(parameters.height);
+
+ // Assume that the buffer size matches the surface size at creation time
+ mBufferSize = geom.size();
+ platformWindow->QPlatformWindow::setGeometry(geom);
+ QWindowSystemInterface::handleGeometryChange(mWindow, geom);
+
+ qCDebug(mirclient) << "Created surface with geometry:" << geom << "title:" << mWindow->title()
+ << "role:" << roleFor(mWindow);
+ qCDebug(mirclientGraphics)
+ << "Requested format:" << mWindow->requestedFormat()
+ << "\nActual format:" << mFormat
+ << "with associated Mir pixel format:" << mirPixelFormatToStr(mPixelFormat);
}
-void QMirClientSurface::setState(Qt::WindowState newState)
+UbuntuSurface::~UbuntuSurface()
{
- mir_wait_for(mir_surface_set_state(mMirSurface, qtWindowStateToMirSurfaceState(newState)));
- mWindowState = newState;
+ if (mEglSurface != EGL_NO_SURFACE)
+ eglDestroySurface(mEglDisplay, mEglSurface);
+ if (mMirSurface) {
+ mir_surface_release_sync(mMirSurface);
+ }
}
-void QMirClientSurface::setVisible(bool visible)
+void UbuntuSurface::updateGeometry(const QRect &newGeometry)
{
- if (mVisible == visible)
- return;
-
- mVisible = visible;
+ qCDebug(mirclient,"updateGeometry(window=%p, width=%d, height=%d)", mWindow,
+ newGeometry.width(), newGeometry.height());
- if (mVisible)
- updateSurface();
-
- // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
- // Will have to change qtmir and unity8 for that.
- const auto newState = visible ? qtWindowStateToMirSurfaceState(mWindowState) : mir_surface_state_minimized;
- mir_wait_for(mir_surface_set_state(mMirSurface, newState));
+ Spec spec;
+ if (isMovable(mWindow->type())) {
+ spec = Spec{makeSurfaceSpec(mWindow, mPixelFormat, mParentWindowHandle, mConnection)};
+ } else {
+ spec = Spec{mir_connection_create_spec_for_changes(mConnection)};
+ mir_surface_spec_set_width(spec.get(), newGeometry.width());
+ mir_surface_spec_set_height(spec.get(), newGeometry.height());
+ }
+ mir_surface_apply_spec(mMirSurface, spec.get());
}
-void QMirClientSurface::updateTitle(const QString& newTitle)
+void UbuntuSurface::updateTitle(const QString& newTitle)
{
const auto title = newTitle.toUtf8();
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
@@ -399,14 +560,14 @@ void QMirClientSurface::updateTitle(const QString& newTitle)
mir_surface_apply_spec(mMirSurface, spec.get());
}
-void QMirClientSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment)
+void UbuntuSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment)
{
Spec spec{mir_connection_create_spec_for_changes(mConnection)};
::setSizingConstraints(spec.get(), minSize, maxSize, increment);
mir_surface_apply_spec(mMirSurface, spec.get());
}
-void QMirClientSurface::handleSurfaceResized(int width, int height)
+void UbuntuSurface::handleSurfaceResized(int width, int height)
{
QMutexLocker lock(&mTargetSizeMutex);
@@ -419,7 +580,7 @@ void QMirClientSurface::handleSurfaceResized(int width, int height)
mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height;
}
-int QMirClientSurface::needsRepaint() const
+int UbuntuSurface::needsRepaint() const
{
if (mNeedsRepaint) {
if (mTargetSize != mBufferSize) {
@@ -436,12 +597,26 @@ int QMirClientSurface::needsRepaint() const
return 0;
}
-void QMirClientSurface::onSwapBuffersDone()
+void UbuntuSurface::setState(MirSurfaceState state)
+{
+ mir_wait_for(mir_surface_set_state(mMirSurface, state));
+}
+
+void UbuntuSurface::setShellChrome(MirShellChrome chrome)
+{
+ if (chrome != mShellChrome) {
+ auto spec = Spec{mir_connection_create_spec_for_changes(mConnection)};
+ mir_surface_spec_set_shell_chrome(spec.get(), chrome);
+ mir_surface_apply_spec(mMirSurface, spec.get());
+
+ mShellChrome = chrome;
+ }
+}
+
+void UbuntuSurface::onSwapBuffersDone()
{
-#if !defined(QT_NO_DEBUG)
static int sFrameNumber = 0;
++sFrameNumber;
-#endif
EGLint eglSurfaceWidth = -1;
EGLint eglSurfaceHeight = -1;
@@ -452,7 +627,7 @@ void QMirClientSurface::onSwapBuffersDone()
if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) {
- DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
+ qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight);
mBufferSize.rwidth() = eglSurfaceWidth;
@@ -464,23 +639,21 @@ void QMirClientSurface::onSwapBuffersDone()
mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
} else {
-#if 0
- DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
+ qCDebug(mirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height());
-#endif
}
}
-void QMirClientSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context)
+void UbuntuSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context)
{
Q_UNUSED(surface);
Q_ASSERT(context != nullptr);
- auto s = static_cast<QMirClientSurface *>(context);
+ auto s = static_cast<UbuntuSurface *>(context);
s->postEvent(event);
}
-void QMirClientSurface::postEvent(const MirEvent *event)
+void UbuntuSurface::postEvent(const MirEvent *event)
{
if (mir_event_type_resize == mir_event_get_type(event)) {
// TODO: The current event queue just accumulates all resize events;
@@ -490,7 +663,7 @@ void QMirClientSurface::postEvent(const MirEvent *event)
const auto resizeEvent = mir_event_get_resize_event(event);
const auto width = mir_resize_event_get_width(resizeEvent);
const auto height = mir_resize_event_get_height(resizeEvent);
- DLOG("[ubuntumirclient QPA] resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height);
+ qCDebug(mirclient, "resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height);
QMutexLocker lock(&mTargetSizeMutex);
mTargetSize.rwidth() = width;
@@ -500,44 +673,57 @@ void QMirClientSurface::postEvent(const MirEvent *event)
mInput->postEvent(mPlatformWindow, event);
}
-void QMirClientSurface::updateSurface()
+void UbuntuSurface::setSurfaceParent(MirSurface* parent)
{
- DLOG("[ubuntumirclient QPA] updateSurface(window=%p)", mWindow);
+ qCDebug(mirclient, "setSurfaceParent(window=%p)", mWindow);
- if (!mParented && mWindow->type() == Qt::Dialog) {
- // The dialog may have been parented after creation time
- // so morph it into a modal dialog
- auto parent = transientParentFor(mWindow);
- if (parent) {
- DLOG("[ubuntumirclient QPA] updateSurface(window=%p) dialog now parented", mWindow);
- mParented = true;
- Spec spec{mir_connection_create_spec_for_changes(mConnection)};
- mir_surface_spec_set_parent(spec.get(), parent->mirSurface());
- mir_surface_apply_spec(mMirSurface, spec.get());
- }
+ mParented = true;
+ Spec spec{mir_connection_create_spec_for_changes(mConnection)};
+ mir_surface_spec_set_parent(spec.get(), parent);
+ mir_surface_apply_spec(mMirSurface, spec.get());
+}
+
+QString UbuntuSurface::persistentSurfaceId()
+{
+ if (mPersistentIdStr.isEmpty()) {
+ MirPersistentId* mirPermaId = mir_surface_request_persistent_id_sync(mMirSurface);
+ mPersistentIdStr = mir_persistent_id_as_string(mirPermaId);
+ mir_persistent_id_release(mirPermaId);
}
+ return mPersistentIdStr;
}
-QMirClientWindow::QMirClientWindow(QWindow *w, const QSharedPointer<QMirClientClipboard> &clipboard, QMirClientScreen *screen,
- QMirClientInput *input, MirConnection *connection)
+QMirClientWindow::QMirClientWindow(QWindow *w, QMirClientInput *input, QMirClientNativeInterface *native,
+ QMirClientAppStateController *appState, EGLDisplay eglDisplay,
+ MirConnection *mirConnection, QMirClientDebugExtension *debugExt)
: QObject(nullptr)
, QPlatformWindow(w)
, mId(makeId())
- , mClipboard(clipboard)
- , mSurface(new QMirClientSurface{this, screen, input, connection})
+ , mWindowState(w->windowState())
+ , mWindowFlags(w->flags())
+ , mWindowVisible(false)
+ , mAppStateController(appState)
+ , mDebugExtention(debugExt)
+ , mNativeInterface(native)
+ , mSurface(new UbuntuSurface{this, eglDisplay, input, mirConnection})
+ , mScale(1.0)
+ , mFormFactor(mir_form_factor_unknown)
{
- DLOG("[ubuntumirclient QPA] QMirClientWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get());
+ mWindowExposed = mSurface->mNeedsExposeCatchup == false;
+
+ qCDebug(mirclient, "QMirClientWindow(window=%p, screen=%p, input=%p, surf=%p) with title '%s', role: '%d'",
+ w, w->screen()->handle(), input, mSurface.get(), qPrintable(window()->title()), roleFor(window()));
}
QMirClientWindow::~QMirClientWindow()
{
- DLOG("[ubuntumirclient QPA] ~QMirClientWindow(window=%p)", this);
+ qCDebug(mirclient, "~QMirClientWindow(window=%p)", this);
}
void QMirClientWindow::handleSurfaceResized(int width, int height)
{
QMutexLocker lock(&mMutex);
- DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height);
+ qCDebug(mirclient, "handleSurfaceResize(window=%p, size=(%dx%d)px", window(), width, height);
mSurface->handleSurfaceResized(width, height);
@@ -547,88 +733,140 @@ void QMirClientWindow::handleSurfaceResized(int width, int height)
// updated size but it still needs re-rendering so another redraw may be needed.
// A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice
auto const numRepaints = mSurface->needsRepaint();
- DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
+ lock.unlock();
+ qCDebug(mirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
for (int i = 0; i < numRepaints; i++) {
- DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height());
+ qCDebug(mirclient, "handleSurfaceResize(window=%p) repainting size=(%dx%d)dp", window(), geometry().size().width(), geometry().size().height());
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
}
}
-void QMirClientWindow::handleSurfaceFocused()
+void QMirClientWindow::handleSurfaceExposeChange(bool exposed)
{
- DLOG("[ubuntumirclient QPA] handleSurfaceFocused(window=%p)", window());
+ QMutexLocker lock(&mMutex);
+ qCDebug(mirclient, "handleSurfaceExposeChange(window=%p, exposed=%s)", window(), exposed ? "true" : "false");
+
+ mSurface->mNeedsExposeCatchup = false;
+ if (mWindowExposed == exposed) return;
+ mWindowExposed = exposed;
- // System clipboard contents might have changed while this window was unfocused and without
- // this process getting notified about it because it might have been suspended (due to
- // application lifecycle policies), thus unable to listen to any changes notified through
- // D-Bus.
- // Therefore let's ensure we are up to date with the system clipboard now that we are getting
- // focused again.
- mClipboard->requestDBusClipboardContents();
+ lock.unlock();
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
+}
+
+void QMirClientWindow::handleSurfaceFocusChanged(bool focused)
+{
+ qCDebug(mirclient, "handleSurfaceFocusChanged(window=%p, focused=%d)", window(), focused);
+ if (focused) {
+ mAppStateController->setWindowFocused(true);
+ QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason);
+ } else {
+ mAppStateController->setWindowFocused(false);
+ }
+}
+
+void QMirClientWindow::handleSurfaceVisibilityChanged(bool visible)
+{
+ qCDebug(mirclient, "handleSurfaceVisibilityChanged(window=%p, visible=%d)", window(), visible);
+
+ if (mWindowVisible == visible) return;
+ mWindowVisible = visible;
+
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
+}
+
+void QMirClientWindow::handleSurfaceStateChanged(Qt::WindowState state)
+{
+ qCDebug(mirclient, "handleSurfaceStateChanged(window=%p, %s)", window(), qtWindowStateToStr(state));
+
+ if (mWindowState == state) return;
+ mWindowState = state;
+
+ QWindowSystemInterface::handleWindowStateChanged(window(), state);
}
void QMirClientWindow::setWindowState(Qt::WindowState state)
{
QMutexLocker lock(&mMutex);
- DLOG("[ubuntumirclient QPA] setWindowState(window=%p, %s)", this, qtWindowStateToStr(state));
- mSurface->setState(state);
+ qCDebug(mirclient, "setWindowState(window=%p, %s)", this, qtWindowStateToStr(state));
+
+ if (mWindowState == state) return;
+ mWindowState = state;
+
+ lock.unlock();
+ updateSurfaceState();
+}
+
+void QMirClientWindow::setWindowFlags(Qt::WindowFlags flags)
+{
+ QMutexLocker lock(&mMutex);
+ qCDebug(mirclient, "setWindowFlags(window=%p, 0x%x)", this, (int)flags);
- updatePanelHeightHack(state);
+ if (mWindowFlags == flags) return;
+ mWindowFlags = flags;
+
+ mSurface->setShellChrome(mWindowFlags & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal);
}
-/*
- FIXME: Mir does not let clients know the position of their windows in the virtual
- desktop space. So we have this ugly hack that assumes a phone situation where the
- window is always on the top-left corner, right below the indicators panel if not
- in fullscreen.
- */
-void QMirClientWindow::updatePanelHeightHack(Qt::WindowState state)
+QRect QMirClientWindow::geometry() const
{
- if (state == Qt::WindowFullScreen && geometry().y() != 0) {
- QRect newGeometry = geometry();
- newGeometry.setY(0);
- QPlatformWindow::setGeometry(newGeometry);
- QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
- } else if (geometry().y() == 0) {
- QRect newGeometry = geometry();
- newGeometry.setY(panelHeight());
- QPlatformWindow::setGeometry(newGeometry);
- QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
+ if (mDebugExtention) {
+ auto geom = QPlatformWindow::geometry();
+ geom.moveTopLeft(mDebugExtention->mapSurfacePointToScreen(mSurface->mirSurface(), QPoint(0,0)));
+ return geom;
+ } else {
+ return QPlatformWindow::geometry();
}
}
void QMirClientWindow::setGeometry(const QRect& rect)
{
QMutexLocker lock(&mMutex);
- DLOG("[ubuntumirclient QPA] setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)",
- window(), rect.x(), rect.y(), rect.width(), rect.height());
- //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates
- const auto newSize = rect.size();
- auto newGeometry = geometry();
- newGeometry.setSize(newSize);
- QPlatformWindow::setGeometry(newGeometry);
+ if (window()->windowState() == Qt::WindowFullScreen || window()->windowState() == Qt::WindowMaximized) {
+ qCDebug(mirclient, "setGeometry(window=%p) - not resizing, window is maximized or fullscreen", window());
+ return;
+ }
+
+ qCDebug(mirclient, "setGeometry (window=%p, position=(%d, %d)dp, size=(%dx%d)dp)",
+ window(), rect.x(), rect.y(), rect.width(), rect.height());
+ // Immediately update internal geometry so Qt believes position updated
+ QRect newPosition(geometry());
+ newPosition.moveTo(rect.topLeft());
+ QPlatformWindow::setGeometry(newPosition);
- mSurface->resize(newSize);
+ mSurface->updateGeometry(rect);
+ // Note: don't call handleGeometryChange here, wait to see what Mir replies with.
}
void QMirClientWindow::setVisible(bool visible)
{
QMutexLocker lock(&mMutex);
- DLOG("[ubuntumirclient QPA] setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false");
-
- mSurface->setVisible(visible);
- const QRect& exposeRect = visible ? QRect(QPoint(), geometry().size()) : QRect();
+ qCDebug(mirclient, "setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false");
+
+ if (mWindowVisible == visible) return;
+ mWindowVisible = visible;
+
+ if (visible) {
+ if (!mSurface->hasParent() && window()->type() == Qt::Dialog) {
+ // The dialog may have been parented after creation time
+ // so morph it into a modal dialog
+ auto parent = transientParentFor(window());
+ if (parent) {
+ mSurface->setSurfaceParent(parent->mirSurface());
+ }
+ }
+ }
lock.unlock();
- QWindowSystemInterface::handleExposeEvent(window(), exposeRect);
- QWindowSystemInterface::flushWindowSystemEvents();
+ updateSurfaceState();
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
}
void QMirClientWindow::setWindowTitle(const QString& title)
{
QMutexLocker lock(&mMutex);
- DLOG("[ubuntumirclient QPA] setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());
+ qCDebug(mirclient, "setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());
mSurface->updateTitle(title);
}
@@ -636,13 +874,33 @@ void QMirClientWindow::propagateSizeHints()
{
QMutexLocker lock(&mMutex);
const auto win = window();
- DLOG("[ubuntumirclient QPA] propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)",
- win, win->minimumSize().width(), win->minimumSize().height(),
- win->maximumSize().width(), win->maximumSize().height(),
- win->sizeIncrement().width(), win->sizeIncrement().height());
+ qCDebug(mirclient, "propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)",
+ win, win->minimumSize().width(), win->minimumSize().height(),
+ win->maximumSize().width(), win->maximumSize().height(),
+ win->sizeIncrement().width(), win->sizeIncrement().height());
mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement());
}
+bool QMirClientWindow::isExposed() const
+{
+ // mNeedsExposeCatchup because we need to render a frame to get the expose surface event from mir.
+ return mWindowVisible && (mWindowExposed || (mSurface && mSurface->mNeedsExposeCatchup));
+}
+
+QSurfaceFormat QMirClientWindow::format() const
+{
+ return mSurface->format();
+}
+
+QPoint QMirClientWindow::mapToGlobal(const QPoint &pos) const
+{
+ if (mDebugExtention) {
+ return mDebugExtention->mapSurfacePointToScreen(mSurface->mirSurface(), pos);
+ } else {
+ return pos;
+ }
+}
+
void* QMirClientWindow::eglSurface() const
{
return mSurface->eglSurface();
@@ -662,4 +920,43 @@ void QMirClientWindow::onSwapBuffersDone()
{
QMutexLocker lock(&mMutex);
mSurface->onSwapBuffersDone();
+
+ if (mSurface->mNeedsExposeCatchup) {
+ mSurface->mNeedsExposeCatchup = false;
+ mWindowExposed = false;
+
+ lock.unlock();
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
+ }
+}
+
+void QMirClientWindow::handleScreenPropertiesChange(MirFormFactor formFactor, float scale)
+{
+ // Update the scale & form factor native-interface properties for the windows affected
+ // as there is no convenient way to emit signals for those custom properties on a QScreen
+ if (formFactor != mFormFactor) {
+ mFormFactor = formFactor;
+ Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("formFactor"));
+ }
+
+ if (!qFuzzyCompare(scale, mScale)) {
+ mScale = scale;
+ Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("scale"));
+ }
+}
+
+void QMirClientWindow::updateSurfaceState()
+{
+ QMutexLocker lock(&mMutex);
+ MirSurfaceState newState = mWindowVisible ? qtWindowStateToMirSurfaceState(mWindowState) :
+ mir_surface_state_hidden;
+ qCDebug(mirclient, "updateSurfaceState (window=%p, surfaceState=%s)", window(), mirSurfaceStateToStr(newState));
+ if (newState != mSurface->state()) {
+ mSurface->setState(newState);
+ }
+}
+
+QString QMirClientWindow::persistentSurfaceId()
+{
+ return mSurface->persistentSurfaceId();
}
diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.h b/src/plugins/platforms/mirclient/qmirclientwindow.h
index 025976c130..324e7691ff 100644
--- a/src/plugins/platforms/mirclient/qmirclientwindow.h
+++ b/src/plugins/platforms/mirclient/qmirclientwindow.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2014-2015 Canonical, Ltd.
+** Copyright (C) 2014-2016 Canonical, Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -45,44 +45,74 @@
#include <QSharedPointer>
#include <QMutex>
+#include <mir_toolkit/common.h> // needed only for MirFormFactor enum
+
#include <memory>
-class QMirClientClipboard;
+#include <EGL/egl.h>
+
+class QMirClientAppStateController;
+class QMirClientDebugExtension;
+class QMirClientNativeInterface;
class QMirClientInput;
class QMirClientScreen;
-class QMirClientSurface;
-struct MirConnection;
+class UbuntuSurface;
struct MirSurface;
+class MirConnection;
class QMirClientWindow : public QObject, public QPlatformWindow
{
Q_OBJECT
public:
- QMirClientWindow(QWindow *w, const QSharedPointer<QMirClientClipboard> &clipboard, QMirClientScreen *screen,
- QMirClientInput *input, MirConnection *mirConnection);
+ QMirClientWindow(QWindow *w, QMirClientInput *input, QMirClientNativeInterface* native,
+ QMirClientAppStateController *appState, EGLDisplay eglDisplay,
+ MirConnection *mirConnection, QMirClientDebugExtension *debugExt);
virtual ~QMirClientWindow();
// QPlatformWindow methods.
WId winId() const override;
+ QRect geometry() const override;
void setGeometry(const QRect&) override;
void setWindowState(Qt::WindowState state) override;
+ void setWindowFlags(Qt::WindowFlags flags) override;
void setVisible(bool visible) override;
void setWindowTitle(const QString &title) override;
void propagateSizeHints() override;
+ bool isExposed() const override;
+
+ QPoint mapToGlobal(const QPoint &pos) const override;
+ QSurfaceFormat format() const override;
+
+ // Additional Window properties exposed by NativeInterface
+ MirFormFactor formFactor() const { return mFormFactor; }
+ float scale() const { return mScale; }
// New methods.
void *eglSurface() const;
MirSurface *mirSurface() const;
void handleSurfaceResized(int width, int height);
- void handleSurfaceFocused();
+ void handleSurfaceExposeChange(bool exposed);
+ void handleSurfaceFocusChanged(bool focused);
+ void handleSurfaceVisibilityChanged(bool visible);
+ void handleSurfaceStateChanged(Qt::WindowState state);
void onSwapBuffersDone();
+ void handleScreenPropertiesChange(MirFormFactor formFactor, float scale);
+ QString persistentSurfaceId();
private:
- void updatePanelHeightHack(Qt::WindowState);
+ void updateSurfaceState();
mutable QMutex mMutex;
const WId mId;
- const QSharedPointer<QMirClientClipboard> mClipboard;
- std::unique_ptr<QMirClientSurface> mSurface;
+ Qt::WindowState mWindowState;
+ Qt::WindowFlags mWindowFlags;
+ bool mWindowVisible;
+ bool mWindowExposed;
+ QMirClientAppStateController *mAppStateController;
+ QMirClientDebugExtension *mDebugExtention;
+ QMirClientNativeInterface *mNativeInterface;
+ std::unique_ptr<UbuntuSurface> mSurface;
+ float mScale;
+ MirFormFactor mFormFactor;
};
#endif // QMIRCLIENTWINDOW_H
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
index 56e6075cb2..0c39950019 100644
--- a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -49,7 +49,7 @@
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
#endif
#elif defined(Q_OS_WIN)
-#include <QtFontDatabaseSupport/private/qbasicfontdatabase_p.h>
+#include <QtFontDatabaseSupport/private/qfreetypefontdatabase_p.h>
#ifndef Q_OS_WINRT
#include <QtCore/private/qeventdispatcher_win_p.h>
#else
@@ -103,7 +103,7 @@ QOffscreenIntegration::QOffscreenIntegration()
m_fontDatabase.reset(new QGenericUnixFontDatabase());
#endif
#elif defined(Q_OS_WIN)
- m_fontDatabase.reset(new QBasicFontDatabase());
+ m_fontDatabase.reset(new QFreeTypeFontDatabase());
#endif
#ifndef QT_NO_DRAGANDDROP
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
index 892168a1dc..81f262f9ed 100644
--- a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
@@ -157,10 +157,13 @@ QMargins QOffscreenWindow::frameMargins() const
void QOffscreenWindow::setFrameMarginsEnabled(bool enabled)
{
- if (enabled && !(window()->flags() & Qt::FramelessWindowHint))
+ if (enabled
+ && !(window()->flags() & Qt::FramelessWindowHint)
+ && (parent() == nullptr)) {
m_margins = QMargins(2, 2, 2, 2);
- else
+ } else {
m_margins = QMargins(0, 0, 0, 0);
+ }
}
void QOffscreenWindow::setWindowState(Qt::WindowState state)
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index 2a6e059243..9ccc2b54b9 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -36,7 +36,7 @@ qtConfig(directfb) {
qtConfig(linuxfb): SUBDIRS += linuxfb
-unix:!android:!darwin: SUBDIRS += vnc
+qtConfig(vnc): SUBDIRS += vnc
freebsd {
SUBDIRS += bsdfb
diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro
index 9da3d6811b..0b052adf0f 100644
--- a/src/plugins/platforms/qnx/qnx.pro
+++ b/src/plugins/platforms/qnx/qnx.pro
@@ -7,8 +7,6 @@ QT += \
# Uncomment this to build with support for IMF once it becomes available in the BBNDK
#CONFIG += qqnx_imf
-CONFIG += qqnx_screeneventthread
-
# Uncomment these to enable debugging output for various aspects of the plugin
#DEFINES += QQNXBUFFER_DEBUG
#DEFINES += QQNXBUTTON_DEBUG
@@ -47,7 +45,8 @@ SOURCES = main.cpp \
qqnxservices.cpp \
qqnxcursor.cpp \
qqnxrasterwindow.cpp \
- qqnxglobal.cpp
+ qqnxglobal.cpp \
+ qqnxscreeneventthread.cpp
HEADERS = main.h \
qqnxbuffer.h \
@@ -67,13 +66,8 @@ HEADERS = main.h \
qqnxrasterwindow.h \
qqnxscreeneventfilter.h \
qqnxglobal.h \
- qqnxlgmon.h
-
-CONFIG(qqnx_screeneventthread) {
- DEFINES += QQNX_SCREENEVENTTHREAD
- SOURCES += qqnxscreeneventthread.cpp
- HEADERS += qqnxscreeneventthread.h
-}
+ qqnxlgmon.h \
+ qqnxscreeneventthread.h
LIBS += -lscreen
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index 7229d7d2a8..eee0581709 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -40,9 +40,7 @@
#include "qqnxglobal.h"
#include "qqnxintegration.h"
-#if defined(QQNX_SCREENEVENTTHREAD)
#include "qqnxscreeneventthread.h"
-#endif
#include "qqnxnativeinterface.h"
#include "qqnxrasterbackingstore.h"
#include "qqnxscreen.h"
@@ -125,9 +123,7 @@ static inline QQnxIntegration::Options parseOptions(const QStringList &paramList
QQnxIntegration::QQnxIntegration(const QStringList &paramList)
: QPlatformIntegration()
-#if defined(QQNX_SCREENEVENTTHREAD)
, m_screenEventThread(0)
-#endif
, m_navigatorEventHandler(new QQnxNavigatorEventHandler())
, m_virtualKeyboard(0)
#if defined(QQNX_PPS)
@@ -169,10 +165,8 @@ QQnxIntegration::QQnxIntegration(const QStringList &paramList)
#endif
// Create/start event thread
-#if defined(QQNX_SCREENEVENTTHREAD)
m_screenEventThread = new QQnxScreenEventThread(ms_screenContext, m_screenEventHandler);
m_screenEventThread->start();
-#endif
#if defined(QQNX_PPS)
// Create/start the keyboard class.
@@ -235,10 +229,8 @@ QQnxIntegration::~QQnxIntegration()
#endif
delete m_navigatorEventHandler;
-#if defined(QQNX_SCREENEVENTTHREAD)
// Stop/destroy screen event thread
delete m_screenEventThread;
-#endif
// In case the event-dispatcher was never transferred to QCoreApplication
delete m_eventDispatcher;
diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h
index 6f2af82100..b2008baa0c 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.h
+++ b/src/plugins/platforms/qnx/qqnxintegration.h
@@ -48,9 +48,7 @@
QT_BEGIN_NAMESPACE
-#if defined(QQNX_SCREENEVENTTHREAD)
class QQnxScreenEventThread;
-#endif
class QQnxFileDialogHelper;
class QQnxNativeInterface;
class QQnxWindow;
@@ -142,9 +140,7 @@ private:
static void removeWindow(screen_window_t qnxWindow);
static screen_context_t ms_screenContext;
-#if defined(QQNX_SCREENEVENTTHREAD)
QQnxScreenEventThread *m_screenEventThread;
-#endif
QQnxNavigatorEventHandler *m_navigatorEventHandler;
QQnxAbstractVirtualKeyboard *m_virtualKeyboard;
#if defined(QQNX_PPS)
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
index beda6e1a49..5d230e2145 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
@@ -40,9 +40,7 @@
#include "qqnxglobal.h"
#include "qqnxscreeneventhandler.h"
-#if defined(QQNX_SCREENEVENTTHREAD)
#include "qqnxscreeneventthread.h"
-#endif
#include "qqnxintegration.h"
#include "qqnxkeytranslator.h"
#include "qqnxscreen.h"
@@ -67,9 +65,7 @@ QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration)
, m_lastButtonState(Qt::NoButton)
, m_lastMouseWindow(0)
, m_touchDevice(0)
-#if defined(QQNX_SCREENEVENTTHREAD)
, m_eventThread(0)
-#endif
, m_focusLostTimer(-1)
{
// Create a touch device
@@ -198,7 +194,6 @@ void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifie
}
}
-#if defined(QQNX_SCREENEVENTTHREAD)
void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventThread)
{
m_eventThread = eventThread;
@@ -233,7 +228,6 @@ void QQnxScreenEventHandler::processEventsFromScreenThread()
m_eventThread->unlock();
}
-#endif
void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event)
{
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
index 80798a8a2d..d872f9b9aa 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
@@ -48,9 +48,7 @@ QT_BEGIN_NAMESPACE
class QQnxIntegration;
class QQnxScreenEventFilter;
-#if defined(QQNX_SCREENEVENTTHREAD)
class QQnxScreenEventThread;
-#endif
class QQnxScreenEventHandler : public QObject
{
@@ -66,9 +64,7 @@ public:
static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
-#if defined(QQNX_SCREENEVENTTHREAD)
void setScreenEventThread(QQnxScreenEventThread *eventThread);
-#endif
Q_SIGNALS:
void newWindowCreated(void *window);
@@ -77,10 +73,8 @@ Q_SIGNALS:
protected:
void timerEvent(QTimerEvent *event) override;
-#if defined(QQNX_SCREENEVENTTHREAD)
private Q_SLOTS:
void processEventsFromScreenThread();
-#endif
private:
void handleKeyboardEvent(screen_event_t event);
@@ -105,9 +99,7 @@ private:
QTouchDevice *m_touchDevice;
QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints];
QList<QQnxScreenEventFilter*> m_eventFilters;
-#if defined(QQNX_SCREENEVENTTHREAD)
QQnxScreenEventThread *m_eventThread;
-#endif
int m_focusLostTimer;
};
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index 6fd0191e43..30288ccb20 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -694,7 +694,7 @@ void QQnxWindow::initWindow()
void QQnxWindow::createWindowGroup()
{
// Generate a random window group name
- m_windowGroupName = QUuid::createUuid().toString().toLatin1();
+ m_windowGroupName = QUuid::createUuid().toByteArray();
// Create window group so child windows can be parented by container window
Q_SCREEN_CHECKERROR(screen_create_window_group(m_window, m_windowGroupName.constData()),
diff --git a/src/plugins/platforms/vnc/main.cpp b/src/plugins/platforms/vnc/main.cpp
index 6ee8bf1ec6..3ec0f0b78d 100644
--- a/src/plugins/platforms/vnc/main.cpp
+++ b/src/plugins/platforms/vnc/main.cpp
@@ -48,7 +48,7 @@ class QVncIntegrationPlugin : public QPlatformIntegrationPlugin
Q_OBJECT
Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "vnc.json")
public:
- QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE;
+ QPlatformIntegration *create(const QString&, const QStringList&) override;
};
QPlatformIntegration* QVncIntegrationPlugin::create(const QString& system, const QStringList& paramList)
diff --git a/src/plugins/platforms/vnc/qvnc.cpp b/src/plugins/platforms/vnc/qvnc.cpp
index a45bb1c19c..fa65e8c9a4 100644
--- a/src/plugins/platforms/vnc/qvnc.cpp
+++ b/src/plugins/platforms/vnc/qvnc.cpp
@@ -531,13 +531,12 @@ void QRfbRawEncoder::write()
socket->flush();
}
+#if QT_CONFIG(cursor)
QVncClientCursor::QVncClientCursor()
{
-#ifndef QT_NO_CURSOR
QWindow *w = QGuiApplication::focusWindow();
QCursor c = w ? w->cursor() : QCursor(Qt::ArrowCursor);
changeCursor(&c, 0);
-#endif
}
QVncClientCursor::~QVncClientCursor()
@@ -587,7 +586,6 @@ void QVncClientCursor::write(QVncClient *client) const
void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window)
{
Q_UNUSED(window);
-#ifndef QT_NO_CURSOR
const Qt::CursorShape shape = widgetCursor ? widgetCursor->shape() : Qt::ArrowCursor;
if (shape == Qt::BitmapCursor) {
@@ -601,9 +599,6 @@ void QVncClientCursor::changeCursor(QCursor *widgetCursor, QWindow *window)
cursor = *platformImage.image();
hotspot = platformImage.hotspot();
}
-#else // !QT_NO_CURSOR
- Q_UNUSED(widgetCursor);
-#endif
for (auto client : clients)
client->setDirtyCursor();
}
@@ -619,6 +614,7 @@ uint QVncClientCursor::removeClient(QVncClient *client)
clients.removeOne(client);
return clients.count();
}
+#endif // QT_CONFIG(cursor)
QVncServer::QVncServer(QVncScreen *screen, quint16 port)
: qvnc_screen(screen)
diff --git a/src/plugins/platforms/vnc/qvnc_p.h b/src/plugins/platforms/vnc/qvnc_p.h
index 1c44cd1569..338fae9f87 100644
--- a/src/plugins/platforms/vnc/qvnc_p.h
+++ b/src/plugins/platforms/vnc/qvnc_p.h
@@ -95,7 +95,7 @@ public:
QVncDirtyMapOptimized(QVncScreen *screen) : QVncDirtyMap(screen) {}
~QVncDirtyMapOptimized() {}
- void setDirty(int x, int y, bool force = false);
+ void setDirty(int x, int y, bool force = false) override;
};
@@ -216,7 +216,7 @@ class QRfbRawEncoder : public QRfbEncoder
public:
QRfbRawEncoder(QVncClient *s) : QRfbEncoder(s) {}
- void write();
+ void write() override;
private:
QByteArray buffer;
@@ -364,6 +364,7 @@ private:
friend class QRfbMultiColorHextile<SRC>;
};
+#if QT_CONFIG(cursor)
class QVncClientCursor : public QPlatformCursor
{
public:
@@ -372,7 +373,7 @@ public:
void write(QVncClient *client) const;
- void changeCursor(QCursor *widgetCursor, QWindow *window);
+ void changeCursor(QCursor *widgetCursor, QWindow *window) override;
void addClient(QVncClient *client);
uint removeClient(QVncClient *client);
@@ -381,7 +382,7 @@ public:
QPoint hotspot;
QVector<QVncClient *> clients;
};
-
+#endif // QT_CONFIG(cursor)
class QVncServer : public QObject
{
diff --git a/src/plugins/platforms/vnc/qvncclient.cpp b/src/plugins/platforms/vnc/qvncclient.cpp
index 58dcfc9b51..9dfe873927 100644
--- a/src/plugins/platforms/vnc/qvncclient.cpp
+++ b/src/plugins/platforms/vnc/qvncclient.cpp
@@ -425,14 +425,14 @@ void QVncClient::checkUpdate()
{
if (!m_wantUpdate)
return;
-
+#if QT_CONFIG(cursor)
if (m_dirtyCursor) {
m_server->screen()->clientCursor->write(this);
m_dirtyCursor = false;
m_wantUpdate = false;
return;
}
-
+#endif
if (!m_dirtyRegion.isEmpty()) {
if (m_encoder)
m_encoder->write();
diff --git a/src/plugins/platforms/vnc/qvncintegration.cpp b/src/plugins/platforms/vnc/qvncintegration.cpp
index 025112c790..8516e994f5 100644
--- a/src/plugins/platforms/vnc/qvncintegration.cpp
+++ b/src/plugins/platforms/vnc/qvncintegration.cpp
@@ -1,34 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
-** This file is part of the FOO module of the Qt Toolkit.
+** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL3$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/vnc/qvncintegration.h b/src/plugins/platforms/vnc/qvncintegration.h
index 293ff54376..34a6a6b941 100644
--- a/src/plugins/platforms/vnc/qvncintegration.h
+++ b/src/plugins/platforms/vnc/qvncintegration.h
@@ -55,19 +55,19 @@ public:
QVncIntegration(const QStringList &paramList);
~QVncIntegration();
- void initialize() Q_DECL_OVERRIDE;
- bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
+ void initialize() override;
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
- QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE;
- QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
- QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE;
+ QAbstractEventDispatcher *createEventDispatcher() const override;
- QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE;
- QPlatformServices *services() const Q_DECL_OVERRIDE;
- QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE { return m_inputContext; }
+ QPlatformFontDatabase *fontDatabase() const override;
+ QPlatformServices *services() const override;
+ QPlatformInputContext *inputContext() const override { return m_inputContext; }
- QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE;
+ QPlatformNativeInterface *nativeInterface() const override;
QList<QPlatformScreen *> screens() const;
diff --git a/src/plugins/platforms/vnc/qvncscreen.cpp b/src/plugins/platforms/vnc/qvncscreen.cpp
index 64f1bc0bf7..cd43ce4e69 100644
--- a/src/plugins/platforms/vnc/qvncscreen.cpp
+++ b/src/plugins/platforms/vnc/qvncscreen.cpp
@@ -58,8 +58,10 @@ QVncScreen::QVncScreen(const QStringList &args)
QVncScreen::~QVncScreen()
{
+#if QT_CONFIG(cursor)
if (clientCursor)
delete clientCursor;
+#endif
}
bool QVncScreen::initialize()
@@ -120,17 +122,21 @@ QRegion QVncScreen::doRedraw()
return touched;
}
+
void QVncScreen::enableClientCursor(QVncClient *client)
{
+#if QT_CONFIG(cursor)
delete mCursor;
mCursor = nullptr;
if (!clientCursor)
clientCursor = new QVncClientCursor();
clientCursor->addClient(client);
+#endif
}
void QVncScreen::disableClientCursor(QVncClient *client)
{
+#if QT_CONFIG(cursor)
uint clientCount = clientCursor->removeClient(client);
if (clientCount == 0) {
delete clientCursor;
@@ -138,11 +144,16 @@ void QVncScreen::disableClientCursor(QVncClient *client)
}
mCursor = new QFbCursor(this);
+#endif
}
QPlatformCursor *QVncScreen::cursor() const
{
+#if QT_CONFIG(cursor)
return mCursor ? static_cast<QPlatformCursor *>(mCursor) : static_cast<QPlatformCursor *>(clientCursor);
+#else
+ return nullptr;
+#endif
}
// grabWindow() grabs "from the screen" not from the backingstores.
@@ -151,10 +162,10 @@ QPixmap QVncScreen::grabWindow(WId wid, int x, int y, int width, int height) con
{
if (!wid) {
if (width < 0)
- width = mScreenImage->width() - x;
+ width = mScreenImage.width() - x;
if (height < 0)
- height = mScreenImage->height() - y;
- return QPixmap::fromImage(*mScreenImage).copy(x, y, width, height);
+ height = mScreenImage.height() - y;
+ return QPixmap::fromImage(mScreenImage).copy(x, y, width, height);
}
QFbWindow *window = windowForId(wid);
@@ -166,7 +177,7 @@ QPixmap QVncScreen::grabWindow(WId wid, int x, int y, int width, int height) con
height = geom.height() - y;
QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height));
rect &= window->geometry();
- return QPixmap::fromImage(*mScreenImage).copy(rect);
+ return QPixmap::fromImage(mScreenImage).copy(rect);
}
return QPixmap();
@@ -188,5 +199,10 @@ bool QVncScreen::swapBytes() const
}
#endif
+QFbScreen::Flags QVncScreen::flags() const
+{
+ return QFbScreen::DontForceFirstWindowToFullScreen;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/vnc/qvncscreen.h b/src/plugins/platforms/vnc/qvncscreen.h
index 0b42c3c7ea..e69aa90d41 100644
--- a/src/plugins/platforms/vnc/qvncscreen.h
+++ b/src/plugins/platforms/vnc/qvncscreen.h
@@ -59,16 +59,18 @@ public:
QVncScreen(const QStringList &args);
~QVncScreen();
- bool initialize();
+ bool initialize() override;
- QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE;
+ QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override;
- QRegion doRedraw() Q_DECL_OVERRIDE;
- QImage *image() const { return mScreenImage; }
+ QRegion doRedraw() override;
+ QImage *image() { return &mScreenImage; }
void enableClientCursor(QVncClient *client);
void disableClientCursor(QVncClient *client);
- QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
+ QPlatformCursor *cursor() const override;
+
+ Flags flags() const override;
void clearDirty() { dirtyRegion = QRegion(); }
@@ -84,7 +86,9 @@ public:
QRegion dirtyRegion;
int refreshRate = 30;
QVncServer *vncServer = 0;
+#if QT_CONFIG(cursor)
QVncClientCursor *clientCursor = 0;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
index e035e3924a..8621e93120 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
@@ -53,7 +53,7 @@ class QWindowsAccessibility : public QPlatformAccessibility
public:
QWindowsAccessibility();
static bool handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
- void notifyAccessibilityUpdate(QAccessibleEvent *event) Q_DECL_OVERRIDE;
+ void notifyAccessibilityUpdate(QAccessibleEvent *event) override;
static IAccessible *wrap(QAccessibleInterface *acc);
static QWindow *windowHelper(const QAccessibleInterface *iface);
};
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
index 85aab84c2c..25b1577772 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
@@ -1052,11 +1052,24 @@ HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BS
return S_FALSE;
}
-HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accValue(VARIANT, BSTR)
+HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accValue(VARIANT, BSTR value)
{
QAccessibleInterface *accessible = accessibleInterface();
accessibleDebugClientCalls(accessible);
- return DISP_E_MEMBERNOTFOUND;
+
+ if (!accessible || !accessible->isValid()) {
+ return E_FAIL;
+ }
+
+ QString qstrValue = QString::fromWCharArray(value);
+
+ if (accessible->valueInterface()) {
+ accessible->valueInterface()->setCurrentValue(qstrValue);
+ } else {
+ accessible->setText(QAccessible::Value, qstrValue);
+ }
+
+ return S_OK;
}
// moz: [important]
diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json
index dd99e674ec..69f4a54d05 100644
--- a/src/plugins/platforms/windows/openglblacklists/default.json
+++ b/src/plugins/platforms/windows/openglblacklists/default.json
@@ -114,6 +114,18 @@
"features": [
"disable_desktopgl"
]
- }
+ },
+ {
+ "id": 10,
+ "description": "Intel(R) HD Graphics IronLake (Arrandale) crashes on makeCurrent QTBUG-53888",
+ "vendor_id": "0x8086",
+ "device_id": [ "0x0046" ],
+ "os": {
+ "type": "win"
+ },
+ "features": [
+ "disable_desktopgl"
+ ]
+ }
]
}
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index ec6a8f62ae..e703b5d47e 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -56,6 +56,10 @@
# define WM_GESTURE 0x0119
#endif
+#ifndef WM_DPICHANGED
+# define WM_DPICHANGED 0x02E0
+#endif
+
QT_BEGIN_NAMESPACE
namespace QtWindows
@@ -96,12 +100,14 @@ enum WindowsEventType // Simplify event types
FocusInEvent = WindowEventFlag + 17,
FocusOutEvent = WindowEventFlag + 18,
WhatsThisEvent = WindowEventFlag + 19,
+ DpiChangedEvent = WindowEventFlag + 21,
MouseEvent = MouseEventFlag + 1,
MouseWheelEvent = MouseEventFlag + 2,
CursorEvent = MouseEventFlag + 3,
TouchEvent = TouchEventFlag + 1,
NonClientMouseEvent = NonClientEventFlag + MouseEventFlag + 1,
NonClientHitTest = NonClientEventFlag + 2,
+ NonClientCreate = NonClientEventFlag + 3,
KeyEvent = KeyEventFlag + 1,
KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1,
KeyboardLayoutChangeEvent = KeyEventFlag + 2,
@@ -114,6 +120,7 @@ enum WindowsEventType // Simplify event types
QueryEndSessionApplicationEvent = ApplicationEventFlag + 4,
EndSessionApplicationEvent = ApplicationEventFlag + 5,
AppCommandEvent = ApplicationEventFlag + 6,
+ DeviceChangeEvent = ApplicationEventFlag + 7,
InputMethodStartCompositionEvent = InputMethodEventFlag + 1,
InputMethodCompositionEvent = InputMethodEventFlag + 2,
InputMethodEndCompositionEvent = InputMethodEventFlag + 3,
@@ -177,6 +184,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
return QtWindows::HideEvent;
case WM_SIZE:
return QtWindows::ResizeEvent;
+ case WM_NCCREATE:
+ return QtWindows::NonClientCreate;
case WM_NCCALCSIZE:
return QtWindows::CalculateSize;
case WM_NCHITTEST:
@@ -263,6 +272,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
#endif
case WM_GESTURE:
return QtWindows::GestureEvent;
+ case WM_DEVICECHANGE:
+ return QtWindows::DeviceChangeEvent;
+ case WM_DPICHANGED:
+ return QtWindows::DpiChangedEvent;
default:
break;
}
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h
index 46a7fcc676..9e62266697 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.h
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.h
@@ -57,15 +57,15 @@ public:
QWindowsBackingStore(QWindow *window);
~QWindowsBackingStore();
- QPaintDevice *paintDevice() Q_DECL_OVERRIDE;
- void flush(QWindow *window, const QRegion &region, const QPoint &offset) Q_DECL_OVERRIDE;
- void resize(const QSize &size, const QRegion &r) Q_DECL_OVERRIDE;
- bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE;
- void beginPaint(const QRegion &) Q_DECL_OVERRIDE;
+ QPaintDevice *paintDevice() override;
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
+ void resize(const QSize &size, const QRegion &r) override;
+ bool scroll(const QRegion &area, int dx, int dy) override;
+ void beginPaint(const QRegion &) override;
HDC getDC() const;
- QImage toImage() const Q_DECL_OVERRIDE;
+ QImage toImage() const override;
private:
QScopedPointer<QWindowsNativeImage> m_image;
diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp
index d4a7e27762..01191a7dc1 100644
--- a/src/plugins/platforms/windows/qwindowsclipboard.cpp
+++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp
@@ -81,7 +81,7 @@ static QDebug operator<<(QDebug d, const QMimeData *mimeData)
d << "QMimeData(";
if (mimeData) {
const QStringList formats = mimeData->formats();
- d << "formats=" << formats.join(QStringLiteral(", "));
+ d << "formats=" << formats.join(QLatin1String(", "));
if (mimeData->hasText())
d << ", text=" << mimeData->text();
if (mimeData->hasHtml())
@@ -149,8 +149,7 @@ static void cleanClipboardPostRoutine()
QWindowsClipboard *QWindowsClipboard::m_instance = 0;
-QWindowsClipboard::QWindowsClipboard() :
- m_data(0), m_clipboardViewer(0), m_nextClipboardViewer(0), m_formatListenerRegistered(false)
+QWindowsClipboard::QWindowsClipboard()
{
QWindowsClipboard::m_instance = this;
qAddPostRoutine(cleanClipboardPostRoutine);
@@ -322,7 +321,7 @@ void QWindowsClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
const HRESULT src = OleSetClipboard(m_data);
if (src != S_OK) {
QString mimeDataFormats = mimeData ?
- mimeData->formats().join(QStringLiteral(", ")) : QString(QStringLiteral("NULL"));
+ mimeData->formats().join(QLatin1String(", ")) : QString(QStringLiteral("NULL"));
qErrnoWarning("OleSetClipboard: Failed to set mime data (%s) on clipboard: %s",
qPrintable(mimeDataFormats),
QWindowsContext::comErrorString(src).constData());
diff --git a/src/plugins/platforms/windows/qwindowsclipboard.h b/src/plugins/platforms/windows/qwindowsclipboard.h
index 992d34d492..4f3e7437f6 100644
--- a/src/plugins/platforms/windows/qwindowsclipboard.h
+++ b/src/plugins/platforms/windows/qwindowsclipboard.h
@@ -52,8 +52,8 @@ class QWindowsClipboardRetrievalMimeData : public QWindowsInternalMimeData {
public:
protected:
- IDataObject *retrieveDataObject() const Q_DECL_OVERRIDE;
- void releaseDataObject(IDataObject *) const Q_DECL_OVERRIDE;
+ IDataObject *retrieveDataObject() const override;
+ void releaseDataObject(IDataObject *) const override;
};
class QWindowsClipboard : public QPlatformClipboard
@@ -64,10 +64,10 @@ public:
void registerViewer(); // Call in initialization, when context is up.
void cleanup();
- QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE;
- void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE;
- bool supportsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE;
- bool ownsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE;
+ QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override;
+ void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) override;
+ bool supportsMode(QClipboard::Mode mode) const override;
+ bool ownsMode(QClipboard::Mode mode) const override;
inline bool clipboardViewerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *result);
@@ -85,10 +85,10 @@ private:
static QWindowsClipboard *m_instance;
QWindowsClipboardRetrievalMimeData m_retrievalData;
- QWindowsOleDataObject *m_data;
- HWND m_clipboardViewer;
- HWND m_nextClipboardViewer;
- bool m_formatListenerRegistered;
+ QWindowsOleDataObject *m_data = nullptr;
+ HWND m_clipboardViewer = 0;
+ HWND m_nextClipboardViewer = 0;
+ bool m_formatListenerRegistered = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index bb9ed730a3..ff4ab1accb 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -68,6 +68,7 @@
#include <QtCore/QHash>
#include <QtCore/QStringList>
#include <QtCore/QDebug>
+#include <QtCore/QOperatingSystemVersion>
#include <QtCore/QSysInfo>
#include <QtCore/QScopedArrayPointer>
#include <QtCore/private/qsystemlibrary_p.h>
@@ -78,6 +79,7 @@
#include <stdio.h>
#include <windowsx.h>
#include <comdef.h>
+#include <dbt.h>
QT_BEGIN_NAMESPACE
@@ -127,6 +129,28 @@ static inline QWindowsSessionManager *platformSessionManager() {
}
#endif
+static inline int windowDpiAwareness(HWND hwnd)
+{
+ return QWindowsContext::user32dll.getWindowDpiAwarenessContext && QWindowsContext::user32dll.getWindowDpiAwarenessContext
+ ? QWindowsContext::user32dll.getAwarenessFromDpiAwarenessContext(QWindowsContext::user32dll.getWindowDpiAwarenessContext(hwnd))
+ : -1;
+}
+
+// Note: This only works within WM_NCCREATE
+static bool enableNonClientDpiScaling(HWND hwnd)
+{
+ bool result = false;
+ if (QWindowsContext::user32dll.enableNonClientDpiScaling && windowDpiAwareness(hwnd) == 2) {
+ result = QWindowsContext::user32dll.enableNonClientDpiScaling(hwnd) != FALSE;
+ if (!result) {
+ const DWORD errorCode = GetLastError();
+ qErrnoWarning(int(errorCode), "EnableNonClientDpiScaling() failed for HWND %p (%lu)",
+ hwnd, errorCode);
+ }
+ }
+ return result;
+}
+
/*!
\class QWindowsUser32DLL
\brief Struct that contains dynamically resolved symbols of User32.dll.
@@ -142,14 +166,6 @@ static inline QWindowsSessionManager *platformSessionManager() {
\internal
\ingroup qt-lighthouse-win
*/
-QWindowsUser32DLL::QWindowsUser32DLL() :
- isTouchWindow(0),
- registerTouchWindow(0), unregisterTouchWindow(0),
- getTouchInputInfo(0), closeTouchInputHandle(0), setProcessDPIAware(0),
- addClipboardFormatListener(0), removeClipboardFormatListener(0),
- getDisplayAutoRotationPreferences(0), setDisplayAutoRotationPreferences(0)
-{
-}
void QWindowsUser32DLL::init()
{
@@ -161,6 +177,12 @@ void QWindowsUser32DLL::init()
getDisplayAutoRotationPreferences = (GetDisplayAutoRotationPreferences)library.resolve("GetDisplayAutoRotationPreferences");
setDisplayAutoRotationPreferences = (SetDisplayAutoRotationPreferences)library.resolve("SetDisplayAutoRotationPreferences");
+
+ if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS10) { // Appears in 10.0.14393, October 2016
+ enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling");
+ getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext");
+ getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext");
+ }
}
bool QWindowsUser32DLL::initTouch()
@@ -176,16 +198,9 @@ bool QWindowsUser32DLL::initTouch()
return isTouchWindow && registerTouchWindow && unregisterTouchWindow && getTouchInputInfo && closeTouchInputHandle;
}
-QWindowsShcoreDLL::QWindowsShcoreDLL()
- : getProcessDpiAwareness(0)
- , setProcessDpiAwareness(0)
- , getDpiForMonitor(0)
-{
-}
-
void QWindowsShcoreDLL::init()
{
- if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8_1)
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1)
return;
QSystemLibrary library(QStringLiteral("SHCore"));
getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness");
@@ -211,14 +226,13 @@ QWindowsContext *QWindowsContext::m_instance = 0;
typedef QHash<HWND, QWindowsWindow *> HandleBaseWindowHash;
struct QWindowsContextPrivate {
-
QWindowsContextPrivate();
- unsigned m_systemInfo;
+ unsigned m_systemInfo = 0;
QSet<QString> m_registeredWindowClassNames;
HandleBaseWindowHash m_windows;
- HDC m_displayContext;
- int m_defaultDPI;
+ HDC m_displayContext = 0;
+ int m_defaultDPI = 96;
QWindowsKeyMapper m_keyMapper;
QWindowsMouseHandler m_mouseHandler;
QWindowsMimeConverter m_mimeConverter;
@@ -229,15 +243,13 @@ struct QWindowsContextPrivate {
#endif
const HRESULT m_oleInitializeResult;
const QByteArray m_eventType;
- QWindow *m_lastActiveWindow;
- bool m_asyncExpose;
+ QWindow *m_lastActiveWindow = nullptr;
+ bool m_asyncExpose = false;
};
QWindowsContextPrivate::QWindowsContextPrivate()
- : m_systemInfo(0)
- , m_oleInitializeResult(OleInitialize(NULL))
+ : m_oleInitializeResult(OleInitialize(NULL))
, m_eventType(QByteArrayLiteral("windows_generic_MSG"))
- , m_lastActiveWindow(0), m_asyncExpose(0)
{
QWindowsContext::user32dll.init();
QWindowsContext::shcoredll.init();
@@ -311,6 +323,13 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
QWindowSystemInterface::registerTouchDevice(touchDevice);
d->m_systemInfo |= QWindowsContext::SI_SupportsTouch;
+
+ // A touch device was plugged while the app is running. Register all windows for touch.
+ if (QGuiApplicationPrivate::is_app_running) {
+ for (QWindowsWindow *w : qAsConst(d->m_windows))
+ w->registerTouchWindow();
+ }
+
return true;
}
@@ -379,6 +398,11 @@ void QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreat
d->m_creationContext = ctx;
}
+QSharedPointer<QWindowCreationContext> QWindowsContext::windowCreationContext() const
+{
+ return d->m_creationContext;
+}
+
int QWindowsContext::defaultDPI() const
{
return d->m_defaultDPI;
@@ -807,7 +831,9 @@ static inline QWindowsInputContext *windowsInputContext()
bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
QtWindows::WindowsEventType et,
- WPARAM wParam, LPARAM lParam, LRESULT *result)
+ WPARAM wParam, LPARAM lParam,
+ LRESULT *result,
+ QWindowsWindow **platformWindowPtr)
{
*result = 0;
@@ -838,6 +864,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
}
QWindowsWindow *platformWindow = findPlatformWindow(hwnd);
+ *platformWindowPtr = platformWindow;
if (platformWindow) {
filterResult = 0;
if (QWindowSystemInterface::handleNativeEvent(platformWindow->window(), d->m_eventType, &msg, &filterResult)) {
@@ -919,6 +946,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::MoveEvent:
d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return true;
+ case QtWindows::NonClientCreate:
+ if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS10 && d->m_creationContext->window->isTopLevel())
+ enableNonClientDpiScaling(msg.hwnd);
+ return false;
case QtWindows::CalculateSize:
return QWindowsGeometryHint::handleCalculateSize(d->m_creationContext->customMargins, msg, result);
case QtWindows::GeometryChangingEvent:
@@ -942,6 +973,13 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
}
switch (et) {
+ case QtWindows::DeviceChangeEvent:
+ if (d->m_systemInfo & QWindowsContext::SI_SupportsTouch)
+ break;
+ // See if there are any touch devices added
+ if (wParam == DBT_DEVNODES_CHANGED)
+ initTouch();
+ break;
case QtWindows::KeyboardLayoutChangeEvent:
if (QWindowsInputContext *wic = windowsInputContext())
wic->handleInputLanguageChanged(wParam, lParam);
@@ -1026,9 +1064,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return true;
case QtWindows::ThemeChanged: {
// Switch from Aero to Classic changes margins.
- const Qt::WindowFlags flags = platformWindow->window()->flags();
- if ((flags & Qt::WindowType_Mask) != Qt::Desktop && !(flags & Qt::FramelessWindowHint))
- platformWindow->setFlag(QWindowsWindow::FrameDirty);
if (QWindowsTheme *theme = QWindowsTheme::instance())
theme->windowsThemeChanged(platformWindow->window());
return true;
@@ -1068,6 +1103,18 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return true;
#endif
} break;
+ case QtWindows::DpiChangedEvent: {
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_DLGFRAME)
+ return false; // Fixed-size window should not be resized
+
+ platformWindow->setFlag(QWindowsWindow::WithinDpiChanged);
+ const RECT *prcNewWindow = reinterpret_cast<RECT *>(lParam);
+ SetWindowPos(hwnd, NULL, prcNewWindow->left, prcNewWindow->top,
+ prcNewWindow->right - prcNewWindow->left,
+ prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE);
+ platformWindow->clearFlag(QWindowsWindow::WithinDpiChanged);
+ return true;
+ }
#if !defined(QT_NO_SESSIONMANAGER)
case QtWindows::QueryEndSessionApplicationEvent: {
QWindowsSessionManager *sessionManager = platformSessionManager();
@@ -1201,6 +1248,37 @@ QTouchDevice *QWindowsContext::touchDevice() const
return d->m_mouseHandler.touchDevice();
}
+static inline bool isEmptyRect(const RECT &rect)
+{
+ return rect.right - rect.left == 0 && rect.bottom - rect.top == 0;
+}
+
+static inline QMargins marginsFromRects(const RECT &frame, const RECT &client)
+{
+ return QMargins(client.left - frame.left, client.top - frame.top,
+ frame.right - client.right, frame.bottom - client.bottom);
+}
+
+static RECT rectFromNcCalcSize(UINT message, WPARAM wParam, LPARAM lParam, int n)
+{
+ RECT result = {0, 0, 0, 0};
+ if (message == WM_NCCALCSIZE && wParam)
+ result = reinterpret_cast<const NCCALCSIZE_PARAMS *>(lParam)->rgrc[n];
+ return result;
+}
+
+static inline bool isMinimized(HWND hwnd)
+{
+ WINDOWPLACEMENT windowPlacement;
+ windowPlacement.length = sizeof(WINDOWPLACEMENT);
+ return GetWindowPlacement(hwnd, &windowPlacement) && windowPlacement.showCmd == SW_SHOWMINIMIZED;
+}
+
+static inline bool isTopLevel(HWND hwnd)
+{
+ return (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CHILD) == 0;
+}
+
/*!
\brief Windows functions for actual windows.
@@ -1214,7 +1292,9 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR
{
LRESULT result;
const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam);
- const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result);
+ QWindowsWindow *platformWindow = nullptr;
+ const RECT ncCalcSizeFrame = rectFromNcCalcSize(message, wParam, lParam, 0);
+ const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result, &platformWindow);
if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) {
if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) {
qCDebug(lcQpaEvents) << "EVENT: hwd=" << hwnd << eventName << hex << "msg=0x" << message
@@ -1224,6 +1304,24 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR
}
if (!handled)
result = DefWindowProc(hwnd, message, wParam, lParam);
+
+ // Capture WM_NCCALCSIZE on top level windows and obtain the window margins by
+ // subtracting the rectangles before and after processing. This will correctly
+ // capture client code overriding the message and allow for per-monitor margins
+ // for High DPI (QTBUG-53255, QTBUG-40578).
+ if (message == WM_NCCALCSIZE && !isEmptyRect(ncCalcSizeFrame) && isTopLevel(hwnd) && !isMinimized(hwnd)) {
+ const QMargins margins =
+ marginsFromRects(ncCalcSizeFrame, rectFromNcCalcSize(message, wParam, lParam, 0));
+ if (margins.left() >= 0) {
+ if (platformWindow) {
+ platformWindow->setFrameMargins(margins);
+ } else {
+ const QSharedPointer<QWindowCreationContext> ctx = QWindowsContext::instance()->windowCreationContext();
+ if (!ctx.isNull())
+ ctx->margins = margins;
+ }
+ }
+ }
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 9dfde67797..b50010321b 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -80,7 +80,6 @@ class QTouchDevice;
struct QWindowsUser32DLL
{
- QWindowsUser32DLL();
inline void init();
inline bool initTouch();
@@ -94,30 +93,36 @@ struct QWindowsUser32DLL
typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND);
typedef BOOL (WINAPI *GetDisplayAutoRotationPreferences)(DWORD *);
typedef BOOL (WINAPI *SetDisplayAutoRotationPreferences)(DWORD);
+ typedef BOOL (WINAPI *EnableNonClientDpiScaling)(HWND);
+ typedef int (WINAPI *GetWindowDpiAwarenessContext)(HWND);
+ typedef int (WINAPI *GetAwarenessFromDpiAwarenessContext)(int);
// Touch functions from Windows 7 onwards (also for use with Q_CC_MSVC).
- IsTouchWindow isTouchWindow;
- RegisterTouchWindow registerTouchWindow;
- UnregisterTouchWindow unregisterTouchWindow;
- GetTouchInputInfo getTouchInputInfo;
- CloseTouchInputHandle closeTouchInputHandle;
+ IsTouchWindow isTouchWindow = nullptr;
+ RegisterTouchWindow registerTouchWindow = nullptr;
+ UnregisterTouchWindow unregisterTouchWindow = nullptr;
+ GetTouchInputInfo getTouchInputInfo = nullptr;
+ CloseTouchInputHandle closeTouchInputHandle = nullptr;
// Windows Vista onwards
- SetProcessDPIAware setProcessDPIAware;
+ SetProcessDPIAware setProcessDPIAware = nullptr;
// Clipboard listeners are present on Windows Vista onwards
// but missing in MinGW 4.9 stub libs. Can be removed in MinGW 5.
- AddClipboardFormatListener addClipboardFormatListener;
- RemoveClipboardFormatListener removeClipboardFormatListener;
+ AddClipboardFormatListener addClipboardFormatListener = nullptr;
+ RemoveClipboardFormatListener removeClipboardFormatListener = nullptr;
// Rotation API
- GetDisplayAutoRotationPreferences getDisplayAutoRotationPreferences;
- SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences;
+ GetDisplayAutoRotationPreferences getDisplayAutoRotationPreferences = nullptr;
+ SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences = nullptr;
+
+ EnableNonClientDpiScaling enableNonClientDpiScaling = nullptr;
+ GetWindowDpiAwarenessContext getWindowDpiAwarenessContext = nullptr;
+ GetAwarenessFromDpiAwarenessContext getAwarenessFromDpiAwarenessContext = nullptr;
};
// Shell scaling library (Windows 8.1 onwards)
struct QWindowsShcoreDLL {
- QWindowsShcoreDLL();
void init();
inline bool isValid() const { return getProcessDpiAwareness && setProcessDpiAwareness && getDpiForMonitor; }
@@ -125,9 +130,9 @@ struct QWindowsShcoreDLL {
typedef HRESULT (WINAPI *SetProcessDpiAwareness)(int);
typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *);
- GetProcessDpiAwareness getProcessDpiAwareness;
- SetProcessDpiAwareness setProcessDpiAwareness;
- GetDpiForMonitor getDpiForMonitor;
+ GetProcessDpiAwareness getProcessDpiAwareness = nullptr;
+ SetProcessDpiAwareness setProcessDpiAwareness = nullptr;
+ GetDpiForMonitor getDpiForMonitor = nullptr;
};
class QWindowsContext
@@ -181,12 +186,14 @@ public:
inline bool windowsProc(HWND hwnd, UINT message,
QtWindows::WindowsEventType et,
- WPARAM wParam, LPARAM lParam, LRESULT *result);
+ WPARAM wParam, LPARAM lParam, LRESULT *result,
+ QWindowsWindow **platformWindowPtr);
QWindow *keyGrabber() const;
void setKeyGrabber(QWindow *hwnd);
void setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx);
+ QSharedPointer<QWindowCreationContext> windowCreationContext() const;
void setTabletAbsoluteRange(int a);
void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness);
diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h
index 6fff5f9ab1..df2e22733b 100644
--- a/src/plugins/platforms/windows/qwindowscursor.h
+++ b/src/plugins/platforms/windows/qwindowscursor.h
@@ -104,9 +104,9 @@ public:
explicit QWindowsCursor(const QPlatformScreen *screen);
- void changeCursor(QCursor * widgetCursor, QWindow * widget) Q_DECL_OVERRIDE;
- QPoint pos() const Q_DECL_OVERRIDE;
- void setPos(const QPoint &pos) Q_DECL_OVERRIDE;
+ void changeCursor(QCursor * widgetCursor, QWindow * widget) override;
+ QPoint pos() const override;
+ void setPos(const QPoint &pos) override;
static HCURSOR createPixmapCursor(QPixmap pixmap, const QPoint &hotSpot, qreal scaleFactor = 1);
static HCURSOR createPixmapCursor(const PixmapCursor &pc, qreal scaleFactor = 1) { return createPixmapCursor(pc.pixmap, pc.hotSpot, scaleFactor); }
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 8f1358de6c..f4527bcc60 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -66,9 +66,11 @@
#include <QtCore/QMutexLocker>
#include <QtCore/QUuid>
#include <QtCore/QRegularExpression>
+#include <QtCore/QTemporaryFile>
#include <QtCore/private/qsystemlibrary_p.h>
#include <algorithm>
+#include <vector>
#include <QtCore/qt_windows.h>
@@ -212,15 +214,6 @@ private:
*/
template <class BaseClass>
-QWindowsDialogHelperBase<BaseClass>::QWindowsDialogHelperBase() :
- m_nativeDialog(0),
- m_ownerWindow(0),
- m_timerId(0),
- m_thread(0)
-{
-}
-
-template <class BaseClass>
void QWindowsDialogHelperBase<BaseClass>::cleanupThread()
{
if (m_thread) { // Thread may be running if the dialog failed to close.
@@ -549,11 +542,11 @@ public:
IFACEMETHODIMP OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; }
QWindowsNativeFileDialogEventHandler(QWindowsNativeFileDialogBase *nativeFileDialog) :
- m_ref(1), m_nativeFileDialog(nativeFileDialog) {}
+ m_nativeFileDialog(nativeFileDialog) {}
virtual ~QWindowsNativeFileDialogEventHandler() {}
private:
- long m_ref;
+ long m_ref = 1;
QWindowsNativeFileDialogBase *m_nativeFileDialog;
};
@@ -570,6 +563,235 @@ IFileDialogEvents *QWindowsNativeFileDialogEventHandler::create(QWindowsNativeFi
}
/*!
+ \class QWindowsShellItem
+ \brief Wrapper for IShellItem
+
+ \sa QWindowsNativeFileDialogBase
+ \internal
+ \ingroup qt-lighthouse-win
+*/
+class QWindowsShellItem
+{
+public:
+ typedef std::vector<IShellItem *> IShellItems;
+
+ explicit QWindowsShellItem(IShellItem *item);
+
+ SFGAOF attributes() const { return m_attributes; }
+ QString normalDisplay() const // base name, usually
+ { return displayName(m_item, SIGDN_NORMALDISPLAY); }
+ QString desktopAbsoluteParsing() const
+ { return displayName(m_item, SIGDN_DESKTOPABSOLUTEPARSING); }
+ QString path() const; // Only set for 'FileSystem' (SFGAO_FILESYSTEM) items
+ QUrl url() const;
+
+ bool isFileSystem() const { return (m_attributes & SFGAO_FILESYSTEM) != 0; }
+ bool isDir() const { return (m_attributes & SFGAO_FOLDER) != 0; }
+ // Copy using IFileOperation
+ bool canCopy() const { return (m_attributes & SFGAO_CANCOPY) != 0; }
+ // Supports IStream
+ bool canStream() const { return (m_attributes & SFGAO_STREAM) != 0; }
+
+ bool copyData(QIODevice *out);
+
+ static IShellItems itemsFromItemArray(IShellItemArray *items);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void format(QDebug &d) const;
+#endif
+
+private:
+ static QString displayName(IShellItem *item, SIGDN mode);
+ static QString libraryItemDefaultSaveFolder(IShellItem *item);
+ QUrl urlValue() const;
+
+ IShellItem *m_item;
+ SFGAOF m_attributes;
+};
+
+QWindowsShellItem::QWindowsShellItem(IShellItem *item)
+ : m_item(item)
+ , m_attributes(0)
+{
+ if (FAILED(item->GetAttributes(SFGAO_CAPABILITYMASK | SFGAO_DISPLAYATTRMASK | SFGAO_CONTENTSMASK | SFGAO_STORAGECAPMASK, &m_attributes)))
+ m_attributes = 0;
+}
+
+QString QWindowsShellItem::path() const
+{
+ if (isFileSystem())
+ return QDir::cleanPath(QWindowsShellItem::displayName(m_item, SIGDN_FILESYSPATH));
+ // Check for a "Library" item (Windows 7)
+ if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7 && isDir())
+ return QWindowsShellItem::libraryItemDefaultSaveFolder(m_item);
+ return QString();
+}
+
+QUrl QWindowsShellItem::urlValue() const // plain URL as returned by SIGDN_URL, not set for all items
+{
+ QUrl result;
+ const QString urlString = displayName(m_item, SIGDN_URL);
+ if (!urlString.isEmpty()) {
+ const QUrl parsed = QUrl(urlString);
+ if (parsed.isValid()) {
+ result = parsed;
+ } else {
+ qWarning("%s: Unable to decode URL \"%s\": %s", __FUNCTION__,
+ qPrintable(urlString), qPrintable(parsed.errorString()));
+ }
+ }
+ return result;
+}
+
+QUrl QWindowsShellItem::url() const
+{
+ // Prefer file if existent to avoid any misunderstandings about UNC shares
+ const QString fsPath = path();
+ if (!fsPath.isEmpty())
+ return QUrl::fromLocalFile(fsPath);
+ const QUrl urlV = urlValue();
+ if (urlV.isValid())
+ return urlV;
+ // Last resort: encode the absolute desktop parsing id as data URL
+ const QString data = QStringLiteral("data:text/plain;base64,")
+ + QLatin1String(desktopAbsoluteParsing().toLatin1().toBase64());
+ return QUrl(data);
+}
+
+QString QWindowsShellItem::displayName(IShellItem *item, SIGDN mode)
+{
+ LPWSTR name = nullptr;
+ QString result;
+ if (SUCCEEDED(item->GetDisplayName(mode, &name))) {
+ result = QString::fromWCharArray(name);
+ CoTaskMemFree(name);
+ }
+ return result;
+}
+
+QWindowsShellItem::IShellItems QWindowsShellItem::itemsFromItemArray(IShellItemArray *items)
+{
+ IShellItems result;
+ DWORD itemCount = 0;
+ if (FAILED(items->GetCount(&itemCount)) || itemCount == 0)
+ return result;
+ result.reserve(itemCount);
+ for (DWORD i = 0; i < itemCount; ++i) {
+ IShellItem *item = nullptr;
+ if (SUCCEEDED(items->GetItemAt(i, &item)))
+ result.push_back(item);
+ }
+ return result;
+}
+
+bool QWindowsShellItem::copyData(QIODevice *out)
+{
+ if (!canCopy() || !canStream())
+ return false;
+ IStream *istream = nullptr;
+ HRESULT hr = m_item->BindToHandler(NULL, BHID_Stream, IID_PPV_ARGS(&istream));
+ if (FAILED(hr))
+ return false;
+ enum : ULONG { bufSize = 102400 };
+ char buffer[bufSize];
+ ULONG bytesRead;
+ forever {
+ bytesRead = 0;
+ hr = istream->Read(buffer, bufSize, &bytesRead); // S_FALSE: EOF reached
+ if ((hr == S_OK || hr == S_FALSE) && bytesRead)
+ out->write(buffer, bytesRead);
+ else
+ break;
+ }
+ istream->Release();
+ return hr == S_OK || hr == S_FALSE;
+}
+
+// Helper for "Libraries": collections of folders appearing from Windows 7
+// on, visible in the file dialogs.
+
+// Load a library from a IShellItem (sanitized copy of the inline function
+// SHLoadLibraryFromItem from ShObjIdl.h, which does not exist for MinGW).
+static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode)
+{
+ // ID symbols present from Windows 7 on:
+ static const CLSID classId_ShellLibrary = {0xd9b3211d, 0xe57f, 0x4426, {0xaa, 0xef, 0x30, 0xa8, 0x6, 0xad, 0xd3, 0x97}};
+ static const IID iId_IShellLibrary = {0x11a66efa, 0x382e, 0x451a, {0x92, 0x34, 0x1e, 0xe, 0x12, 0xef, 0x30, 0x85}};
+
+ IShellLibrary *helper = nullptr;
+ IShellLibrary *result = nullptr;
+ if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast<void **>(&helper))))
+ if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem, mode)))
+ helper->QueryInterface(iId_IShellLibrary, reinterpret_cast<void **>(&result));
+ if (helper)
+ helper->Release();
+ return result;
+}
+
+// Return default save folders of a library-type item.
+QString QWindowsShellItem::libraryItemDefaultSaveFolder(IShellItem *item)
+{
+ QString result;
+ if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) {
+ IShellItem *item = Q_NULLPTR;
+ if (SUCCEEDED(library->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, reinterpret_cast<void **>(&item)))) {
+ result = QDir::cleanPath(QWindowsShellItem::displayName(item, SIGDN_FILESYSPATH));
+ item->Release();
+ }
+ library->Release();
+ }
+ return result;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void QWindowsShellItem::format(QDebug &d) const
+{
+ d << "attributes=0x" << hex << attributes() << dec;
+ if (isFileSystem())
+ d << " [filesys]";
+ if (isDir())
+ d << " [dir]";
+ if (canStream())
+ d << " [stream]";
+ if (canCopy())
+ d << " [copyable]";
+ d << ", normalDisplay=\"" << normalDisplay()
+ << "\", desktopAbsoluteParsing=\"" << desktopAbsoluteParsing() << '"';
+ const QString pathS = path();
+ if (!pathS.isEmpty())
+ d << ", path=\"" << pathS << '"';
+ const QUrl urlV = urlValue();
+ if (urlV.isValid())
+ d << "\", url=" << urlV;
+}
+
+QDebug operator<<(QDebug d, const QWindowsShellItem &i)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d.noquote();
+ d << "QShellItem(";
+ i.format(d);
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, IShellItem *i)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d.noquote();
+ d << "IShellItem(" << static_cast<const void *>(i);
+ if (i) {
+ d << ", ";
+ QWindowsShellItem(i).format(d);
+ }
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+/*!
\class QWindowsNativeFileDialogBase
\brief Windows native file dialog wrapper around IFileOpenDialog, IFileSaveDialog.
@@ -590,12 +812,12 @@ public:
inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data);
- void setWindowTitle(const QString &title) Q_DECL_OVERRIDE;
+ void setWindowTitle(const QString &title) override;
inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::AcceptMode acceptMode, QFileDialogOptions::FileDialogOptions options);
inline void setDirectory(const QUrl &directory);
inline void updateDirectory() { setDirectory(m_data.directory()); }
inline QString directory() const;
- void doExec(HWND owner = 0) Q_DECL_OVERRIDE;
+ void doExec(HWND owner = 0) override;
virtual void setNameFilters(const QStringList &f);
inline void selectNameFilter(const QString &filter);
inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); }
@@ -624,36 +846,31 @@ signals:
void filterSelected(const QString & filter);
public slots:
- void close() Q_DECL_OVERRIDE;
+ void close() override;
protected:
explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data);
bool init(const CLSID &clsId, const IID &iid);
void setDefaultSuffixSys(const QString &s);
inline IFileDialog * fileDialog() const { return m_fileDialog; }
- static QString itemPath(IShellItem *item);
- static QList<QUrl> libraryItemFolders(IShellItem *item);
- static QString libraryItemDefaultSaveFolder(IShellItem *item);
- static int itemPaths(IShellItemArray *items, QList<QUrl> *fileResult = 0);
static IShellItem *shellItem(const QUrl &url);
const QWindowsFileDialogSharedData &data() const { return m_data; }
QWindowsFileDialogSharedData &data() { return m_data; }
private:
- IFileDialog *m_fileDialog;
- IFileDialogEvents *m_dialogEvents;
- DWORD m_cookie;
+ IFileDialog *m_fileDialog = nullptr;
+ IFileDialogEvents *m_dialogEvents = nullptr;
+ DWORD m_cookie = 0;
QStringList m_nameFilters;
- bool m_hideFiltersDetails;
- bool m_hasDefaultSuffix;
+ bool m_hideFiltersDetails = false;
+ bool m_hasDefaultSuffix = false;
QWindowsFileDialogSharedData m_data;
QString m_title;
};
QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) :
- m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false),
- m_hasDefaultSuffix(false), m_data(data)
+ m_data(data)
{
}
@@ -753,7 +970,7 @@ QString QWindowsNativeFileDialogBase::directory() const
QString result;
IShellItem *item = 0;
if (m_fileDialog && SUCCEEDED(m_fileDialog->GetFolder(&item)) && item) {
- result = QWindowsNativeFileDialogBase::itemPath(item);
+ result = QWindowsShellItem(item).path();
item->Release();
}
return result;
@@ -807,113 +1024,6 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode,
qErrnoWarning("%s: SetOptions() failed", __FUNCTION__);
}
-#if defined(__IShellLibrary_INTERFACE_DEFINED__) // Windows SDK 7
-
-// Helper for "Libraries": collections of folders appearing from Windows 7
-// on, visible in the file dialogs.
-
-// Load a library from a IShellItem (sanitized copy of the inline function
-// SHLoadLibraryFromItem from ShObjIdl.h, which does not exist for MinGW).
-static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode)
-{
- // ID symbols present from Windows 7 on:
- static const CLSID classId_ShellLibrary = {0xd9b3211d, 0xe57f, 0x4426, {0xaa, 0xef, 0x30, 0xa8, 0x6, 0xad, 0xd3, 0x97}};
- static const IID iId_IShellLibrary = {0x11a66efa, 0x382e, 0x451a, {0x92, 0x34, 0x1e, 0xe, 0x12, 0xef, 0x30, 0x85}};
-
- IShellLibrary *helper = 0;
- IShellLibrary *result = 0;
- if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast<void **>(&helper))))
- if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem, mode)))
- helper->QueryInterface(iId_IShellLibrary, reinterpret_cast<void **>(&result));
- if (helper)
- helper->Release();
- return result;
-}
-
-// Return all folders of a library-type item.
-QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item)
-{
- QList<QUrl> result;
- if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) {
- IShellItemArray *itemArray = 0;
- if (SUCCEEDED(library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, reinterpret_cast<void **>(&itemArray)))) {
- QWindowsNativeFileDialogBase::itemPaths(itemArray, &result);
- itemArray->Release();
- }
- library->Release();
- }
- return result;
-}
-
-// Return default save folders of a library-type item.
-QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *item)
-{
- QString result;
- if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) {
- IShellItem *item = 0;
- if (SUCCEEDED(library->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, reinterpret_cast<void **>(&item)))) {
- result = QWindowsNativeFileDialogBase::itemPath(item);
- item->Release();
- }
- library->Release();
- }
- return result;
-}
-
-#else // __IShellLibrary_INTERFACE_DEFINED__
-
-QList<QUrl> QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *)
-{
- return QList<QUrl>();
-}
-
-QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *)
-{
- return QString();
-}
-
-#endif // !__IShellLibrary_INTERFACE_DEFINED__
-
-QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item)
-{
- SFGAOF attributes = 0;
- // Check whether it has a file system representation?
- if (FAILED(item->GetAttributes(SFGAO_FILESYSTEM, &attributes)))
- return QString();
- if (attributes & SFGAO_FILESYSTEM) {
- LPWSTR name = 0;
- QString result;
- if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) {
- result = QDir::cleanPath(QString::fromWCharArray(name));
- CoTaskMemFree(name);
- }
- return result;
- }
- // Check for a "Library" item
- if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) && QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7)
- return QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(item);
- return QString();
-}
-
-int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items,
- QList<QUrl> *result /* = 0 */)
-{
- DWORD itemCount = 0;
- if (result)
- result->clear();
- if (FAILED(items->GetCount(&itemCount)))
- return 0;
- if (result && itemCount) {
- result->reserve(itemCount);
- for (DWORD i = 0; i < itemCount; ++i) {
- IShellItem *item = 0;
- if (SUCCEEDED(items->GetItemAt(i, &item)))
- result->push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item)));
- }
- }
- return itemCount;
-}
-
// Split a list of name filters into description and actual filters
struct FilterSpec
{
@@ -1011,6 +1121,13 @@ void QWindowsNativeFileDialogBase::setDefaultSuffixSys(const QString &s)
m_fileDialog->SetDefaultExtension(wSuffix);
}
+static inline IFileDialog2 *getFileDialog2(IFileDialog *fileDialog)
+{
+ IFileDialog2 *result;
+ return SUCCEEDED(fileDialog->QueryInterface(IID_IFileDialog2, reinterpret_cast<void **>(&result)))
+ ? result : nullptr;
+}
+
void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel l, const QString &text)
{
wchar_t *wText = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(text.utf16()));
@@ -1021,8 +1138,13 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel
case QFileDialogOptions::Accept:
m_fileDialog->SetOkButtonLabel(wText);
break;
- case QFileDialogOptions::LookIn:
case QFileDialogOptions::Reject:
+ if (IFileDialog2 *dialog2 = getFileDialog2(m_fileDialog)) {
+ dialog2->SetCancelButtonLabel(wText);
+ dialog2->Release();
+ }
+ break;
+ case QFileDialogOptions::LookIn:
case QFileDialogOptions::FileType:
case QFileDialogOptions::DialogLabelCount:
break;
@@ -1067,7 +1189,7 @@ void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter)
if (index < 0) {
qWarning("%s: Invalid parameter '%s' not found in '%s'.",
__FUNCTION__, qPrintable(filter),
- qPrintable(m_nameFilters.join(QStringLiteral(", "))));
+ qPrintable(m_nameFilters.join(QLatin1String(", "))));
return;
}
m_fileDialog->SetFileTypeIndex(index + 1); // one-based.
@@ -1087,7 +1209,7 @@ QString QWindowsNativeFileDialogBase::selectedNameFilter() const
void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item)
{
if (item) {
- const QUrl directory = QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item));
+ const QUrl directory = QWindowsShellItem(item).url();
m_data.setDirectory(directory);
emit directoryEntered(directory);
}
@@ -1165,9 +1287,9 @@ class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase
public:
explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data)
: QWindowsNativeFileDialogBase(data) {}
- void setNameFilters(const QStringList &f) Q_DECL_OVERRIDE;
- QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE;
- QList<QUrl> dialogResult() const Q_DECL_OVERRIDE;
+ void setNameFilters(const QStringList &f) override;
+ QList<QUrl> selectedFiles() const override;
+ QList<QUrl> dialogResult() const override;
};
// Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo".
@@ -1210,7 +1332,7 @@ QList<QUrl> QWindowsNativeSaveFileDialog::dialogResult() const
QList<QUrl> result;
IShellItem *item = 0;
if (SUCCEEDED(fileDialog()->GetResult(&item)) && item)
- result.push_back(QUrl::fromLocalFile(QWindowsNativeFileDialogBase::itemPath(item)));
+ result.append(QWindowsShellItem(item).url());
return result;
}
@@ -1220,7 +1342,7 @@ QList<QUrl> QWindowsNativeSaveFileDialog::selectedFiles() const
IShellItem *item = 0;
const HRESULT hr = fileDialog()->GetCurrentSelection(&item);
if (SUCCEEDED(hr) && item) {
- result.push_back(QUrl::fromLocalFile(QWindowsNativeSaveFileDialog::itemPath(item)));
+ result.append(QWindowsShellItem(item).url());
item->Release();
}
return result;
@@ -1241,20 +1363,69 @@ class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase
public:
explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) :
QWindowsNativeFileDialogBase(data) {}
- QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE;
- QList<QUrl> dialogResult() const Q_DECL_OVERRIDE;
+ QList<QUrl> selectedFiles() const override;
+ QList<QUrl> dialogResult() const override;
private:
inline IFileOpenDialog *openFileDialog() const
{ return static_cast<IFileOpenDialog *>(fileDialog()); }
};
+// Helpers for managing a list of temporary copies of items with no
+// file system representation (SFGAO_FILESYSTEM unset, for example devices
+// using MTP) returned by IFileOpenDialog. This emulates the behavior
+// of the Win32 API GetOpenFileName() used in Qt 4 (QTBUG-57070).
+
+Q_GLOBAL_STATIC(QStringList, temporaryItemCopies)
+
+static void cleanupTemporaryItemCopies()
+{
+ for (const QString &file : qAsConst(*temporaryItemCopies()))
+ QFile::remove(file);
+}
+
+static QString createTemporaryItemCopy(QWindowsShellItem &qItem)
+{
+ if (!qItem.canCopy() || !qItem.canStream())
+ return QString();
+ QString pattern = qItem.normalDisplay();
+ const int lastDot = pattern.lastIndexOf(QLatin1Char('.'));
+ const QString placeHolder = QStringLiteral("_XXXXXX");
+ if (lastDot >= 0)
+ pattern.insert(lastDot, placeHolder);
+ else
+ pattern.append(placeHolder);
+
+ QTemporaryFile targetFile(QDir::tempPath() + QLatin1Char('/') + pattern);
+ targetFile.setAutoRemove(false);
+ if (!targetFile.open() || !qItem.copyData(&targetFile))
+ return QString();
+ const QString result = targetFile.fileName();
+ if (temporaryItemCopies()->isEmpty())
+ qAddPostRoutine(cleanupTemporaryItemCopies);
+ temporaryItemCopies()->append(result);
+ return result;
+}
+
QList<QUrl> QWindowsNativeOpenFileDialog::dialogResult() const
{
QList<QUrl> result;
IShellItemArray *items = 0;
- if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items)
- QWindowsNativeFileDialogBase::itemPaths(items, &result);
+ if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items) {
+ for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) {
+ QWindowsShellItem qItem(item);
+ const QString path = qItem.path();
+ if (path.isEmpty()) {
+ const QString temporaryCopy = createTemporaryItemCopy(qItem);
+ if (temporaryCopy.isEmpty())
+ qWarning() << "Unable to create a local copy of" << qItem;
+ else
+ result.append(QUrl::fromLocalFile(temporaryCopy));
+ } else {
+ result.append(qItem.url());
+ }
+ }
+ }
return result;
}
@@ -1263,8 +1434,16 @@ QList<QUrl> QWindowsNativeOpenFileDialog::selectedFiles() const
QList<QUrl> result;
IShellItemArray *items = 0;
const HRESULT hr = openFileDialog()->GetSelectedItems(&items);
- if (SUCCEEDED(hr) && items)
- QWindowsNativeFileDialogBase::itemPaths(items, &result);
+ if (SUCCEEDED(hr) && items) {
+ for (IShellItem *item : QWindowsShellItem::itemsFromItemArray(items)) {
+ const QWindowsShellItem qItem(item);
+ const QUrl url = qItem.url();
+ if (url.isValid())
+ result.append(url);
+ else
+ qWarning().nospace() << __FUNCTION__<< ": Unable to obtain URL of " << qItem;
+ }
+ }
return result;
}
@@ -1309,19 +1488,19 @@ class QWindowsFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDi
{
public:
QWindowsFileDialogHelper() {}
- virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const Q_DECL_OVERRIDE { return false; }
- virtual bool defaultNameFilterDisables() const Q_DECL_OVERRIDE
+ bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const override { return false; }
+ bool defaultNameFilterDisables() const override
{ return false; }
- virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE;
- virtual QUrl directory() const Q_DECL_OVERRIDE;
- virtual void selectFile(const QUrl &filename) Q_DECL_OVERRIDE;
- virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE;
- virtual void setFilter() Q_DECL_OVERRIDE;
- virtual void selectNameFilter(const QString &filter) Q_DECL_OVERRIDE;
- virtual QString selectedNameFilter() const Q_DECL_OVERRIDE;
+ void setDirectory(const QUrl &directory) override;
+ QUrl directory() const override;
+ void selectFile(const QUrl &filename) override;
+ QList<QUrl> selectedFiles() const override;
+ void setFilter() override;
+ void selectNameFilter(const QString &filter) override;
+ QString selectedNameFilter() const override;
private:
- QWindowsNativeDialogBase *createNativeDialog() Q_DECL_OVERRIDE;
+ QWindowsNativeDialogBase *createNativeDialog() override;
inline QWindowsNativeFileDialogBase *nativeFileDialog() const
{ return static_cast<QWindowsNativeFileDialogBase *>(nativeDialog()); }
@@ -1357,6 +1536,8 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
result->setLabelText(QFileDialogOptions::FileName, opts->labelText(QFileDialogOptions::FileName));
if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
result->setLabelText(QFileDialogOptions::Accept, opts->labelText(QFileDialogOptions::Accept));
+ if (opts->isLabelExplicitlySet(QFileDialogOptions::Reject))
+ result->setLabelText(QFileDialogOptions::Reject, opts->labelText(QFileDialogOptions::Reject));
result->updateDirectory();
result->updateSelectedNameFilter();
const QList<QUrl> initialSelection = opts->initiallySelectedFiles();
@@ -1447,13 +1628,13 @@ public:
static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data);
- void setWindowTitle(const QString &t) Q_DECL_OVERRIDE { m_title = t; }
- void doExec(HWND owner = 0) Q_DECL_OVERRIDE;
+ void setWindowTitle(const QString &t) override { m_title = t; }
+ void doExec(HWND owner = 0) override;
int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam);
public slots:
- void close() Q_DECL_OVERRIDE {}
+ void close() override {}
private:
typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW);
@@ -1689,19 +1870,19 @@ class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFile
{
public:
QWindowsXpFileDialogHelper() {}
- bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const Q_DECL_OVERRIDE { return false; }
- bool defaultNameFilterDisables() const Q_DECL_OVERRIDE
+ bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const override { return false; }
+ bool defaultNameFilterDisables() const override
{ return true; }
- void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE;
- QUrl directory() const Q_DECL_OVERRIDE;
- void selectFile(const QUrl &url) Q_DECL_OVERRIDE;
- QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE;
- void setFilter() Q_DECL_OVERRIDE {}
- void selectNameFilter(const QString &) Q_DECL_OVERRIDE;
- QString selectedNameFilter() const Q_DECL_OVERRIDE;
+ void setDirectory(const QUrl &directory) override;
+ QUrl directory() const override;
+ void selectFile(const QUrl &url) override;
+ QList<QUrl> selectedFiles() const override;
+ void setFilter() override {}
+ void selectNameFilter(const QString &) override;
+ QString selectedNameFilter() const override;
private:
- QWindowsNativeDialogBase *createNativeDialog() Q_DECL_OVERRIDE;
+ QWindowsNativeDialogBase *createNativeDialog() override;
inline QWindowsXpNativeFileDialog *nativeFileDialog() const
{ return static_cast<QWindowsXpNativeFileDialog *>(nativeDialog()); }
@@ -1773,13 +1954,13 @@ public:
explicit QWindowsNativeColorDialog(const SharedPointerColor &color);
- void setWindowTitle(const QString &) Q_DECL_OVERRIDE {}
+ void setWindowTitle(const QString &) override {}
public slots:
- void close() Q_DECL_OVERRIDE {}
+ void close() override {}
private:
- void doExec(HWND owner = 0) Q_DECL_OVERRIDE;
+ void doExec(HWND owner = 0) override;
COLORREF m_customColors[CustomColorCount];
QPlatformDialogHelper::DialogCode m_code;
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
index b3101a1419..55f112c57a 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
@@ -69,19 +69,19 @@ public:
typedef QSharedPointer<QWindowsNativeDialogBase> QWindowsNativeDialogBasePtr;
~QWindowsDialogHelperBase() { cleanupThread(); }
- void exec() Q_DECL_OVERRIDE;
+ void exec() override;
bool show(Qt::WindowFlags windowFlags,
- Qt::WindowModality windowModality,
- QWindow *parent) Q_DECL_OVERRIDE;
- void hide() Q_DECL_OVERRIDE;
+ Qt::WindowModality windowModality,
+ QWindow *parent) override;
+ void hide() override;
virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; }
protected:
- QWindowsDialogHelperBase();
+ QWindowsDialogHelperBase() {}
QWindowsNativeDialogBase *nativeDialog() const;
inline bool hasNativeDialog() const { return m_nativeDialog; }
- void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE;
+ void timerEvent(QTimerEvent *) override;
private:
virtual QWindowsNativeDialogBase *createNativeDialog() = 0;
@@ -91,9 +91,9 @@ private:
void cleanupThread();
QWindowsNativeDialogBasePtr m_nativeDialog;
- HWND m_ownerWindow;
- int m_timerId;
- QThread *m_thread;
+ HWND m_ownerWindow = 0;
+ int m_timerId = 0;
+ QThread *m_thread = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 26a5131927..58175b39fa 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -84,7 +84,7 @@ public:
void setPixmap(const QPixmap &p);
protected:
- void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE
+ void paintEvent(QPaintEvent *) override
{
QPainter painter(this);
painter.drawPixmap(0, 0, m_pixmap);
@@ -190,6 +190,20 @@ static inline Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState)
return modifiers;
}
+static inline Qt::MouseButtons toQtMouseButtons(DWORD keyState)
+{
+ Qt::MouseButtons buttons = Qt::NoButton;
+
+ if (keyState & MK_LBUTTON)
+ buttons |= Qt::LeftButton;
+ if (keyState & MK_RBUTTON)
+ buttons |= Qt::RightButton;
+ if (keyState & MK_MBUTTON)
+ buttons |= Qt::MidButton;
+
+ return buttons;
+}
+
/*!
\class QWindowsOleDropSource
\brief Implementation of IDropSource
@@ -398,43 +412,39 @@ QWindowsOleDropSource::Release(void)
QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
- HRESULT hr = S_OK;
- do {
- if (fEscapePressed || QWindowsDrag::isCanceled()) {
- hr = ResultFromScode(DRAGDROP_S_CANCEL);
- break;
- }
-
- // grfKeyState is broken on CE & some Windows XP versions,
- // therefore we need to check the state manually
- if ((GetAsyncKeyState(VK_LBUTTON) == 0)
- && (GetAsyncKeyState(VK_MBUTTON) == 0)
- && (GetAsyncKeyState(VK_RBUTTON) == 0)) {
- hr = ResultFromScode(DRAGDROP_S_DROP);
- break;
- }
+ Qt::MouseButtons buttons = toQtMouseButtons(grfKeyState);
- const Qt::MouseButtons buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState);
- if (m_currentButtons == Qt::NoButton) {
- m_currentButtons = buttons;
+ SCODE result = S_OK;
+ if (fEscapePressed || QWindowsDrag::isCanceled()) {
+ result = DRAGDROP_S_CANCEL;
+ buttons = Qt::NoButton;
} else {
- // Button changed: Complete Drop operation.
- if (!(m_currentButtons & buttons)) {
- hr = ResultFromScode(DRAGDROP_S_DROP);
- break;
+ if (buttons && !m_currentButtons) {
+ m_currentButtons = buttons;
+ } else if (!(m_currentButtons & buttons)) { // Button changed: Complete Drop operation.
+ result = DRAGDROP_S_DROP;
}
}
- QGuiApplication::processEvents();
+ switch (result) {
+ case DRAGDROP_S_DROP:
+ case DRAGDROP_S_CANCEL:
+ QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState);
+ QGuiApplicationPrivate::mouse_buttons = buttons;
+ m_currentButtons = Qt::NoButton;
+ break;
- } while (false);
+ default:
+ QGuiApplication::processEvents();
+ break;
+ }
- if (QWindowsContext::verbose > 1 || hr != S_OK) {
+ if (QWindowsContext::verbose > 1 || result != S_OK) {
qCDebug(lcQpaMime) << __FUNCTION__ << "fEscapePressed=" << fEscapePressed
<< "grfKeyState=" << grfKeyState << "buttons" << m_currentButtons
- << "returns 0x" << hex <<int(hr) << dec;
+ << "returns 0x" << hex << int(result) << dec;
}
- return hr;
+ return ResultFromScode(result);
}
/*!
@@ -489,8 +499,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
\ingroup qt-lighthouse-win
*/
-QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) :
- m_refs(1), m_window(w), m_chosenEffect(0), m_lastKeyState(0)
+QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) : m_window(w)
{
qCDebug(lcQpaMime) << __FUNCTION__ << this << w;
}
@@ -538,7 +547,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState,
QWindowsDrag *windowsDrag = QWindowsDrag::instance();
const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect);
QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState);
- QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState);
+ QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(grfKeyState);
const QPlatformDragQtResponse response =
QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions);
@@ -606,6 +615,12 @@ QWindowsOleDropTarget::DragLeave()
qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window;
QWindowSystemInterface::handleDrag(m_window, 0, QPoint(), Qt::IgnoreAction);
+
+ if (!QDragManager::self()->source()) {
+ QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
+ QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
+ m_lastKeyState = 0;
+ }
QWindowsDrag::instance()->releaseDropDataObject();
return NOERROR;
@@ -624,11 +639,9 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
<< "keys=" << grfKeyState << "pt=" << pt.x << ',' << pt.y;
m_lastPoint = QWindowsGeometryHint::mapFromGlobal(m_window, QPoint(pt.x,pt.y));
- // grfKeyState does not all ways contain button state in the drop so if
- // it doesn't then use the last known button state;
- if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0)
- grfKeyState |= m_lastKeyState & KEY_STATE_BUTTON_MASK;
- m_lastKeyState = grfKeyState;
+ // grfKeyState does not all ways contain button state in the drop
+ QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(m_lastKeyState);
+ QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState);
QWindowsDrag *windowsDrag = QWindowsDrag::instance();
@@ -636,6 +649,10 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(),
m_lastPoint,
translateToQDragDropActions(*pdwEffect));
+
+ QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(grfKeyState);
+ m_lastKeyState = grfKeyState;
+
if (response.isAccepted()) {
const Qt::DropAction action = response.acceptedAction();
if (action == Qt::MoveAction || action == Qt::TargetMoveAction) {
@@ -682,10 +699,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
bool QWindowsDrag::m_canceled = false;
-QWindowsDrag::QWindowsDrag() :
- m_dropDataObject(0), m_cachedDropTargetHelper(0)
-{
-}
+QWindowsDrag::QWindowsDrag() = default;
QWindowsDrag::~QWindowsDrag()
{
diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h
index e81bc7dc61..983f3a67b4 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.h
+++ b/src/plugins/platforms/windows/qwindowsdrag.h
@@ -54,7 +54,7 @@ class QPlatformScreen;
class QWindowsDropMimeData : public QWindowsInternalMimeData {
public:
QWindowsDropMimeData() {}
- IDataObject *retrieveDataObject() const Q_DECL_OVERRIDE;
+ IDataObject *retrieveDataObject() const override;
};
class QWindowsOleDropTarget : public IDropTarget
@@ -77,12 +77,12 @@ public:
private:
void handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &, LPDWORD pdwEffect);
- ULONG m_refs;
+ ULONG m_refs = 1;
QWindow *const m_window;
QRect m_answerRect;
QPoint m_lastPoint;
- DWORD m_chosenEffect;
- DWORD m_lastKeyState;
+ DWORD m_chosenEffect = 0;
+ DWORD m_lastKeyState = 0;
};
class QWindowsDrag : public QPlatformDrag
@@ -91,12 +91,12 @@ public:
QWindowsDrag();
virtual ~QWindowsDrag();
- QMimeData *platformDropData() Q_DECL_OVERRIDE { return &m_dropData; }
+ QMimeData *platformDropData() override { return &m_dropData; }
- Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE;
+ Qt::DropAction drag(QDrag *drag) override;
static QWindowsDrag *instance();
- void cancelDrag() Q_DECL_OVERRIDE { QWindowsDrag::m_canceled = true; }
+ void cancelDrag() override { QWindowsDrag::m_canceled = true; }
static bool isCanceled() { return QWindowsDrag::m_canceled; }
IDataObject *dropDataObject() const { return m_dropDataObject; }
@@ -110,9 +110,9 @@ private:
static bool m_canceled;
QWindowsDropMimeData m_dropData;
- IDataObject *m_dropDataObject;
+ IDataObject *m_dropDataObject = nullptr;
- IDropTargetHelper* m_cachedDropTargetHelper;
+ IDropTargetHelper* m_cachedDropTargetHelper = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp
index a4738dc100..4632c9c157 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp
@@ -384,8 +384,6 @@ QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext,
QPlatformOpenGLContext *share)
: m_staticContext(staticContext)
, m_eglDisplay(staticContext->display())
- , m_api(EGL_OPENGL_ES_API)
- , m_swapInterval(-1)
{
if (!m_staticContext)
return;
diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h
index 48a19f81e5..47878a7169 100644
--- a/src/plugins/platforms/windows/qwindowseglcontext.h
+++ b/src/plugins/platforms/windows/qwindowseglcontext.h
@@ -117,12 +117,12 @@ public:
EGLDisplay display() const { return m_display; }
- QWindowsOpenGLContext *createContext(QOpenGLContext *context) Q_DECL_OVERRIDE;
- void *moduleHandle() const Q_DECL_OVERRIDE { return libGLESv2.moduleHandle(); }
- QOpenGLContext::OpenGLModuleType moduleType() const Q_DECL_OVERRIDE { return QOpenGLContext::LibGLES; }
+ QWindowsOpenGLContext *createContext(QOpenGLContext *context) override;
+ void *moduleHandle() const override { return libGLESv2.moduleHandle(); }
+ QOpenGLContext::OpenGLModuleType moduleType() const override { return QOpenGLContext::LibGLES; }
- void *createWindowSurface(void *nativeWindow, void *nativeConfig, int *err) Q_DECL_OVERRIDE;
- void destroyWindowSurface(void *nativeSurface) Q_DECL_OVERRIDE;
+ void *createWindowSurface(void *nativeWindow, void *nativeConfig, int *err) override;
+ void destroyWindowSurface(void *nativeSurface) override;
QSurfaceFormat formatFromConfig(EGLDisplay display, EGLConfig config, const QSurfaceFormat &referenceFormat);
@@ -145,18 +145,18 @@ public:
QPlatformOpenGLContext *share);
~QWindowsEGLContext();
- bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE;
- void doneCurrent() Q_DECL_OVERRIDE;
- void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE;
- QFunctionPointer getProcAddress(const char *procName) Q_DECL_OVERRIDE;
+ bool makeCurrent(QPlatformSurface *surface) override;
+ void doneCurrent() override;
+ void swapBuffers(QPlatformSurface *surface) override;
+ QFunctionPointer getProcAddress(const char *procName) override;
- QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; }
- bool isSharing() const Q_DECL_OVERRIDE { return m_shareContext != EGL_NO_CONTEXT; }
- bool isValid() const Q_DECL_OVERRIDE { return m_eglContext != EGL_NO_CONTEXT; }
+ QSurfaceFormat format() const override { return m_format; }
+ bool isSharing() const override { return m_shareContext != EGL_NO_CONTEXT; }
+ bool isValid() const override { return m_eglContext != EGL_NO_CONTEXT; }
- void *nativeContext() const Q_DECL_OVERRIDE { return m_eglContext; }
- void *nativeDisplay() const Q_DECL_OVERRIDE { return m_eglDisplay; }
- void *nativeConfig() const Q_DECL_OVERRIDE { return m_eglConfig; }
+ void *nativeContext() const override { return m_eglContext; }
+ void *nativeDisplay() const override { return m_eglDisplay; }
+ void *nativeConfig() const override { return m_eglConfig; }
private:
EGLConfig chooseConfig(const QSurfaceFormat &format);
@@ -167,8 +167,8 @@ private:
EGLDisplay m_eglDisplay;
EGLConfig m_eglConfig;
QSurfaceFormat m_format;
- EGLenum m_api;
- int m_swapInterval;
+ EGLenum m_api = EGL_OPENGL_ES_API;
+ int m_swapInterval = -1;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsgdiintegration.h b/src/plugins/platforms/windows/qwindowsgdiintegration.h
index 46af20a083..ec67a99bc9 100644
--- a/src/plugins/platforms/windows/qwindowsgdiintegration.h
+++ b/src/plugins/platforms/windows/qwindowsgdiintegration.h
@@ -51,9 +51,9 @@ public:
explicit QWindowsGdiIntegration(const QStringList &paramList);
virtual ~QWindowsGdiIntegration();
- QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE;
- QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const Q_DECL_OVERRIDE;
- QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE;
+ QPlatformNativeInterface *nativeInterface() const override;
+ QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const override;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
private:
QScopedPointer<QWindowsGdiIntegrationPrivate> d;
diff --git a/src/plugins/platforms/windows/qwindowsgdinativeinterface.h b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h
index f0464bc823..c86d3cbb47 100644
--- a/src/plugins/platforms/windows/qwindowsgdinativeinterface.h
+++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.h
@@ -48,7 +48,7 @@ class QWindowsGdiNativeInterface : public QWindowsNativeInterface
{
Q_OBJECT
public:
- void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) Q_DECL_OVERRIDE;
+ void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
index c1eb664324..751807e897 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -825,13 +825,6 @@ static inline QOpenGLContextData createDummyWindowOpenGLContextData()
\ingroup qt-lighthouse-win
*/
-QWindowsOpenGLContextFormat::QWindowsOpenGLContextFormat() :
- profile(QSurfaceFormat::NoProfile),
- version(0),
- options(0)
-{
-}
-
QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current()
{
QWindowsOpenGLContextFormat result;
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h
index 048b22bbf7..dfaa428520 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.h
+++ b/src/plugins/platforms/windows/qwindowsglcontext.h
@@ -73,24 +73,23 @@ struct QWindowsOpenGLAdditionalFormat
struct QOpenGLContextData
{
QOpenGLContextData(HGLRC r, HWND h, HDC d) : renderingContext(r), hwnd(h), hdc(d) {}
- QOpenGLContextData() : renderingContext(0), hwnd(0), hdc(0) {}
+ QOpenGLContextData() {}
- HGLRC renderingContext;
- HWND hwnd;
- HDC hdc;
+ HGLRC renderingContext = 0;
+ HWND hwnd = 0;
+ HDC hdc = 0;
};
class QOpenGLStaticContext;
struct QWindowsOpenGLContextFormat
{
- QWindowsOpenGLContextFormat();
static QWindowsOpenGLContextFormat current();
void apply(QSurfaceFormat *format) const;
- QSurfaceFormat::OpenGLContextProfile profile;
- int version; //! majorVersion<<8 + minorVersion
- QSurfaceFormat::FormatOptions options;
+ QSurfaceFormat::OpenGLContextProfile profile = QSurfaceFormat::NoProfile;
+ int version = 0; //! majorVersion<<8 + minorVersion
+ QSurfaceFormat::FormatOptions options = 0;
};
#ifndef QT_NO_DEBUG_STREAM
@@ -195,22 +194,22 @@ class QWindowsGLContext : public QWindowsOpenGLContext
public:
explicit QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context);
~QWindowsGLContext();
- bool isSharing() const Q_DECL_OVERRIDE { return m_context->shareHandle(); }
- bool isValid() const Q_DECL_OVERRIDE { return m_renderingContext && !m_lost; }
- QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_obtainedFormat; }
+ bool isSharing() const override { return m_context->shareHandle(); }
+ bool isValid() const override { return m_renderingContext && !m_lost; }
+ QSurfaceFormat format() const override { return m_obtainedFormat; }
- void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE;
+ void swapBuffers(QPlatformSurface *surface) override;
- bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE;
- void doneCurrent() Q_DECL_OVERRIDE;
+ bool makeCurrent(QPlatformSurface *surface) override;
+ void doneCurrent() override;
typedef void (*GL_Proc) ();
- QFunctionPointer getProcAddress(const char *procName) Q_DECL_OVERRIDE;
+ QFunctionPointer getProcAddress(const char *procName) override;
HGLRC renderingContext() const { return m_renderingContext; }
- void *nativeContext() const Q_DECL_OVERRIDE { return m_renderingContext; }
+ void *nativeContext() const override { return m_renderingContext; }
private:
inline void releaseDCs();
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index 8adbd494c4..e7ebf73d5d 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -166,15 +166,8 @@ Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id); // from qlocale_win.cpp
HIMC QWindowsInputContext::m_defaultContext = 0;
-QWindowsInputContext::CompositionContext::CompositionContext() :
- hwnd(0), haveCaret(false), position(0), isComposing(false),
- factor(1)
-{
-}
-
QWindowsInputContext::QWindowsInputContext() :
m_WM_MSIME_MOUSE(RegisterWindowMessage(L"MSIMEMouseOperation")),
- m_endCompositionRecursionGuard(false),
m_languageId(currentInputLanguageId()),
m_locale(qt_localeFromLCID(m_languageId))
{
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h
index a7fa2c4f94..617ef30cef 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.h
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.h
@@ -57,15 +57,13 @@ class QWindowsInputContext : public QPlatformInputContext
struct CompositionContext
{
- CompositionContext();
-
- HWND hwnd;
- bool haveCaret;
+ HWND hwnd = 0;
+ bool haveCaret = false;
QString composition;
- int position;
- bool isComposing;
+ int position = 0;
+ bool isComposing = false;
QPointer<QObject> focusObject;
- qreal factor;
+ qreal factor = 1;
};
public:
explicit QWindowsInputContext();
@@ -73,13 +71,13 @@ public:
static void setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled);
- bool hasCapability(Capability capability) const Q_DECL_OVERRIDE;
- QLocale locale() const Q_DECL_OVERRIDE { return m_locale; }
+ bool hasCapability(Capability capability) const override;
+ QLocale locale() const override { return m_locale; }
- void reset() Q_DECL_OVERRIDE;
- void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE;
- void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE;
- void setFocusObject(QObject *object) Q_DECL_OVERRIDE;
+ void reset() override;
+ void update(Qt::InputMethodQueries) override;
+ void invokeAction(QInputMethod::Action, int cursorPosition) override;
+ void setFocusObject(QObject *object) override;
bool startComposition(HWND hwnd);
bool composition(HWND hwnd, LPARAM lParam);
@@ -104,7 +102,7 @@ private:
const DWORD m_WM_MSIME_MOUSE;
static HIMC m_defaultContext;
CompositionContext m_compositionContext;
- bool m_endCompositionRecursionGuard;
+ bool m_endCompositionRecursionGuard = false;
LCID m_languageId;
QLocale m_locale;
};
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 3f74fd5296..316f93e3ac 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -129,9 +129,9 @@ struct QWindowsIntegrationPrivate
explicit QWindowsIntegrationPrivate(const QStringList &paramList);
~QWindowsIntegrationPrivate();
- unsigned m_options;
+ unsigned m_options = 0;
QWindowsContext m_context;
- QPlatformFontDatabase *m_fontDatabase;
+ QPlatformFontDatabase *m_fontDatabase = nullptr;
#ifndef QT_NO_CLIPBOARD
QWindowsClipboard m_clipboard;
# ifndef QT_NO_DRAGANDDROP
@@ -209,8 +209,6 @@ static inline unsigned parseOptions(const QStringList &paramList,
}
QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramList)
- : m_options(0)
- , m_fontDatabase(0)
{
Q_INIT_RESOURCE(openglblacklists);
@@ -306,24 +304,6 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons
return result;
}
- if (window->type() == Qt::ForeignWindow) {
- const HWND hwnd = reinterpret_cast<HWND>(window->winId());
- if (!IsWindow(hwnd)) {
- qWarning("Windows QPA: Invalid foreign window ID %p.", hwnd);
- return nullptr;
- }
- QWindowsForeignWindow *result = new QWindowsForeignWindow(window, hwnd);
- const QRect obtainedGeometry = result->geometry();
- QScreen *screen = Q_NULLPTR;
- if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry))
- screen = pScreen->screen();
- if (screen && screen != window->screen())
- window->setScreen(screen);
- qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex
- << result->winId() << noshowbase << dec << obtainedGeometry << screen;
- return result;
- }
-
QWindowsWindowData requested;
requested.flags = window->flags();
requested.geometry = QHighDpi::toNativePixels(window->geometry(), window);
@@ -367,6 +347,25 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons
return result;
}
+QPlatformWindow *QWindowsIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
+{
+ const HWND hwnd = reinterpret_cast<HWND>(nativeHandle);
+ if (!IsWindow(hwnd)) {
+ qWarning("Windows QPA: Invalid foreign window ID %p.", hwnd);
+ return nullptr;
+ }
+ QWindowsForeignWindow *result = new QWindowsForeignWindow(window, hwnd);
+ const QRect obtainedGeometry = result->geometry();
+ QScreen *screen = Q_NULLPTR;
+ if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry))
+ screen = pScreen->screen();
+ if (screen && screen != window->screen())
+ window->setScreen(screen);
+ qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex
+ << result->winId() << noshowbase << dec << obtainedGeometry << screen;
+ return result;
+}
+
// Overridden to return a QWindowsDirect2DWindow in Direct2D plugin.
QWindowsWindow *QWindowsIntegration::createPlatformWindowHelper(QWindow *window, const QWindowsWindowData &data) const
{
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index a668470993..607203829f 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -70,34 +70,35 @@ public:
explicit QWindowsIntegration(const QStringList &paramList);
virtual ~QWindowsIntegration();
- bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
+ bool hasCapability(QPlatformIntegration::Capability cap) const override;
- QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
#ifndef QT_NO_OPENGL
- QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE;
- QOpenGLContext::OpenGLModuleType openGLModuleType() Q_DECL_OVERRIDE;
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
+ QOpenGLContext::OpenGLModuleType openGLModuleType() override;
static QWindowsStaticOpenGLContext *staticOpenGLContext();
#endif
- QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE;
- void initialize() Q_DECL_OVERRIDE;
+ QAbstractEventDispatcher *createEventDispatcher() const override;
+ void initialize() override;
#ifndef QT_NO_CLIPBOARD
- QPlatformClipboard *clipboard() const Q_DECL_OVERRIDE;
+ QPlatformClipboard *clipboard() const override;
# ifndef QT_NO_DRAGANDDROP
- QPlatformDrag *drag() const Q_DECL_OVERRIDE;
+ QPlatformDrag *drag() const override;
# endif
#endif // !QT_NO_CLIPBOARD
- QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE;
+ QPlatformInputContext *inputContext() const override;
#ifndef QT_NO_ACCESSIBILITY
- QPlatformAccessibility *accessibility() const Q_DECL_OVERRIDE;
+ QPlatformAccessibility *accessibility() const override;
#endif
- QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE;
- QStringList themeNames() const Q_DECL_OVERRIDE;
- QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE;
- QPlatformServices *services() const Q_DECL_OVERRIDE;
- QVariant styleHint(StyleHint hint) const Q_DECL_OVERRIDE;
+ QPlatformFontDatabase *fontDatabase() const override;
+ QStringList themeNames() const override;
+ QPlatformTheme *createPlatformTheme(const QString &name) const override;
+ QPlatformServices *services() const override;
+ QVariant styleHint(StyleHint hint) const override;
- Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE;
- QList<int> possibleKeys(const QKeyEvent *e) const Q_DECL_OVERRIDE;
+ Qt::KeyboardModifiers queryKeyboardModifiers() const override;
+ QList<int> possibleKeys(const QKeyEvent *e) const override;
static QWindowsIntegration *instance() { return m_instance; }
@@ -106,10 +107,10 @@ public:
unsigned options() const;
- void beep() const Q_DECL_OVERRIDE;
+ void beep() const override;
#if !defined(QT_NO_SESSIONMANAGER)
- QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const Q_DECL_OVERRIDE;
+ QPlatformSessionManager *createPlatformSessionManager(const QString &id, const QString &key) const override;
#endif
protected:
diff --git a/src/plugins/platforms/windows/qwindowsinternalmimedata.h b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
index 4d775b1f21..a7df1ee6e0 100644
--- a/src/plugins/platforms/windows/qwindowsinternalmimedata.h
+++ b/src/plugins/platforms/windows/qwindowsinternalmimedata.h
@@ -52,9 +52,9 @@ class QDebug;
// Implementation in qwindowsclipboard.cpp.
class QWindowsInternalMimeData : public QInternalMimeData {
public:
- bool hasFormat_sys(const QString &mimetype) const Q_DECL_OVERRIDE;
- QStringList formats_sys() const Q_DECL_OVERRIDE;
- QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const Q_DECL_OVERRIDE;
+ bool hasFormat_sys(const QString &mimetype) const override;
+ QStringList formats_sys() const override;
+ QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const override;
protected:
virtual IDataObject *retrieveDataObject() const = 0;
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index b84b586f7c..24c2df86d4 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -144,13 +144,11 @@ struct KeyRecord {
static const int QT_MAX_KEY_RECORDINGS = 64; // User has LOTS of fingers...
struct KeyRecorder
{
- KeyRecorder() : nrecs(0) {}
-
inline KeyRecord *findKey(int code, bool remove);
inline void storeKey(int code, int ascii, int state, const QString& text);
inline void clearKeys();
- int nrecs;
+ int nrecs = 0;
KeyRecord deleted_record; // A copy of last entry removed from records[]
KeyRecord records[QT_MAX_KEY_RECORDINGS];
};
@@ -973,7 +971,8 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
state = state ^ Qt::ShiftModifier;
else if (code == Qt::Key_Alt)
state = state ^ Qt::AltModifier;
-
+ else if (code == 0 && modifiersIndex != 0)
+ code = keyLayout[vk_key].qtKey[0];
// If the bit 24 of lParm is set you received a enter,
// otherwise a Return. (This is the extended key bit)
if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000))
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 30d438a127..bd4822c664 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -717,7 +717,7 @@ QVariant QWindowsMimeText::convertToMime(const QString &mime, LPDATAOBJECT pData
if (preferredType == QVariant::String)
ret = str;
else
- ret = str.toUtf8();
+ ret = std::move(str).toUtf8();
}
qCDebug(lcQpaMime) << __FUNCTION__ << ret;
return ret;
@@ -893,14 +893,14 @@ public:
QWindowsMimeHtml();
// for converting from Qt
- bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE;
- bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE;
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
// for converting to Qt
- bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE;
- QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE;
- QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE;
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override;
+ QString mimeForFormat(const FORMATETC &formatetc) const override;
private:
int CF_HTML;
@@ -1025,14 +1025,14 @@ class QWindowsMimeImage : public QWindowsMime
public:
QWindowsMimeImage();
// for converting from Qt
- bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE;
- bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE;
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
// for converting to Qt
- bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE;
- QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE;
- QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE;
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override;
+ QString mimeForFormat(const FORMATETC &formatetc) const override;
private:
bool hasOriginalDIBV5(IDataObject *pDataObj) const;
UINT CF_PNG;
@@ -1179,14 +1179,14 @@ public:
QBuiltInMimes();
// for converting from Qt
- bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE;
- bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE;
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
// for converting to Qt
- bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE;
- QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE;
- QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE;
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override;
+ QString mimeForFormat(const FORMATETC &formatetc) const override;
private:
QMap<int, QString> outFormats;
@@ -1299,14 +1299,14 @@ public:
QLastResortMimes();
// for converting from Qt
- bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE;
- bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE;
- QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE;
+ bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const override;
+ bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const override;
+ QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const override;
// for converting to Qt
- bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE;
- QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE;
- QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE;
+ bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const override;
+ QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const override;
+ QString mimeForFormat(const FORMATETC &formatetc) const override;
private:
QMap<int, QString> formats;
@@ -1496,9 +1496,7 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const
\sa QWindowsMime
*/
-QWindowsMimeConverter::QWindowsMimeConverter() : m_internalMimeCount(0)
-{
-}
+QWindowsMimeConverter::QWindowsMimeConverter() = default;
QWindowsMimeConverter::~QWindowsMimeConverter()
{
diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h
index 4c0cbf9f31..1ed2aa933f 100644
--- a/src/plugins/platforms/windows/qwindowsmime.h
+++ b/src/plugins/platforms/windows/qwindowsmime.h
@@ -96,7 +96,7 @@ private:
void ensureInitialized() const;
mutable QList<QWindowsMime *> m_mimes;
- mutable int m_internalMimeCount;
+ mutable int m_internalMimeCount = 0;
};
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index e4025fe60d..34c34fd28e 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -185,14 +185,7 @@ static inline QTouchDevice *createTouchDevice()
\ingroup qt-lighthouse-win
*/
-QWindowsMouseHandler::QWindowsMouseHandler() :
- m_windowUnderMouse(0),
- m_trackedWindow(0),
- m_touchDevice(Q_NULLPTR),
- m_leftButtonDown(false),
- m_previousCaptureWindow(0)
-{
-}
+QWindowsMouseHandler::QWindowsMouseHandler() = default;
QTouchDevice *QWindowsMouseHandler::ensureTouchDevice()
{
@@ -421,7 +414,7 @@ static bool isValidWheelReceiver(QWindow *candidate)
{
if (candidate) {
const QWindow *toplevel = QWindowsWindow::topLevelOf(candidate);
- if (toplevel->type() == Qt::ForeignWindow)
+ if (toplevel->handle() && toplevel->handle()->isForeignWindow())
return true;
if (const QWindowsWindow *ww = QWindowsWindow::windowsWindowOf(toplevel))
return !ww->testFlag(QWindowsWindow::BlockedByModal);
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h
index bd36d9f44c..86f18a0482 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.h
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.h
@@ -88,9 +88,9 @@ private:
QPointer<QWindow> m_trackedWindow;
QHash<DWORD, int> m_touchInputIDToTouchPointID;
QHash<int, QPointF> m_lastTouchPositions;
- QTouchDevice *m_touchDevice;
- bool m_leftButtonDown;
- QWindow *m_previousCaptureWindow;
+ QTouchDevice *m_touchDevice = nullptr;
+ bool m_leftButtonDown = false;
+ QWindow *m_previousCaptureWindow = nullptr;
};
Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(int wParam)
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
index eaa6e45b9f..d750eef19d 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qwindowsnativeinterface.h"
+#include "qwindowsclipboard.h"
#include "qwindowswindow.h"
#include "qwindowscontext.h"
#include "qwindowscursor.h"
@@ -45,6 +46,7 @@
#include "qwindowsopengltester.h"
#include "qwindowsintegration.h"
#include "qwindowsmime.h"
+#include "qwin10helpers.h"
#include <QtGui/QWindow>
#include <QtGui/QOpenGLContext>
@@ -108,6 +110,7 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc
}
break;
case QWindow::OpenGLSurface:
+ case QWindow::OpenVGSurface:
break;
}
qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
@@ -252,14 +255,23 @@ QFont QWindowsNativeInterface::logFontToQFont(const void *logFont, int verticalD
return QWindowsFontDatabase::LOGFONT_to_QFont(*reinterpret_cast<const LOGFONT *>(logFont), verticalDpi);
}
+bool QWindowsNativeInterface::isTabletMode()
+{
+#if QT_CONFIG(clipboard)
+ if (const QWindowsClipboard *clipboard = QWindowsClipboard::instance())
+ return qt_windowsIsTabletMode(clipboard->clipboardViewer());
+#endif
+ return false;
+}
+
QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &function) const
{
if (function == QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier())
return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic);
else if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier())
return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic);
- else if (function == QWindowsWindowFunctions::setWindowActivationBehaviorIdentifier())
- return QFunctionPointer(QWindowsNativeInterface::setWindowActivationBehavior);
+ else if (function == QWindowsWindowFunctions::isTabletModeIdentifier())
+ return QFunctionPointer(QWindowsNativeInterface::isTabletMode);
return Q_NULLPTR;
}
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h
index 9fc43ddcce..d085a4afb3 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.h
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h
@@ -68,13 +68,13 @@ class QWindowsNativeInterface : public QPlatformNativeInterface
Q_PROPERTY(QVariant gpu READ gpu STORED false)
public:
- void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE;
+ void *nativeResourceForIntegration(const QByteArray &resource) override;
#ifndef QT_NO_OPENGL
- void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE;
+ void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override;
#endif
- void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE;
+ void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override;
#ifndef QT_NO_CURSOR
- void *nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor) Q_DECL_OVERRIDE;
+ void *nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor) override;
#endif
Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate,
const QString &windowName,
@@ -92,17 +92,19 @@ public:
QVariant gpu() const;
- QVariantMap windowProperties(QPlatformWindow *window) const Q_DECL_OVERRIDE;
- QVariant windowProperty(QPlatformWindow *window, const QString &name) const Q_DECL_OVERRIDE;
- QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const Q_DECL_OVERRIDE;
- void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) Q_DECL_OVERRIDE;
+ QVariantMap windowProperties(QPlatformWindow *window) const override;
+ QVariant windowProperty(QPlatformWindow *window, const QString &name) const override;
+ QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const override;
+ void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) override;
static QWindowsWindowFunctions::WindowActivationBehavior windowActivationBehavior()
{ return QWindowsNativeInterface::m_windowActivationBehavior; }
static void setWindowActivationBehavior(QWindowsWindowFunctions::WindowActivationBehavior b)
{ QWindowsNativeInterface::m_windowActivationBehavior = b; }
- QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE;
+ static bool isTabletMode();
+
+ QFunctionPointer platformFunction(const QByteArray &function) const override;
private:
static QWindowsWindowFunctions::WindowActivationBehavior m_windowActivationBehavior;
diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp
index a1a8c0b499..9b71061aa5 100644
--- a/src/plugins/platforms/windows/qwindowsole.cpp
+++ b/src/plugins/platforms/windows/qwindowsole.cpp
@@ -74,9 +74,8 @@ QT_BEGIN_NAMESPACE
*/
QWindowsOleDataObject::QWindowsOleDataObject(QMimeData *mimeData) :
- m_refs(1), data(mimeData),
- CF_PERFORMEDDROPEFFECT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT)),
- performedEffect(DROPEFFECT_NONE)
+ data(mimeData),
+ CF_PERFORMEDDROPEFFECT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT))
{
qCDebug(lcQpaMime) << __FUNCTION__ << mimeData->formats();
}
@@ -267,8 +266,7 @@ QWindowsOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*)
\ingroup qt-lighthouse-win
*/
-QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) :
- m_dwRefs(1), m_nIndex(0), m_isNull(false)
+QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs)
{
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaMime) << __FUNCTION__ << fmtetcs;
@@ -285,8 +283,7 @@ QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs)
}
}
-QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs) :
- m_dwRefs(1), m_nIndex(0), m_isNull(false)
+QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs)
{
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaMime) << __FUNCTION__;
diff --git a/src/plugins/platforms/windows/qwindowsole.h b/src/plugins/platforms/windows/qwindowsole.h
index dc31c793e9..643011272b 100644
--- a/src/plugins/platforms/windows/qwindowsole.h
+++ b/src/plugins/platforms/windows/qwindowsole.h
@@ -82,10 +82,10 @@ public:
STDMETHOD(EnumDAdvise)(LPENUMSTATDATA FAR* ppenumAdvise);
private:
- ULONG m_refs;
+ ULONG m_refs = 1;
QPointer<QMimeData> data;
- int CF_PERFORMEDDROPEFFECT;
- DWORD performedEffect;
+ const int CF_PERFORMEDDROPEFFECT;
+ DWORD performedEffect = DROPEFFECT_NONE;
};
class QWindowsOleEnumFmtEtc : public IEnumFORMATETC
@@ -111,10 +111,10 @@ public:
private:
bool copyFormatEtc(LPFORMATETC dest, const FORMATETC *src) const;
- ULONG m_dwRefs;
- ULONG m_nIndex;
+ ULONG m_dwRefs = 1;
+ ULONG m_nIndex = 0;
QVector<LPFORMATETC> m_lpfmtetcs;
- bool m_isNull;
+ bool m_isNull = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h
index 39e20b55d1..e3fec59dd5 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.h
+++ b/src/plugins/platforms/windows/qwindowsopengltester.h
@@ -51,16 +51,14 @@ class QVariant;
struct GpuDescription
{
- GpuDescription() : vendorId(0), deviceId(0), revision(0), subSysId(0) {}
-
static GpuDescription detect();
QString toString() const;
QVariant toVariant() const;
- uint vendorId;
- uint deviceId;
- uint revision;
- uint subSysId;
+ uint vendorId = 0;
+ uint deviceId = 0;
+ uint revision = 0;
+ uint subSysId = 0;
QVersionNumber driverVersion;
QByteArray driverName;
QByteArray description;
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index c70323c06f..24fb12d27a 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -56,13 +56,6 @@
QT_BEGIN_NAMESPACE
-QWindowsScreenData::QWindowsScreenData() :
- dpi(96, 96), depth(32), format(QImage::Format_ARGB32_Premultiplied),
- flags(VirtualDesktop), orientation(Qt::LandscapeOrientation),
- refreshRateHz(60)
-{
-}
-
static inline QDpi deviceDPI(HDC hdc)
{
return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
@@ -89,6 +82,7 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
if (GetMonitorInfo(hMonitor, &info) == FALSE)
return false;
+ data->hMonitor = hMonitor;
data->geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1));
data->availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1));
data->name = QString::fromWCharArray(info.szDevice);
@@ -423,10 +417,7 @@ QPlatformScreen::SubpixelAntialiasingType QWindowsScreen::subpixelAntialiasingTy
\ingroup qt-lighthouse-win
*/
-QWindowsScreenManager::QWindowsScreenManager() :
- m_lastDepth(-1), m_lastHorizontalResolution(0), m_lastVerticalResolution(0)
-{
-}
+QWindowsScreenManager::QWindowsScreenManager() = default;
/*!
\brief Triggers synchronization of screens (WM_DISPLAYCHANGE).
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index 02a9dc3bc3..9a8997326b 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -59,18 +59,17 @@ struct QWindowsScreenData
LockScreen = 0x4 // Temporary screen existing during user change, etc.
};
- QWindowsScreenData();
-
QRect geometry;
QRect availableGeometry;
- QDpi dpi;
+ QDpi dpi{96, 96};
QSizeF physicalSizeMM;
- int depth;
- QImage::Format format;
- unsigned flags;
+ int depth = 32;
+ QImage::Format format = QImage::Format_ARGB32_Premultiplied;
+ unsigned flags = VirtualDesktop;
QString name;
- Qt::ScreenOrientation orientation;
- qreal refreshRateHz;
+ Qt::ScreenOrientation orientation = Qt::LandscapeOrientation;
+ qreal refreshRateHz = 60;
+ HMONITOR hMonitor = nullptr;
};
class QWindowsScreen : public QPlatformScreen
@@ -82,23 +81,23 @@ public:
explicit QWindowsScreen(const QWindowsScreenData &data);
- QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; }
- QRect availableGeometry() const Q_DECL_OVERRIDE { return m_data.availableGeometry; }
- int depth() const Q_DECL_OVERRIDE { return m_data.depth; }
- QImage::Format format() const Q_DECL_OVERRIDE { return m_data.format; }
- QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_data.physicalSizeMM; }
- QDpi logicalDpi() const Q_DECL_OVERRIDE { return m_data.dpi; }
- qreal pixelDensity() const Q_DECL_OVERRIDE;
- qreal devicePixelRatio() const Q_DECL_OVERRIDE { return 1.0; }
- qreal refreshRate() const Q_DECL_OVERRIDE { return m_data.refreshRateHz; }
- QString name() const Q_DECL_OVERRIDE { return m_data.name; }
- Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_data.orientation; }
- QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE;
- QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE;
+ QRect geometry() const override { return m_data.geometry; }
+ QRect availableGeometry() const override { return m_data.availableGeometry; }
+ int depth() const override { return m_data.depth; }
+ QImage::Format format() const override { return m_data.format; }
+ QSizeF physicalSize() const override { return m_data.physicalSizeMM; }
+ QDpi logicalDpi() const override { return m_data.dpi; }
+ qreal pixelDensity() const override;
+ qreal devicePixelRatio() const override { return 1.0; }
+ qreal refreshRate() const override { return m_data.refreshRateHz; }
+ QString name() const override { return m_data.name; }
+ Qt::ScreenOrientation orientation() const override { return m_data.orientation; }
+ QList<QPlatformScreen *> virtualSiblings() const override;
+ QWindow *topLevelAt(const QPoint &point) const override;
static QWindow *windowAt(const QPoint &point, unsigned flags);
- QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const Q_DECL_OVERRIDE;
- QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const Q_DECL_OVERRIDE;
+ QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const override;
+ QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override;
static Qt::ScreenOrientation orientationPreference();
static bool setOrientationPreference(Qt::ScreenOrientation o);
@@ -106,7 +105,7 @@ public:
inline void handleChanges(const QWindowsScreenData &newData);
#ifndef QT_NO_CURSOR
- QPlatformCursor *cursor() const Q_DECL_OVERRIDE { return m_cursor.data(); }
+ QPlatformCursor *cursor() const override { return m_cursor.data(); }
const CursorPtr &cursorPtr() const { return m_cursor; }
#else
QPlatformCursor *cursor() const { return 0; }
@@ -140,9 +139,9 @@ private:
void removeScreen(int index);
WindowsScreenList m_screens;
- int m_lastDepth;
- WORD m_lastHorizontalResolution;
- WORD m_lastVerticalResolution;
+ int m_lastDepth = -1;
+ WORD m_lastHorizontalResolution = 0;
+ WORD m_lastVerticalResolution = 0;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp
index 7f9c9bd205..48332b35f8 100644
--- a/src/plugins/platforms/windows/qwindowsservices.cpp
+++ b/src/plugins/platforms/windows/qwindowsservices.cpp
@@ -98,7 +98,11 @@ static inline QString mailCommand()
RegQueryValueEx(handle, L"", 0, 0, reinterpret_cast<unsigned char*>(command), &bufferSize);
RegCloseKey(handle);
}
- if (!command[0])
+ // QTBUG-57816: As of Windows 10, if there is no mail client installed, an entry like
+ // "rundll32.exe .. url.dll,MailToProtocolHandler %l" is returned. Launching it
+ // silently fails or brings up a broken dialog after a long time, so exclude it and
+ // fall back to ShellExecute() which brings up the URL assocation dialog.
+ if (!command[0] || wcsstr(command, L",MailToProtocolHandler") != nullptr)
return QString();
wchar_t expandedCommand[MAX_PATH] = {0};
return ExpandEnvironmentStrings(command, expandedCommand, MAX_PATH) ?
diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.cpp b/src/plugins/platforms/windows/qwindowssessionmanager.cpp
index 2db9e44388..500fdc750c 100644
--- a/src/plugins/platforms/windows/qwindowssessionmanager.cpp
+++ b/src/plugins/platforms/windows/qwindowssessionmanager.cpp
@@ -44,9 +44,6 @@ QT_BEGIN_NAMESPACE
QWindowsSessionManager::QWindowsSessionManager(const QString &id, const QString &key)
: QPlatformSessionManager(id, key)
- , m_isActive(false)
- , m_blockUserInput(false)
- , m_canceled(false)
{
}
diff --git a/src/plugins/platforms/windows/qwindowssessionmanager.h b/src/plugins/platforms/windows/qwindowssessionmanager.h
index 25d0636650..4c4256f2b0 100644
--- a/src/plugins/platforms/windows/qwindowssessionmanager.h
+++ b/src/plugins/platforms/windows/qwindowssessionmanager.h
@@ -59,15 +59,15 @@ class QWindowsSessionManager : public QPlatformSessionManager
public:
explicit QWindowsSessionManager(const QString &id, const QString &key);
- bool allowsInteraction() Q_DECL_OVERRIDE;
- bool allowsErrorInteraction() Q_DECL_OVERRIDE;
+ bool allowsInteraction() override;
+ bool allowsErrorInteraction() override;
void blocksInteraction() { m_blockUserInput = true; }
bool isInteractionBlocked() const { return m_blockUserInput; }
- void release() Q_DECL_OVERRIDE;
+ void release() override;
- void cancel() Q_DECL_OVERRIDE;
+ void cancel() override;
void clearCancellation() { m_canceled = false; }
bool wasCanceled() const { return m_canceled; }
@@ -75,9 +75,9 @@ public:
bool isActive() const { return m_isActive;}
private:
- bool m_isActive;
- bool m_blockUserInput;
- bool m_canceled;
+ bool m_isActive = false;
+ bool m_blockUserInput = false;
+ bool m_canceled = false;
Q_DISABLE_COPY(QWindowsSessionManager)
};
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h
index 2c05dcddfc..97eceaf2cc 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.h
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.h
@@ -57,9 +57,6 @@ class QRect;
struct QWindowsWinTab32DLL
{
- QWindowsWinTab32DLL() : wTOpen(0), wTClose(0), wTInfo(0), wTEnable(0), wTOverlap(0), wTPacketsGet(0), wTGet(0),
- wTQueueSizeGet(0), wTQueueSizeSet(0) {}
-
bool init();
typedef HCTX (API *PtrWTOpen)(HWND, LPLOGCONTEXT, BOOL);
@@ -72,15 +69,15 @@ struct QWindowsWinTab32DLL
typedef int (API *PtrWTQueueSizeGet)(HCTX);
typedef BOOL (API *PtrWTQueueSizeSet)(HCTX, int);
- PtrWTOpen wTOpen;
- PtrWTClose wTClose;
- PtrWTInfo wTInfo;
- PtrWTEnable wTEnable;
- PtrWTOverlap wTOverlap;
- PtrWTPacketsGet wTPacketsGet;
- PtrWTGet wTGet;
- PtrWTQueueSizeGet wTQueueSizeGet;
- PtrWTQueueSizeSet wTQueueSizeSet;
+ PtrWTOpen wTOpen = nullptr;
+ PtrWTClose wTClose = nullptr;
+ PtrWTInfo wTInfo = nullptr;
+ PtrWTEnable wTEnable = nullptr;
+ PtrWTOverlap wTOverlap = nullptr;
+ PtrWTPacketsGet wTPacketsGet = nullptr;
+ PtrWTGet wTGet = nullptr;
+ PtrWTQueueSizeGet wTQueueSizeGet = nullptr;
+ PtrWTQueueSizeSet wTQueueSizeSet = nullptr;
};
struct QWindowsTabletDeviceData
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index ed12c8124e..3e2cb5e9e9 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -61,6 +61,9 @@
#include <QtCore/QTextStream>
#include <QtCore/QSysInfo>
#include <QtCore/QCache>
+#include <QtCore/QThread>
+#include <QtCore/QMutex>
+#include <QtCore/QWaitCondition>
#include <QtGui/QColor>
#include <QtGui/QPalette>
#include <QtGui/QGuiApplication>
@@ -127,40 +130,114 @@ static inline QColor getSysColor(int index)
// QTBUG-48823/Windows 10: SHGetFileInfo() (as called by item views on file system
// models has been observed to trigger a WM_PAINT on the mainwindow. Suppress the
// behavior by running it in a thread.
-class ShGetFileInfoFunction
+
+struct QShGetFileInfoParams
+{
+ QShGetFileInfoParams(const QString &fn, DWORD a, SHFILEINFO *i, UINT f, bool *r)
+ : fileName(fn), attributes(a), flags(f), info(i), result(r)
+ { }
+
+ const QString &fileName;
+ const DWORD attributes;
+ const UINT flags;
+ SHFILEINFO *const info;
+ bool *const result;
+};
+
+class QShGetFileInfoThread : public QThread
{
public:
- explicit ShGetFileInfoFunction(const wchar_t *fn, DWORD a, SHFILEINFO *i, UINT f, bool *r) :
- m_fileName(fn), m_attributes(a), m_flags(f), m_info(i), m_result(r) {}
+ explicit QShGetFileInfoThread()
+ : QThread(), m_params(nullptr)
+ {
+ connect(this, &QThread::finished, this, &QObject::deleteLater);
+ }
- void operator()() const
+ void run() override
{
+ m_init = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+ QMutexLocker readyLocker(&m_readyMutex);
+ while (!m_cancelled.load()) {
+ if (!m_params && !m_cancelled.load()
+ && !m_readyCondition.wait(&m_readyMutex, 1000))
+ continue;
+
+ if (m_params) {
+ const QString fileName = m_params->fileName;
+ SHFILEINFO info;
#ifndef Q_OS_WINCE
- const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+ const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
#endif
- *m_result = SHGetFileInfo(m_fileName, m_attributes, m_info, sizeof(SHFILEINFO), m_flags);
+ const bool result = SHGetFileInfo(reinterpret_cast<const wchar_t *>(fileName.utf16()),
+ m_params->attributes, &info, sizeof(SHFILEINFO),
+ m_params->flags);
#ifndef Q_OS_WINCE
- SetErrorMode(oldErrorMode);
+ SetErrorMode(oldErrorMode);
#endif
+ m_doneMutex.lock();
+ if (!m_cancelled.load()) {
+ *m_params->result = result;
+ memcpy(m_params->info, &info, sizeof(SHFILEINFO));
+ }
+ m_params = nullptr;
+
+ m_doneCondition.wakeAll();
+ m_doneMutex.unlock();
+ }
+ }
+
+ if (m_init != S_FALSE)
+ CoUninitialize();
+ }
+
+ bool runWithParams(QShGetFileInfoParams *params, unsigned long timeOutMSecs)
+ {
+ QMutexLocker doneLocker(&m_doneMutex);
+
+ m_readyMutex.lock();
+ m_params = params;
+ m_readyCondition.wakeAll();
+ m_readyMutex.unlock();
+
+ return m_doneCondition.wait(&m_doneMutex, timeOutMSecs);
+ }
+
+ void cancel()
+ {
+ QMutexLocker doneLocker(&m_doneMutex);
+ m_cancelled.store(1);
+ m_readyCondition.wakeAll();
}
private:
- const wchar_t *m_fileName;
- const DWORD m_attributes;
- const UINT m_flags;
- SHFILEINFO *const m_info;
- bool *m_result;
+ HRESULT m_init;
+ QShGetFileInfoParams *m_params;
+ QAtomicInt m_cancelled;
+ QWaitCondition m_readyCondition;
+ QWaitCondition m_doneCondition;
+ QMutex m_readyMutex;
+ QMutex m_doneMutex;
};
-static bool shGetFileInfoBackground(QWindowsThreadPoolRunner &r,
- const wchar_t *fileName, DWORD attributes,
+static bool shGetFileInfoBackground(const QString &fileName, DWORD attributes,
SHFILEINFO *info, UINT flags,
unsigned long timeOutMSecs = 5000)
{
+ static QShGetFileInfoThread *getFileInfoThread = nullptr;
+ if (!getFileInfoThread) {
+ getFileInfoThread = new QShGetFileInfoThread;
+ getFileInfoThread->start();
+ }
+
bool result = false;
- if (!r.run(ShGetFileInfoFunction(fileName, attributes, info, flags, &result), timeOutMSecs)) {
- qWarning().noquote() << "ShGetFileInfoBackground() timed out for "
- << QString::fromWCharArray(fileName);
+ QShGetFileInfoParams params(fileName, attributes, info, flags, &result);
+ if (!getFileInfoThread->runWithParams(&params, timeOutMSecs)) {
+ // Cancel and reset getFileInfoThread. It'll
+ // be reinitialized the next time we get called.
+ getFileInfoThread->cancel();
+ getFileInfoThread = nullptr;
+ qWarning().noquote() << "SHGetFileInfo() timed out for " << fileName;
return false;
}
return result;
@@ -315,7 +392,6 @@ const char *QWindowsTheme::name = "windows";
QWindowsTheme *QWindowsTheme::m_instance = 0;
QWindowsTheme::QWindowsTheme()
- : m_threadPoolRunner(new QWindowsThreadPoolRunner)
{
m_instance = this;
std::fill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0));
@@ -718,10 +794,8 @@ static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
class QWindowsFileIconEngine : public QAbstractFileIconEngine
{
public:
- explicit QWindowsFileIconEngine(const QFileInfo &info,
- QPlatformTheme::IconOptions opts,
- const QSharedPointer<QWindowsThreadPoolRunner> &runner) :
- QAbstractFileIconEngine(info, opts), m_threadPoolRunner(runner) {}
+ explicit QWindowsFileIconEngine(const QFileInfo &info, QPlatformTheme::IconOptions opts) :
+ QAbstractFileIconEngine(info, opts) {}
QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) const override
{ return QWindowsTheme::instance()->availableFileIconSizes(); }
@@ -729,9 +803,6 @@ public:
protected:
QString cacheKey() const override;
QPixmap filePixmap(const QSize &size, QIcon::Mode mode, QIcon::State) override;
-
-private:
- const QSharedPointer<QWindowsThreadPoolRunner> m_threadPoolRunner;
};
QString QWindowsFileIconEngine::cacheKey() const
@@ -744,14 +815,14 @@ QString QWindowsFileIconEngine::cacheKey() const
// Return "" for .exe, .lnk and .ico extensions.
// It is faster to just look at the file extensions;
// avoiding slow QFileInfo::isExecutable() (QTBUG-13182)
- const QString &suffix = fileInfo().suffix();
+ QString suffix = fileInfo().suffix();
if (!suffix.compare(QLatin1String("exe"), Qt::CaseInsensitive)
|| !suffix.compare(QLatin1String("lnk"), Qt::CaseInsensitive)
|| !suffix.compare(QLatin1String("ico"), Qt::CaseInsensitive)) {
return QString();
}
return QLatin1String("qt_.")
- + (suffix.isEmpty() ? fileInfo().fileName() : suffix.toUpper()); // handle "Makefile" ;)
+ + (suffix.isEmpty() ? fileInfo().fileName() : std::move(suffix).toUpper()); // handle "Makefile" ;)
}
QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon::State)
@@ -797,10 +868,8 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon
SHGFI_ICON|iconSize|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS|SHGFI_OVERLAYINDEX;
const bool val = cacheableDirIcon && useDefaultFolderIcon
- ? shGetFileInfoBackground(*m_threadPoolRunner.data(), L"dummy", FILE_ATTRIBUTE_DIRECTORY,
- &info, flags | SHGFI_USEFILEATTRIBUTES)
- : shGetFileInfoBackground(*m_threadPoolRunner.data(), reinterpret_cast<const wchar_t *>(filePath.utf16()), 0,
- &info, flags);
+ ? shGetFileInfoBackground(QString::fromWCharArray(L"dummy"), FILE_ATTRIBUTE_DIRECTORY, &info, flags | SHGFI_USEFILEATTRIBUTES)
+ : shGetFileInfoBackground(filePath, 0, &info, flags);
// Even if GetFileInfo returns a valid result, hIcon can be empty in some cases
if (val && info.hIcon) {
@@ -844,7 +913,7 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon
QIcon QWindowsTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const
{
- return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions, m_threadPoolRunner));
+ return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions));
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index 0384899efa..a3019ff6eb 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -40,7 +40,6 @@
#ifndef QWINDOWSTHEME_H
#define QWINDOWSTHEME_H
-#include "qwindowsthreadpoolrunner.h"
#include <qpa/qplatformtheme.h>
#include <QtCore/QSharedPointer>
@@ -58,15 +57,15 @@ public:
static QWindowsTheme *instance() { return m_instance; }
- bool usePlatformNativeDialog(DialogType type) const Q_DECL_OVERRIDE;
- QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const Q_DECL_OVERRIDE;
- QVariant themeHint(ThemeHint) const Q_DECL_OVERRIDE;
- const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE
+ bool usePlatformNativeDialog(DialogType type) const override;
+ QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
+ QVariant themeHint(ThemeHint) const override;
+ const QPalette *palette(Palette type = SystemPalette) const override
{ return m_palettes[type]; }
- const QFont *font(Font type = SystemFont) const Q_DECL_OVERRIDE
+ const QFont *font(Font type = SystemFont) const override
{ return m_fonts[type]; }
- QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const Q_DECL_OVERRIDE;
+ QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override;
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions = 0) const override;
@@ -88,7 +87,6 @@ private:
static QWindowsTheme *m_instance;
QPalette *m_palettes[NPalettes];
QFont *m_fonts[NFonts];
- const QSharedPointer<QWindowsThreadPoolRunner> m_threadPoolRunner;
QList<QSize> m_fileIconSizes;
};
diff --git a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
index 0361aa90f5..5601cc9305 100644
--- a/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
+++ b/src/plugins/platforms/windows/qwindowsthreadpoolrunner.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -63,7 +69,7 @@ class QWindowsThreadPoolRunner
explicit Runnable(QMutex *m, QWaitCondition *c, RunnableFunction f)
: m_mutex(m), m_condition(c), m_function(f) {}
- void run() Q_DECL_OVERRIDE
+ void run() override
{
m_function();
m_mutex->lock();
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 48835f26a6..2875463e62 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -118,6 +118,35 @@ static QByteArray debugWinExStyle(DWORD exStyle)
return rc;
}
+static QByteArray debugWinSwpPos(UINT flags)
+{
+ QByteArray rc = "0x";
+ rc += QByteArray::number(flags, 16);
+ if (flags & SWP_FRAMECHANGED)
+ rc += " SWP_FRAMECHANGED";
+ if (flags & SWP_HIDEWINDOW)
+ rc += " SWP_HIDEWINDOW";
+ if (flags & SWP_NOACTIVATE)
+ rc += " SWP_NOACTIVATE";
+ if (flags & SWP_NOCOPYBITS)
+ rc += " SWP_NOCOPYBITS";
+ if (flags & SWP_NOMOVE)
+ rc += " SWP_NOMOVE";
+ if (flags & SWP_NOOWNERZORDER)
+ rc += " SWP_NOOWNERZORDER";
+ if (flags & SWP_NOREDRAW)
+ rc += " SWP_NOREDRAW";
+ if (flags & SWP_NOSENDCHANGING)
+ rc += " SWP_NOSENDCHANGING";
+ if (flags & SWP_NOSIZE)
+ rc += " SWP_NOSIZE";
+ if (flags & SWP_NOZORDER)
+ rc += " SWP_NOZORDER";
+ if (flags & SWP_SHOWWINDOW)
+ rc += " SWP_SHOWWINDOW";
+ return rc;
+}
+
static inline QSize qSizeOfRect(const RECT &rect)
{
return QSize(rect.right -rect.left, rect.bottom - rect.top);
@@ -141,8 +170,9 @@ QDebug operator<<(QDebug d, const RECT &r)
{
QDebugStateSaver saver(d);
d.nospace();
- d << "RECT: left/top=" << r.left << ',' << r.top
- << " right/bottom=" << r.right << ',' << r.bottom;
+ d << "RECT(left=" << r.left << ", top=" << r.top
+ << ", right=" << r.right << ", bottom=" << r.bottom
+ << " (" << r.right - r.left << 'x' << r.bottom - r.top << "))";
return d;
}
@@ -152,12 +182,23 @@ QDebug operator<<(QDebug d, const POINT &p)
return d;
}
+QDebug operator<<(QDebug d, const WINDOWPOS &wp)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d.noquote();
+ d << "WINDOWPOS(flags=" << debugWinSwpPos(wp.flags) << ", hwnd="
+ << wp.hwnd << ", hwndInsertAfter=" << wp.hwndInsertAfter << ", x=" << wp.x
+ << ", y=" << wp.y << ", cx=" << wp.cx << ", cy=" << wp.cy << ')';
+ return d;
+}
+
QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p)
{
QDebugStateSaver saver(d);
d.nospace();
- d << "NCCALCSIZE_PARAMS " << qrectFromRECT(p.rgrc[0])
- << ' ' << qrectFromRECT(p.rgrc[1]) << ' ' << qrectFromRECT(p.rgrc[2]);
+ d << "NCCALCSIZE_PARAMS(rgrc=[" << p.rgrc[0] << ' ' << p.rgrc[1] << ' '
+ << p.rgrc[2] << "], lppos=" << *p.lppos << ')';
return d;
}
@@ -177,6 +218,7 @@ QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp)
{
QDebugStateSaver saver(d);
d.nospace();
+ d.noquote();
d << "WINDOWPLACEMENT(flags=0x" << hex << wp.flags << dec << ", showCmd="
<< wp.showCmd << ", ptMinPosition=" << wp.ptMinPosition << ", ptMaxPosition=" << wp.ptMaxPosition
<< ", rcNormalPosition=" << wp.rcNormalPosition;
@@ -939,9 +981,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
DWORD style_, DWORD exStyle_) :
geometryHint(w, cm), window(w), style(style_), exStyle(exStyle_),
requestedGeometry(geometry), obtainedGeometry(geometry),
- margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm),
- frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT),
- frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT)
+ margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm)
{
// Geometry of toplevels does not consider window frames.
// TODO: No concept of WA_wasMoved yet that would indicate a
@@ -994,17 +1034,8 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) :
QWindowsBaseWindow(aWindow),
m_data(data),
- m_flags(WithinCreate),
- m_hdc(0),
- m_windowState(Qt::WindowNoState),
- m_opacity(1.0),
m_cursor(new CursorHandle),
- m_dropTarget(0),
- m_savedStyle(0),
- m_format(aWindow->requestedFormat()),
- m_iconSmall(0),
- m_iconBig(0),
- m_surface(0)
+ m_format(aWindow->requestedFormat())
{
// Clear the creation context as the window can be found in QWindowsContext's map.
QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>());
@@ -1095,7 +1126,7 @@ void QWindowsWindow::updateDropSite(bool topLevel)
// if the parent window is a foreign window wrapped via QWindow::fromWinId, we need to enable the drop site
// on the first child window
const QWindow *parent = window()->parent();
- if (parent && (parent->type() == Qt::ForeignWindow))
+ if (parent && parent->handle() && parent->handle()->isForeignWindow())
parentIsEmbedded = true;
}
@@ -1216,18 +1247,14 @@ bool QWindowsWindow::isActive() const
return false;
}
-bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const
+bool QWindowsWindow::isAncestorOf(const QPlatformWindow *child) const
{
- if (parentWindow) {
- const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(parentWindow);
- const HWND hwnd = ww->handle();
- if (!IsChild(hwnd, m_data.hwnd))
- return false;
- }
-
- if (!m_data.embedded && parent())
- return parent()->isEmbedded();
+ const QWindowsWindow *childWindow = static_cast<const QWindowsWindow *>(child);
+ return IsChild(m_data.hwnd, childWindow->handle());
+}
+bool QWindowsWindow::isEmbedded() const
+{
return m_data.embedded;
}
@@ -1471,18 +1498,22 @@ void QWindowsWindow::handleResized(int wParam)
case SIZE_MAXHIDE: // Some other window affected.
case SIZE_MAXSHOW:
return;
- case SIZE_MINIMIZED:
- handleWindowStateChange(Qt::WindowMinimized);
+ case SIZE_MINIMIZED: // QTBUG-53577, prevent state change events during programmatic state change
+ if (!testFlag(WithinSetStyle))
+ handleWindowStateChange(Qt::WindowMinimized);
return;
case SIZE_MAXIMIZED:
- handleWindowStateChange(Qt::WindowMaximized);
+ if (!testFlag(WithinSetStyle))
+ handleWindowStateChange(Qt::WindowMaximized);
handleGeometryChange();
break;
case SIZE_RESTORED:
- if (isFullScreen_sys())
- handleWindowStateChange(Qt::WindowFullScreen);
- else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen))
- handleWindowStateChange(Qt::WindowNoState);
+ if (!testFlag(WithinSetStyle)) {
+ if (isFullScreen_sys())
+ handleWindowStateChange(Qt::WindowFullScreen);
+ else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen))
+ handleWindowStateChange(Qt::WindowNoState);
+ }
handleGeometryChange();
break;
}
@@ -1490,9 +1521,6 @@ void QWindowsWindow::handleResized(int wParam)
void QWindowsWindow::handleGeometryChange()
{
- //Prevent recursive resizes for Windows CE
- if (testFlag(WithinSetStyle))
- return;
const QRect previousGeometry = m_data.geometry;
m_data.geometry = geometry_sys();
QPlatformWindow::setGeometry(m_data.geometry);
@@ -1505,10 +1533,16 @@ void QWindowsWindow::handleGeometryChange()
&& !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) {
fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true);
}
- if (previousGeometry.topLeft() != m_data.geometry.topLeft()) {
- QPlatformScreen *newScreen = screenForGeometry(m_data.geometry);
- if (newScreen != screen())
- QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
+ if (!parent() && previousGeometry.topLeft() != m_data.geometry.topLeft()) {
+ HMONITOR hMonitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONULL);
+ QPlatformScreen *currentScreen = screen();
+ const auto screens = QWindowsContext::instance()->screenManager().screens();
+ auto newScreenIt = std::find_if(screens.begin(), screens.end(), [&](QWindowsScreen *s) {
+ return s->data().hMonitor == hMonitor
+ && s->data().flags & QWindowsScreenData::VirtualDesktop;
+ });
+ if (newScreenIt != screens.end() && *newScreenIt != currentScreen)
+ QWindowSystemInterface::handleWindowScreenChanged(window(), (*newScreenIt)->screen());
}
if (testFlag(SynchronousGeometryChangeEvent))
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
@@ -1588,7 +1622,8 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
if (message == WM_ERASEBKGND) // Backing store - ignored.
return true;
// Ignore invalid update bounding rectangles
- if (!GetUpdateRect(m_data.hwnd, 0, FALSE))
+ RECT updateRect;
+ if (!GetUpdateRect(m_data.hwnd, &updateRect, FALSE))
return false;
PAINTSTRUCT ps;
@@ -1612,7 +1647,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
// we still need to send isExposed=true, for compatibility.
// Our tests depend on it.
fireExpose(QRegion(qrectFromRECT(ps.rcPaint)), true);
- if (!QWindowsContext::instance()->asyncExpose())
+ if (qSizeOfRect(updateRect) == m_data.geometry.size() && !QWindowsContext::instance()->asyncExpose())
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
EndPaint(hwnd, &ps);
@@ -1659,7 +1694,6 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt,
QWindowsWindowData result = m_data;
result.flags = creationData.flags;
result.embedded = creationData.embedded;
- setFlag(FrameDirty);
return result;
}
@@ -1667,7 +1701,6 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
{
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window()
<< "\n from " << m_windowState << " to " << state;
- setFlag(FrameDirty);
m_windowState = state;
QWindowSystemInterface::handleWindowStateChanged(window(), state);
switch (state) {
@@ -1717,10 +1750,9 @@ bool QWindowsWindow::isFullScreen_sys() const
const QWindow *w = window();
if (!w->isTopLevel())
return false;
- const QScreen *screen = w->screen();
- if (!screen)
- screen = QGuiApplication::primaryScreen();
- return screen && geometry_sys() == QHighDpi::toNativePixels(screen->geometry(), w);
+ QRect geometry = geometry_sys();
+ QPlatformScreen *screen = screenForGeometry(geometry);
+ return screen && geometry == QHighDpi::toNativePixels(screen->geometry(), screen);
}
/*!
@@ -1744,8 +1776,6 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
const bool visible = isVisible();
- setFlag(FrameDirty);
-
if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) {
if (newState == Qt::WindowFullScreen) {
#ifndef Q_FLATTEN_EXPOSE
@@ -1794,6 +1824,13 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
newStyle |= WS_VISIBLE;
setStyle(newStyle);
+ const QScreen *screen = window()->screen();
+ if (!screen)
+ screen = QGuiApplication::primaryScreen();
+ // That area of the virtual desktop might not be covered by a screen anymore.
+ if (!screen->geometry().intersects(m_savedFrameGeometry))
+ m_savedFrameGeometry.moveTo(screen->geometry().topLeft());
+
UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE;
if (!m_savedFrameGeometry.isValid())
swpf |= SWP_NOSIZE | SWP_NOMOVE;
@@ -1839,7 +1876,6 @@ void QWindowsWindow::setStyle(unsigned s) const
{
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << debugWinStyle(s);
setFlag(WithinSetStyle);
- setFlag(FrameDirty);
SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s);
clearFlag(WithinSetStyle);
}
@@ -1848,7 +1884,6 @@ void QWindowsWindow::setExStyle(unsigned s) const
{
qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
<< " 0x" << QByteArray::number(s, 16);
- setFlag(FrameDirty);
SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
}
@@ -1904,22 +1939,17 @@ bool QWindowsWindow::handleGeometryChanging(MSG *message) const
return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins);
}
-QMargins QWindowsWindow::frameMargins() const
+void QWindowsWindow::setFrameMargins(const QMargins &newMargins)
{
- // Frames are invalidated by style changes (window state, flags).
- // As they are also required for geometry calculations in resize
- // event sequences, introduce a dirty flag mechanism to be able
- // to cache results.
- if (testFlag(FrameDirty)) {
- // Always skip calculating style-dependent margins for windows claimed to be frameless.
- // This allows users to remove the margins by handling WM_NCCALCSIZE with WS_THICKFRAME set
- // to ensure Areo snap still works (QTBUG-40578).
- m_data.frame = m_data.flags & Qt::FramelessWindowHint
- ? QMargins(0, 0, 0, 0)
- : QWindowsGeometryHint::frame(style(), exStyle());
- clearFlag(FrameDirty);
+ if (m_data.frame != newMargins) {
+ qCDebug(lcQpaWindows) << __FUNCTION__ << window() << m_data.frame << "->" << newMargins;
+ m_data.frame = newMargins;
}
- return m_data.frame + m_data.customMargins;
+}
+
+QMargins QWindowsWindow::frameMargins() const
+{
+ return m_data.frame;
}
void QWindowsWindow::setOpacity(qreal level)
@@ -2091,8 +2121,12 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
{
- const QWindowsGeometryHint hint(window(), m_data.customMargins);
- hint.applyToMinMaxInfo(m_data.hwnd, mmi);
+ // We don't apply the min/max size hint as we change the dpi, because we did not adjust the
+ // QScreen of the window yet so we don't have the min/max with the right ratio
+ if (!testFlag(QWindowsWindow::WithinDpiChanged)) {
+ const QWindowsGeometryHint hint(window(), m_data.customMargins);
+ hint.applyToMinMaxInfo(m_data.hwnd, mmi);
+ }
if ((testFlag(WithinMaximize) || (window()->windowState() == Qt::WindowMinimized))
&& (m_data.flags & Qt::FramelessWindowHint)) {
@@ -2335,7 +2369,6 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins)
const QPoint topLeft = currentFrameGeometry.topLeft();
QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins;
newFrame.moveTo(topLeft);
- setFlag(FrameDirty);
qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins
<< currentFrameGeometry << "->" << newFrame;
SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED);
@@ -2378,7 +2411,8 @@ void QWindowsWindow::setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWind
void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes)
{
- if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)) {
+ if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)
+ && !testFlag(TouchRegistered)) {
ULONG touchFlags = 0;
const bool ret = QWindowsContext::user32dll.isTouchWindow(m_data.hwnd, &touchFlags);
// Return if it is not a touch window or the flags are already set by a hook
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index 924f242e6e..e541b110a6 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -89,22 +89,20 @@ struct QWindowCreationContext
QRect obtainedGeometry;
QMargins margins;
QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE
- int frameX; // Passed on to CreateWindowEx(), including frame.
- int frameY;
- int frameWidth;
- int frameHeight;
+ int frameX = CW_USEDEFAULT; // Passed on to CreateWindowEx(), including frame.
+ int frameY = CW_USEDEFAULT;
+ int frameWidth = CW_USEDEFAULT;
+ int frameHeight = CW_USEDEFAULT;
};
struct QWindowsWindowData
{
- QWindowsWindowData() : hwnd(0), embedded(false) {}
-
Qt::WindowFlags flags;
QRect geometry;
QMargins frame; // Do not use directly for windows, see FrameDirty.
QMargins customMargins; // User-defined, additional frame for NCCALCSIZE
- HWND hwnd;
- bool embedded;
+ HWND hwnd = 0;
+ bool embedded = false;
static QWindowsWindowData create(const QWindow *w,
const QWindowsWindowData &parameters,
@@ -116,11 +114,11 @@ class QWindowsBaseWindow : public QPlatformWindow
public:
explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {}
- WId winId() const Q_DECL_OVERRIDE { return WId(handle()); }
- QRect geometry() const Q_DECL_OVERRIDE { return geometry_sys(); }
- QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMargins_sys(); }
- QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE;
- QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE;
+ WId winId() const override { return WId(handle()); }
+ QRect geometry() const override { return geometry_sys(); }
+ QMargins frameMargins() const override { return frameMargins_sys(); }
+ QPoint mapToGlobal(const QPoint &pos) const override;
+ QPoint mapFromGlobal(const QPoint &pos) const override;
using QPlatformWindow::screenForGeometry;
@@ -152,11 +150,11 @@ public:
explicit QWindowsDesktopWindow(QWindow *window)
: QWindowsBaseWindow(window), m_hwnd(GetDesktopWindow()) {}
- QMargins frameMargins() const Q_DECL_OVERRIDE { return QMargins(); }
- bool isTopLevel() const Q_DECL_OVERRIDE { return true; }
+ QMargins frameMargins() const override { return QMargins(); }
+ bool isTopLevel() const override { return true; }
protected:
- HWND handle() const Q_DECL_OVERRIDE { return m_hwnd; }
+ HWND handle() const override { return m_hwnd; }
private:
const HWND m_hwnd;
@@ -167,15 +165,16 @@ class QWindowsForeignWindow : public QWindowsBaseWindow
public:
explicit QWindowsForeignWindow(QWindow *window, HWND hwnd);
- void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE;
- void setGeometry(const QRect &rect) Q_DECL_OVERRIDE { setGeometry_sys(rect); }
- void setVisible(bool visible) Q_DECL_OVERRIDE;
- void raise() Q_DECL_OVERRIDE { raise_sys(); }
- void lower() Q_DECL_OVERRIDE { lower_sys(); }
- void setWindowTitle(const QString &title) Q_DECL_OVERRIDE { setWindowTitle_sys(title); }
+ void setParent(const QPlatformWindow *window) override;
+ void setGeometry(const QRect &rect) override { setGeometry_sys(rect); }
+ void setVisible(bool visible) override;
+ void raise() override { raise_sys(); }
+ void lower() override { lower_sys(); }
+ void setWindowTitle(const QString &title) override { setWindowTitle_sys(title); }
+ bool isForeignWindow() const override { return true; }
protected:
- HWND handle() const Q_DECL_OVERRIDE { return m_hwnd; }
+ HWND handle() const override { return m_hwnd; }
private:
const HWND m_hwnd;
@@ -189,7 +188,6 @@ public:
{
AutoMouseCapture = 0x1, //! Automatic mouse capture on button press.
WithinSetParent = 0x2,
- FrameDirty = 0x4, //! Frame outdated by setStyle, recalculate in next query.
OpenGLSurface = 0x10,
OpenGL_ES2 = 0x20,
OpenGLDoubleBuffered = 0x40,
@@ -208,7 +206,8 @@ public:
MaximizeToFullScreen = 0x80000,
InputMethodDisabled = 0x100000,
Compositing = 0x200000,
- HasBorderInFullScreen = 0x400000
+ HasBorderInFullScreen = 0x400000,
+ WithinDpiChanged = 0x800000,
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
@@ -216,52 +215,54 @@ public:
using QPlatformWindow::screenForGeometry;
- QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; }
- void setGeometry(const QRect &rect) Q_DECL_OVERRIDE;
- QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; }
- QRect normalGeometry() const Q_DECL_OVERRIDE;
+ QSurfaceFormat format() const override { return m_format; }
+ void setGeometry(const QRect &rect) override;
+ QRect geometry() const override { return m_data.geometry; }
+ QRect normalGeometry() const override;
- void setVisible(bool visible) Q_DECL_OVERRIDE;
+ void setVisible(bool visible) override;
bool isVisible() const;
- bool isExposed() const Q_DECL_OVERRIDE { return testFlag(Exposed); }
- bool isActive() const Q_DECL_OVERRIDE;
- bool isEmbedded(const QPlatformWindow *parentWindow = 0) const Q_DECL_OVERRIDE;
- QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE;
- QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE;
+ bool isExposed() const override { return testFlag(Exposed); }
+ bool isActive() const override;
+ bool isAncestorOf(const QPlatformWindow *child) const override;
+ bool isEmbedded() const override;
+ QPoint mapToGlobal(const QPoint &pos) const override;
+ QPoint mapFromGlobal(const QPoint &pos) const override;
- void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE;
- void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE;
+ void setWindowFlags(Qt::WindowFlags flags) override;
+ void setWindowState(Qt::WindowState state) override;
- void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE;
+ void setParent(const QPlatformWindow *window) override;
- void setWindowTitle(const QString &title) Q_DECL_OVERRIDE;
- void raise() Q_DECL_OVERRIDE { raise_sys(); }
- void lower() Q_DECL_OVERRIDE { lower_sys(); }
+ void setWindowTitle(const QString &title) override;
+ void raise() override { raise_sys(); }
+ void lower() override { lower_sys(); }
- void windowEvent(QEvent *event) Q_DECL_OVERRIDE;
+ void windowEvent(QEvent *event) override;
- void propagateSizeHints() Q_DECL_OVERRIDE;
+ void propagateSizeHints() override;
static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp);
bool handleGeometryChanging(MSG *message) const;
- QMargins frameMargins() const Q_DECL_OVERRIDE;
+ QMargins frameMargins() const override;
+ void setFrameMargins(const QMargins &newMargins);
- void setOpacity(qreal level) Q_DECL_OVERRIDE;
- void setMask(const QRegion &region) Q_DECL_OVERRIDE;
+ void setOpacity(qreal level) override;
+ void setMask(const QRegion &region) override;
qreal opacity() const { return m_opacity; }
- void requestActivateWindow() Q_DECL_OVERRIDE;
+ void requestActivateWindow() override;
- bool setKeyboardGrabEnabled(bool grab) Q_DECL_OVERRIDE;
- bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE;
+ bool setKeyboardGrabEnabled(bool grab) override;
+ bool setMouseGrabEnabled(bool grab) override;
inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; }
- bool startSystemResize(const QPoint &pos, Qt::Corner corner) Q_DECL_OVERRIDE;
+ bool startSystemResize(const QPoint &pos, Qt::Corner corner) override;
- void setFrameStrutEventsEnabled(bool enabled) Q_DECL_OVERRIDE;
- bool frameStrutEventsEnabled() const Q_DECL_OVERRIDE { return testFlag(FrameStrutEventsEnabled); }
+ void setFrameStrutEventsEnabled(bool enabled) override;
+ bool frameStrutEventsEnabled() const override { return testFlag(FrameStrutEventsEnabled); }
// QWindowsBaseWindow overrides
- HWND handle() const Q_DECL_OVERRIDE { return m_data.hwnd; }
- bool isTopLevel() const Q_DECL_OVERRIDE;
+ HWND handle() const override { return m_data.hwnd; }
+ bool isTopLevel() const override;
QMargins customMargins() const { return m_data.customMargins; }
void setCustomMargins(const QMargins &m);
@@ -301,14 +302,14 @@ public:
void setEnabled(bool enabled);
bool isEnabled() const;
- void setWindowIcon(const QIcon &icon) Q_DECL_OVERRIDE;
+ void setWindowIcon(const QIcon &icon) override;
void *surface(void *nativeConfig, int *err);
- void invalidateSurface() Q_DECL_OVERRIDE;
+ void invalidateSurface() override;
void aboutToMakeCurrent();
- void setAlertState(bool enabled) Q_DECL_OVERRIDE;
- bool isAlertState() const Q_DECL_OVERRIDE { return testFlag(AlertState); }
+ void setAlertState(bool enabled) override;
+ bool isAlertState() const override { return testFlag(AlertState); }
void alertWindow(int durationMs = 0);
void stopAlertWindow();
@@ -335,20 +336,20 @@ private:
void fireExpose(const QRegion &region, bool force=false);
mutable QWindowsWindowData m_data;
- mutable unsigned m_flags;
- HDC m_hdc;
- Qt::WindowState m_windowState;
- qreal m_opacity;
+ mutable unsigned m_flags = WithinCreate;
+ HDC m_hdc = 0;
+ Qt::WindowState m_windowState = Qt::WindowNoState;
+ qreal m_opacity = 1;
#ifndef QT_NO_CURSOR
CursorHandlePtr m_cursor;
#endif
- QWindowsOleDropTarget *m_dropTarget;
- unsigned m_savedStyle;
+ QWindowsOleDropTarget *m_dropTarget = nullptr;
+ unsigned m_savedStyle = 0;
QRect m_savedFrameGeometry;
const QSurfaceFormat m_format;
- HICON m_iconSmall;
- HICON m_iconBig;
- void *m_surface;
+ HICON m_iconSmall = 0;
+ HICON m_iconBig = 0;
+ void *m_surface = nullptr;
};
#ifndef QT_NO_DEBUG_STREAM
@@ -357,6 +358,7 @@ QDebug operator<<(QDebug d, const POINT &);
QDebug operator<<(QDebug d, const MINMAXINFO &i);
QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p);
QDebug operator<<(QDebug d, const WINDOWPLACEMENT &);
+QDebug operator<<(QDebug d, const WINDOWPOS &);
#endif // !QT_NO_DEBUG_STREAM
// ---------- QWindowsGeometryHint inline functions.
@@ -385,15 +387,14 @@ QPoint QWindowsGeometryHint::mapFromGlobal(const QWindow *w, const QPoint &p)
inline QWindowsWindow *QWindowsWindow::windowsWindowOf(const QWindow *w)
{
- QWindowsWindow *result = Q_NULLPTR;
- if (w) {
- const Qt::WindowType type = w->type();
- if (type != Qt::Desktop && type != Qt::ForeignWindow) {
- if (QPlatformWindow *pw = w->handle())
- result = static_cast<QWindowsWindow *>(pw);
- }
- }
- return result;
+ if (!w || !w->handle())
+ return nullptr;
+
+ const Qt::WindowType type = w->type();
+ if (type == Qt::Desktop || w->handle()->isForeignWindow())
+ return nullptr;
+
+ return static_cast<QWindowsWindow *>(w->handle());
}
void *QWindowsWindow::userDataOf(HWND hwnd)
diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri
index 20e0b81da9..7d3ecc8aa2 100644
--- a/src/plugins/platforms/windows/windows.pri
+++ b/src/plugins/platforms/windows/windows.pri
@@ -99,5 +99,5 @@ RESOURCES += $$PWD/openglblacklists.qrc
qtConfig(accessibility): include($$PWD/accessible/accessible.pri)
-DEFINES *= LIBEGL_NAME=$${LIBEGL_NAME}
-DEFINES *= LIBGLESV2_NAME=$${LIBGLESV2_NAME}
+DEFINES *= LIBEGL_NAME=$${LIBQTANGLE_NAME}
+DEFINES *= LIBGLESV2_NAME=$${LIBQTANGLE_NAME}
diff --git a/src/plugins/platforms/winrt/qwinrtclipboard.cpp b/src/plugins/platforms/winrt/qwinrtclipboard.cpp
index 0a38b3df34..117cb515df 100644
--- a/src/plugins/platforms/winrt/qwinrtclipboard.cpp
+++ b/src/plugins/platforms/winrt/qwinrtclipboard.cpp
@@ -61,7 +61,6 @@ QT_BEGIN_NAMESPACE
QWinRTClipboard::QWinRTClipboard()
: m_mimeData(Q_NULLPTR)
{
-#ifndef Q_OS_WINPHONE
QEventDispatcherWinRT::runOnXamlThread([this]() {
HRESULT hr;
hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_Clipboard).Get(),
@@ -74,7 +73,6 @@ QWinRTClipboard::QWinRTClipboard()
return hr;
});
-#endif // !Q_OS_WINPHONE
}
QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode)
@@ -82,7 +80,6 @@ QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode)
if (!supportsMode(mode))
return nullptr;
-#ifndef Q_OS_WINPHONE
ComPtr<IDataPackageView> view;
HRESULT hr;
hr = m_nativeClipBoard->GetContent(&view);
@@ -114,9 +111,6 @@ QMimeData *QWinRTClipboard::mimeData(QClipboard::Mode mode)
m_mimeData->setText(text);
return m_mimeData;
-#else // Q_OS_WINPHONE
- return QPlatformClipboard::mimeData(mode);
-#endif // Q_OS_WINPHONE
}
// Inspired by QWindowsMimeText::convertFromMime
@@ -153,7 +147,6 @@ void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
if (!supportsMode(mode))
return;
-#ifndef Q_OS_WINPHONE
const bool newData = !m_mimeData || m_mimeData != data;
if (newData) {
if (m_mimeData)
@@ -178,18 +171,11 @@ void QWinRTClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
return S_OK;
});
RETURN_VOID_IF_FAILED("Could not set clipboard text.");
-#else // Q_OS_WINPHONE
- QPlatformClipboard::setMimeData(data, mode);
-#endif // Q_OS_WINPHONE
}
bool QWinRTClipboard::supportsMode(QClipboard::Mode mode) const
{
-#ifndef Q_OS_WINPHONE
return mode == QClipboard::Clipboard;
-#else
- return QPlatformClipboard::supportsMode(mode);
-#endif
}
HRESULT QWinRTClipboard::onContentChanged(IInspectable *, IInspectable *)
diff --git a/src/plugins/platforms/winrt/qwinrtclipboard.h b/src/plugins/platforms/winrt/qwinrtclipboard.h
index 2e3e2b834d..899fcbe730 100644
--- a/src/plugins/platforms/winrt/qwinrtclipboard.h
+++ b/src/plugins/platforms/winrt/qwinrtclipboard.h
@@ -45,7 +45,6 @@
#include <wrl.h>
-#ifndef Q_OS_WINPHONE
namespace ABI {
namespace Windows {
namespace ApplicationModel {
@@ -55,7 +54,6 @@ namespace ABI {
}
}
}
-#endif // !Q_OS_WINPHONE
QT_BEGIN_NAMESPACE
@@ -70,9 +68,7 @@ public:
HRESULT onContentChanged(IInspectable *, IInspectable *);
private:
-#ifndef Q_OS_WINPHONE
Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IClipboardStatics> m_nativeClipBoard;
-#endif
QMimeData *m_mimeData;
};
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp
index 89ebf7d26f..15ae024d20 100644
--- a/src/plugins/platforms/winrt/qwinrtdrag.cpp
+++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp
@@ -1,34 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL3$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -504,6 +507,8 @@ static HRESULT qt_drop(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventA
class QtDragEventHandler##name : public IDragEventHandler \
{ \
public: \
+ virtual ~QtDragEventHandler##name() {\
+ }\
STDMETHODIMP Invoke(IInspectable *sender, \
ABI::Windows::UI::Xaml::IDragEventArgs *e) \
{ \
diff --git a/src/plugins/platforms/winrt/qwinrtdrag.h b/src/plugins/platforms/winrt/qwinrtdrag.h
index dad3e9892d..6cbabfbf41 100644
--- a/src/plugins/platforms/winrt/qwinrtdrag.h
+++ b/src/plugins/platforms/winrt/qwinrtdrag.h
@@ -1,34 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL3$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl.html.
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or later as published by the Free
-** Software Foundation and appearing in the file LICENSE.GPL included in
-** the packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 2.0 requirements will be
-** met: http://www.gnu.org/licenses/gpl-2.0.html.
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
index 417dbdc1db..62eacba89b 100644
--- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
+++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
@@ -61,11 +61,9 @@ using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::Storage::Pickers;
-#ifndef Q_OS_WINPHONE
typedef IAsyncOperationCompletedHandler<StorageFile *> SingleFileHandler;
typedef IAsyncOperationCompletedHandler<IVectorView<StorageFile *> *> MultipleFileHandler;
typedef IAsyncOperationCompletedHandler<StorageFolder *> SingleFolderHandler;
-#endif
QT_BEGIN_NAMESPACE
@@ -152,16 +150,6 @@ private:
QVector<HSTRING> impl;
};
-#ifdef Q_OS_WINPHONE
-class QActivationEvent : public QEvent
-{
-public:
- IInspectable *args() const {
- return reinterpret_cast<IInspectable *>(d);
- }
-};
-#endif
-
template<typename T>
static bool initializePicker(HSTRING runtimeId, T **picker, const QSharedPointer<QFileDialogOptions> &options)
{
@@ -225,23 +213,6 @@ static bool pickFiles(IFileOpenPicker *picker, QWinRTFileDialogHelper *helper, b
Q_ASSERT(picker);
Q_ASSERT(helper);
HRESULT hr;
-#ifdef Q_OS_WINPHONE
- hr = QEventDispatcherWinRT::runOnXamlThread([picker, singleFile]() {
- HRESULT hr;
- ComPtr<IFileOpenPicker2> picker2;
- hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf()));
- RETURN_HR_IF_FAILED("Failed to cast file picker");
- if (singleFile)
- return picker2->PickSingleFileAndContinue();
- else
- return picker2->PickMultipleFilesAndContinue();
- });
- RETURN_FALSE_IF_FAILED("Failed to open file picker");
- QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher();
- Q_ASSERT(eventDispatcher);
- eventDispatcher->installEventFilter(helper);
- return true;
-#else
hr = QEventDispatcherWinRT::runOnXamlThread([picker, helper, singleFile]() {
HRESULT hr;
if (singleFile) {
@@ -260,7 +231,6 @@ static bool pickFiles(IFileOpenPicker *picker, QWinRTFileDialogHelper *helper, b
return S_OK;
});
return SUCCEEDED(hr);
-#endif
}
static bool pickFolder(IFolderPicker *picker, QWinRTFileDialogHelper *helper)
@@ -268,19 +238,6 @@ static bool pickFolder(IFolderPicker *picker, QWinRTFileDialogHelper *helper)
Q_ASSERT(picker);
Q_ASSERT(helper);
HRESULT hr;
-#ifdef Q_OS_WINPHONE
- hr = QEventDispatcherWinRT::runOnXamlThread([picker]() {
- HRESULT hr;
- ComPtr<IFolderPicker2> picker2;
- hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf()));
- RETURN_HR_IF_FAILED("Failed to cast folder picker");
- return picker2->PickFolderAndContinue();
- });
- RETURN_FALSE_IF_FAILED("Failed to open folder picker");
- QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher();
- Q_ASSERT(eventDispatcher);
- eventDispatcher->installEventFilter(helper);
-#else
hr = QEventDispatcherWinRT::runOnXamlThread([picker, helper]() {
HRESULT hr;
ComPtr<IAsyncOperation<StorageFolder *>> op;
@@ -290,7 +247,6 @@ static bool pickFolder(IFolderPicker *picker, QWinRTFileDialogHelper *helper)
RETURN_HR_IF_FAILED("Failed to attach folder picker callback");
return S_OK;
});
-#endif
return SUCCEEDED(hr);
}
@@ -299,19 +255,6 @@ static bool pickSaveFile(IFileSavePicker *picker, QWinRTFileDialogHelper *helper
Q_ASSERT(picker);
Q_ASSERT(helper);
HRESULT hr;
-#ifdef Q_OS_WINPHONE
- hr = QEventDispatcherWinRT::runOnXamlThread([picker]() {
- HRESULT hr;
- ComPtr<IFileSavePicker2> picker2;
- hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf()));
- RETURN_HR_IF_FAILED("Failed to cast save file picker");
- return picker2->PickSaveFileAndContinue();
- });
- RETURN_FALSE_IF_FAILED("Failed to open single file picker");
- QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher();
- Q_ASSERT(eventDispatcher);
- eventDispatcher->installEventFilter(helper);
-#else
hr = QEventDispatcherWinRT::runOnXamlThread([picker, helper]() {
HRESULT hr;
ComPtr<IAsyncOperation<StorageFile *>> op;
@@ -321,7 +264,6 @@ static bool pickSaveFile(IFileSavePicker *picker, QWinRTFileDialogHelper *helper
RETURN_HR_IF_FAILED("Failed to attach save file picker callback");
return S_OK;
});
-#endif
return SUCCEEDED(hr);
}
@@ -488,68 +430,6 @@ void QWinRTFileDialogHelper::hide()
d->shown = false;
}
-#ifdef Q_OS_WINPHONE
-bool QWinRTFileDialogHelper::eventFilter(QObject *, QEvent *e)
-{
- if (e->type() != QEvent::WinEventAct)
- return false;
-
- HRESULT hr;
- QActivationEvent *event = static_cast<QActivationEvent *>(e);
- ComPtr<IInspectable> inspectable = event->args();
- ComPtr<IActivatedEventArgs> arguments;
- hr = inspectable.As(&arguments);
- Q_ASSERT_SUCCEEDED(hr);
-
- ActivationKind activationKind;
- hr = arguments->get_Kind(&activationKind);
- Q_ASSERT_SUCCEEDED(hr);
-
- // Handle only File, Folder and Save file pick continuation here.
- if (activationKind != ActivationKind_PickFileContinuation
- && activationKind != ActivationKind_PickFolderContinuation
- && activationKind != ActivationKind_PickSaveFileContinuation) {
- return false;
- }
-
- QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher();
- Q_ASSERT(eventDispatcher);
- eventDispatcher->removeEventFilter(this);
- e->accept();
-
- if (activationKind == ActivationKind_PickFileContinuation) {
- ComPtr<IFileOpenPickerContinuationEventArgs> fileContinuationArgs;
- hr = arguments.As(&fileContinuationArgs);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IVectorView<StorageFile *>> files;
- hr = fileContinuationArgs->get_Files(&files);
- Q_ASSERT_SUCCEEDED(hr);
- hr = onFilesPicked(files.Get());
- Q_ASSERT_SUCCEEDED(hr);
- } else if (activationKind == ActivationKind_PickFolderContinuation) {
- ComPtr<IFolderPickerContinuationEventArgs> folderContinuationArgs;
- hr = arguments.As(&folderContinuationArgs);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IStorageFolder> folder;
- hr = folderContinuationArgs->get_Folder(&folder);
- Q_ASSERT_SUCCEEDED(hr);
- hr = onFolderPicked(folder.Get());
- Q_ASSERT_SUCCEEDED(hr);
- } else {
- ComPtr<IFileSavePickerContinuationEventArgs> saveFileContinuationArgs;
- hr = arguments.As(&saveFileContinuationArgs);
- Q_ASSERT_SUCCEEDED(hr);
- ComPtr<IStorageFile> file;
- hr = saveFileContinuationArgs->get_File(&file);
- Q_ASSERT_SUCCEEDED(hr);
- hr = onFilePicked(file.Get());
- Q_ASSERT_SUCCEEDED(hr);
- }
-
- return true;
-}
-#endif
-
void QWinRTFileDialogHelper::setDirectory(const QUrl &directory)
{
Q_D(QWinRTFileDialogHelper);
@@ -586,7 +466,6 @@ QString QWinRTFileDialogHelper::selectedNameFilter() const
return d->selectedNameFilter;
}
-#ifndef Q_OS_WINPHONE
HRESULT QWinRTFileDialogHelper::onSingleFilePicked(IAsyncOperation<StorageFile *> *args, AsyncStatus status)
{
Q_D(QWinRTFileDialogHelper);
@@ -643,17 +522,9 @@ HRESULT QWinRTFileDialogHelper::onSingleFolderPicked(IAsyncOperation<StorageFold
Q_ASSERT_SUCCEEDED(hr);
return onFolderPicked(folder.Get());
}
-#endif //Q_OS_WINPHONE
HRESULT QWinRTFileDialogHelper::onFilesPicked(IVectorView<StorageFile *> *files)
{
-#ifdef Q_OS_WINPHONE
- Q_D(QWinRTFileDialogHelper);
- QEventLoopLocker locker(&d->loop);
- d->shown = false;
- d->selectedFiles.clear();
-#endif
-
HRESULT hr;
quint32 size;
hr = files->get_Size(&size);
@@ -676,13 +547,6 @@ HRESULT QWinRTFileDialogHelper::onFilesPicked(IVectorView<StorageFile *> *files)
HRESULT QWinRTFileDialogHelper::onFolderPicked(IStorageFolder *folder)
{
-#ifdef Q_OS_WINPHONE
- Q_D(QWinRTFileDialogHelper);
- QEventLoopLocker locker(&d->loop);
- d->shown = false;
- d->selectedFiles.clear();
-#endif
-
if (!folder) {
emit reject();
return S_OK;
@@ -695,13 +559,6 @@ HRESULT QWinRTFileDialogHelper::onFolderPicked(IStorageFolder *folder)
HRESULT QWinRTFileDialogHelper::onFilePicked(IStorageFile *file)
{
-#ifdef Q_OS_WINPHONE
- Q_D(QWinRTFileDialogHelper);
- QEventLoopLocker locker(&d->loop);
- d->shown = false;
- d->selectedFiles.clear();
-#endif
-
if (!file) {
emit reject();
return S_OK;
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
index 413dee7459..99239aad3a 100644
--- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
+++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h
@@ -75,9 +75,6 @@ public:
void exec() override;
bool show(Qt::WindowFlags, Qt::WindowModality, QWindow *) override;
void hide() override;
-#ifdef Q_OS_WINPHONE
- bool eventFilter(QObject *o, QEvent *e) override;
-#endif
bool defaultNameFilterDisables() const override { return false; }
void setDirectory(const QUrl &directory) override;
@@ -88,14 +85,12 @@ public:
void selectNameFilter(const QString &selectedNameFilter) override;
QString selectedNameFilter() const override;
-#ifndef Q_OS_WINPHONE
HRESULT onSingleFilePicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile *> *,
ABI::Windows::Foundation::AsyncStatus);
HRESULT onMultipleFilesPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *> *,
ABI::Windows::Foundation::AsyncStatus);
HRESULT onSingleFolderPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFolder *> *,
ABI::Windows::Foundation::AsyncStatus);
-#endif
private:
HRESULT onFilesPicked(ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *files);
diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp
index 557c13cf63..dab2482ab3 100644
--- a/src/plugins/platforms/winrt/qwinrtfileengine.cpp
+++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp
@@ -153,7 +153,6 @@ static HRESULT getDestinationFolder(const QString &fileName, const QString &newF
HRESULT hr;
ComPtr<IAsyncOperation<StorageFolder *>> op;
QFileInfo newFileInfo(newFileName);
-#ifndef Q_OS_WINPHONE
QFileInfo fileInfo(fileName);
if (fileInfo.dir() == newFileInfo.dir()) {
ComPtr<IStorageItem2> item;
@@ -161,12 +160,7 @@ static HRESULT getDestinationFolder(const QString &fileName, const QString &newF
Q_ASSERT_SUCCEEDED(hr);
hr = item->GetParentAsync(&op);
- } else
-#else
- Q_UNUSED(fileName);
- Q_UNUSED(file)
-#endif
- {
+ } else {
ComPtr<IStorageFolderStatics> folderFactory;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_StorageFolder).Get(),
IID_PPV_ARGS(&folderFactory));
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
index ffc3bbf077..7a30c8d98b 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp
@@ -74,10 +74,8 @@
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
# include <windows.phone.ui.input.h>
-# if _MSC_VER >= 1900
-# include <windows.foundation.metadata.h>
- using namespace ABI::Windows::Foundation::Metadata;
-# endif
+# include <windows.foundation.metadata.h>
+ using namespace ABI::Windows::Foundation::Metadata;
#endif
@@ -153,7 +151,6 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate)
Q_ASSERT_SUCCEEDED(hr);
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
-#if _MSC_VER >= 1900
d->hasHardwareButtons = false;
ComPtr<IApiInformationStatics> apiInformationStatics;
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(),
@@ -163,9 +160,6 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate)
const HStringReference valueRef(L"Windows.Phone.UI.Input.HardwareButtons");
hr = apiInformationStatics->IsTypePresent(valueRef.Get(), &d->hasHardwareButtons);
}
-#else
- d->hasHardwareButtons = true;
-#endif // _MSC_VER >= 1900
if (d->hasHardwareButtons) {
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(),
@@ -226,12 +220,11 @@ QWinRTIntegration::~QWinRTIntegration()
// Do not execute this on Windows Phone as the application is already
// shutting down and trying to unregister suspending/resume handler will
// cause exceptions and assert in debug mode
-#ifndef Q_OS_WINPHONE
for (QHash<CoreApplicationCallbackRemover, EventRegistrationToken>::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) {
hr = (d->application.Get()->*i.key())(i.value());
Q_ASSERT_SUCCEEDED(hr);
}
-#endif
+
destroyScreen(d->mainScreen);
Windows::Foundation::Uninitialize();
}
@@ -318,11 +311,7 @@ QPlatformClipboard *QWinRTIntegration::clipboard() const
#ifndef QT_NO_DRAGANDDROP
QPlatformDrag *QWinRTIntegration::drag() const
{
-#if _MSC_VER >= 1900
return QWinRTDrag::instance();
-#else
- return QPlatformIntegration::drag();
-#endif
}
#endif // QT_NO_DRAGANDDROP
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp
index 2a4b6c8907..edfcf038d7 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.cpp
+++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp
@@ -58,7 +58,7 @@
#include <functional>
#include <wrl.h>
#include <windows.system.h>
-#include <Windows.Applicationmodel.h>
+#include <Windows.ApplicationModel.h>
#include <Windows.ApplicationModel.core.h>
#include <windows.devices.input.h>
#include <windows.ui.h>
@@ -91,6 +91,7 @@ typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler;
typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler;
typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler;
typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler;
+typedef ITypedEventHandler<ICorePointerRedirector*, PointerEventArgs*> RedirectHandler;
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
typedef ITypedEventHandler<ApplicationView*, IInspectable*> VisibleBoundsChangedHandler;
#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
@@ -454,6 +455,8 @@ typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistr
uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken);
uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
+typedef HRESULT (__stdcall ICorePointerRedirector::*RedirectorCallbackRemover)(EventRegistrationToken);
+uint qHash(RedirectorCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
typedef HRESULT (__stdcall IApplicationView2::*ApplicationView2CallbackRemover)(EventRegistrationToken);
uint qHash(ApplicationView2CallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); }
@@ -464,6 +467,7 @@ class QWinRTScreenPrivate
public:
QTouchDevice *touchDevice;
ComPtr<ICoreWindow> coreWindow;
+ ComPtr<ICorePointerRedirector> redirect;
ComPtr<Xaml::IDependencyObject> canvas;
ComPtr<IApplicationView> view;
ComPtr<IDisplayInformation> displayInformation;
@@ -482,6 +486,7 @@ public:
QHash<Qt::Key, KeyInfo> activeKeys;
QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens;
QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens;
+ QHash<RedirectorCallbackRemover, EventRegistrationToken> redirectTokens;
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
QHash<ApplicationView2CallbackRemover, EventRegistrationToken> view2Tokens;
ComPtr<IApplicationView2> view2;
@@ -513,6 +518,10 @@ QWinRTScreen::QWinRTScreen()
hr = window->get_CoreWindow(&d->coreWindow);
Q_ASSERT_SUCCEEDED(hr);
+
+ hr = d->coreWindow.As(&d->redirect);
+ Q_ASSERT_SUCCEEDED(hr);
+
hr = d->coreWindow->Activate();
Q_ASSERT_SUCCEEDED(hr);
@@ -562,7 +571,7 @@ QWinRTScreen::QWinRTScreen()
ComPtr<Xaml::IUIElement> uiElement;
hr = canvas.As(&uiElement);
Q_ASSERT_SUCCEEDED(hr);
-#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP)
+#ifndef QT_NO_DRAGANDDROP
QWinRTDrag::instance()->setUiElement(uiElement);
#endif
hr = window->put_Content(uiElement.Get());
@@ -595,6 +604,10 @@ QWinRTScreen::~QWinRTScreen()
hr = (d->displayInformation.Get()->*i.key())(i.value());
Q_ASSERT_SUCCEEDED(hr);
}
+ for (QHash<RedirectorCallbackRemover, EventRegistrationToken>::const_iterator i = d->redirectTokens.begin(); i != d->redirectTokens.end(); ++i) {
+ hr = (d->redirect.Get()->*i.key())(i.value());
+ Q_ASSERT_SUCCEEDED(hr);
+ }
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
for (QHash<ApplicationView2CallbackRemover, EventRegistrationToken>::const_iterator i = d->view2Tokens.begin(); i != d->view2Tokens.end(); ++i) {
hr = (d->view2.Get()->*i.key())(i.value());
@@ -754,6 +767,9 @@ void QWinRTScreen::initialize()
Q_ASSERT_SUCCEEDED(hr);
onOrientationChanged(Q_NULLPTR, Q_NULLPTR);
onVisibilityChanged(nullptr, nullptr);
+
+ hr = d->redirect->add_PointerRoutedReleased(Callback<RedirectHandler>(this, &QWinRTScreen::onRedirectReleased).Get(), &d->redirectTokens[&ICorePointerRedirector::remove_PointerRoutedReleased]);
+ Q_ASSERT_SUCCEEDED(hr);
}
void QWinRTScreen::setCursorRect(const QRectF &cursorRect)
@@ -833,7 +849,7 @@ void QWinRTScreen::addWindow(QWindow *window)
handleExpose();
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
-#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP)
+#ifndef QT_NO_DRAGANDDROP
QWinRTDrag::instance()->setDropTarget(window);
#endif
}
@@ -852,7 +868,7 @@ void QWinRTScreen::removeWindow(QWindow *window)
QWindowSystemInterface::handleWindowActivated(Q_NULLPTR, Qt::OtherFocusReason);
handleExpose();
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
-#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP)
+#ifndef QT_NO_DRAGANDDROP
if (wasTopWindow)
QWinRTDrag::instance()->setDropTarget(topWindow());
#endif
@@ -1221,11 +1237,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args)
properties->get_Pressure(&pressure);
boolean isPressed;
-#ifndef Q_OS_WINPHONE
pointerPoint->get_IsInContact(&isPressed);
-#else
- properties->get_IsLeftButtonPressed(&isPressed); // IsInContact not reliable on phone
-#endif
// Devices like the Hololens set a static pressure of 0.5 independent
// of the pressed state. In those cases we need to synthesize the
@@ -1356,16 +1368,10 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *)
Q_D(QWinRTScreen);
HRESULT hr;
-#ifdef Q_OS_WINPHONE
- ComPtr<IDisplayInformation2> displayInformation;
- hr = d->displayInformation.As(&displayInformation);
- RETURN_OK_IF_FAILED("Failed to cast display information.");
- hr = displayInformation->get_RawPixelsPerViewPixel(&d->scaleFactor);
-#else
ResolutionScale resolutionScale;
hr = d->displayInformation->get_ResolutionScale(&resolutionScale);
d->scaleFactor = qreal(resolutionScale) / 100;
-#endif
+
qCDebug(lcQpaWindows) << __FUNCTION__ << "Scale Factor:" << d->scaleFactor;
RETURN_OK_IF_FAILED("Failed to get scale factor");
@@ -1388,6 +1394,13 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *)
return S_OK;
}
+HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEventArgs *args)
+{
+ // When dragging ends with a non-mouse input device then onRedirectRelease is invoked.
+ // QTBUG-58781
+ return onPointerUpdated(nullptr, args);
+}
+
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *, IInspectable *)
#else
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h
index 7dcdb98ead..fd6499c2b9 100644
--- a/src/plugins/platforms/winrt/qwinrtscreen.h
+++ b/src/plugins/platforms/winrt/qwinrtscreen.h
@@ -52,6 +52,7 @@ namespace ABI {
namespace Core {
struct IAutomationProviderRequestedEventArgs;
struct ICharacterReceivedEventArgs;
+ struct ICorePointerRedirector;
struct ICoreWindow;
struct ICoreWindowEventArgs;
struct IKeyEventArgs;
@@ -149,6 +150,7 @@ private:
#else
HRESULT onWindowSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *);
#endif
+ HRESULT onRedirectReleased(ABI::Windows::UI::Core::ICorePointerRedirector *, ABI::Windows::UI::Core::IPointerEventArgs *);
QScopedPointer<QWinRTScreenPrivate> d_ptr;
QRectF mCursorRect;
diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp
index f84688f045..5696ae7a10 100644
--- a/src/plugins/platforms/winrt/qwinrttheme.cpp
+++ b/src/plugins/platforms/winrt/qwinrttheme.cpp
@@ -84,7 +84,6 @@ static inline QColor fromColor(const Color &color)
return QColor(color.R, color.G, color.B, color.A);
}
-#if _MSC_VER >= 1900
static bool uiColorSettings(const wchar_t *value, UIElementType type, Color *color)
{
static ComPtr<IApiInformationStatics> apiInformationStatics;
@@ -147,6 +146,8 @@ static void nativeColorSettings(QPalette &p)
if (uiColorSettings(L"Hotlight", UIElementType_Hotlight, &color))
p.setColor(QPalette::BrightText, fromColor(color));
+ // Starting with SDK 15063 those have been removed.
+#ifndef QT_WINRT_DISABLE_PHONE_COLORS
//Phone related
if (uiColorSettings(L"PopupBackground", UIElementType_PopupBackground, &color)) {
p.setColor(QPalette::ToolTipBase, fromColor(color));
@@ -187,105 +188,9 @@ static void nativeColorSettings(QPalette &p)
if (uiColorSettings(L"TextContrastWithHigh", UIElementType_TextContrastWithHigh, &color))
p.setColor(QPalette::BrightText, fromColor(color));
+#endif // QT_WINRT_DISABLE_PHONE_COLORS
}
-#else // _MSC_VER >= 1900
-
-static void nativeColorSettings(QPalette &p)
-{
- HRESULT hr;
- Color color;
-
-#ifdef Q_OS_WINPHONE
- hr = uiSettings()->UIElementColor(UIElementType_PopupBackground, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::ToolTipBase, fromColor(color));
- p.setColor(QPalette::AlternateBase, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_NonTextMedium, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Button, fromColor(color));
- hr = uiSettings()->UIElementColor(UIElementType_NonTextMediumHigh, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Midlight, fromColor(color));
- hr = uiSettings()->UIElementColor(UIElementType_NonTextHigh, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Light, fromColor(color));
- hr = uiSettings()->UIElementColor(UIElementType_NonTextMediumLow, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Mid, fromColor(color));
- hr = uiSettings()->UIElementColor(UIElementType_NonTextLow, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Dark, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_TextHigh, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::ButtonText, fromColor(color));
- p.setColor(QPalette::Text, fromColor(color));
- p.setColor(QPalette::WindowText, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_TextMedium, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::ToolTipText, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_AccentColor, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Highlight, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_PageBackground, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Window, fromColor(color));
- p.setColor(QPalette::Base, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_TextContrastWithHigh, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::BrightText, fromColor(color));
-#else
- hr = uiSettings()->UIElementColor(UIElementType_ActiveCaption, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::ToolTipBase, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_Background, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::AlternateBase, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_ButtonFace, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Button, fromColor(color));
- p.setColor(QPalette::Midlight, fromColor(color).lighter(110));
- p.setColor(QPalette::Light, fromColor(color).lighter(150));
- p.setColor(QPalette::Mid, fromColor(color).dark(130));
- p.setColor(QPalette::Dark, fromColor(color).dark(150));
-
- hr = uiSettings()->UIElementColor(UIElementType_ButtonText, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::ButtonText, fromColor(color));
- p.setColor(QPalette::Text, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_CaptionText, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::ToolTipText, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_Highlight, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Highlight, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_HighlightText, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::HighlightedText, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_Window, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::Window, fromColor(color));
- p.setColor(QPalette::Base, fromColor(color));
-
- hr = uiSettings()->UIElementColor(UIElementType_Hotlight, &color);
- Q_ASSERT_SUCCEEDED(hr);
- p.setColor(QPalette::BrightText, fromColor(color));
-#endif
-}
-#endif // _MSC_VER < 1900
-
QWinRTTheme::QWinRTTheme()
: d_ptr(new QWinRTThemePrivate)
{
diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp
index 8f3b86ff3b..c40a1b8c45 100644
--- a/src/plugins/platforms/winrt/qwinrtwindow.cpp
+++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp
@@ -331,7 +331,6 @@ void QWinRTWindow::setWindowState(Qt::WindowState state)
if (d->state == state)
return;
-#if _MSC_VER >= 1900
if (state == Qt::WindowFullScreen) {
HRESULT hr;
boolean success;
@@ -378,7 +377,6 @@ void QWinRTWindow::setWindowState(Qt::WindowState state)
return;
}
}
-#endif // _MSC_VER >= 1900
if (state == Qt::WindowMinimized)
setUIElementVisibility(d->uiElement.Get(), false);
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index be2f5ca7e2..02a848b03f 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -51,8 +51,9 @@ OTHER_FILES += winrt.json
WINRT_SDK_VERSION_STRING = $$(UCRTVersion)
WINRT_SDK_VERSION = $$member($$list($$split(WINRT_SDK_VERSION_STRING, .)), 2)
lessThan(WINRT_SDK_VERSION, 14322): DEFINES += QT_WINRT_LIMITED_DRAGANDDROP
+greaterThan(WINRT_SDK_VERSION, 14393): DEFINES += QT_WINRT_DISABLE_PHONE_COLORS
-*-msvc2013|contains(DEFINES, QT_NO_DRAGANDDROP) {
+contains(DEFINES, QT_NO_DRAGANDDROP) {
SOURCES -= qwinrtdrag.cpp
HEADERS -= qwinrtdrag.h
}
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
index 4e0c73450e..7640a711a9 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
@@ -56,6 +56,8 @@
#include <QtGlxSupport/private/qglxconvenience_p.h>
#include <QtPlatformHeaders/QGLXNativeContext>
+#include "qxcbglintegration.h"
+
#if !defined(QT_STATIC) && QT_CONFIG(dlopen)
#include <dlfcn.h>
#endif
@@ -691,6 +693,10 @@ void QGLXContext::queryDummyContext()
if (const char *renderer = (const char *) glGetString(GL_RENDERER)) {
for (int i = 0; qglx_threadedgl_blacklist_renderer[i]; ++i) {
if (strstr(renderer, qglx_threadedgl_blacklist_renderer[i]) != 0) {
+ qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: "
+ "blacklisted renderer \""
+ << qglx_threadedgl_blacklist_renderer[i]
+ << "\"";
m_supportsThreading = false;
break;
}
@@ -700,6 +706,11 @@ void QGLXContext::queryDummyContext()
if (glxvendor) {
for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) {
if (strstr(glxvendor, qglx_threadedgl_blacklist_vendor[i]) != 0) {
+ qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: "
+ "blacklisted vendor \""
+ << qglx_threadedgl_blacklist_vendor[i]
+ << "\"";
+
m_supportsThreading = false;
break;
}
@@ -709,6 +720,11 @@ void QGLXContext::queryDummyContext()
context.doneCurrent();
if (oldContext && oldSurface)
oldContext->makeCurrent(oldSurface);
+
+ if (!m_supportsThreading) {
+ qCDebug(lcQpaGl) << "Force-enable multithreaded OpenGL by setting "
+ "environment variable QT_OPENGL_NO_SANITY_CHECK";
+ }
}
bool QGLXContext::supportsThreading()
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp
index a293066b93..01b3bca0d2 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -267,11 +267,6 @@ const int QXcbClipboard::clipboard_timeout = 5000;
QXcbClipboard::QXcbClipboard(QXcbConnection *c)
: QXcbObject(c), QPlatformClipboard()
- , m_requestor(XCB_NONE)
- , m_owner(XCB_NONE)
- , m_incr_active(false)
- , m_clipboard_closing(false)
- , m_incr_receive_time(0)
{
Q_ASSERT(QClipboard::Clipboard == 0);
Q_ASSERT(QClipboard::Selection == 1);
diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h
index a0a4f4e5a1..bfeae13e10 100644
--- a/src/plugins/platforms/xcb/qxcbclipboard.h
+++ b/src/plugins/platforms/xcb/qxcbclipboard.h
@@ -102,14 +102,14 @@ private:
QMimeData *m_clientClipboard[2];
xcb_timestamp_t m_timestamp[2];
- xcb_window_t m_requestor;
- xcb_window_t m_owner;
+ xcb_window_t m_requestor = XCB_NONE;
+ xcb_window_t m_owner = XCB_NONE;
static const int clipboard_timeout;
- bool m_incr_active;
- bool m_clipboard_closing;
- xcb_timestamp_t m_incr_receive_time;
+ bool m_incr_active = false;
+ bool m_clipboard_closing = false;
+ xcb_timestamp_t m_incr_receive_time = 0;
};
#endif // QT_NO_CLIPBOARD
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 5e52d4d80f..5c15a9cbcb 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -131,7 +131,7 @@ typedef struct qt_xcb_ge_event_t {
static inline bool isXIEvent(xcb_generic_event_t *event, int opCode)
{
- qt_xcb_ge_event_t *e = (qt_xcb_ge_event_t *)event;
+ qt_xcb_ge_event_t *e = reinterpret_cast<qt_xcb_ge_event_t *>(event);
return e->extension == opCode;
}
#endif // XCB_USE_XINPUT2
@@ -251,7 +251,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event)
// Find a fake screen
const auto scrs = virtualDesktop->screens();
for (QPlatformScreen *scr : scrs) {
- QXcbScreen *xcbScreen = (QXcbScreen *)scr;
+ QXcbScreen *xcbScreen = static_cast<QXcbScreen *>(scr);
if (xcbScreen->output() == XCB_NONE) {
screen = xcbScreen;
break;
@@ -377,7 +377,7 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen)
// When primary screen is removed, set the new primary screen
// which belongs to the primary virtual desktop.
if (screen->isPrimary()) {
- QXcbScreen *newPrimary = (QXcbScreen *)virtualDesktop->screens().at(0);
+ QXcbScreen *newPrimary = static_cast<QXcbScreen *>(virtualDesktop->screens().at(0));
newPrimary->setPrimary(true);
const int idx = m_screens.indexOf(newPrimary);
if (idx > 0)
@@ -552,32 +552,10 @@ void QXcbConnection::initializeScreens()
}
QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName)
- : m_connection(0)
- , m_canGrabServer(canGrabServer)
+ : m_canGrabServer(canGrabServer)
, m_defaultVisualId(defaultVisualId)
- , m_primaryScreenNumber(0)
, m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
, m_nativeInterface(nativeInterface)
-#ifdef XCB_USE_XLIB
- , m_xlib_display(0)
-#endif
- , xfixes_first_event(0)
- , xrandr_first_event(0)
- , xkb_first_event(0)
- , has_xinerama_extension(false)
- , has_shape_extension(false)
- , has_randr_extension(false)
- , has_input_shape(false)
- , has_xkb(false)
- , m_buttons(0)
- , m_focusWindow(0)
- , m_mouseGrabber(0)
- , m_mousePressWindow(0)
- , m_clientLeader(0)
- , m_systemTrayTracker(0)
- , m_glIntegration(Q_NULLPTR)
- , m_xiGrab(false)
- , m_qtSelectionOwner(0)
{
#ifdef XCB_USE_XLIB
Display *dpy = XOpenDisplay(m_displayName.constData());
@@ -618,9 +596,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeAllAtoms();
- m_time = XCB_CURRENT_TIME;
- m_netWmUserTime = XCB_CURRENT_TIME;
-
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR"))
initializeXRandr();
if (!has_randr_extension)
@@ -630,7 +605,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
initializeXRender();
#if defined(XCB_USE_XINPUT2)
- m_xi2Enabled = false;
if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2"))
initializeXInput2();
#endif
@@ -712,7 +686,7 @@ QXcbConnection::~QXcbConnection()
delete m_glIntegration;
#ifdef XCB_USE_XLIB
- XCloseDisplay((Display *)m_xlib_display);
+ XCloseDisplay(static_cast<Display *>(m_xlib_display));
#else
xcb_disconnect(xcb_connection());
#endif
@@ -755,7 +729,7 @@ QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \
{ \
- event_t *e = (event_t *)event; \
+ event_t *e = reinterpret_cast<event_t *>(event); \
if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->windowMember)) { \
handled = eventListener->handleGenericEvent(event, &result); \
if (!handled) \
@@ -766,7 +740,7 @@ break;
#define HANDLE_KEYBOARD_EVENT(event_t, handler) \
{ \
- event_t *e = (event_t *)event; \
+ event_t *e = reinterpret_cast<event_t *>(event); \
if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->event)) { \
handled = eventListener->handleGenericEvent(event, &result); \
if (!handled) \
@@ -1185,11 +1159,13 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->state);
HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
case XCB_MAPPING_NOTIFY:
- m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
+ m_keyboard->handleMappingNotifyEvent(reinterpret_cast<xcb_mapping_notify_event_t *>(event));
break;
case XCB_SELECTION_REQUEST:
{
- xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
+#if QT_CONFIG(draganddrop) || QT_CONFIG(clipboard)
+ xcb_selection_request_event_t *sr = reinterpret_cast<xcb_selection_request_event_t *>(event);
+#endif
#ifndef QT_NO_DRAGANDDROP
if (sr->selection == atom(QXcbAtom::XdndSelection))
m_drag->handleSelectionRequest(sr);
@@ -1203,19 +1179,19 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
break;
}
case XCB_SELECTION_CLEAR:
- setTime(((xcb_selection_clear_event_t *)event)->time);
+ setTime((reinterpret_cast<xcb_selection_clear_event_t *>(event))->time);
#ifndef QT_NO_CLIPBOARD
- m_clipboard->handleSelectionClearRequest((xcb_selection_clear_event_t *)event);
+ m_clipboard->handleSelectionClearRequest(reinterpret_cast<xcb_selection_clear_event_t *>(event));
#endif
handled = true;
break;
case XCB_SELECTION_NOTIFY:
- setTime(((xcb_selection_notify_event_t *)event)->time);
+ setTime((reinterpret_cast<xcb_selection_notify_event_t *>(event))->time);
handled = false;
break;
case XCB_PROPERTY_NOTIFY:
{
- xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
+ xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event);
if (pn->atom == atom(QXcbAtom::_NET_WORKAREA)) {
QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(pn->window);
if (virtualDesktop)
@@ -1240,7 +1216,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
if (!handled) {
if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
- xcb_xfixes_selection_notify_event_t *notify_event = (xcb_xfixes_selection_notify_event_t *)event;
+ xcb_xfixes_selection_notify_event_t *notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event);
setTime(notify_event->timestamp);
#ifndef QT_NO_CLIPBOARD
m_clipboard->handleXFixesSelectionRequest(notify_event);
@@ -1250,10 +1226,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
handled = true;
} else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) {
- updateScreens((xcb_randr_notify_event_t *)event);
+ updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event));
handled = true;
} else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
- xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event;
+ xcb_randr_screen_change_notify_event_t *change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event);
for (QXcbScreen *s : qAsConst(m_screens)) {
if (s->root() == change_event->root )
s->handleScreenChange(change_event);
@@ -1362,7 +1338,7 @@ void QXcbEventReader::run()
void QXcbEventReader::addEvent(xcb_generic_event_t *event)
{
if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE
- && ((xcb_client_message_event_t *)event)->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION))
+ && (reinterpret_cast<xcb_client_message_event_t *>(event))->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION))
m_connection = 0;
m_events << event;
}
@@ -1428,7 +1404,7 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id)
event.type = atom(a);
event.data.data32[0] = id;
- Q_XCB_CALL(xcb_send_event(xcb_connection(), false, eventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, eventListener, XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event)));
Q_XCB_CALL(xcb_destroy_window(m_connection, eventListener));
xcb_flush(xcb_connection());
}
@@ -1448,7 +1424,7 @@ namespace
if ((event->response_type & ~0x80) != type) {
return false;
} else {
- xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
+ xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event);
if ((pn->window == window) && (pn->atom == atom))
return true;
}
@@ -1476,7 +1452,7 @@ xcb_timestamp_t QXcbConnection::getTimestamp()
event = checkEvent(checker);
}
- xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
+ xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event);
xcb_timestamp_t timestamp = pn->time;
free(event);
@@ -1500,7 +1476,8 @@ xcb_window_t QXcbConnection::getQtSelectionOwner()
{
if (!m_qtSelectionOwner) {
xcb_screen_t *xcbScreen = primaryVirtualDesktop()->screen();
- int x = 0, y = 0, w = 3, h = 3;
+ int16_t x = 0, y = 0;
+ uint16_t w = 3, h = 3;
m_qtSelectionOwner = xcb_generate_id(xcb_connection());
Q_XCB_CALL(xcb_create_window(xcb_connection(),
XCB_COPY_FROM_PARENT, // depth -- same as root
@@ -1689,7 +1666,7 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex,
for (int j = nextIndex; j < eventqueue->size(); ++j) {
xcb_generic_event_t *next = eventqueue->at(j);
if (isValid(next) && next->response_type == XCB_CONFIGURE_NOTIFY
- && ((xcb_configure_notify_event_t *)next)->event == ((xcb_configure_notify_event_t*)event)->event)
+ && reinterpret_cast<xcb_configure_notify_event_t *>(next)->event == reinterpret_cast<xcb_configure_notify_event_t *>(event)->event)
{
return true;
}
@@ -1718,7 +1695,7 @@ void QXcbConnection::processXcbEvents()
(*eventqueue)[i] = 0;
if (!(event->response_type & ~0x80)) {
- handleXcbError((xcb_generic_error_t *)event);
+ handleXcbError(reinterpret_cast<xcb_generic_error_t *>(event));
continue;
}
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 22c7d1aa8e..6089265304 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -551,10 +551,9 @@ private:
void destroyScreen(QXcbScreen *screen);
void initializeScreens();
bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const;
-
#ifdef XCB_USE_XINPUT2
- bool m_xi2Enabled;
- int m_xi2Minor;
+ bool m_xi2Enabled = false;
+ int m_xi2Minor = 2;
void initializeXInput2();
void finalizeXInput2();
void xi2SetupDevices();
@@ -568,20 +567,17 @@ private:
#endif // XCB_USE_XINPUT22
#ifndef QT_NO_TABLETEVENT
struct TabletData {
- TabletData() : deviceId(0), pointerType(QTabletEvent::UnknownPointer),
- tool(QTabletEvent::Stylus), buttons(0), serialId(0), inProximity(false) { }
- int deviceId;
- QTabletEvent::PointerType pointerType;
- QTabletEvent::TabletDevice tool;
- Qt::MouseButtons buttons;
- qint64 serialId;
- bool inProximity;
+ int deviceId = 0;
+ QTabletEvent::PointerType pointerType = QTabletEvent::UnknownPointer;
+ QTabletEvent::TabletDevice tool = QTabletEvent::Stylus;
+ Qt::MouseButtons buttons = 0;
+ qint64 serialId = 0;
+ bool inProximity = false;
struct ValuatorClassInfo {
- ValuatorClassInfo() : minVal(0.), maxVal(0.), curVal(0.) { }
- double minVal;
- double maxVal;
- double curVal;
- int number;
+ double minVal = 0;
+ double maxVal = 0;
+ double curVal = 0;
+ int number = -1;
};
QHash<int, ValuatorClassInfo> valuatorInfo;
};
@@ -593,12 +589,13 @@ private:
TabletData *tabletDataForDevice(int id);
#endif // !QT_NO_TABLETEVENT
struct ScrollingDevice {
- ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { }
- int deviceId;
- int verticalIndex, horizontalIndex;
- double verticalIncrement, horizontalIncrement;
- Qt::Orientations orientations;
- Qt::Orientations legacyOrientations;
+ int deviceId = 0;
+ int verticalIndex = 0;
+ int horizontalIndex = 0;
+ double verticalIncrement = 0;
+ double horizontalIncrement = 0;
+ Qt::Orientations orientations = 0;
+ Qt::Orientations legacyOrientations = 0;
QPointF lastScrollPosition;
};
void updateScrollingDevice(ScrollingDevice& scrollingDevice, int num_classes, void *classes);
@@ -609,36 +606,36 @@ private:
static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event);
#endif
- xcb_connection_t *m_connection;
- const xcb_setup_t *m_setup;
- bool m_canGrabServer;
- xcb_visualid_t m_defaultVisualId;
+ xcb_connection_t *m_connection = nullptr;
+ const xcb_setup_t *m_setup = nullptr;
+ const bool m_canGrabServer;
+ const xcb_visualid_t m_defaultVisualId;
QList<QXcbVirtualDesktop *> m_virtualDesktops;
QList<QXcbScreen *> m_screens;
- int m_primaryScreenNumber;
+ int m_primaryScreenNumber = 0;
xcb_atom_t m_allAtoms[QXcbAtom::NAtoms];
- xcb_timestamp_t m_time;
- xcb_timestamp_t m_netWmUserTime;
+ xcb_timestamp_t m_time = XCB_CURRENT_TIME;
+ xcb_timestamp_t m_netWmUserTime = XCB_CURRENT_TIME;
QByteArray m_displayName;
- QXcbKeyboard *m_keyboard;
+ QXcbKeyboard *m_keyboard = nullptr;
#ifndef QT_NO_CLIPBOARD
- QXcbClipboard *m_clipboard;
+ QXcbClipboard *m_clipboard = nullptr;
#endif
#ifndef QT_NO_DRAGANDDROP
- QXcbDrag *m_drag;
+ QXcbDrag *m_drag = nullptr;
#endif
QScopedPointer<QXcbWMSupport> m_wmSupport;
- QXcbNativeInterface *m_nativeInterface;
+ QXcbNativeInterface *m_nativeInterface = nullptr;
#if defined(XCB_USE_XLIB)
- void *m_xlib_display;
+ void *m_xlib_display = nullptr;
#endif
- QXcbEventReader *m_reader;
+ QXcbEventReader *m_reader = nullptr;
#if defined(XCB_USE_XINPUT2)
QHash<int, XInput2TouchDeviceData*> m_touchDevices;
#ifdef XCB_USE_XINPUT22
@@ -671,29 +668,29 @@ private:
QVector<PeekFunc> m_peekFuncs;
- uint32_t xfixes_first_event;
- uint32_t xrandr_first_event;
- uint32_t xkb_first_event;
+ uint32_t xfixes_first_event = 0;
+ uint32_t xrandr_first_event = 0;
+ uint32_t xkb_first_event = 0;
- bool has_xinerama_extension;
- bool has_shape_extension;
- bool has_randr_extension;
+ bool has_xinerama_extension = false;
+ bool has_shape_extension = false;
+ bool has_randr_extension = false;
bool has_input_shape;
- bool has_xkb;
+ bool has_xkb = false;
- Qt::MouseButtons m_buttons;
+ Qt::MouseButtons m_buttons = 0;
- QXcbWindow *m_focusWindow;
- QXcbWindow *m_mouseGrabber;
- QXcbWindow *m_mousePressWindow;
+ QXcbWindow *m_focusWindow = nullptr;
+ QXcbWindow *m_mouseGrabber = nullptr;
+ QXcbWindow *m_mousePressWindow = nullptr;
- xcb_window_t m_clientLeader;
+ xcb_window_t m_clientLeader = 0;
QByteArray m_startupId;
- QXcbSystemTrayTracker *m_systemTrayTracker;
- QXcbGlIntegration *m_glIntegration;
- bool m_xiGrab;
+ QXcbSystemTrayTracker *m_systemTrayTracker = nullptr;
+ QXcbGlIntegration *m_glIntegration = nullptr;
+ bool m_xiGrab = false;
- xcb_window_t m_qtSelectionOwner;
+ xcb_window_t m_qtSelectionOwner = 0;
friend class QXcbEventReader;
};
@@ -704,7 +701,7 @@ Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_MOVABLE_TYPE);
#endif
#endif
-#define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display()))
+#define DISPLAY_FROM_XCB(object) (reinterpret_cast<Display *>(object->connection()->xlib_display()))
#define CREATE_VISUALINFO_FROM_DEFAULT_VISUALID(object) ((XVisualInfo *)(object->connection()->createVisualInfoForDefaultVisualId()))
template<typename T>
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index d91cbfe82d..14c138a911 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -42,6 +42,7 @@
#include "qxcbscreen.h"
#include "qxcbwindow.h"
#include "qtouchdevice.h"
+#include "QtCore/qmetaobject.h"
#include <qpa/qwindowsysteminterface_p.h>
#include <QDebug>
#include <cmath>
@@ -52,14 +53,8 @@
#include <X11/extensions/XI2proto.h>
struct XInput2TouchDeviceData {
- XInput2TouchDeviceData()
- : xiDeviceInfo(0)
- , qtTouchDevice(0)
- , providesTouchOrientation(false)
- {
- }
- XIDeviceInfo *xiDeviceInfo;
- QTouchDevice *qtTouchDevice;
+ XIDeviceInfo *xiDeviceInfo = nullptr;
+ QTouchDevice *qtTouchDevice = nullptr;
QHash<int, QWindowSystemInterface::TouchPoint> touchPoints;
QHash<int, QPointF> pointPressedPosition; // in screen coordinates where each point was pressed
@@ -67,7 +62,7 @@ struct XInput2TouchDeviceData {
QPointF firstPressedPosition; // in screen coordinates where the first point was pressed
QPointF firstPressedNormalPosition; // device coordinates (0 to 1, 0 to 1) where the first point was pressed
QSizeF size; // device size in mm
- bool providesTouchOrientation;
+ bool providesTouchOrientation = false;
};
void QXcbConnection::initializeXInput2()
@@ -80,7 +75,7 @@ void QXcbConnection::initializeXInput2()
Display *xDisplay = static_cast<Display *>(m_xlib_display);
if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
int xiMajor = 2;
- m_xi2Minor = 2; // try 2.2 first, needed for TouchBegin/Update/End
+ // try 2.2 first, needed for TouchBegin/Update/End
if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
m_xi2Minor = 1; // for smooth scrolling 2.1 is enough
if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
@@ -214,6 +209,8 @@ void QXcbConnection::xi2SetupDevices()
isTablet = true;
tabletData.pointerType = QTabletEvent::Cursor;
dbgType = QLatin1String("cursor");
+ } else if (name.contains("wacom") && name.contains("finger touch")) {
+ isTablet = false;
} else if ((name.contains("pen") || name.contains("stylus")) && isTablet) {
tabletData.pointerType = QTabletEvent::Pen;
dbgType = QLatin1String("pen");
@@ -232,6 +229,9 @@ void QXcbConnection::xi2SetupDevices()
isTablet = true;
tabletData.pointerType = QTabletEvent::Pen;
dbgType = QLatin1String("pen");
+ } else if (name.contains("uc-logic") && isTablet) {
+ tabletData.pointerType = QTabletEvent::Pen;
+ dbgType = QLatin1String("pen");
} else {
isTablet = false;
}
@@ -444,10 +444,10 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
dev->size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution);
} else if (vci->label == atom(QXcbAtom::AbsX)) {
caps |= QTouchDevice::Position;
- dev->size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev->size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution);
} else if (vci->label == atom(QXcbAtom::AbsY)) {
caps |= QTouchDevice::Position;
- dev->size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution);
+ dev->size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution);
}
break;
}
@@ -1066,6 +1066,18 @@ static QTabletEvent::TabletDevice toolIdToTabletDevice(quint32 toolId) {
return QTabletEvent::Stylus; // Safe default assumption if nonzero
}
+static const char *toolName(QTabletEvent::TabletDevice tool) {
+ static const QMetaObject *metaObject = qt_getEnumMetaObject(tool);
+ static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(tool)));
+ return me.valueToKey(tool);
+}
+
+static const char *pointerTypeName(QTabletEvent::PointerType ptype) {
+ static const QMetaObject *metaObject = qt_getEnumMetaObject(ptype);
+ static const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(ptype)));
+ return me.valueToKey(ptype);
+}
+
bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletData)
{
bool handled = true;
@@ -1087,10 +1099,7 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
break;
}
case XI_Motion:
- // Report TabletMove only when the stylus is touching the tablet or any button is pressed.
- // TODO: report proximity (hover) motion (no suitable Qt event exists yet).
- if (tabletData->buttons != Qt::NoButton)
- xi2ReportTabletEvent(xiEvent, tabletData);
+ xi2ReportTabletEvent(xiEvent, tabletData);
break;
case XI_PropertyEvent: {
// This is the wacom driver's way of reporting tool proximity.
@@ -1142,9 +1151,9 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
// TODO maybe have a hash of tabletData->deviceId to device data so we can
// look up the tablet name here, and distinguish multiple tablets
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
- qCDebug(lcQpaXInputEvents, "XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x TabletDevice %d",
+ qCDebug(lcQpaXInputEvents, "XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x %s",
tabletData->deviceId, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID],
- ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], tabletData->tool);
+ ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], toolName(tabletData->tool));
}
XFree(data);
}
@@ -1167,6 +1176,7 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD
if (!xcbWindow)
return;
QWindow *window = xcbWindow->window();
+ const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective_mods);
const double scale = 65536.0;
QPointF local(ev->event_x / scale, ev->event_y / scale);
QPointF global(ev->root_x / scale, ev->root_y / scale);
@@ -1207,18 +1217,19 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD
}
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
- qCDebug(lcQpaXInputEvents, "XI2 event on tablet %d with tool %d type %d seq %d detail %d time %d "
- "pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf",
- tabletData->deviceId, tabletData->tool, ev->evtype, ev->sequenceNumber, ev->detail, ev->time,
+ qCDebug(lcQpaXInputEvents, "XI2 event on tablet %d with tool %s type %s seq %d detail %d time %d "
+ "pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf modifiers 0x%x",
+ tabletData->deviceId, toolName(tabletData->tool), pointerTypeName(tabletData->pointerType),
+ ev->sequenceNumber, ev->detail, ev->time,
fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y),
fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y),
- (int)tabletData->buttons, pressure, xTilt, yTilt, rotation);
+ (int)tabletData->buttons, pressure, xTilt, yTilt, rotation, (int)modifiers);
QWindowSystemInterface::handleTabletEvent(window, ev->time, local, global,
tabletData->tool, tabletData->pointerType,
tabletData->buttons, pressure,
xTilt, yTilt, tangentialPressure,
- rotation, 0, tabletData->serialId);
+ rotation, 0, tabletData->serialId, modifiers);
}
QXcbConnection::TabletData *QXcbConnection::tabletDataForDevice(int id)
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index af9ffab8ae..b414bee204 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -214,6 +214,27 @@ QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const
return xcbWindow;
}
+class QXcbForeignWindow : public QXcbWindow
+{
+public:
+ QXcbForeignWindow(QWindow *window, WId nativeHandle)
+ : QXcbWindow(window) { m_window = nativeHandle; }
+ ~QXcbForeignWindow() {}
+ bool isForeignWindow() const override { return true; }
+
+protected:
+ // No-ops
+ void create() override {}
+ void destroy() override {}
+};
+
+QPlatformWindow *QXcbIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
+{
+ QXcbWindow *xcbWindow = new QXcbForeignWindow(window, nativeHandle);
+ xcbWindow->create();
+ return xcbWindow;
+}
+
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
@@ -384,9 +405,6 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
case QPlatformIntegration::PasswordMaskCharacter:
// TODO using various xcb, gnome or KDE settings
break; // Not implemented, use defaults
- case QPlatformIntegration::FontSmoothingGamma:
- // Match Qt 4.8 text rendering, and rendering of other X11 toolkits.
- return qreal(1.0);
case QPlatformIntegration::StartDragDistance: {
// The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but
// on a high-resolution screen it makes sense to increase it.
@@ -448,7 +466,7 @@ QByteArray QXcbIntegration::wmClass() const
}
if (!name.isEmpty() && !className.isEmpty())
- m_wmClass = name.toLocal8Bit() + '\0' + className.toLocal8Bit() + '\0';
+ m_wmClass = std::move(name).toLocal8Bit() + '\0' + std::move(className).toLocal8Bit() + '\0';
}
return m_wmClass;
}
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index f8034f436f..baa5c9d835 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -61,6 +61,7 @@ public:
~QXcbIntegration();
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
#endif
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index a5aff7f11f..2e29c208c7 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -1136,12 +1136,6 @@ int QXcbKeyboard::keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modi
QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
: QXcbObject(connection)
- , m_autorepeat_code(0)
- , xkb_context(0)
- , xkb_keymap(0)
- , xkb_state(0)
- , latin_keymap(0)
- , m_hasLatinLayout(false)
{
memset(&xkb_names, 0, sizeof(xkb_names));
#if QT_CONFIG(xkb)
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index dfd2926435..74f9da0353 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -106,14 +106,14 @@ protected:
private:
void updateXKBStateFromState(struct xkb_state *kb_state, quint16 state);
- bool m_config;
- xcb_keycode_t m_autorepeat_code;
+ bool m_config = false;
+ xcb_keycode_t m_autorepeat_code = 0;
- struct xkb_context *xkb_context;
- struct xkb_keymap *xkb_keymap;
- struct xkb_state *xkb_state;
+ struct xkb_context *xkb_context = nullptr;
+ struct xkb_keymap *xkb_keymap = nullptr;
+ struct xkb_state *xkb_state = nullptr;
struct xkb_rule_names xkb_names;
- mutable struct xkb_keymap *latin_keymap;
+ mutable struct xkb_keymap *latin_keymap = nullptr;
struct _mod_masks {
uint alt;
@@ -143,7 +143,7 @@ private:
_mod_masks vmod_masks;
int core_device_id;
#endif
- bool m_hasLatinLayout;
+ bool m_hasLatinLayout = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp
index 3ec8fa491f..2848446098 100644
--- a/src/plugins/platforms/xcb/qxcbmime.cpp
+++ b/src/plugins/platforms/xcb/qxcbmime.cpp
@@ -299,7 +299,7 @@ xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString
QString formatWithCharset = format;
formatWithCharset.append(QLatin1String(";charset=utf-8"));
- xcb_atom_t a = connection->internAtom(formatWithCharset.toLatin1());
+ xcb_atom_t a = connection->internAtom(std::move(formatWithCharset).toLatin1());
if (a && atoms.contains(a)) {
*requestedEncoding = "utf-8";
return a;
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index b1575cbee4..725288633a 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -90,8 +90,7 @@ static int resourceType(const QByteArray &key)
}
QXcbNativeInterface::QXcbNativeInterface() :
- m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")),
- m_sysTraySelectionAtom(XCB_ATOM_NONE)
+ m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t"))
{
}
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index a830829311..4186d77f4d 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -129,7 +129,7 @@ private:
const QByteArray m_genericEventFilterType;
- xcb_atom_t m_sysTraySelectionAtom;
+ xcb_atom_t m_sysTraySelectionAtom = XCB_ATOM_NONE;
static QXcbScreen *qPlatformScreenForWindow(QWindow *window);
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 0ad9c97521..5e136b5d7e 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -59,7 +59,6 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
: QXcbObject(connection)
, m_screen(screen)
, m_number(number)
- , m_xSettings(Q_NULLPTR)
{
const QByteArray cmAtomName = "_NET_WM_CM_S" + QByteArray::number(m_number);
m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
@@ -175,20 +174,10 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
, m_virtualDesktop(virtualDesktop)
, m_output(outputId)
, m_crtc(output ? output->crtc : XCB_NONE)
- , m_mode(XCB_NONE)
- , m_primary(false)
- , m_rotation(XCB_RANDR_ROTATION_ROTATE_0)
, m_outputName(getOutputName(output))
, m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize())
, m_virtualSize(virtualDesktop->size())
, m_virtualSizeMillimeters(virtualDesktop->physicalSize())
- , m_orientation(Qt::PrimaryOrientation)
- , m_refreshRate(60)
- , m_forcedDpi(-1)
- , m_pixelDensity(1)
- , m_hintStyle(QFontEngine::HintStyle(-1))
- , m_subpixelType(QFontEngine::SubpixelAntialiasingType(-1))
- , m_antialiasingEnabled(-1)
{
if (connection->hasXRandr()) {
xcb_randr_select_input(xcb_connection(), screen()->root, true);
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 627397fcaf..4163be2969 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -95,12 +95,12 @@ private:
QRect getWorkArea() const;
xcb_screen_t *m_screen;
- int m_number;
+ const int m_number;
QList<QPlatformScreen *> m_screens;
- QXcbXSettings *m_xSettings;
- xcb_atom_t m_net_wm_cm_atom;
- bool m_compositingActive;
+ QXcbXSettings *m_xSettings = nullptr;
+ xcb_atom_t m_net_wm_cm_atom = 0;
+ bool m_compositingActive = false;
QRect m_workArea;
};
@@ -186,9 +186,9 @@ private:
QXcbVirtualDesktop *m_virtualDesktop;
xcb_randr_output_t m_output;
xcb_randr_crtc_t m_crtc;
- xcb_randr_mode_t m_mode;
- bool m_primary;
- uint8_t m_rotation;
+ xcb_randr_mode_t m_mode = XCB_NONE;
+ bool m_primary = false;
+ uint8_t m_rotation = XCB_RANDR_ROTATION_ROTATE_0;
QString m_outputName;
QSizeF m_outputSizeMillimeters;
@@ -197,18 +197,18 @@ private:
QRect m_availableGeometry;
QSize m_virtualSize;
QSizeF m_virtualSizeMillimeters;
- Qt::ScreenOrientation m_orientation;
+ Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
QString m_windowManagerName;
- bool m_syncRequestSupported;
+ bool m_syncRequestSupported = false;
QMap<xcb_visualid_t, xcb_visualtype_t> m_visuals;
QMap<xcb_visualid_t, quint8> m_visualDepths;
QXcbCursor *m_cursor;
- int m_refreshRate;
- int m_forcedDpi;
- int m_pixelDensity;
- QFontEngine::HintStyle m_hintStyle;
- QFontEngine::SubpixelAntialiasingType m_subpixelType;
- int m_antialiasingEnabled;
+ int m_refreshRate = 60;
+ int m_forcedDpi = -1;
+ int m_pixelDensity = 1;
+ QFontEngine::HintStyle m_hintStyle = QFontEngine::HintStyle(-1);
+ QFontEngine::SubpixelAntialiasingType m_subpixelType = QFontEngine::SubpixelAntialiasingType(-1);
+ int m_antialiasingEnabled = -1;
};
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
index 5522af86de..fb0a4a3939 100644
--- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
+++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
@@ -80,7 +80,6 @@ QXcbSystemTrayTracker::QXcbSystemTrayTracker(QXcbConnection *connection,
, m_selection(selection)
, m_trayAtom(trayAtom)
, m_connection(connection)
- , m_trayWindow(0)
{
}
diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
index a6131e6d0e..a95b9374e9 100644
--- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
+++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
@@ -77,7 +77,7 @@ private:
const xcb_atom_t m_selection;
const xcb_atom_t m_trayAtom;
QXcbConnection *m_connection;
- xcb_window_t m_trayWindow;
+ xcb_window_t m_trayWindow = 0;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 509bc9b038..6365a6e9cb 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -284,6 +284,8 @@ static inline XTextProperty* qstringToXTP(Display *dpy, const QString& s)
free_prop = false;
#if QT_CONFIG(textcodec)
}
+#else
+ Q_UNUSED(dpy);
#endif
return &tp;
}
@@ -314,22 +316,6 @@ static const char *wm_window_role_property_id = "_q_xcb_wm_window_role";
QXcbWindow::QXcbWindow(QWindow *window)
: QPlatformWindow(window)
- , m_window(0)
- , m_cmap(0)
- , m_syncCounter(0)
- , m_gravity(XCB_GRAVITY_STATIC)
- , m_mapped(false)
- , m_transparent(false)
- , m_usingSyncProtocol(false)
- , m_deferredActivation(false)
- , m_embedded(false)
- , m_alertState(false)
- , m_netWmUserTimeWindow(XCB_NONE)
- , m_dirtyFrameMargins(false)
- , m_lastWindowStateEvent(-1)
- , m_syncState(NoSyncNeeded)
- , m_pendingSyncRequest(0)
- , m_currentBitmapCursor(XCB_CURSOR_NONE)
{
setConnection(xcbScreen()->connection());
}
@@ -357,11 +343,6 @@ enum {
void QXcbWindow::create()
{
- if (window()->type() == Qt::ForeignWindow) {
- m_window = window()->winId();
- return;
- }
-
destroy();
m_windowState = Qt::WindowNoState;
@@ -413,7 +394,7 @@ void QXcbWindow::create()
xcb_window_t xcb_parent_id = platformScreen->root();
if (parent()) {
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
- m_embedded = parent()->window()->type() == Qt::ForeignWindow;
+ m_embedded = parent()->isForeignWindow();
QSurfaceFormat parentFormat = parent()->window()->requestedFormat();
if (window()->surfaceType() != QSurface::OpenGLSurface && parentFormat.hasAlpha()) {
@@ -606,9 +587,10 @@ QXcbWindow::~QXcbWindow()
if (m_currentBitmapCursor != XCB_CURSOR_NONE) {
xcb_free_cursor(xcb_connection(), m_currentBitmapCursor);
}
- if (window()->type() != Qt::ForeignWindow)
- destroy();
- else {
+
+ destroy();
+
+ if (isForeignWindow()) {
if (connection()->mouseGrabber() == this)
connection()->setMouseGrabber(Q_NULLPTR);
if (connection()->mousePressWindow() == this)
@@ -1520,7 +1502,7 @@ void QXcbWindow::setParent(const QPlatformWindow *parent)
if (parent) {
const QXcbWindow *qXcbParent = static_cast<const QXcbWindow *>(parent);
xcb_parent_id = qXcbParent->xcb_window();
- m_embedded = qXcbParent->window()->type() == Qt::ForeignWindow;
+ m_embedded = qXcbParent->isForeignWindow();
} else {
xcb_parent_id = xcbScreen()->root();
m_embedded = false;
@@ -1530,8 +1512,8 @@ void QXcbWindow::setParent(const QPlatformWindow *parent)
void QXcbWindow::setWindowTitle(const QString &title)
{
- const QString fullTitle = formatWindowTitle(title, QString::fromUtf8(" \xe2\x80\x94 ")); // unicode character U+2014, EM DASH
- const QByteArray ba = fullTitle.toUtf8();
+ QString fullTitle = formatWindowTitle(title, QString::fromUtf8(" \xe2\x80\x94 ")); // unicode character U+2014, EM DASH
+ const QByteArray ba = std::move(fullTitle).toUtf8();
Q_XCB_CALL(xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
m_window,
@@ -2153,12 +2135,9 @@ bool QXcbWindow::isExposed() const
return m_mapped;
}
-bool QXcbWindow::isEmbedded(const QPlatformWindow *parentWindow) const
+bool QXcbWindow::isEmbedded() const
{
- if (!m_embedded)
- return false;
-
- return parentWindow ? (parentWindow == parent()) : true;
+ return m_embedded;
}
QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index d100120d46..b4d947e700 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -87,7 +87,7 @@ public:
void setParent(const QPlatformWindow *window) override;
bool isExposed() const override;
- bool isEmbedded(const QPlatformWindow *parentWindow = 0) const override;
+ bool isEmbedded() const override;
QPoint mapToGlobal(const QPoint &pos) const override;
QPoint mapFromGlobal(const QPoint &pos) const override;
@@ -233,48 +233,48 @@ protected:
void handleLeaveNotifyEvent(int root_x, int root_y,
quint8 mode, quint8 detail, xcb_timestamp_t timestamp);
- xcb_window_t m_window;
- xcb_colormap_t m_cmap;
+ xcb_window_t m_window = 0;
+ xcb_colormap_t m_cmap = 0;
- uint m_depth;
- QImage::Format m_imageFormat;
- bool m_imageRgbSwap;
+ uint m_depth = 0;
+ QImage::Format m_imageFormat = QImage::Format_ARGB32_Premultiplied;
+ bool m_imageRgbSwap = false;
xcb_sync_int64_t m_syncValue;
- xcb_sync_counter_t m_syncCounter;
+ xcb_sync_counter_t m_syncCounter = 0;
- Qt::WindowState m_windowState;
+ Qt::WindowState m_windowState = Qt::WindowNoState;
- xcb_gravity_t m_gravity;
+ xcb_gravity_t m_gravity = XCB_GRAVITY_STATIC;
- bool m_mapped;
- bool m_transparent;
- bool m_usingSyncProtocol;
- bool m_deferredActivation;
- bool m_embedded;
- bool m_alertState;
- xcb_window_t m_netWmUserTimeWindow;
+ bool m_mapped = false;
+ bool m_transparent = false;
+ bool m_usingSyncProtocol = false;
+ bool m_deferredActivation = false;
+ bool m_embedded = false;
+ bool m_alertState = false;
+ xcb_window_t m_netWmUserTimeWindow = XCB_NONE;
QSurfaceFormat m_format;
- mutable bool m_dirtyFrameMargins;
+ mutable bool m_dirtyFrameMargins = false;
mutable QMargins m_frameMargins;
QRegion m_exposeRegion;
QSize m_oldWindowSize;
- xcb_visualid_t m_visualId;
- int m_lastWindowStateEvent;
+ xcb_visualid_t m_visualId = 0;
+ int m_lastWindowStateEvent = -1;
enum SyncState {
NoSyncNeeded,
SyncReceived,
SyncAndConfigureReceived
};
- SyncState m_syncState;
+ SyncState m_syncState = NoSyncNeeded;
- QXcbSyncWindowRequest *m_pendingSyncRequest;
- xcb_cursor_t m_currentBitmapCursor;
+ QXcbSyncWindowRequest *m_pendingSyncRequest = nullptr;
+ xcb_cursor_t m_currentBitmapCursor = XCB_CURSOR_NONE;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/gtk3/gtk3.pro b/src/plugins/platformthemes/gtk3/gtk3.pro
index c291ac56a0..cac6f7054d 100644
--- a/src/plugins/platformthemes/gtk3/gtk3.pro
+++ b/src/plugins/platformthemes/gtk3/gtk3.pro
@@ -9,6 +9,7 @@ QT += core-private gui-private theme_support-private
CONFIG += X11
QMAKE_USE += gtk3
+DEFINES += GDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6
HEADERS += \
qgtk3dialoghelpers.h \
diff --git a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
index eb7f0d8c2c..c64a02fa0c 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
@@ -57,11 +57,6 @@
QT_BEGIN_NAMESPACE
-static QByteArray standardButtonText(int button)
-{
- return QGtk3Theme::defaultStandardButtonText(button).toUtf8();
-}
-
class QGtk3Dialog : public QWindow
{
Q_OBJECT
@@ -236,7 +231,7 @@ void QGtk3ColorDialogHelper::onColorChanged(QGtk3ColorDialogHelper *dialog)
void QGtk3ColorDialogHelper::applyOptions()
{
GtkDialog *gtkDialog = d->gtkDialog();
- gtk_window_set_title(GTK_WINDOW(gtkDialog), options()->windowTitle().toUtf8());
+ gtk_window_set_title(GTK_WINDOW(gtkDialog), qUtf8Printable(options()->windowTitle()));
gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(gtkDialog), options()->testOption(QColorDialogOptions::ShowAlphaChannel));
}
@@ -245,8 +240,8 @@ QGtk3FileDialogHelper::QGtk3FileDialogHelper()
{
d.reset(new QGtk3Dialog(gtk_file_chooser_dialog_new("", 0,
GTK_FILE_CHOOSER_ACTION_OPEN,
- standardButtonText(QPlatformDialogHelper::Cancel).constData(), GTK_RESPONSE_CANCEL,
- standardButtonText(QPlatformDialogHelper::Ok).constData(), GTK_RESPONSE_OK,
+ qUtf8Printable(QGtk3Theme::defaultStandardButtonText(QPlatformDialogHelper::Cancel)), GTK_RESPONSE_CANCEL,
+ qUtf8Printable(QGtk3Theme::defaultStandardButtonText(QPlatformDialogHelper::Ok)), GTK_RESPONSE_OK,
NULL)));
connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
@@ -294,7 +289,7 @@ bool QGtk3FileDialogHelper::defaultNameFilterDisables() const
void QGtk3FileDialogHelper::setDirectory(const QUrl &directory)
{
GtkDialog *gtkDialog = d->gtkDialog();
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), directory.toLocalFile().toUtf8());
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), qUtf8Printable(directory.toLocalFile()));
}
QUrl QGtk3FileDialogHelper::directory() const
@@ -316,13 +311,19 @@ QUrl QGtk3FileDialogHelper::directory() const
void QGtk3FileDialogHelper::selectFile(const QUrl &filename)
{
+ setFileChooserAction();
+ selectFileInternal(filename);
+}
+
+void QGtk3FileDialogHelper::selectFileInternal(const QUrl &filename)
+{
GtkDialog *gtkDialog = d->gtkDialog();
if (options()->acceptMode() == QFileDialogOptions::AcceptSave) {
QFileInfo fi(filename.toLocalFile());
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), fi.path().toUtf8());
- gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(gtkDialog), fi.fileName().toUtf8());
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), qUtf8Printable(fi.path()));
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(gtkDialog), qUtf8Printable(fi.fileName()));
} else {
- gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toLocalFile().toUtf8());
+ gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), qUtf8Printable(filename.toLocalFile()));
}
}
@@ -409,16 +410,23 @@ static GtkFileChooserAction gtkFileChooserAction(const QSharedPointer<QFileDialo
}
}
+void QGtk3FileDialogHelper::setFileChooserAction()
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+
+ const GtkFileChooserAction action = gtkFileChooserAction(options());
+ gtk_file_chooser_set_action(GTK_FILE_CHOOSER(gtkDialog), action);
+}
+
void QGtk3FileDialogHelper::applyOptions()
{
GtkDialog *gtkDialog = d->gtkDialog();
const QSharedPointer<QFileDialogOptions> &opts = options();
- gtk_window_set_title(GTK_WINDOW(gtkDialog), opts->windowTitle().toUtf8());
+ gtk_window_set_title(GTK_WINDOW(gtkDialog), qUtf8Printable(opts->windowTitle()));
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(gtkDialog), true);
- const GtkFileChooserAction action = gtkFileChooserAction(opts);
- gtk_file_chooser_set_action(GTK_FILE_CHOOSER(gtkDialog), action);
+ setFileChooserAction();
const bool selectMultiple = opts->fileMode() == QFileDialogOptions::ExistingFiles;
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(gtkDialog), selectMultiple);
@@ -437,7 +445,7 @@ void QGtk3FileDialogHelper::applyOptions()
setDirectory(opts->initialDirectory());
foreach (const QUrl &filename, opts->initiallySelectedFiles())
- selectFile(filename);
+ selectFileInternal(filename);
const QString initialNameFilter = opts->initiallySelectedNameFilter();
if (!initialNameFilter.isEmpty())
@@ -446,19 +454,19 @@ void QGtk3FileDialogHelper::applyOptions()
GtkWidget *acceptButton = gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_OK);
if (acceptButton) {
if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
- gtk_button_set_label(GTK_BUTTON(acceptButton), opts->labelText(QFileDialogOptions::Accept).toUtf8());
+ gtk_button_set_label(GTK_BUTTON(acceptButton), qUtf8Printable(opts->labelText(QFileDialogOptions::Accept)));
else if (opts->acceptMode() == QFileDialogOptions::AcceptOpen)
- gtk_button_set_label(GTK_BUTTON(acceptButton), standardButtonText(QPlatformDialogHelper::Open));
+ gtk_button_set_label(GTK_BUTTON(acceptButton), qUtf8Printable(QGtk3Theme::defaultStandardButtonText(QPlatformDialogHelper::Open)));
else
- gtk_button_set_label(GTK_BUTTON(acceptButton), standardButtonText(QPlatformDialogHelper::Save));
+ gtk_button_set_label(GTK_BUTTON(acceptButton), qUtf8Printable(QGtk3Theme::defaultStandardButtonText(QPlatformDialogHelper::Save)));
}
GtkWidget *rejectButton = gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_CANCEL);
if (rejectButton) {
if (opts->isLabelExplicitlySet(QFileDialogOptions::Reject))
- gtk_button_set_label(GTK_BUTTON(rejectButton), opts->labelText(QFileDialogOptions::Reject).toUtf8());
+ gtk_button_set_label(GTK_BUTTON(rejectButton), qUtf8Printable(opts->labelText(QFileDialogOptions::Reject)));
else
- gtk_button_set_label(GTK_BUTTON(rejectButton), standardButtonText(QPlatformDialogHelper::Cancel));
+ gtk_button_set_label(GTK_BUTTON(rejectButton), qUtf8Printable(QGtk3Theme::defaultStandardButtonText(QPlatformDialogHelper::Cancel)));
}
}
@@ -473,12 +481,12 @@ void QGtk3FileDialogHelper::setNameFilters(const QStringList &filters)
foreach (const QString &filter, filters) {
GtkFileFilter *gtkFilter = gtk_file_filter_new();
- const QStringRef name = filter.leftRef(filter.indexOf(QLatin1Char('(')));
+ const QString name = filter.left(filter.indexOf(QLatin1Char('(')));
const QStringList extensions = cleanFilterList(filter);
- gtk_file_filter_set_name(gtkFilter, name.isEmpty() ? extensions.join(QLatin1String(", ")).toUtf8() : name.toUtf8());
+ gtk_file_filter_set_name(gtkFilter, qUtf8Printable(name.isEmpty() ? extensions.join(QLatin1String(", ")) : name));
foreach (const QString &ext, extensions)
- gtk_file_filter_add_pattern(gtkFilter, ext.toUtf8());
+ gtk_file_filter_add_pattern(gtkFilter, qUtf8Printable(ext));
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter);
@@ -520,7 +528,7 @@ static QString qt_fontToString(const QFont &font)
{
PangoFontDescription *desc = pango_font_description_new();
pango_font_description_set_size(desc, (font.pointSizeF() > 0.0 ? font.pointSizeF() : QFontInfo(font).pointSizeF()) * PANGO_SCALE);
- pango_font_description_set_family(desc, QFontInfo(font).family().toUtf8());
+ pango_font_description_set_family(desc, qUtf8Printable(QFontInfo(font).family()));
int weight = font.weight();
if (weight >= QFont::Black)
@@ -560,7 +568,7 @@ static QString qt_fontToString(const QFont &font)
static QFont qt_fontFromString(const QString &name)
{
QFont font;
- PangoFontDescription *desc = pango_font_description_from_string(name.toUtf8());
+ PangoFontDescription *desc = pango_font_description_from_string(qUtf8Printable(name));
font.setPointSizeF(static_cast<float>(pango_font_description_get_size(desc)) / PANGO_SCALE);
QString family = QString::fromUtf8(pango_font_description_get_family(desc));
@@ -585,7 +593,7 @@ static QFont qt_fontFromString(const QString &name)
void QGtk3FontDialogHelper::setCurrentFont(const QFont &font)
{
GtkFontChooser *gtkDialog = GTK_FONT_CHOOSER(d->gtkDialog());
- gtk_font_chooser_set_font(gtkDialog, qt_fontToString(font).toUtf8());
+ gtk_font_chooser_set_font(gtkDialog, qUtf8Printable(qt_fontToString(font)));
}
QFont QGtk3FontDialogHelper::currentFont() const
@@ -612,7 +620,7 @@ void QGtk3FontDialogHelper::applyOptions()
GtkDialog *gtkDialog = d->gtkDialog();
const QSharedPointer<QFontDialogOptions> &opts = options();
- gtk_window_set_title(GTK_WINDOW(gtkDialog), opts->windowTitle().toUtf8());
+ gtk_window_set_title(GTK_WINDOW(gtkDialog), qUtf8Printable(opts->windowTitle()));
}
QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h
index 99add3bda3..ba43046e04 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h
+++ b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.h
@@ -110,6 +110,8 @@ private:
static void onFilterChanged(QGtk3FileDialogHelper *helper);
void applyOptions();
void setNameFilters(const QStringList &filters);
+ void selectFileInternal(const QUrl &filename);
+ void setFileChooserAction();
QUrl _dir;
QList<QUrl> _selection;
diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
index 52757587b4..38c2d251b4 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
-** This file is part of the plugins of the Qt Toolkit.
+** This file is part of the QtGui module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.h b/src/plugins/platformthemes/gtk3/qgtk3menu.h
index 21e6178ec4..b43f363fa4 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3menu.h
+++ b/src/plugins/platformthemes/gtk3/qgtk3menu.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
index 6df631bff3..7e64906476 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
@@ -51,11 +51,18 @@ QT_BEGIN_NAMESPACE
const char *QGtk3Theme::name = "gtk3";
-static QString gtkSetting(const gchar *propertyName)
+template <typename T>
+static T gtkSetting(const gchar *propertyName)
{
GtkSettings *settings = gtk_settings_get_default();
- gchararray value;
+ T value;
g_object_get(settings, propertyName, &value, NULL);
+ return value;
+}
+
+static QString gtkSetting(const gchar *propertyName)
+{
+ gchararray value = gtkSetting<gchararray>(propertyName);
QString str = QString::fromUtf8(value);
g_free(value);
return str;
@@ -98,6 +105,18 @@ QGtk3Theme::QGtk3Theme()
QVariant QGtk3Theme::themeHint(QPlatformTheme::ThemeHint hint) const
{
switch (hint) {
+ case QPlatformTheme::CursorFlashTime:
+ return QVariant(gtkSetting<gint>("gtk-cursor-blink-time"));
+ case QPlatformTheme::MouseDoubleClickDistance:
+ return QVariant(gtkSetting<gint>("gtk-double-click-distance"));
+ case QPlatformTheme::MouseDoubleClickInterval:
+ return QVariant(gtkSetting<gint>("gtk-double-click-time"));
+ case QPlatformTheme::MousePressAndHoldInterval:
+ return QVariant(gtkSetting<guint>("gtk-long-press-time"));
+ case QPlatformTheme::PasswordMaskDelay:
+ return QVariant(gtkSetting<guint>("gtk-entry-password-hint-timeout"));
+ case QPlatformTheme::StartDragDistance:
+ return QVariant(gtkSetting<gint>("gtk-dnd-drag-threshold"));
case QPlatformTheme::SystemIconThemeName:
return QVariant(gtkSetting("gtk-icon-theme-name"));
case QPlatformTheme::SystemIconFallbackThemeName:
diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
index 7e6eb7c559..99e8ec8999 100644
--- a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
+++ b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp
@@ -86,7 +86,7 @@ static LPDEVMODE getDevmode(HANDLE hPrinter, const QString &printerId)
LPWSTR printerIdUtf16 = const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(printerId.utf16()));
// Allocate the required DEVMODE buffer
LONG dmSize = DocumentProperties(NULL, hPrinter, printerIdUtf16, NULL, NULL, 0);
- if (dmSize < 0)
+ if (dmSize <= 0)
return Q_NULLPTR;
LPDEVMODE pDevMode = reinterpret_cast<LPDEVMODE>(malloc(dmSize));
// Get the default DevMode
diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp
index 1faab22f66..acadc830b2 100644
--- a/src/plugins/sqldrivers/psql/qsql_psql.cpp
+++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp
@@ -667,7 +667,7 @@ bool QPSQLResult::exec()
if (params.isEmpty())
stmt = QString::fromLatin1("EXECUTE %1").arg(d->preparedStmtId);
else
- stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId).arg(params);
+ stmt = QString::fromLatin1("EXECUTE %1 (%2)").arg(d->preparedStmtId, params);
d->result = d->drv_d_func()->exec(stmt);
@@ -911,7 +911,7 @@ bool QPSQLDriver::open(const QString & db,
connectString.append(QLatin1Char(' ')).append(opt);
}
- d->connection = PQconnectdb(connectString.toLocal8Bit().constData());
+ d->connection = PQconnectdb(std::move(connectString).toLocal8Bit().constData());
if (PQstatus(d->connection) == CONNECTION_BAD) {
setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
setOpenError(true);
@@ -1073,12 +1073,12 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
if (isIdentifierEscaped(tbl, QSqlDriver::TableName))
tbl = stripDelimiters(tbl, QSqlDriver::TableName);
else
- tbl = tbl.toLower();
+ tbl = std::move(tbl).toLower();
if (isIdentifierEscaped(schema, QSqlDriver::TableName))
schema = stripDelimiters(schema, QSqlDriver::TableName);
else
- schema = schema.toLower();
+ schema = std::move(schema).toLower();
switch(d->pro) {
case QPSQLDriver::Version6:
@@ -1153,12 +1153,12 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
if (isIdentifierEscaped(tbl, QSqlDriver::TableName))
tbl = stripDelimiters(tbl, QSqlDriver::TableName);
else
- tbl = tbl.toLower();
+ tbl = std::move(tbl).toLower();
if (isIdentifierEscaped(schema, QSqlDriver::TableName))
schema = stripDelimiters(schema, QSqlDriver::TableName);
else
- schema = schema.toLower();
+ schema = std::move(schema).toLower();
QString stmt;
switch(d->pro) {
diff --git a/src/plugins/sqldrivers/tds/qsql_tds.cpp b/src/plugins/sqldrivers/tds/qsql_tds.cpp
index 940fd05c74..6ebd09a572 100644
--- a/src/plugins/sqldrivers/tds/qsql_tds.cpp
+++ b/src/plugins/sqldrivers/tds/qsql_tds.cpp
@@ -259,10 +259,9 @@ static int CS_PUBLIC qTdsErrHandler(DBPROCESS* dbproc,
return INT_CANCEL;
}
-
- QString errMsg = QString::fromLatin1("%1 %2\n").arg(QLatin1String(dberrstr)).arg(
- QLatin1String(oserrstr));
- errMsg += p->getErrorMsgs();
+ const QString errMsg = QLatin1String(dberrstr) + QLatin1Char(' ')
+ + QLatin1String(oserrstr) + QLatin1Char('\n')
+ + p->getErrorMsgs();
p->lastError = qMakeError(errMsg, QSqlError::UnknownError, dberr);
p->clearErrorMsgs();
diff --git a/src/printsupport/configure.json b/src/printsupport/configure.json
index 58fb039534..8d2a633481 100644
--- a/src/printsupport/configure.json
+++ b/src/printsupport/configure.json
@@ -28,13 +28,20 @@
"label": "CUPS",
"purpose": "Provides support for the Common Unix Printing System.",
"section": "Painting",
- "condition": "libs.cups && features.printer",
+ "condition": "libs.cups && features.printer && features.datestring",
"output": [ "privateFeature", "feature" ]
},
"cupsjobwidget": {
"label": "CUPS job control widget",
"section": "Widgets",
- "condition": "features.cups && features.calendarwidget && features.datetimeedit && features.groupbox && features.combobox",
+ "condition": [
+ "features.calendarwidget",
+ "features.checkbox",
+ "features.combobox",
+ "features.cups",
+ "features.datetimeedit",
+ "features.groupbox"
+ ],
"output": [ "privateFeature", "feature" ]
},
"printer": {
@@ -55,14 +62,26 @@
"label": "QPrintDialog",
"purpose": "Provides a dialog widget for specifying printer configuration.",
"section": "Dialogs",
- "condition": "features.printer && features.combobox && features.buttongroup && features.spinbox && features.treeview && features.tabwidget && features.datetimeedit",
+ "condition": [
+ "features.buttongroup",
+ "features.checkbox",
+ "features.combobox",
+ "features.dialog",
+ "features.datetimeedit",
+ "features.dialogbuttonbox",
+ "features.printer",
+ "features.radiobutton",
+ "features.spinbox",
+ "features.tabwidget",
+ "features.treeview"
+ ],
"output": [ "publicFeature", "feature" ]
},
"printpreviewdialog": {
"label": "QPrintPreviewDialog",
"purpose": "Provides a dialog for previewing and configuring page layouts for printer output.",
"section": "Dialogs",
- "condition": "features.printpreviewwidget && features.printdialog && features.toolbar",
+ "condition": "features.printpreviewwidget && features.printdialog && features.toolbar && features.formlayout",
"output": [ "publicFeature", "feature" ]
}
},
diff --git a/src/printsupport/dialogs/qabstractprintdialog.h b/src/printsupport/dialogs/qabstractprintdialog.h
index f18406af4b..e6d34cdb5b 100644
--- a/src/printsupport/dialogs/qabstractprintdialog.h
+++ b/src/printsupport/dialogs/qabstractprintdialog.h
@@ -41,13 +41,14 @@
#define QABSTRACTPRINTDIALOG_H
#include <QtPrintSupport/qtprintsupportglobal.h>
+
+#if QT_CONFIG(printdialog)
+
#include <QtWidgets/qdialog.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_PRINTER
-
class QAbstractPrintDialogPrivate;
class QPrinter;
@@ -76,10 +77,11 @@ public:
DontUseSheet = 0x0020,
PrintCurrentPage = 0x0040
};
+ Q_ENUM(PrintDialogOption)
Q_DECLARE_FLAGS(PrintDialogOptions, PrintDialogOption)
+ Q_FLAG(PrintDialogOptions)
-#ifndef QT_NO_PRINTDIALOG
explicit QAbstractPrintDialog(QPrinter *printer, QWidget *parent = Q_NULLPTR);
~QAbstractPrintDialog();
@@ -112,13 +114,12 @@ protected:
private:
Q_DISABLE_COPY(QAbstractPrintDialog)
-#endif // QT_NO_PRINTDIALOG
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractPrintDialog::PrintDialogOptions)
-#endif // QT_NO_PRINTER
-
QT_END_NAMESPACE
+#endif // QT_NO_PRINTDIALOG
+
#endif // QABSTRACTPRINTDIALOG_H
diff --git a/src/printsupport/dialogs/qabstractprintdialog_p.h b/src/printsupport/dialogs/qabstractprintdialog_p.h
index fe4e18cfc3..12de4ee882 100644
--- a/src/printsupport/dialogs/qabstractprintdialog_p.h
+++ b/src/printsupport/dialogs/qabstractprintdialog_p.h
@@ -52,10 +52,10 @@
//
#include <QtPrintSupport/private/qtprintsupportglobal_p.h>
-#include "private/qdialog_p.h"
#ifndef QT_NO_PRINTDIALOG
+#include "private/qdialog_p.h"
#include "QtPrintSupport/qabstractprintdialog.h"
QT_BEGIN_NAMESPACE
diff --git a/src/printsupport/dialogs/qpagesetupdialog.h b/src/printsupport/dialogs/qpagesetupdialog.h
index 124d215700..bc7462ebaa 100644
--- a/src/printsupport/dialogs/qpagesetupdialog.h
+++ b/src/printsupport/dialogs/qpagesetupdialog.h
@@ -41,13 +41,14 @@
#define QPAGESETUPDIALOG_H
#include <QtPrintSupport/qtprintsupportglobal.h>
+
+#ifndef QT_NO_PRINTDIALOG
+
#include <QtWidgets/qdialog.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_PRINTDIALOG
-
class QPrinter;
class QPageSetupDialogPrivate;
@@ -74,8 +75,8 @@ public:
QPrinter *printer();
};
-#endif // QT_NO_PRINTDIALOG
-
QT_END_NAMESPACE
+#endif // QT_NO_PRINTDIALOG
+
#endif // QPAGESETUPDIALOG_H
diff --git a/src/printsupport/dialogs/qpagesetupdialog_mac.mm b/src/printsupport/dialogs/qpagesetupdialog_mac.mm
index c29b911e35..581c0271f1 100644
--- a/src/printsupport/dialogs/qpagesetupdialog_mac.mm
+++ b/src/printsupport/dialogs/qpagesetupdialog_mac.mm
@@ -78,7 +78,7 @@ QT_USE_NAMESPACE
QPageSetupDialog *dialog = static_cast<QPageSetupDialog *>(contextInfo);
QPrinter *printer = dialog->printer();
- if (returnCode == NSOKButton) {
+ if (returnCode == NSModalResponseOK) {
PMPageFormat format = static_cast<PMPageFormat>([printInfo PMPageFormat]);
PMRect paperRect;
PMGetUnadjustedPaperRect(format, &paperRect);
@@ -89,7 +89,7 @@ QT_USE_NAMESPACE
printer->printEngine()->setProperty(QPrintEngine::PPK_Orientation, orientation == kPMLandscape ? QPrinter::Landscape : QPrinter::Portrait);
}
- dialog->done((returnCode == NSOKButton) ? QDialog::Accepted : QDialog::Rejected);
+ dialog->done((returnCode == NSModalResponseOK) ? QDialog::Accepted : QDialog::Rejected);
}
@end
diff --git a/src/printsupport/dialogs/qpagesetupdialog_p.h b/src/printsupport/dialogs/qpagesetupdialog_p.h
index 46e178fef9..98b466ccdc 100644
--- a/src/printsupport/dialogs/qpagesetupdialog_p.h
+++ b/src/printsupport/dialogs/qpagesetupdialog_p.h
@@ -53,10 +53,11 @@
//
#include <QtPrintSupport/private/qtprintsupportglobal_p.h>
-#include "private/qdialog_p.h"
#ifndef QT_NO_PRINTDIALOG
+#include "private/qdialog_p.h"
+
#include "qbytearray.h"
#include "qpagesetupdialog.h"
#include "qpointer.h"
diff --git a/src/printsupport/dialogs/qprintdialog.h b/src/printsupport/dialogs/qprintdialog.h
index a1d79b2310..35d650a7fc 100644
--- a/src/printsupport/dialogs/qprintdialog.h
+++ b/src/printsupport/dialogs/qprintdialog.h
@@ -41,13 +41,14 @@
#define QPRINTDIALOG_H
#include <QtPrintSupport/qtprintsupportglobal.h>
+
+#ifndef QT_NO_PRINTDIALOG
+
#include <QtPrintSupport/qabstractprintdialog.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_PRINTDIALOG
-
class QPrintDialogPrivate;
class QPushButton;
class QPrinter;
@@ -56,7 +57,6 @@ class Q_PRINTSUPPORT_EXPORT QPrintDialog : public QAbstractPrintDialog
{
Q_OBJECT
Q_DECLARE_PRIVATE(QPrintDialog)
- Q_ENUMS(PrintDialogOption)
Q_PROPERTY(PrintDialogOptions options READ options WRITE setOptions)
public:
@@ -102,8 +102,8 @@ private:
# endif // Q_OS_UNIX
};
-#endif // QT_NO_PRINTDIALOG
-
QT_END_NAMESPACE
+#endif // QT_NO_PRINTDIALOG
+
#endif // QPRINTDIALOG_H
diff --git a/src/printsupport/dialogs/qprintdialog_mac.mm b/src/printsupport/dialogs/qprintdialog_mac.mm
index c630ab634a..4595ed71ff 100644
--- a/src/printsupport/dialogs/qprintdialog_mac.mm
+++ b/src/printsupport/dialogs/qprintdialog_mac.mm
@@ -103,7 +103,7 @@ QT_USE_NAMESPACE
QPrintDialog *dialog = static_cast<QPrintDialog *>(contextInfo);
QPrinter *printer = dialog->printer();
- if (returnCode == NSOKButton) {
+ if (returnCode == NSModalResponseOK) {
PMPrintSession session = static_cast<PMPrintSession>([printInfo PMPrintSession]);
PMPrintSettings settings = static_cast<PMPrintSettings>([printInfo PMPrintSettings]);
@@ -192,7 +192,7 @@ QT_USE_NAMESPACE
printer->setPageSize(pageSize);
printer->setOrientation(orientation == kPMLandscape ? QPrinter::Landscape : QPrinter::Portrait);
- dialog->done((returnCode == NSOKButton) ? QDialog::Accepted : QDialog::Rejected);
+ dialog->done((returnCode == NSModalResponseOK) ? QDialog::Accepted : QDialog::Rejected);
}
@end
diff --git a/src/printsupport/dialogs/qprintpreviewdialog.cpp b/src/printsupport/dialogs/qprintpreviewdialog.cpp
index c996e0d556..33ba842a1f 100644
--- a/src/printsupport/dialogs/qprintpreviewdialog.cpp
+++ b/src/printsupport/dialogs/qprintpreviewdialog.cpp
@@ -40,13 +40,11 @@
#include "qprintpreviewdialog.h"
#include "qprintpreviewwidget.h"
#include <private/qprinter_p.h>
-#include "private/qdialog_p.h"
#include "qprintdialog.h"
#include <QtWidgets/qaction.h>
#include <QtWidgets/qboxlayout.h>
#include <QtWidgets/qcombobox.h>
-#include <QtWidgets/qlabel.h>
#include <QtWidgets/qlineedit.h>
#include <QtPrintSupport/qpagesetupdialog.h>
#include <QtPrintSupport/qprinter.h>
@@ -56,11 +54,15 @@
#include <QtWidgets/qfiledialog.h>
#include <QtWidgets/qmainwindow.h>
#include <QtWidgets/qtoolbar.h>
-#include <QtWidgets/qformlayout.h>
#include <QtCore/QCoreApplication>
#ifndef QT_NO_PRINTPREVIEWDIALOG
+#include "private/qdialog_p.h"
+
+#include <QtWidgets/qformlayout.h>
+#include <QtWidgets/qlabel.h>
+
static void initResources()
{
static bool resourcesInitialized = false;
diff --git a/src/printsupport/dialogs/qprintpreviewdialog.h b/src/printsupport/dialogs/qprintpreviewdialog.h
index 903083167c..640369fdf3 100644
--- a/src/printsupport/dialogs/qprintpreviewdialog.h
+++ b/src/printsupport/dialogs/qprintpreviewdialog.h
@@ -41,10 +41,11 @@
#define QPRINTPREVIEWDIALOG_H
#include <QtPrintSupport/qtprintsupportglobal.h>
-#include <QtWidgets/qdialog.h>
#ifndef QT_NO_PRINTPREVIEWDIALOG
+#include <QtWidgets/qdialog.h>
+
QT_BEGIN_NAMESPACE
diff --git a/src/printsupport/kernel/qplatformprintplugin.cpp b/src/printsupport/kernel/qplatformprintplugin.cpp
index 9bc4b61829..a80f369040 100644
--- a/src/printsupport/kernel/qplatformprintplugin.cpp
+++ b/src/printsupport/kernel/qplatformprintplugin.cpp
@@ -42,6 +42,7 @@
#include "qprinterinfo.h"
#include "private/qfactoryloader_p.h"
#include <qcoreapplication.h>
+#include <qdebug.h>
#ifndef QT_NO_PRINTER
@@ -79,8 +80,17 @@ QPlatformPrinterSupport *QPlatformPrinterSupportPlugin::get()
{
if (!printerSupport) {
const QMultiMap<int, QString> keyMap = loader()->keyMap();
- if (!keyMap.isEmpty())
- printerSupport = qLoadPlugin<QPlatformPrinterSupport, QPlatformPrinterSupportPlugin>(loader(), keyMap.constBegin().value());
+ QMultiMap<int, QString>::const_iterator it = keyMap.cbegin();
+ if (!qEnvironmentVariableIsEmpty("QT_PRINTER_MODULE")) {
+ QString module = QString::fromLocal8Bit(qgetenv("QT_PRINTER_MODULE"));
+ QMultiMap<int, QString>::const_iterator it2 = std::find_if(keyMap.cbegin(), keyMap.cend(), [module](const QString &value){ return value == module; });
+ if (it2 == keyMap.cend())
+ qWarning() << "Unable to load printer plugin" << module;
+ else
+ it = it2;
+ }
+ if (it != keyMap.cend())
+ printerSupport = qLoadPlugin<QPlatformPrinterSupport, QPlatformPrinterSupportPlugin>(loader(), it.value());
if (printerSupport)
qAddPostRoutine(cleanupPrinterSupport);
}
diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp
index 706a7c4b02..37f2290d94 100644
--- a/src/printsupport/kernel/qprintengine_win.cpp
+++ b/src/printsupport/kernel/qprintengine_win.cpp
@@ -106,7 +106,7 @@ static QByteArray msgBeginFailed(const char *function, const DOCINFO &d)
str << ", document \"" << QString::fromWCharArray(d.lpszDocName) << '"';
if (d.lpszOutput && d.lpszOutput[0])
str << ", file \"" << QString::fromWCharArray(d.lpszOutput) << '"';
- return result.toLocal8Bit();
+ return std::move(result).toLocal8Bit();
}
bool QWin32PrintEngine::begin(QPaintDevice *pdev)
@@ -1224,11 +1224,20 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
if (!ps)
return;
+
+ QVariant pageSize = QVariant::fromValue(d->m_pageLayout.pageSize());
+ const bool isFullPage = (d->m_pageLayout.mode() == QPageLayout::FullPageMode);
+ QVariant orientation = QVariant::fromValue(d->m_pageLayout.orientation());
+ QVariant margins = QVariant::fromValue(
+ QPair<QMarginsF, QPageLayout::Unit>(d->m_pageLayout.margins(), d->m_pageLayout.units()));
QPrintDevice printDevice = ps->createPrintDevice(id.isEmpty() ? ps->defaultPrintDeviceId() : id);
if (printDevice.isValid()) {
d->m_printDevice = printDevice;
- // TODO Do we need to check if the page size is valid on new printer?
d->initialize();
+ setProperty(PPK_QPageSize, pageSize);
+ setProperty(PPK_FullPage, QVariant(isFullPage));
+ setProperty(PPK_Orientation, orientation);
+ setProperty(PPK_QPageMargins, margins);
}
break;
}
@@ -1650,9 +1659,33 @@ void QWin32PrintEnginePrivate::updatePageLayout()
m_pageLayout.setOrientation(devMode->dmOrientation == DMORIENT_LANDSCAPE ? QPageLayout::Landscape : QPageLayout::Portrait);
if (devMode->dmPaperSize >= DMPAPER_LAST) {
// Is a custom size
- QPageSize pageSize = QPageSize(QSizeF(devMode->dmPaperWidth / 10.0f, devMode->dmPaperLength / 10.0f),
- QPageSize::Millimeter);
- setPageSize(pageSize);
+ // Check if it is using the Postscript Custom Size first
+ bool hasCustom = false;
+ int feature = PSIDENT_GDICENTRIC;
+ if (ExtEscape(hdc, POSTSCRIPT_IDENTIFY,
+ sizeof(DWORD), reinterpret_cast<LPCSTR>(&feature), 0, 0) >= 0) {
+ PSFEATURE_CUSTPAPER custPaper;
+ feature = FEATURESETTING_CUSTPAPER;
+ if (ExtEscape(hdc, GET_PS_FEATURESETTING, sizeof(INT), reinterpret_cast<LPCSTR>(&feature),
+ sizeof(custPaper), reinterpret_cast<LPSTR>(&custPaper)) > 0) {
+ // If orientation is 1 and width/height is 0 then it's not really custom
+ if (!(custPaper.lOrientation == 1 && custPaper.lWidth == 0 && custPaper.lHeight == 0)) {
+ if (custPaper.lOrientation == 0 || custPaper.lOrientation == 2)
+ m_pageLayout.setOrientation(QPageLayout::Portrait);
+ else
+ m_pageLayout.setOrientation(QPageLayout::Landscape);
+ QPageSize pageSize = QPageSize(QSizeF(custPaper.lWidth, custPaper.lHeight),
+ QPageSize::Point);
+ setPageSize(pageSize);
+ hasCustom = true;
+ }
+ }
+ }
+ if (!hasCustom) {
+ QPageSize pageSize = QPageSize(QSizeF(devMode->dmPaperWidth / 10.0f, devMode->dmPaperLength / 10.0f),
+ QPageSize::Millimeter);
+ setPageSize(pageSize);
+ }
} else {
// Is a supported size
setPageSize(QPageSize(QPageSize::id(devMode->dmPaperSize)));
diff --git a/src/printsupport/kernel/qprinter.cpp b/src/printsupport/kernel/qprinter.cpp
index 7824d28ac5..53bed87dfc 100644
--- a/src/printsupport/kernel/qprinter.cpp
+++ b/src/printsupport/kernel/qprinter.cpp
@@ -449,143 +449,17 @@ public:
*/
/*!
- \enum QPrinter::PaperSize
+ \typedef QPrinter::PaperSize
\since 4.4
+ typdef for the enum QPagedPaintDevice::PageSize.
+
This enum type specifies what paper size QPrinter should use.
QPrinter does not check that the paper size is available; it just
uses this information, together with QPrinter::Orientation and
QPrinter::setFullPage(), to determine the printable area.
- The defined sizes (with setFullPage(true)) are:
-
- \value A0 841 x 1189 mm
- \value A1 594 x 841 mm
- \value A2 420 x 594 mm
- \value A3 297 x 420 mm
- \value A4 210 x 297 mm, 8.26 x 11.69 inches
- \value A5 148 x 210 mm
- \value A6 105 x 148 mm
- \value A7 74 x 105 mm
- \value A8 52 x 74 mm
- \value A9 37 x 52 mm
- \value B0 1000 x 1414 mm
- \value B1 707 x 1000 mm
- \value B2 500 x 707 mm
- \value B3 353 x 500 mm
- \value B4 250 x 353 mm
- \value B5 176 x 250 mm, 6.93 x 9.84 inches
- \value B6 125 x 176 mm
- \value B7 88 x 125 mm
- \value B8 62 x 88 mm
- \value B9 33 x 62 mm
- \value B10 31 x 44 mm
- \value C5E 163 x 229 mm
- \value Comm10E 105 x 241 mm, U.S. Common 10 Envelope
- \value DLE 110 x 220 mm
- \value Executive 7.5 x 10 inches, 190.5 x 254 mm
- \value Folio 210 x 330 mm
- \value Ledger 431.8 x 279.4 mm
- \value Legal 8.5 x 14 inches, 215.9 x 355.6 mm
- \value Letter 8.5 x 11 inches, 215.9 x 279.4 mm
- \value Tabloid 279.4 x 431.8 mm
- \value Custom Unknown, or a user defined size.
- \value A10
- \value A3Extra
- \value A4Extra
- \value A4Plus
- \value A4Small
- \value A5Extra
- \value B5Extra
- \value JisB0
- \value JisB1
- \value JisB2
- \value JisB3
- \value JisB4
- \value JisB5
- \value JisB6,
- \value JisB7
- \value JisB8
- \value JisB9
- \value JisB10
- \value AnsiA = Letter
- \value AnsiB = Ledger
- \value AnsiC
- \value AnsiD
- \value AnsiE
- \value LegalExtra
- \value LetterExtra
- \value LetterPlus
- \value LetterSmall
- \value TabloidExtra
- \value ArchA
- \value ArchB
- \value ArchC
- \value ArchD
- \value ArchE
- \value Imperial7x9
- \value Imperial8x10
- \value Imperial9x11
- \value Imperial9x12
- \value Imperial10x11
- \value Imperial10x13
- \value Imperial10x14
- \value Imperial12x11
- \value Imperial15x11
- \value ExecutiveStandard
- \value Note
- \value Quarto
- \value Statement
- \value SuperA
- \value SuperB
- \value Postcard
- \value DoublePostcard
- \value Prc16K
- \value Prc32K
- \value Prc32KBig
- \value FanFoldUS
- \value FanFoldGerman
- \value FanFoldGermanLegal
- \value EnvelopeB4
- \value EnvelopeB5
- \value EnvelopeB6
- \value EnvelopeC0
- \value EnvelopeC1
- \value EnvelopeC2
- \value EnvelopeC3
- \value EnvelopeC4
- \value EnvelopeC5 = C5E
- \value EnvelopeC6
- \value EnvelopeC65
- \value EnvelopeC7
- \value EnvelopeDL = DLE
- \value Envelope9
- \value Envelope10 = Comm10E
- \value Envelope11
- \value Envelope12
- \value Envelope14
- \value EnvelopeMonarch
- \value EnvelopePersonal
- \value EnvelopeChou3
- \value EnvelopeChou4
- \value EnvelopeInvite
- \value EnvelopeItalian
- \value EnvelopeKaku2
- \value EnvelopeKaku3
- \value EnvelopePrc1
- \value EnvelopePrc2
- \value EnvelopePrc3
- \value EnvelopePrc4
- \value EnvelopePrc5
- \value EnvelopePrc6
- \value EnvelopePrc7
- \value EnvelopePrc8
- \value EnvelopePrc9
- \value EnvelopePrc10
- \value EnvelopeYou4
- \value LastPageSize = EnvelopeYou4
- \omitvalue NPageSize
- \omitvalue NPaperSize
+ The defined sizes (with setFullPage(true)) are found in QPagedPaintDevice.
With setFullPage(false) (the default), the metrics will be a bit
smaller; how much depends on the printer in use.
@@ -1032,7 +906,7 @@ void QPrinter::setCreator(const QString &creator)
}
// Defined in QPagedPaintDevice but non-virtual, add QPrinter specific doc here
-#ifdef Q_QDOC
+#ifdef Q_CLANG_QDOC
/*!
\fn bool QPrinter::setPageLayout(const QPageLayout &newLayout)
\since 5.3
@@ -1997,7 +1871,7 @@ QPrinter::PrinterState QPrinter::printerState() const
return d->printEngine->printerState();
}
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
/*!
Returns the supported paper sizes for this printer.
diff --git a/src/printsupport/kernel/qprinter.h b/src/printsupport/kernel/qprinter.h
index 4650d5432a..33a2d4dbc8 100644
--- a/src/printsupport/kernel/qprinter.h
+++ b/src/printsupport/kernel/qprinter.h
@@ -77,161 +77,7 @@ public:
enum Orientation { Portrait, Landscape };
// ### Qt6 Remove in favor of QPage::PageSize
- // NOTE: Must keep in sync with QPageSize and QPagedPaintDevice
-#ifndef Q_QDOC
typedef PageSize PaperSize;
-#else
- enum PaperSize {
- // Existing Qt sizes
- A4,
- B5,
- Letter,
- Legal,
- Executive,
- A0,
- A1,
- A2,
- A3,
- A5,
- A6,
- A7,
- A8,
- A9,
- B0,
- B1,
- B10,
- B2,
- B3,
- B4,
- B6,
- B7,
- B8,
- B9,
- C5E,
- Comm10E,
- DLE,
- Folio,
- Ledger,
- Tabloid,
- Custom,
-
- // New values derived from PPD standard
- A10,
- A3Extra,
- A4Extra,
- A4Plus,
- A4Small,
- A5Extra,
- B5Extra,
-
- JisB0,
- JisB1,
- JisB2,
- JisB3,
- JisB4,
- JisB5,
- JisB6,
- JisB7,
- JisB8,
- JisB9,
- JisB10,
-
- // AnsiA = Letter,
- // AnsiB = Ledger,
- AnsiC,
- AnsiD,
- AnsiE,
- LegalExtra,
- LetterExtra,
- LetterPlus,
- LetterSmall,
- TabloidExtra,
-
- ArchA,
- ArchB,
- ArchC,
- ArchD,
- ArchE,
-
- Imperial7x9,
- Imperial8x10,
- Imperial9x11,
- Imperial9x12,
- Imperial10x11,
- Imperial10x13,
- Imperial10x14,
- Imperial12x11,
- Imperial15x11,
-
- ExecutiveStandard,
- Note,
- Quarto,
- Statement,
- SuperA,
- SuperB,
- Postcard,
- DoublePostcard,
- Prc16K,
- Prc32K,
- Prc32KBig,
-
- FanFoldUS,
- FanFoldGerman,
- FanFoldGermanLegal,
-
- EnvelopeB4,
- EnvelopeB5,
- EnvelopeB6,
- EnvelopeC0,
- EnvelopeC1,
- EnvelopeC2,
- EnvelopeC3,
- EnvelopeC4,
- // EnvelopeC5 = C5E,
- EnvelopeC6,
- EnvelopeC65,
- EnvelopeC7,
- // EnvelopeDL = DLE,
-
- Envelope9,
- // Envelope10 = Comm10E,
- Envelope11,
- Envelope12,
- Envelope14,
- EnvelopeMonarch,
- EnvelopePersonal,
-
- EnvelopeChou3,
- EnvelopeChou4,
- EnvelopeInvite,
- EnvelopeItalian,
- EnvelopeKaku2,
- EnvelopeKaku3,
- EnvelopePrc1,
- EnvelopePrc2,
- EnvelopePrc3,
- EnvelopePrc4,
- EnvelopePrc5,
- EnvelopePrc6,
- EnvelopePrc7,
- EnvelopePrc8,
- EnvelopePrc9,
- EnvelopePrc10,
- EnvelopeYou4,
-
- // Last item, with commonly used synynoms from QPagedPrintEngine / QPrinter
- LastPageSize = EnvelopeYou4,
- NPageSize = LastPageSize,
- NPaperSize = LastPageSize,
-
- // Convenience overloads for naming consistency
- AnsiA = Letter,
- AnsiB = Ledger,
- EnvelopeC5 = C5E,
- EnvelopeDL = DLE,
- Envelope10 = Comm10E
- };
-#endif
enum PageOrder { FirstPageFirst,
LastPageFirst };
@@ -305,7 +151,8 @@ public:
void setCreator(const QString &);
QString creator() const;
-#ifdef Q_QDOC
+#ifdef Q_CLANG_QDOC
+ // ### Qt6 Remove when these are made virtual in QPagedPaintDevice
bool setPageLayout(const QPageLayout &pageLayout);
bool setPageSize(const QPageSize &pageSize);
bool setPageOrientation(QPageLayout::Orientation orientation);
@@ -366,7 +213,7 @@ public:
QList<int> supportedResolutions() const;
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
QList<PaperSource> supportedPaperSources() const;
#endif
diff --git a/src/sql/configure.json b/src/sql/configure.json
index 9555b64f39..49444c7e5f 100644
--- a/src/sql/configure.json
+++ b/src/sql/configure.json
@@ -153,7 +153,7 @@
},
"sql-odbc": {
"label": "ODBC",
- "condition": "libs.odbc",
+ "condition": "libs.odbc && features.datestring",
"output": [ "publicFeature" ]
},
"sql-psql": {
@@ -168,6 +168,7 @@
},
"sql-sqlite": {
"label": "SQLite",
+ "condition": "features.datestring",
"output": [ "publicFeature" ]
},
"system-sqlite": {
@@ -178,7 +179,7 @@
},
"sql-tds": {
"label": "TDS (Sybase)",
- "condition": "libs.tds",
+ "condition": "libs.tds && features.datestring",
"output": [ "publicFeature" ]
}
},
diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp
index 66cd98bbe4..9d6daa2634 100644
--- a/src/sql/models/qsqlrelationaltablemodel.cpp
+++ b/src/sql/models/qsqlrelationaltablemodel.cpp
@@ -303,9 +303,6 @@ int QSqlRelationalTableModelPrivate::nameToIndex(const QString &name) const
return idx;
}
-/*!
- \reimp
-*/
void QSqlRelationalTableModelPrivate::clearCache()
{
for (int i = 0; i < relations.count(); ++i)
@@ -587,7 +584,8 @@ QString QSqlRelationalTableModel::selectStatement() const
QString displayColumn = relation.displayColumn();
if (d->db.driver()->isIdentifierEscaped(displayColumn, QSqlDriver::FieldName))
displayColumn = d->db.driver()->stripDelimiters(displayColumn, QSqlDriver::FieldName);
- const QString alias = QString::fromLatin1("%1_%2_%3").arg(relTableName).arg(displayColumn).arg(fieldNames.value(fieldList[i]));
+ const QString alias = QString::fromLatin1("%1_%2_%3")
+ .arg(relTableName, displayColumn, QString::number(fieldNames.value(fieldList[i])));
displayTableField = Sql::as(displayTableField, alias);
--fieldNames[fieldList[i]];
}
diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp
index 8166613e53..c0706ac22d 100644
--- a/src/sql/models/qsqltablemodel.cpp
+++ b/src/sql/models/qsqltablemodel.cpp
@@ -986,8 +986,8 @@ QString QSqlTableModel::orderByClause() const
//we can safely escape the field because it would have been obtained from the database
//and have the correct case
- QString field = d->db.driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
- field.prepend(QLatin1Char('.')).prepend(d->tableName);
+ QString field = d->tableName + QLatin1Char('.')
+ + d->db.driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
field = d->sortOrder == Qt::AscendingOrder ? Sql::asc(field) : Sql::desc(field);
return Sql::orderBy(field);
}
diff --git a/src/src.pro b/src/src.pro
index 24c550a5cd..43fc06f2e5 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -21,6 +21,10 @@ src_tools_rcc.subdir = tools/rcc
src_tools_rcc.target = sub-rcc
src_tools_rcc.depends = src_tools_bootstrap
+src_tools_qfloat16_tables.subdir = tools/qfloat16-tables
+src_tools_qfloat16_tables.target = sub-qfloat16-tables
+src_tools_qfloat16_tables.depends = src_tools_bootstrap
+
src_tools_qlalr.subdir = tools/qlalr
src_tools_qlalr.target = sub-qlalr
force_bootstrap: src_tools_qlalr.depends = src_tools_bootstrap
@@ -51,7 +55,7 @@ src_winmain.depends = sub-corelib # just for the module .pri file
src_corelib.subdir = $$PWD/corelib
src_corelib.target = sub-corelib
-src_corelib.depends = src_tools_moc src_tools_rcc
+src_corelib.depends = src_tools_moc src_tools_rcc src_tools_qfloat16_tables
src_xml.subdir = $$PWD/xml
src_xml.target = sub-xml
@@ -78,8 +82,8 @@ src_testlib.subdir = $$PWD/testlib
src_testlib.target = sub-testlib
src_testlib.depends = src_corelib # testlib links only to corelib, but see below for the headers
-src_3rdparty_pcre.subdir = $$PWD/3rdparty/pcre
-src_3rdparty_pcre.target = sub-3rdparty-pcre
+src_3rdparty_pcre2.subdir = $$PWD/3rdparty/pcre2
+src_3rdparty_pcre2.target = sub-3rdparty-pcre2
src_3rdparty_harfbuzzng.subdir = $$PWD/3rdparty/harfbuzz-ng
src_3rdparty_harfbuzzng.target = sub-3rdparty-harfbuzzng
@@ -138,13 +142,13 @@ src_android.subdir = $$PWD/android
src_3rdparty_freetype.depends += src_corelib
}
}
-SUBDIRS += src_tools_bootstrap src_tools_moc src_tools_rcc
-qtConfig(regularexpression):pcre {
- SUBDIRS += src_3rdparty_pcre
- src_corelib.depends += src_3rdparty_pcre
+SUBDIRS += src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_qfloat16_tables
+qtConfig(regularexpression):pcre2 {
+ SUBDIRS += src_3rdparty_pcre2
+ src_corelib.depends += src_3rdparty_pcre2
}
SUBDIRS += src_corelib src_tools_qlalr
-TOOLS = src_tools_moc src_tools_rcc src_tools_qlalr
+TOOLS = src_tools_moc src_tools_rcc src_tools_qlalr src_tools_qfloat16_tables
win32:SUBDIRS += src_winmain
qtConfig(network) {
SUBDIRS += src_network
@@ -208,7 +212,7 @@ android: SUBDIRS += src_android src_3rdparty_gradle
TR_EXCLUDE = \
src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_uic src_tools_qlalr \
src_tools_bootstrap_dbus src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml \
- src_3rdparty_pcre src_3rdparty_harfbuzzng src_3rdparty_freetype
+ src_3rdparty_pcre2 src_3rdparty_harfbuzzng src_3rdparty_freetype
sub-tools.depends = $$TOOLS
QMAKE_EXTRA_TARGETS = sub-tools
diff --git a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp
index 2c57550c3d..01ee8102f4 100644
--- a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp
+++ b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp
@@ -208,6 +208,17 @@ void myTestFunction_data()
//! [20]
+//! [addRow]
+void myTestFunction_data()
+{
+ QTest::addColumn<int>("input");
+ QTest::addColumn<QString>("output");
+ QTest::addRow("%d", 0) << 0 << QString("0");
+ QTest::addRow("%d", 1) << 1 << QString("1");
+}
+//! [addRow]
+
+
//! [21]
void myTestFunction_data() {
QTest::addColumn<int>("intval");
diff --git a/src/testlib/qbenchmark_p.h b/src/testlib/qbenchmark_p.h
index 69b33d2d58..dbfa0127b6 100644
--- a/src/testlib/qbenchmark_p.h
+++ b/src/testlib/qbenchmark_p.h
@@ -91,8 +91,8 @@ struct QBenchmarkContext
QString toString() const
{
- QString s = QString::fromLatin1("%1,%2,%3").arg(slotName).arg(tag).arg(checkpointIndex);
- return s;
+ return QString::fromLatin1("%1,%2,%3")
+ .arg(slotName, tag, QString::number(checkpointIndex));
}
QBenchmarkContext() : checkpointIndex(-1) {}
diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp
index dc20d922e5..77959341cf 100644
--- a/src/testlib/qplaintestlogger.cpp
+++ b/src/testlib/qplaintestlogger.cpp
@@ -199,8 +199,8 @@ namespace QTest {
int formatResult(char * buffer, int bufferSize, T number, int significantDigits)
{
QString result = formatResult(number, significantDigits);
- qstrncpy(buffer, result.toLatin1().constData(), bufferSize);
int size = result.count();
+ qstrncpy(buffer, std::move(result).toLatin1().constData(), bufferSize);
return size;
}
}
diff --git a/src/testlib/qteamcitylogger.cpp b/src/testlib/qteamcitylogger.cpp
index 1d700d8201..81c2499bcb 100644
--- a/src/testlib/qteamcitylogger.cpp
+++ b/src/testlib/qteamcitylogger.cpp
@@ -167,17 +167,16 @@ void QTeamCityLogger::addIncident(IncidentTypes type, const char *description,
messageText += QString(QLatin1String(" |[Loc: %1(%2)|]")).arg(QString::fromUtf8(file)).arg(line);
buf = QString(QLatin1String("##teamcity[testFailed name='%1' message='%2' details='%3']\n"))
- .arg(tmpFuncName)
- .arg(messageText)
- .arg(detailedText);
+ .arg(tmpFuncName,
+ messageText,
+ detailedText);
outputString(qPrintable(buf));
}
if (!pendingMessages.isEmpty()) {
buf = QString(QLatin1String("##teamcity[testStdOut name='%1' out='%2']\n"))
- .arg(tmpFuncName)
- .arg(pendingMessages);
+ .arg(tmpFuncName, pendingMessages);
outputString(qPrintable(buf));
@@ -209,8 +208,7 @@ void QTeamCityLogger::addMessage(MessageTypes type, const QString &message,
escapedMessage.append(QString(QLatin1String(" |[Loc: %1(%2)|]")).arg(QString::fromUtf8(file)).arg(line));
buf = QString(QLatin1String("##teamcity[testIgnored name='%1' message='%2']\n"))
- .arg(escapedTestFuncName())
- .arg(escapedMessage);
+ .arg(escapedTestFuncName(), escapedMessage);
outputString(qPrintable(buf));
}
@@ -259,10 +257,7 @@ QString QTeamCityLogger::escapedTestFuncName() const
: "UnknownTestFunc";
const char *tag = QTestResult::currentDataTag() ? QTestResult::currentDataTag() : "";
- QString str = QString(QLatin1String("%1(%2)")).arg(QString::fromUtf8(fn)).arg(QString::fromUtf8(tag));
- str = tcEscapedString(str);
-
- return str;
+ return tcEscapedString(QString::asprintf("%s(%s)", fn, tag));
}
void QTeamCityLogger::addPendingMessage(const char *type, const QString &msg, const char *file, int line)
@@ -274,16 +269,14 @@ void QTeamCityLogger::addPendingMessage(const char *type, const QString &msg, co
if (file) {
pendMessage += QString(QLatin1String("%1 |[Loc: %2(%3)|]: %4"))
- .arg(QString::fromUtf8(type))
- .arg(QString::fromUtf8(file))
+ .arg(QString::fromUtf8(type), QString::fromUtf8(file))
.arg(line)
.arg(msg);
}
else {
pendMessage += QString(QLatin1String("%1: %2"))
- .arg(QString::fromUtf8(type))
- .arg(msg);
+ .arg(QString::fromUtf8(type), msg);
}
pendingMessages.append(pendMessage);
diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h
index b9bb10818e..ba63df5f36 100644
--- a/src/testlib/qtest.h
+++ b/src/testlib/qtest.h
@@ -53,6 +53,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qvariant.h>
#include <QtCore/qurl.h>
+#include <QtCore/quuid.h>
#include <QtCore/qpoint.h>
#include <QtCore/qsize.h>
@@ -164,6 +165,11 @@ template<> inline char *toString(const QUrl &uri)
return qstrdup(uri.toEncoded().constData());
}
+template <> inline char *toString(const QUuid &uuid)
+{
+ return qstrdup(uuid.toByteArray().constData());
+}
+
template<> inline char *toString(const QVariant &v)
{
QByteArray vstring("QVariant(");
diff --git a/src/testlib/qtestaccessible.h b/src/testlib/qtestaccessible.h
index c4c79b7deb..464f87fb5c 100644
--- a/src/testlib/qtestaccessible.h
+++ b/src/testlib/qtestaccessible.h
@@ -47,8 +47,6 @@
#include <QtCore/qglobal.h>
-#ifndef QT_NO_ACCESSIBILITY
-
#define QVERIFY_EVENT(event) \
QVERIFY(QTestAccessibility::verifyEvent(event))
@@ -59,6 +57,8 @@
#include <QtTest/qtest_global.h>
#include <QtTest/qtestsystem.h>
+#if QT_CONFIG(accessibility)
+
QT_BEGIN_NAMESPACE
@@ -294,5 +294,5 @@ private:
QT_END_NAMESPACE
-#endif // QT_NO_ACCESSIBILITY
+#endif // QT_CONFIG(accessibility)
#endif // QTESTACCESSIBLE_H
diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp
index 587930ca73..0ebc800fe1 100644
--- a/src/testlib/qtestblacklist.cpp
+++ b/src/testlib/qtestblacklist.cpp
@@ -82,7 +82,9 @@ QT_BEGIN_NAMESPACE
msvc-2010
Keys are lower-case. Distribution name and version are supported if
- QSysInfo's productType() and productVersion() return them.
+ QSysInfo's productType() and productVersion() return them. Keys can be
+ added via the space-separated QTEST_ENVIRONMENT environment variable.
+
The other known keys are listed below:
*/
@@ -184,6 +186,11 @@ static QSet<QByteArray> activeConditions()
}
}
+ if (qEnvironmentVariableIsSet("QTEST_ENVIRONMENT")) {
+ for (const QByteArray &k : qgetenv("QTEST_ENVIRONMENT").split(' '))
+ result.insert(k);
+ }
+
return result;
}
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index ac71954a55..8b0820b941 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -98,11 +98,16 @@
#include <errno.h>
#include <signal.h>
#include <time.h>
-#include <sys/resource.h>
+# if !defined(Q_OS_INTEGRITY)
+# include <sys/resource.h>
+# endif
#endif
#if defined(Q_OS_MACX)
#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <mach/task.h>
+#include <mach/mach_init.h>
+#include <CoreFoundation/CFPreferences.h>
#endif
#include <vector>
@@ -137,6 +142,40 @@ static bool debuggerPresent()
return pid != 0;
#elif defined(Q_OS_WIN)
return IsDebuggerPresent();
+#elif defined(Q_OS_MACOS)
+ auto equals = [](CFStringRef str1, CFStringRef str2) -> bool {
+ return CFStringCompare(str1, str2, kCFCompareCaseInsensitive) == kCFCompareEqualTo;
+ };
+
+ // Check if there is an exception handler for the process:
+ mach_msg_type_number_t portCount = 0;
+ exception_mask_t masks[EXC_TYPES_COUNT];
+ mach_port_t ports[EXC_TYPES_COUNT];
+ exception_behavior_t behaviors[EXC_TYPES_COUNT];
+ thread_state_flavor_t flavors[EXC_TYPES_COUNT];
+ exception_mask_t mask = EXC_MASK_ALL & ~(EXC_MASK_RESOURCE | EXC_MASK_GUARD);
+ kern_return_t result = task_get_exception_ports(mach_task_self(), mask, masks, &portCount,
+ ports, behaviors, flavors);
+ if (result == KERN_SUCCESS) {
+ for (mach_msg_type_number_t portIndex = 0; portIndex < portCount; ++portIndex) {
+ if (MACH_PORT_VALID(ports[portIndex])) {
+ return true;
+ }
+ }
+ }
+
+ // Ok, no debugger attached. So, let's see if CrashReporter will throw up a dialog. If so, we
+ // leave it to the OS to do the stack trace.
+ CFStringRef crashReporterType = static_cast<CFStringRef>(
+ CFPreferencesCopyAppValue(CFSTR("DialogType"), CFSTR("com.apple.CrashReporter")));
+ if (crashReporterType == nullptr)
+ return true;
+
+ const bool createsStackTrace =
+ !equals(crashReporterType, CFSTR("server")) &&
+ !equals(crashReporterType, CFSTR("none"));
+ CFRelease(crashReporterType);
+ return createsStackTrace;
#else
// TODO
return false;
@@ -148,7 +187,7 @@ static void disableCoreDump()
bool ok = false;
const int disableCoreDump = qEnvironmentVariableIntValue("QTEST_DISABLE_CORE_DUMP", &ok);
if (ok && disableCoreDump == 1) {
-#if defined(Q_OS_UNIX)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
struct rlimit limit;
limit.rlim_cur = 0;
limit.rlim_max = 0;
@@ -2060,7 +2099,7 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co
// 5. Try current directory
if (found.isEmpty()) {
- QString candidate = QString::fromLatin1("%1/%2").arg(QDir::currentPath()).arg(base);
+ const QString candidate = QDir::currentPath() + QLatin1Char('/') + base;
if (QFileInfo::exists(candidate))
found = candidate;
}
@@ -2159,6 +2198,48 @@ QTestData &QTest::newRow(const char *dataTag)
return *tbl->newData(dataTag);
}
+/*!
+ \since 5.9
+
+ Appends a new row to the current test data. The function's arguments are passed
+ to qsnprintf() for formatting according to \a format. See the qvsnprintf()
+ documentation for caveats and limitations.
+
+ The formatted string will appear as the name of this test data in the test output.
+
+ Returns a QTestData reference that can be used to stream in data.
+
+ Example:
+ \snippet code/src_qtestlib_qtestcase.cpp addRow
+
+ \b {Note:} This function can only be used in a test's data function
+ that is invoked by the test framework.
+
+ See \l {Chapter 2: Data Driven Testing}{Data Driven Testing} for
+ a more extensive example.
+
+ \sa addColumn(), QFETCH()
+*/
+QTestData &QTest::addRow(const char *format, ...)
+{
+ QTEST_ASSERT_X(format, "QTest::addRow()", "Format string cannot be null");
+ QTestTable *tbl = QTestTable::currentTestTable();
+ QTEST_ASSERT_X(tbl, "QTest::addRow()", "Cannot add testdata outside of a _data slot.");
+ QTEST_ASSERT_X(tbl->elementCount(), "QTest::addRow()", "Must add columns before attempting to add rows.");
+
+ char buf[1024];
+
+ va_list va;
+ va_start(va, format);
+ // we don't care about failures, we accept truncation, as well as trailing garbage.
+ // Names with more than 1K characters are nonsense, anyway.
+ (void)qvsnprintf(buf, sizeof buf, format, va);
+ buf[sizeof buf - 1] = '\0';
+ va_end(va);
+
+ return *tbl->newData(buf);
+}
+
/*! \fn void QTest::addColumn(const char *name, T *dummy = 0)
Adds a column with type \c{T} to the current test data.
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h
index 57e0486686..a7e825396a 100644
--- a/src/testlib/qtestcase.h
+++ b/src/testlib/qtestcase.h
@@ -51,7 +51,6 @@
#include <string.h>
-#include <type_traits>
#ifndef QT_NO_EXCEPTIONS
# include <exception>
#endif // QT_NO_EXCEPTIONS
@@ -240,14 +239,14 @@ namespace QTest
namespace Internal {
template<typename T> // Output registered enums
- inline typename QtPrivate::QEnableIf<QtPrivate::IsQEnumHelper<T>::Value, char*>::Type toString(T e)
+ inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e)
{
QMetaEnum me = QMetaEnum::fromType<T>();
return qstrdup(me.valueToKey(int(e))); // int cast is necessary to support enum classes
}
template <typename T> // Fallback
- inline typename QtPrivate::QEnableIf<!QtPrivate::IsQEnumHelper<T>::Value, char*>::Type toString(const T &)
+ inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(const T &)
{
return Q_NULLPTR;
}
@@ -318,6 +317,7 @@ namespace QTest
addColumnInternal(qMetaTypeId<T>(), name);
}
Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag);
+ Q_TESTLIB_EXPORT QTestData &addRow(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2);
template <typename T>
inline bool qCompare(T const &t1, T const &t2, const char *actual, const char *expected,
diff --git a/src/testlib/qtestsystem.h b/src/testlib/qtestsystem.h
index 9c509690e4..f38a156936 100644
--- a/src/testlib/qtestsystem.h
+++ b/src/testlib/qtestsystem.h
@@ -116,14 +116,14 @@ namespace QTest
#ifdef QT_WIDGETS_LIB
inline static bool qWaitForWindowActive(QWidget *widget, int timeout = 5000)
{
- if (QWindow *window = widget->windowHandle())
+ if (QWindow *window = widget->window()->windowHandle())
return qWaitForWindowActive(window, timeout);
return false;
}
inline static bool qWaitForWindowExposed(QWidget *widget, int timeout = 5000)
{
- if (QWindow *window = widget->windowHandle())
+ if (QWindow *window = widget->window()->windowHandle())
return qWaitForWindowExposed(window, timeout);
return false;
}
diff --git a/src/testlib/qtestutil_macos.mm b/src/testlib/qtestutil_macos.mm
index 852c9f75f2..70a7fb9f85 100644
--- a/src/testlib/qtestutil_macos.mm
+++ b/src/testlib/qtestutil_macos.mm
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtTest module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/testlib/qtestutil_macos_p.h b/src/testlib/qtestutil_macos_p.h
index 85f9ace82f..d7cc5bc251 100644
--- a/src/testlib/qtestutil_macos_p.h
+++ b/src/testlib/qtestutil_macos_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtTest module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro
index 2acc3fc77c..507b5260cd 100644
--- a/src/tools/bootstrap/bootstrap.pro
+++ b/src/tools/bootstrap/bootstrap.pro
@@ -28,6 +28,7 @@ SOURCES += \
../../corelib/global/qlogging.cpp \
../../corelib/global/qmalloc.cpp \
../../corelib/global/qnumeric.cpp \
+ ../../corelib/global/qoperatingsystemversion.cpp \
../../corelib/io/qabstractfileengine.cpp \
../../corelib/io/qbuffer.cpp \
../../corelib/io/qdatastream.cpp \
@@ -45,6 +46,7 @@ SOURCES += \
../../corelib/io/qresource.cpp \
../../corelib/io/qtemporaryfile.cpp \
../../corelib/io/qtextstream.cpp \
+ ../../corelib/io/qsavefile.cpp \
../../corelib/io/qstandardpaths.cpp \
../../corelib/io/qloggingcategory.cpp \
../../corelib/io/qloggingregistry.cpp \
@@ -95,7 +97,8 @@ unix:SOURCES += ../../corelib/io/qfilesystemengine_unix.cpp \
../../corelib/io/qfilesystemiterator_unix.cpp \
../../corelib/io/qfsfileengine_unix.cpp
-win32:SOURCES += ../../corelib/io/qfilesystemengine_win.cpp \
+win32:SOURCES += ../../corelib/global/qoperatingsystemversion_win.cpp \
+ ../../corelib/io/qfilesystemengine_win.cpp \
../../corelib/io/qfilesystemiterator_win.cpp \
../../corelib/io/qfsfileengine_win.cpp \
../../corelib/kernel/qcoreapplication_win.cpp \
@@ -106,6 +109,7 @@ mac {
../../corelib/kernel/qcoreapplication_mac.cpp \
../../corelib/kernel/qcore_mac.cpp
OBJECTIVE_SOURCES += \
+ ../../corelib/global/qoperatingsystemversion_darwin.mm \
../../corelib/kernel/qcore_mac_objc.mm \
../../corelib/kernel/qcore_foundation.mm
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index ccc6d795d7..c4184929ef 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -515,7 +515,7 @@ void Generator::generateCode()
for (int i = 0; i < extraList.count(); ++i) {
fprintf(out, " &%s::staticMetaObject,\n", extraList.at(i).constData());
}
- fprintf(out, " Q_NULLPTR\n};\n\n");
+ fprintf(out, " nullptr\n};\n\n");
}
//
@@ -527,24 +527,24 @@ void Generator::generateCode()
fprintf(out, "const QMetaObject %s::staticMetaObject = {\n", cdef->qualified.constData());
if (isQObject)
- fprintf(out, " { Q_NULLPTR, ");
+ fprintf(out, " { nullptr, ");
else if (cdef->superclassList.size() && (!cdef->hasQGadget || knownGadgets.contains(purestSuperClass)))
fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData());
else
- fprintf(out, " { Q_NULLPTR, ");
+ fprintf(out, " { nullptr, ");
fprintf(out, "qt_meta_stringdata_%s.data,\n"
" qt_meta_data_%s, ", qualifiedClassNameIdentifier.constData(),
qualifiedClassNameIdentifier.constData());
if (hasStaticMetaCall)
fprintf(out, " qt_static_metacall, ");
else
- fprintf(out, " Q_NULLPTR, ");
+ fprintf(out, " nullptr, ");
if (extraList.isEmpty())
- fprintf(out, "Q_NULLPTR, ");
+ fprintf(out, "nullptr, ");
else
fprintf(out, "qt_meta_extradata_%s, ", qualifiedClassNameIdentifier.constData());
- fprintf(out, "Q_NULLPTR}\n};\n\n");
+ fprintf(out, "nullptr}\n};\n\n");
if(isQt)
return;
@@ -559,7 +559,7 @@ void Generator::generateCode()
// Generate smart cast function
//
fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
- fprintf(out, " if (!_clname) return Q_NULLPTR;\n");
+ fprintf(out, " if (!_clname) return nullptr;\n");
fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata0))\n"
" return static_cast<void*>(const_cast< %s*>(this));\n",
qualifiedClassNameIdentifier.constData(), cdef->classname.constData());
@@ -584,7 +584,7 @@ void Generator::generateCode()
QByteArray superClass = purestSuperClass;
fprintf(out, " return %s::qt_metacast(_clname);\n", superClass.constData());
} else {
- fprintf(out, " return Q_NULLPTR;\n");
+ fprintf(out, " return nullptr;\n");
}
fprintf(out, "}\n");
@@ -918,8 +918,6 @@ void Generator::generateMetacall()
fprintf(out, " _id = %s::qt_metacall(_c, _id, _a);\n", superClass.constData());
}
- fprintf(out, " if (_id < 0)\n return _id;\n");
- fprintf(out, " ");
bool needElse = false;
QVector<FunctionDef> methodList;
@@ -927,6 +925,15 @@ void Generator::generateMetacall()
methodList += cdef->slotList;
methodList += cdef->methodList;
+ // If there are no methods or properties, we will return _id anyway, so
+ // don't emit this comparison -- it is unnecessary, and it makes coverity
+ // unhappy.
+ if (methodList.size() || cdef->propertyList.size()) {
+ fprintf(out, " if (_id < 0)\n return _id;\n");
+ }
+
+ fprintf(out, " ");
+
if (methodList.size()) {
needElse = true;
fprintf(out, "if (_c == QMetaObject::InvokeMetaMethod) {\n");
@@ -1067,7 +1074,7 @@ void Generator::generateMetacall()
fprintf(out, "\n#endif // QT_NO_PROPERTIES");
}
- if (methodList.size() || cdef->signalList.size() || cdef->propertyList.size())
+ if (methodList.size() || cdef->propertyList.size())
fprintf(out, "\n ");
fprintf(out,"return _id;\n}\n");
}
@@ -1186,7 +1193,7 @@ void Generator::generateStaticMetacall()
}
fprintf(out, ");");
if (f.normalizedType != "void") {
- fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ",
+ fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = std::move(_r); } ",
noRef(f.normalizedType).constData());
isUsed_a = true;
}
@@ -1476,12 +1483,9 @@ void Generator::generateSignal(FunctionDef *def,int index)
}
Q_ASSERT(!def->normalizedType.isEmpty());
- if (def->arguments.isEmpty() && def->normalizedType == "void") {
- if (def->isPrivateSignal)
- fprintf(out, "QPrivateSignal");
-
+ if (def->arguments.isEmpty() && def->normalizedType == "void" && !def->isPrivateSignal) {
fprintf(out, ")%s\n{\n"
- " QMetaObject::activate(%s, &staticMetaObject, %d, Q_NULLPTR);\n"
+ " QMetaObject::activate(%s, &staticMetaObject, %d, nullptr);\n"
"}\n", constQualifier, thisPtr.constData(), index);
return;
}
@@ -1496,22 +1500,18 @@ void Generator::generateSignal(FunctionDef *def,int index)
if (def->isPrivateSignal) {
if (!def->arguments.isEmpty())
fprintf(out, ", ");
- fprintf(out, "QPrivateSignal");
+ fprintf(out, "QPrivateSignal _t%d", offset++);
}
fprintf(out, ")%s\n{\n", constQualifier);
if (def->type.name.size() && def->normalizedType != "void") {
QByteArray returnType = noRef(def->normalizedType);
- if (returnType.endsWith('*')) {
- fprintf(out, " %s _t0 = 0;\n", returnType.constData());
- } else {
- fprintf(out, " %s _t0 = %s();\n", returnType.constData(), returnType.constData());
- }
+ fprintf(out, " %s _t0{};\n", returnType.constData());
}
fprintf(out, " void *_a[] = { ");
if (def->normalizedType == "void") {
- fprintf(out, "Q_NULLPTR");
+ fprintf(out, "nullptr");
} else {
if (def->returnTypeIsVolatile)
fprintf(out, "const_cast<void*>(reinterpret_cast<const volatile void*>(&_t0))");
@@ -1520,7 +1520,7 @@ void Generator::generateSignal(FunctionDef *def,int index)
}
int i;
for (i = 1; i < offset; ++i)
- if (def->arguments.at(i - 1).type.isVolatile)
+ if (i <= def->arguments.count() && def->arguments.at(i - 1).type.isVolatile)
fprintf(out, ", const_cast<void*>(reinterpret_cast<const volatile void*>(&_t%d))", i);
else
fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(&_t%d))", i);
diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp
index 6128d5490b..b30de66258 100644
--- a/src/tools/moc/main.cpp
+++ b/src/tools/moc/main.cpp
@@ -305,7 +305,7 @@ int runMoc(int argc, char **argv)
const QStringList files = parser.positionalArguments();
if (files.count() > 1) {
- error(qPrintable(QStringLiteral("Too many input files specified: '") + files.join(QStringLiteral("' '")) + QLatin1Char('\'')));
+ error(qPrintable(QLatin1String("Too many input files specified: '") + files.join(QLatin1String("' '")) + QLatin1Char('\'')));
parser.showHelp(1);
} else if (!files.isEmpty()) {
filename = files.first();
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 03f022da69..36d84a61d8 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -549,12 +549,20 @@ void Moc::parse()
case NAMESPACE: {
int rewind = index;
if (test(IDENTIFIER)) {
+ QByteArray nsName = lexem();
+ QByteArrayList nested;
+ while (test(SCOPE)) {
+ next(IDENTIFIER);
+ nested.append(nsName);
+ nsName = lexem();
+ }
if (test(EQ)) {
// namespace Foo = Bar::Baz;
until(SEMIC);
} else if (!test(SEMIC)) {
NamespaceDef def;
- def.classname = lexem();
+ def.classname = nsName;
+
next(LBRACE);
def.begin = index - 1;
until(RBRACE);
@@ -568,11 +576,23 @@ void Moc::parse()
def.qualified.prepend(namespaceList.at(i).classname + "::");
}
}
+ for (const QByteArray &ns : nested) {
+ NamespaceDef parentNs;
+ parentNs.classname = ns;
+ parentNs.qualified = def.qualified;
+ def.qualified += ns + "::";
+ parentNs.begin = def.begin;
+ parentNs.end = def.end;
+ namespaceList += parentNs;
+ }
}
+
while (parseNamespace && inNamespace(&def) && hasNext()) {
switch (next()) {
case NAMESPACE:
if (test(IDENTIFIER)) {
+ while (test(SCOPE))
+ next(IDENTIFIER);
if (test(EQ)) {
// namespace Foo = Bar::Baz;
until(SEMIC);
@@ -1294,7 +1314,12 @@ void Moc::parsePluginData(ClassDef *def)
return;
}
QFile file(fi.canonicalFilePath());
- file.open(QFile::ReadOnly);
+ if (!file.open(QFile::ReadOnly)) {
+ QByteArray msg = "Plugin Metadata file " + lexem() + " could not be opened: "
+ + file.errorString().toUtf8();
+ error(msg.constData());
+ return;
+ }
metaData = file.readAll();
}
}
diff --git a/src/tools/moc/mwerks_mac.cpp b/src/tools/moc/mwerks_mac.cpp
deleted file mode 100644
index fe8bf680fb..0000000000
--- a/src/tools/moc/mwerks_mac.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifdef MOC_MWERKS_PLUGIN
-
-#include "mwerks_mac.h"
-#include "qt_mac.h"
-
-/* compiler headers */
-#include "DropInCompilerLinker.h"
-#include "CompilerMapping.h"
-#include "CWPluginErrors.h"
-
-/* standard headers */
-#include <stdio.h>
-#include <string.h>
-
-QT_BEGIN_NAMESPACE
-
-//qglobal.cpp
-const unsigned char * p_str(const char * c);
-QCString pstring2qstring(const unsigned char *c);
-
-#if CW_USE_PRAGMA_EXPORT
-#pragma export on
-#endif
-
-CWPLUGIN_ENTRY(CWPlugin_GetDropInFlags)(const DropInFlags** flags, long* flagsSize)
-{
- static const DropInFlags sFlags = {
- kCurrentDropInFlagsVersion,
- CWDROPINCOMPILERTYPE,
- DROPINCOMPILERLINKERAPIVERSION_7,
- kCompAlwaysReload|kCompRequiresProjectBuildStartedMsg,
- Lang_C_CPP,
- DROPINCOMPILERLINKERAPIVERSION
- };
- *flags = &sFlags;
- *flagsSize = sizeof(sFlags);
- return cwNoErr;
-}
-
-
-
-CWPLUGIN_ENTRY(CWPlugin_GetDropInName)(const char** dropinName)
-{
- static const char sDropInName[] = "McMoc";
- *dropinName = sDropInName;
- return cwNoErr;
-}
-
-CWPLUGIN_ENTRY(CWPlugin_GetDisplayName)(const char** displayName)
-{
- static const char sDisplayName[] = "McMoc";
- *displayName = sDisplayName;
- return cwNoErr;
-}
-
-CWPLUGIN_ENTRY(CWPlugin_GetTargetList)(const CWTargetList** targetList)
-{
- static CWDataType sCPU = targetCPUAny;
- static CWDataType sOS = targetOSMacintosh;
- static CWTargetList sTargetList = {kCurrentCWTargetListVersion, 1, &sCPU, 1, &sOS};
- *targetList = &sTargetList;
- return cwNoErr;
-}
-
-CWPLUGIN_ENTRY(CWPlugin_GetDefaultMappingList)(const CWExtMapList** defaultMappingList)
-{
- static CWExtensionMapping sExtension[] = { {'TEXT', ".mocs", kPrecompile } };
- static CWExtMapList sExtensionMapList = {kCurrentCWExtMapListVersion, 3, sExtension};
- *defaultMappingList = &sExtensionMapList;
- return cwNoErr;
-}
-
-#if CW_USE_PRAGMA_EXPORT
-#pragma export off
-#endif
-typedef short CWFileRef;
-
-static int line_count = 0;
-moc_status do_moc(CWPluginContext, const QCString &, const QCString &, CWFileSpec *, bool);
-
-static CWResult mocify(CWPluginContext context, const QCString &source)
-{
- CWDisplayLines(context, line_count++);
-
- source.stripWhiteSpace();
-
- CWResult err;
- bool dotmoc=false;
- QCString stem = source, ext;
- int dotpos = stem.findRev('.');
- if(dotpos != -1) {
- ext = stem.right(stem.length() - (dotpos+1));
- stem = stem.left(dotpos);
- if(ext == "cpp")
- dotmoc = true;
- } else {
- //whoa!
- }
- QCString dest;
- if(dotmoc)
- dest = stem + ".moc";
- else
- dest = "moc_" + stem + ".cpp";
-
- //moc it
- CWFileSpec destSpec;
- moc_status mocd = do_moc(context, source, dest, &destSpec, dotmoc);
-
-#if 0
- QCString derr = "Weird";
- switch(mocd) {
- case moc_success: derr = "Success"; break;
- case moc_parse_error: derr = "Parser Error"; break;
- case moc_no_qobject:derr = "No QOBJECT"; break;
- case moc_not_time: derr = "Not Time"; break;
- case moc_no_source: derr = "No Source"; break;
- case moc_general_error: derr = "General Error"; break;
- }
- char dmsg[200];
- sprintf(dmsg, "\"%s\" %s", source.data(), derr.data());
- CWReportMessage(context, NULL, dmsg, NULL, messagetypeError, 0);
-#endif
-
- //handle project
- if(mocd == moc_no_qobject) {
- char msg[400];
- sprintf(msg, "\"%s\" No relevant classes found. No output generated.", source.data());
- CWReportMessage(context, NULL, msg, NULL, messagetypeWarning, 0);
- } else if ((mocd == moc_success || mocd == moc_not_time) && !dotmoc)
- {
- long whichFile;
- CWNewProjectEntryInfo ei;
- memset(&ei, '\0', sizeof(ei));
- ei.groupPath = "QtGenerated";
- err = CWAddProjectEntry(context, &destSpec, true, &ei, &whichFile);
- if (!CWSUCCESS(err))
- {
- char msg[200];
- sprintf(msg, "\"%s\" not added", dest.data());
- CWReportMessage(context, NULL, msg, NULL, messagetypeWarning, 0);
- }
- if(mocd == moc_success)
- CWSetModDate(context, &destSpec, NULL, true);
- }
- return cwNoErr;
-}
-
-pascal short main(CWPluginContext context)
-{
- short result;
- long request;
-
- if (CWGetPluginRequest(context, &request) != cwNoErr)
- return cwErrRequestFailed;
- result = cwErrInvalidParameter;
-
- /* dispatch on compiler request */
- switch (request)
- {
- case reqInitCompiler:
- case reqTermCompiler:
- result = cwNoErr;
- break;
-
- case reqCompile:
- {
- line_count = 0;
- const char *files = NULL;
- long filelen;
- CWGetMainFileText(context, &files, &filelen);
- const char *beg = files;
- for(int x = 0; x < filelen; x++) {
- if(*(files++) == '\r') {
- char file[1024];
- memcpy(file, beg, files - beg);
- file[(files-beg)-1] = '\0';
- mocify(context, file);
- beg = files;
- }
- }
- if(beg != files) {
- char file[1024];
- memcpy(file, beg, files - beg);
- file[(files-beg)] = '\0';
- mocify(context, file);
- }
-
- result = cwNoErr;
- break;
- }
- }
-
- /* return result code */
- return result;
-}
-
-#endif
-
-QT_END_NAMESPACE
diff --git a/src/tools/moc/mwerks_mac.h b/src/tools/moc/mwerks_mac.h
deleted file mode 100644
index 9f6f074036..0000000000
--- a/src/tools/moc/mwerks_mac.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef MWERKS_MAC_H
-#define MWERKS_MAC_H
-
-#include <qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifdef Q_OS_MAC
-
-#define macintosh
-
-/*make moc a plugin*/
-enum moc_status {
- moc_success = 1,
- moc_parse_error = 2,
- moc_no_qobject = 3,
- moc_not_time = 4,
- moc_no_source = 5,
- moc_general_error = 6
-};
-
-#endif
-
-QT_END_NAMESPACE
-
-#endif // MWERKS_MAC_H
diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp
index 11bf8d7937..32c94639ab 100644
--- a/src/tools/moc/preprocessor.cpp
+++ b/src/tools/moc/preprocessor.cpp
@@ -236,7 +236,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
data -= 2;
break;
case DIGIT:
- while (is_digit_char(*data))
+ while (is_digit_char(*data) || *data == '\'')
++data;
if (!*data || *data != '.') {
token = INTEGER_LITERAL;
@@ -244,7 +244,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
(*data == 'x' || *data == 'X')
&& *lexem == '0') {
++data;
- while (is_hex_char(*data))
+ while (is_hex_char(*data) || *data == '\'')
++data;
}
break;
@@ -253,13 +253,13 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
++data;
Q_FALLTHROUGH();
case FLOATING_LITERAL:
- while (is_digit_char(*data))
+ while (is_digit_char(*data) || *data == '\'')
++data;
if (*data == '+' || *data == '-')
++data;
if (*data == 'e' || *data == 'E') {
++data;
- while (is_digit_char(*data))
+ while (is_digit_char(*data) || *data == '\'')
++data;
}
if (*data == 'f' || *data == 'F'
@@ -413,7 +413,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
token = PP_CHARACTER_LITERAL;
break;
case PP_DIGIT:
- while (is_digit_char(*data))
+ while (is_digit_char(*data) || *data == '\'')
++data;
if (!*data || *data != '.') {
token = PP_INTEGER_LITERAL;
@@ -421,7 +421,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
(*data == 'x' || *data == 'X')
&& *lexem == '0') {
++data;
- while (is_hex_char(*data))
+ while (is_hex_char(*data) || *data == '\'')
++data;
}
break;
@@ -430,13 +430,13 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
++data;
Q_FALLTHROUGH();
case PP_FLOATING_LITERAL:
- while (is_digit_char(*data))
+ while (is_digit_char(*data) || *data == '\'')
++data;
if (*data == '+' || *data == '-')
++data;
if (*data == 'e' || *data == 'E') {
++data;
- while (is_digit_char(*data))
+ while (is_digit_char(*data) || *data == '\'')
++data;
}
if (*data == 'f' || *data == 'F'
@@ -1005,22 +1005,20 @@ static void mergeStringLiterals(Symbols *_symbols)
}
}
-QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteArray &relativeTo)
+static QByteArray searchIncludePaths(const QList<Parser::IncludePath> &includepaths,
+ const QByteArray &include)
{
- // #### stringery
QFileInfo fi;
- if (!relativeTo.isEmpty())
- fi.setFile(QFileInfo(QString::fromLocal8Bit(relativeTo.constData())).dir(), QString::fromLocal8Bit(include.constData()));
- for (int j = 0; j < Preprocessor::includes.size() && !fi.exists(); ++j) {
- const IncludePath &p = Preprocessor::includes.at(j);
+ for (int j = 0; j < includepaths.size() && !fi.exists(); ++j) {
+ const Parser::IncludePath &p = includepaths.at(j);
if (p.isFrameworkPath) {
const int slashPos = include.indexOf('/');
if (slashPos == -1)
continue;
fi.setFile(QString::fromLocal8Bit(p.path + '/' + include.left(slashPos) + ".framework/Headers/"),
- QString::fromLocal8Bit(include.mid(slashPos + 1).constData()));
+ QString::fromLocal8Bit(include.mid(slashPos + 1)));
} else {
- fi.setFile(QString::fromLocal8Bit(p.path.constData()), QString::fromLocal8Bit(include.constData()));
+ fi.setFile(QString::fromLocal8Bit(p.path), QString::fromLocal8Bit(include));
}
// try again, maybe there's a file later in the include paths with the same name
// (186067)
@@ -1035,6 +1033,21 @@ QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteAr
return fi.canonicalFilePath().toLocal8Bit();
}
+QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteArray &relativeTo)
+{
+ if (!relativeTo.isEmpty()) {
+ QFileInfo fi;
+ fi.setFile(QFileInfo(QString::fromLocal8Bit(relativeTo)).dir(), QString::fromLocal8Bit(include));
+ if (fi.exists() && !fi.isDir())
+ return fi.canonicalFilePath().toLocal8Bit();
+ }
+
+ auto it = nonlocalIncludePathResolutionCache.find(include);
+ if (it == nonlocalIncludePathResolutionCache.end())
+ it = nonlocalIncludePathResolutionCache.insert(include, searchIncludePaths(includes, include));
+ return it.value();
+}
+
void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
{
currentFilenames.push(filename);
diff --git a/src/tools/moc/preprocessor.h b/src/tools/moc/preprocessor.h
index a7eb1a19e1..39f56d6e92 100644
--- a/src/tools/moc/preprocessor.h
+++ b/src/tools/moc/preprocessor.h
@@ -61,6 +61,7 @@ public:
static bool preprocessOnly;
QList<QByteArray> frameworks;
QSet<QByteArray> preprocessedIncludes;
+ QHash<QByteArray, QByteArray> nonlocalIncludePathResolutionCache;
Macros macros;
QByteArray resolveInclude(const QByteArray &filename, const QByteArray &relativeTo);
Symbols preprocessed(const QByteArray &filename, QFile *device);
diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
index 26e7b086d9..7ddd0fcf5d 100644
--- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
+++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
@@ -103,9 +103,8 @@ static inline QString typeNameToXml(const char *typeName)
static QString addFunction(const FunctionDef &mm, bool isSignal = false) {
- QString xml = QString::fromLatin1(" <%1 name=\"%2\">\n")
- .arg(isSignal ? QLatin1String("signal") : QLatin1String("method"))
- .arg(QLatin1String(mm.name));
+ QString xml = QString::asprintf(" <%s name=\"%s\">\n",
+ isSignal ? "signal" : "method", mm.name.constData());
// check the return type first
int typeId = QMetaType::type(mm.normalizedType.constData());
@@ -156,9 +155,9 @@ static QString addFunction(const FunctionDef &mm, bool isSignal = false) {
const char *signature = QDBusMetaType::typeToSignature(types.at(j));
xml += QString::fromLatin1(" <arg %1type=\"%2\" direction=\"%3\"/>\n")
- .arg(name)
- .arg(QLatin1String(signature))
- .arg(isOutput ? QLatin1String("out") : QLatin1String("in"));
+ .arg(name,
+ QLatin1String(signature),
+ isOutput ? QLatin1String("out") : QLatin1String("in"));
// do we need to describe this argument?
if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) {
@@ -220,9 +219,9 @@ static QString generateInterfaceXml(const ClassDef *mo)
continue;
retval += QString::fromLatin1(" <property name=\"%1\" type=\"%2\" access=\"%3\"")
- .arg(QLatin1String(mp.name))
- .arg(QLatin1String(signature))
- .arg(QLatin1String(accessvalues[access]));
+ .arg(QLatin1String(mp.name),
+ QLatin1String(signature),
+ QLatin1String(accessvalues[access]));
if (QDBusMetaType::signatureToType(signature) == QVariant::Invalid) {
retval += QString::fromLatin1(">\n <annotation name=\"org.qtproject.QtDBus.QtTypeName\" value=\"%3\"/>\n </property>\n")
@@ -448,7 +447,7 @@ int main(int argc, char **argv)
output.write("<node>\n");
for (const ClassDef &cdef : qAsConst(classes)) {
QString xml = qDBusGenerateClassDefXml(&cdef);
- output.write(xml.toLocal8Bit());
+ output.write(std::move(xml).toLocal8Bit());
}
output.write("</node>\n");
diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
index cdf3ad3310..9ccf8be73a 100644
--- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
+++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
@@ -217,7 +217,7 @@ static QByteArray qtTypeName(const QString &signature, const QDBusIntrospection:
annotationName += QString::fromLatin1(".%1%2").arg(QLatin1String(direction)).arg(paramId);
QString qttype = annotations.value(annotationName);
if (!qttype.isEmpty())
- return qttype.toLatin1();
+ return std::move(qttype).toLatin1();
QString oldAnnotationName = QString::fromLatin1("com.trolltech.QtDBus.QtTypeName");
if (paramId >= 0)
@@ -242,7 +242,7 @@ static QByteArray qtTypeName(const QString &signature, const QDBusIntrospection:
"suggest updating to '%s'\n",
PROGRAMNAME, qPrintable(oldAnnotationName), qPrintable(inputFile),
qPrintable(annotationName));
- return qttype.toLatin1();
+ return std::move(qttype).toLatin1();
}
return QVariant::typeToName(QVariant::Type(type));
diff --git a/src/tools/qfloat16-tables/gen_qfloat16_tables.cpp b/src/tools/qfloat16-tables/gen_qfloat16_tables.cpp
new file mode 100644
index 0000000000..f5051e25fc
--- /dev/null
+++ b/src/tools/qfloat16-tables/gen_qfloat16_tables.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 by Southwest Research Institute (R)
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qfile.h>
+#include <qdebug.h>
+
+quint32 convertmantissa(qint32 i)
+{
+ quint32 m = i << 13; // Zero pad mantissa bits
+ quint32 e = 0; // Zero exponent
+
+ while (!(m & 0x00800000)) { // While not normalized
+ e -= 0x00800000; // Decrement exponent (1<<23)
+ m <<= 1; // Shift mantissa
+ }
+ m &= ~0x00800000; // Clear leading 1 bit
+ e += 0x38800000; // Adjust bias ((127-14)<<23)
+ return m | e; // Return combined number
+}
+
+// we first build these tables up and then print them out as a separate step in order
+// to more closely map the implementation given in the paper.
+quint32 basetable[512];
+quint32 shifttable[512];
+
+#define PRINTHEX(a) "0x" + QByteArray::number(a,16).toUpper() + "U,\n"
+
+qint32 main(qint32 argc, char **argv)
+{
+ if (argc < 2) {
+ qWarning() << "Must provide output filename as argument.";
+ return -1;
+ }
+
+ QFile fid(argv[1]);
+ if (!fid.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ qWarning() << "Abort: Failed to open/create file" << fid.fileName();
+ return -1;
+ }
+ quint32 i;
+
+ fid.write("/* This file was generated by gen_qfloat16_tables.cpp */\n\n");
+ fid.write("#include <QtCore/qfloat16.h>\n\n");
+
+ fid.write("QT_BEGIN_NAMESPACE\n\n");
+
+ fid.write("const quint32 qfloat16::mantissatable[2048] = {\n");
+ fid.write("0,\n");
+ for (i = 1; i < 1024; i++)
+ fid.write(PRINTHEX(convertmantissa(i)));
+ for (i = 1024; i < 2048; i++)
+ fid.write(PRINTHEX(0x38000000U + ((i - 1024) << 13)));
+ fid.write("};\n\n");
+
+ fid.write("const quint32 qfloat16::exponenttable[64] = {\n");
+ fid.write("0,\n");
+ for (i = 1; i < 31; i++)
+ fid.write(PRINTHEX(i << 23));
+ fid.write("0x47800000U,\n"); // 31
+ fid.write("0x80000000U,\n"); // 32
+ for (i = 33; i < 63; i++)
+ fid.write(PRINTHEX(0x80000000U + ((i - 32) << 23)));
+ fid.write("0xC7800000U,\n"); // 63
+ fid.write("};\n\n");
+
+ fid.write("const quint32 qfloat16::offsettable[64] = {\n");
+ fid.write("0,\n");
+ for (i = 1; i < 32; i++)
+ fid.write("1024U,\n");
+ fid.write("0,\n");
+ for (i = 33; i < 64; i++)
+ fid.write("1024U,\n");
+ fid.write("};\n\n");
+
+ qint32 e;
+ for (i = 0; i < 256; ++i) {
+ e = i - 127;
+ if (e < -24) { // Very small numbers map to zero
+ basetable[i | 0x000] = 0x0000;
+ basetable[i | 0x100] = 0x8000;
+ shifttable[i | 0x000] = 24;
+ shifttable[i | 0x100] = 24;
+
+ } else if (e < -14) { // Small numbers map to denorms
+ basetable[i | 0x000] = (0x0400 >> (-e - 14));
+ basetable[i | 0x100] = (0x0400 >> (-e - 14)) | 0x8000;
+ shifttable[i | 0x000] = -e - 1;
+ shifttable[i | 0x100] = -e - 1;
+
+ } else if (e <= 15) { // Normal numbers just lose precision
+ basetable[i | 0x000] = ((e + 15) << 10);
+ basetable[i | 0x100] = ((e + 15) << 10) | 0x8000;
+ shifttable[i | 0x000] = 13;
+ shifttable[i | 0x100] = 13;
+
+ } else if (e < 128) { // Large numbers map to Infinity
+ basetable[i | 0x000] = 0x7C00;
+ basetable[i | 0x100] = 0xFC00;
+ shifttable[i | 0x000] = 24;
+ shifttable[i | 0x100] = 24;
+
+ } else { // Infinity and NaN's stay Infinity and NaN's
+ basetable[i | 0x000] = 0x7C00;
+ basetable[i | 0x100] = 0xFC00;
+ shifttable[i | 0x000] = 13;
+ shifttable[i | 0x100] = 13;
+ }
+ }
+
+ fid.write("const quint32 qfloat16::basetable[512] = {\n");
+ for (i = 0; i < 512; i++)
+ fid.write(PRINTHEX(basetable[i]));
+
+ fid.write("};\n\n");
+
+ fid.write("const quint32 qfloat16::shifttable[512] = {\n");
+ for (i = 0; i < 512; i++)
+ fid.write(PRINTHEX(shifttable[i]));
+
+ fid.write("};\n\n");
+
+ fid.write("QT_END_NAMESPACE\n");
+ fid.close();
+ return 0;
+}
diff --git a/src/tools/qfloat16-tables/qfloat16-tables.pro b/src/tools/qfloat16-tables/qfloat16-tables.pro
new file mode 100644
index 0000000000..a7d10ac197
--- /dev/null
+++ b/src/tools/qfloat16-tables/qfloat16-tables.pro
@@ -0,0 +1,9 @@
+option(host_build)
+
+CONFIG += force_bootstrap
+SOURCES += gen_qfloat16_tables.cpp
+
+load(qt_tool)
+
+lib.CONFIG = dummy_install
+INSTALLS = lib
diff --git a/src/tools/rcc/main.cpp b/src/tools/rcc/main.cpp
index d09d36c659..fba47b74c3 100644
--- a/src/tools/rcc/main.cpp
+++ b/src/tools/rcc/main.cpp
@@ -32,6 +32,7 @@
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
+#include <qhashfunctions.h>
#include <qtextstream.h>
#include <qatomic.h>
#include <qglobal.h>
@@ -276,7 +277,8 @@ int runRcc(int argc, char *argv[])
} else {
out.setFileName(outFilename);
if (!out.open(mode)) {
- const QString msg = QString::fromLatin1("Unable to open %1 for writing: %2\n").arg(outFilename).arg(out.errorString());
+ const QString msg = QString::fromLatin1("Unable to open %1 for writing: %2\n")
+ .arg(outFilename, out.errorString());
errorDevice.write(msg.toUtf8());
return 1;
}
@@ -297,7 +299,7 @@ int runRcc(int argc, char *argv[])
temp.setFileName(tempFilename);
if (!temp.open(QIODevice::ReadOnly)) {
const QString msg = QString::fromUtf8("Unable to open temporary file %1 for reading: %2\n")
- .arg(outFilename).arg(out.errorString());
+ .arg(outFilename, out.errorString());
errorDevice.write(msg.toUtf8());
return 1;
}
@@ -311,16 +313,17 @@ int runRcc(int argc, char *argv[])
return 0;
}
-Q_CORE_EXPORT extern QBasicAtomicInt qt_qhash_seed; // from qhash.cpp
-
QT_END_NAMESPACE
int main(int argc, char *argv[])
{
// rcc uses a QHash to store files in the resource system.
// we must force a certain hash order when testing or tst_rcc will fail, see QTBUG-25078
- if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_RCC_TEST") && !qt_qhash_seed.testAndSetRelaxed(-1, 0)))
- qFatal("Cannot force QHash seed for testing as requested");
+ if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QT_RCC_TEST"))) {
+ qSetGlobalQHashSeed(0);
+ if (qGlobalQHashSeed() != 0)
+ qFatal("Cannot force QHash seed for testing as requested");
+ }
return QT_PREPEND_NAMESPACE(runRcc)(argc, argv);
}
diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp
index 26dacc48ec..84fe6ef5c7 100644
--- a/src/tools/rcc/rcc.cpp
+++ b/src/tools/rcc/rcc.cpp
@@ -73,7 +73,7 @@ void RCCResourceLibrary::writeByteArray(const QByteArray &other)
static inline QString msgOpenReadFailed(const QString &fname, const QString &why)
{
- return QString::fromLatin1("Unable to open %1 for reading: %2\n").arg(fname).arg(why);
+ return QString::fromLatin1("Unable to open %1 for reading: %2\n").arg(fname, why);
}
@@ -502,7 +502,8 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
QFileInfo file(absFileName);
if (!file.exists()) {
m_failedResources.push_back(absFileName);
- const QString msg = QString::fromLatin1("RCC: Error in '%1': Cannot find file '%2'\n").arg(fname).arg(fileName);
+ const QString msg = QString::fromLatin1("RCC: Error in '%1': Cannot find file '%2'\n")
+ .arg(fname, fileName);
m_errorDevice->write(msg.toUtf8());
if (ignoreErrors)
continue;
diff --git a/src/tools/uic/cpp/cppwriteincludes.cpp b/src/tools/uic/cpp/cppwriteincludes.cpp
index a99d6adf07..dcbe400224 100644
--- a/src/tools/uic/cpp/cppwriteincludes.cpp
+++ b/src/tools/uic/cpp/cppwriteincludes.cpp
@@ -114,8 +114,9 @@ void WriteIncludes::acceptUI(DomUI *node)
TreeWalker::acceptUI(node);
- if (!m_uic->option().includeFile.isEmpty())
- m_globalIncludes.insert(m_uic->option().includeFile, true);
+ const auto includeFile = m_uic->option().includeFile;
+ if (!includeFile.isEmpty())
+ m_globalIncludes.insert(includeFile);
writeHeaders(m_globalIncludes, true);
writeHeaders(m_localIncludes, false);
@@ -272,10 +273,11 @@ void WriteIncludes::insertInclude(const QString &header, bool global)
fprintf(stderr, "%s %s %d\n", Q_FUNC_INFO, qPrintable(header), global);
OrderedSet &includes = global ? m_globalIncludes : m_localIncludes;
- if (includes.contains(header))
+ // Insert (if not already done).
+ const bool isNewHeader = includes.insert(header).second;
+ if (!isNewHeader)
return;
- // Insert. Also remember base name for quick check of suspicious custom plugins
- includes.insert(header, false);
+ // Also remember base name for quick check of suspicious custom plugins
const QString lowerBaseName = QFileInfo(header).completeBaseName ().toLower();
m_includeBaseNames.insert(lowerBaseName);
}
@@ -286,13 +288,11 @@ void WriteIncludes::writeHeaders(const OrderedSet &headers, bool global)
const QChar closingQuote = global ? QLatin1Char('>') : QLatin1Char('"');
// Check for the old headers 'qslider.h' and replace by 'QtGui/QSlider'
- const OrderedSet::const_iterator cend = headers.constEnd();
- for (OrderedSet::const_iterator sit = headers.constBegin(); sit != cend; ++sit) {
- const StringMap::const_iterator hit = m_oldHeaderToNewHeader.constFind(sit.key());
- const bool mapped = hit != m_oldHeaderToNewHeader.constEnd();
- const QString header = mapped ? hit.value() : sit.key();
- if (!QStringRef(&header).trimmed().isEmpty())
- m_output << "#include " << openingQuote << header << closingQuote << QLatin1Char('\n');
+ for (const QString &header : headers) {
+ const QString value = m_oldHeaderToNewHeader.value(header, header);
+ const auto trimmed = QStringRef(&value).trimmed();
+ if (!trimmed.isEmpty())
+ m_output << "#include " << openingQuote << trimmed << closingQuote << QLatin1Char('\n');
}
}
diff --git a/src/tools/uic/cpp/cppwriteincludes.h b/src/tools/uic/cpp/cppwriteincludes.h
index 397c6a26e1..7a6a499536 100644
--- a/src/tools/uic/cpp/cppwriteincludes.h
+++ b/src/tools/uic/cpp/cppwriteincludes.h
@@ -35,6 +35,8 @@
#include <qset.h>
#include <qstring.h>
+#include <set>
+
QT_BEGIN_NAMESPACE
class QTextStream;
@@ -72,7 +74,7 @@ private:
void add(const QString &className, bool determineHeader = true, const QString &header = QString(), bool global = false);
private:
- typedef QMap<QString, bool> OrderedSet;
+ typedef std::set<QString> OrderedSet;
void insertIncludeForClass(const QString &className, QString header = QString(), bool global = false);
void insertInclude(const QString &header, bool global);
void writeHeaders(const OrderedSet &headers, bool global);
diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp
index 2fc6f20782..bbef010a9c 100644
--- a/src/tools/uic/cpp/cppwriteinitialization.cpp
+++ b/src/tools/uic/cpp/cppwriteinitialization.cpp
@@ -48,10 +48,11 @@ namespace {
// Fixup an enumeration name from class Qt.
// They are currently stored as "BottomToolBarArea" instead of "Qt::BottomToolBarArea".
// due to MO issues. This might be fixed in the future.
- void fixQtEnumerationName(QString& name) {
+ QLatin1String qtEnumerationPrefix(const QString &name) {
static const QLatin1String prefix("Qt::");
if (name.indexOf(prefix) != 0)
- name.prepend(prefix);
+ return prefix;
+ return QLatin1String();
}
// figure out the toolbar area of a DOM attrib list.
// By legacy, it is stored as an integer. As of 4.3.0, it is the enumeration value.
@@ -62,16 +63,12 @@ namespace {
switch (pstyle->kind()) {
case DomProperty::Number: {
- QString area = QLatin1String("static_cast<Qt::ToolBarArea>(");
- area += QString::number(pstyle->elementNumber());
- area += QLatin1String("), ");
- return area;
+ return QLatin1String("static_cast<Qt::ToolBarArea>(")
+ + QString::number(pstyle->elementNumber()) + QLatin1String("), ");
}
case DomProperty::Enum: {
- QString area = pstyle->elementEnum();
- fixQtEnumerationName(area);
- area += QLatin1String(", ");
- return area;
+ const QString area = pstyle->elementEnum();
+ return qtEnumerationPrefix(area) + area + QLatin1String(", ");
}
default:
break;
@@ -152,7 +149,8 @@ namespace {
if (const DomResourceIcon *dri = p->elementIconSet()) {
if (!isIconFormat44(dri)) {
if (dri->text().isEmpty()) {
- const QString msg = QString::fromUtf8("%1: Warning: An invalid icon property '%2' was encountered.").arg(fileName).arg(p->attributeName());
+ const QString msg = QString::fromLatin1("%1: Warning: An invalid icon property '%2' was encountered.")
+ .arg(fileName, p->attributeName());
qWarning("%s", qPrintable(msg));
return false;
}
@@ -162,7 +160,8 @@ namespace {
case DomProperty::Pixmap:
if (const DomResourcePixmap *drp = p->elementPixmap())
if (drp->text().isEmpty()) {
- const QString msg = QString::fromUtf8("%1: Warning: An invalid pixmap property '%2' was encountered.").arg(fileName).arg(p->attributeName());
+ const QString msg = QString::fromUtf8("%1: Warning: An invalid pixmap property '%2' was encountered.")
+ .arg(fileName, p->attributeName());
qWarning("%s", qPrintable(msg));
return false;
}
@@ -1029,7 +1028,7 @@ void WriteInitialization::acceptLayoutItem(DomLayoutItem *node)
const int row = node->attributeRow();
const int colSpan = node->hasAttributeColSpan() ? node->attributeColSpan() : 1;
const QString role = formLayoutRole(node->attributeColumn(), colSpan);
- addArgs = QString::fromLatin1("%1, %2, %3").arg(row).arg(role).arg(itemName);
+ addArgs = QString::fromLatin1("%1, %2, %3").arg(row).arg(role, itemName);
} else {
addArgs = itemName;
if (layout->attributeClass().contains(QLatin1String("Box")) && !node->attributeAlignment().isEmpty())
@@ -1365,7 +1364,7 @@ void WriteInitialization::writeProperties(const QString &varName,
case DomProperty::Locale: {
const DomLocale *locale = p->elementLocale();
propertyValue = QString::fromLatin1("QLocale(QLocale::%1, QLocale::%2)")
- .arg(locale->attributeLanguage()).arg(locale->attributeCountry());
+ .arg(locale->attributeLanguage(), locale->attributeCountry());
break;
}
case DomProperty::SizePolicy: {
@@ -1482,6 +1481,8 @@ void WriteInitialization::writeProperties(const QString &varName,
defineC = whatsThisDefineC;
else if (propertyName == QLatin1String("statusTip"))
defineC = statusTipDefineC;
+ else if (propertyName == QLatin1String("shortcut"))
+ defineC = shortcutDefineC;
else if (propertyName == QLatin1String("accessibleName") || propertyName == QLatin1String("accessibleDescription"))
defineC = accessibilityDefineC;
diff --git a/src/tools/uic/main.cpp b/src/tools/uic/main.cpp
index e2399cd1fd..3599470403 100644
--- a/src/tools/uic/main.cpp
+++ b/src/tools/uic/main.cpp
@@ -32,6 +32,7 @@
#include <qfile.h>
#include <qdir.h>
+#include <qhashfunctions.h>
#include <qtextstream.h>
#include <qtextcodec.h>
#include <qcoreapplication.h>
@@ -39,11 +40,10 @@
#include <qcommandlineparser.h>
QT_BEGIN_NAMESPACE
-extern Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed;
int runUic(int argc, char *argv[])
{
- qt_qhash_seed.testAndSetRelaxed(-1, 0); // set the hash seed to 0 if it wasn't set yet
+ qSetGlobalQHashSeed(0); // set the hash seed to 0
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationVersion(QString::fromLatin1(QT_VERSION_STR));
@@ -115,7 +115,7 @@ int runUic(int argc, char *argv[])
QString inputFile;
if (!parser.positionalArguments().isEmpty())
- inputFile = parser.positionalArguments().first();
+ inputFile = parser.positionalArguments().at(0);
else // reading from stdin
driver.option().headerProtection = false;
diff --git a/src/tools/uic/uic.pro b/src/tools/uic/uic.pro
index 9afb2d847f..02469cdd1b 100644
--- a/src/tools/uic/uic.pro
+++ b/src/tools/uic/uic.pro
@@ -1,5 +1,5 @@
option(host_build)
-!force_bootstrap:if(!qtConfig(commandlineparser)|!qtConfig(textcodec)): \
+!force_bootstrap:if(!qtConfig(commandlineparser)|!qtConfig(textcodec)|!qtConfig(xmlstreamreader)|!qtConfig(xmlstreamwriter)): \
CONFIG += force_bootstrap
DEFINES += QT_UIC QT_NO_CAST_FROM_ASCII QT_NO_FOREACH
diff --git a/src/widgets/accessible/complexwidgets.cpp b/src/widgets/accessible/complexwidgets.cpp
index ea3b88468b..397a58a5d4 100644
--- a/src/widgets/accessible/complexwidgets.cpp
+++ b/src/widgets/accessible/complexwidgets.cpp
@@ -41,7 +41,6 @@
#include <qaccessible.h>
#include <qapplication.h>
-#include <qabstractbutton.h>
#include <qevent.h>
#include <qheaderview.h>
#include <qtabbar.h>
diff --git a/src/widgets/accessible/qaccessiblewidget.cpp b/src/widgets/accessible/qaccessiblewidget.cpp
index 840a990799..94cf58ae3b 100644
--- a/src/widgets/accessible/qaccessiblewidget.cpp
+++ b/src/widgets/accessible/qaccessiblewidget.cpp
@@ -44,7 +44,9 @@
#include "qaction.h"
#include "qapplication.h"
#include "qgroupbox.h"
+#if QT_CONFIG(label)
#include "qlabel.h"
+#endif
#include "qtooltip.h"
#include "qwhatsthis.h"
#include "qwidget.h"
@@ -81,7 +83,7 @@ static QString buddyString(const QWidget *widget)
QWidget *parent = widget->parentWidget();
if (!parent)
return QString();
-#ifndef QT_NO_SHORTCUT
+#if QT_CONFIG(shortcut) && QT_CONFIG(label)
for (QObject *o : parent->children()) {
QLabel *label = qobject_cast<QLabel*>(o);
if (label && label->buddy() == widget)
@@ -309,7 +311,7 @@ QAccessibleWidget::relations(QAccessible::Relation match /*= QAccessible::AllRel
if (match & QAccessible::Label) {
const QAccessible::Relation rel = QAccessible::Label;
if (QWidget *parent = widget()->parentWidget()) {
-#ifndef QT_NO_SHORTCUT
+#if QT_CONFIG(shortcut) && QT_CONFIG(label)
// first check for all siblings that are labels to us
// ideally we would go through all objects and check, but that
// will be too expensive
diff --git a/src/widgets/accessible/qaccessiblewidgetfactory.cpp b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
index da184fd90d..e7db53c251 100644
--- a/src/widgets/accessible/qaccessiblewidgetfactory.cpp
+++ b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
@@ -45,7 +45,6 @@
#include "complexwidgets_p.h"
#include "itemviews_p.h"
-#include <qpushbutton.h>
#include <qtoolbutton.h>
#include <qtreeview.h>
#include <qvariant.h>
@@ -104,11 +103,13 @@ QAccessibleInterface *qAccessibleFactory(const QString &classname, QObject *obje
} else if (classname == QLatin1String("QToolButton")) {
iface = new QAccessibleToolButton(widget);
#endif // QT_NO_TOOLBUTTON
+#if QT_CONFIG(abstractbutton)
} else if (classname == QLatin1String("QCheckBox")
|| classname == QLatin1String("QRadioButton")
|| classname == QLatin1String("QPushButton")
|| classname == QLatin1String("QAbstractButton")) {
iface = new QAccessibleButton(widget);
+#endif
} else if (classname == QLatin1String("QDialog")) {
iface = new QAccessibleWidget(widget, QAccessible::Dialog);
} else if (classname == QLatin1String("QMessageBox")) {
@@ -184,8 +185,10 @@ QAccessibleInterface *qAccessibleFactory(const QString &classname, QObject *obje
} else if (classname == QLatin1String("QMdiSubWindow")) {
iface = new QAccessibleMdiSubWindow(widget);
#endif
+#if QT_CONFIG(dialogbuttonbox)
} else if (classname == QLatin1String("QDialogButtonBox")) {
iface = new QAccessibleDialogButtonBox(widget);
+#endif
#ifndef QT_NO_DIAL
} else if (classname == QLatin1String("QDial")) {
iface = new QAccessibleDial(widget);
diff --git a/src/widgets/accessible/qaccessiblewidgets.cpp b/src/widgets/accessible/qaccessiblewidgets.cpp
index 4c48ecb465..7f77f7c524 100644
--- a/src/widgets/accessible/qaccessiblewidgets.cpp
+++ b/src/widgets/accessible/qaccessiblewidgets.cpp
@@ -54,7 +54,9 @@
#include <QToolBox>
#include <QMdiArea>
#include <QMdiSubWindow>
+#if QT_CONFIG(dialogbuttonbox)
#include <QDialogButtonBox>
+#endif
#include <limits.h>
#include <QRubberBand>
#include <QTextBrowser>
@@ -62,7 +64,6 @@
#include <QAbstractItemView>
#include <QDockWidget>
#include <QMainWindow>
-#include <QAbstractButton>
#include <private/qdockwidget_p.h>
#include <QFocusFrame>
@@ -480,7 +481,7 @@ QMdiSubWindow *QAccessibleMdiSubWindow::mdiSubWindow() const
}
#endif // QT_NO_MDIAREA
-#ifndef QT_NO_DIALOGBUTTONBOX
+#if QT_CONFIG(dialogbuttonbox)
// ======================= QAccessibleDialogButtonBox ======================
QAccessibleDialogButtonBox::QAccessibleDialogButtonBox(QWidget *widget)
: QAccessibleWidget(widget, QAccessible::Grouping)
@@ -488,7 +489,7 @@ QAccessibleDialogButtonBox::QAccessibleDialogButtonBox(QWidget *widget)
Q_ASSERT(qobject_cast<QDialogButtonBox*>(widget));
}
-#endif // QT_NO_DIALOGBUTTONBOX
+#endif // QT_CONFIG(dialogbuttonbox)
#if !defined(QT_NO_TEXTBROWSER) && !defined(QT_NO_CURSOR)
QAccessibleTextBrowser::QAccessibleTextBrowser(QWidget *widget)
diff --git a/src/widgets/accessible/qaccessiblewidgets_p.h b/src/widgets/accessible/qaccessiblewidgets_p.h
index 052958d4c7..4d945a2016 100644
--- a/src/widgets/accessible/qaccessiblewidgets_p.h
+++ b/src/widgets/accessible/qaccessiblewidgets_p.h
@@ -248,11 +248,13 @@ protected:
};
#endif // QT_NO_MDIAREA
+#if QT_CONFIG(dialogbuttonbox)
class QAccessibleDialogButtonBox : public QAccessibleWidget
{
public:
explicit QAccessibleDialogButtonBox(QWidget *widget);
};
+#endif
#if !defined(QT_NO_TEXTBROWSER) && !defined(QT_NO_CURSOR)
class QAccessibleTextBrowser : public QAccessibleTextEdit
diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp
index a806cb7af6..a53e5eaf30 100644
--- a/src/widgets/accessible/simplewidgets.cpp
+++ b/src/widgets/accessible/simplewidgets.cpp
@@ -39,15 +39,25 @@
#include "simplewidgets_p.h"
+#if QT_CONFIG(abstractbutton)
#include <qabstractbutton.h>
+#endif
+#if QT_CONFIG(checkbox)
#include <qcheckbox.h>
+#endif
+#if QT_CONFIG(pushbutton)
#include <qpushbutton.h>
+#endif
#include <qprogressbar.h>
#include <qstatusbar.h>
+#if QT_CONFIG(radiobutton)
#include <qradiobutton.h>
+#endif
#include <qtoolbutton.h>
#include <qmenu.h>
+#if QT_CONFIG(label)
#include <qlabel.h>
+#endif
#include <qgroupbox.h>
#include <qlcdnumber.h>
#include <qlineedit.h>
@@ -72,6 +82,7 @@ extern QList<QWidget*> childWidgets(const QWidget *widget);
QString qt_accStripAmp(const QString &text);
QString qt_accHotKey(const QString &text);
+#if QT_CONFIG(abstractbutton)
/*!
\class QAccessibleButton
\brief The QAccessibleButton class implements the QAccessibleInterface for button type widgets.
@@ -109,7 +120,7 @@ QString QAccessibleButton::text(QAccessible::Text t) const
switch (t) {
case QAccessible::Accelerator:
{
-#ifndef QT_NO_SHORTCUT
+#if QT_CONFIG(shortcut) && QT_CONFIG(pushbutton)
QPushButton *pb = qobject_cast<QPushButton*>(object());
if (pb && pb->isDefault())
str = QKeySequence(Qt::Key_Enter).toString(QKeySequence::NativeText);
@@ -136,15 +147,20 @@ QAccessible::State QAccessibleButton::state() const
QAccessible::State state = QAccessibleWidget::state();
QAbstractButton *b = button();
+#if QT_CONFIG(checkbox)
QCheckBox *cb = qobject_cast<QCheckBox *>(b);
+#endif
if (b->isCheckable())
state.checkable = true;
if (b->isChecked())
state.checked = true;
+#if QT_CONFIG(checkbox)
else if (cb && cb->checkState() == Qt::PartiallyChecked)
state.checkStateMixed = true;
+#endif
if (b->isDown())
state.pressed = true;
+#if QT_CONFIG(pushbutton)
QPushButton *pb = qobject_cast<QPushButton*>(b);
if (pb) {
if (pb->isDefault())
@@ -154,6 +170,7 @@ QAccessible::State QAccessibleButton::state() const
state.hasPopup = true;
#endif
}
+#endif
return state;
}
@@ -164,17 +181,22 @@ QRect QAccessibleButton::rect() const
if (!ab->isVisible())
return QRect();
+#if QT_CONFIG(checkbox)
if (QCheckBox *cb = qobject_cast<QCheckBox *>(ab)) {
QPoint wpos = cb->mapToGlobal(QPoint(0, 0));
QStyleOptionButton opt;
cb->initStyleOption(&opt);
return cb->style()->subElementRect(QStyle::SE_CheckBoxClickRect, &opt, cb).translated(wpos);
- } else if (QRadioButton *rb = qobject_cast<QRadioButton *>(ab)) {
+ }
+#endif
+#if QT_CONFIG(radiobutton)
+ else if (QRadioButton *rb = qobject_cast<QRadioButton *>(ab)) {
QPoint wpos = rb->mapToGlobal(QPoint(0, 0));
QStyleOptionButton opt;
rb->initStyleOption(&opt);
return rb->style()->subElementRect(QStyle::SE_RadioButtonClickRect, &opt, rb).translated(wpos);
}
+#endif
return QAccessibleWidget::rect();
}
@@ -248,7 +270,7 @@ QStringList QAccessibleButton::keyBindingsForAction(const QString &actionName) c
}
return QStringList();
}
-
+#endif // QT_CONFIG(abstractbutton)
#ifndef QT_NO_TOOLBUTTON
/*!
@@ -390,6 +412,7 @@ QAccessibleDisplay::QAccessibleDisplay(QWidget *w, QAccessible::Role role)
QAccessible::Role QAccessibleDisplay::role() const
{
+#if QT_CONFIG(label)
QLabel *l = qobject_cast<QLabel*>(object());
if (l) {
if (l->pixmap())
@@ -411,6 +434,7 @@ QAccessible::Role QAccessibleDisplay::role() const
return QAccessible::StatusBar;
#endif
}
+#endif
return QAccessibleWidget::role();
}
@@ -421,7 +445,9 @@ QString QAccessibleDisplay::text(QAccessible::Text t) const
case QAccessible::Name:
str = widget()->accessibleName();
if (str.isEmpty()) {
- if (qobject_cast<QLabel*>(object())) {
+ if (false) {
+#if QT_CONFIG(label)
+ } else if (qobject_cast<QLabel*>(object())) {
QLabel *label = qobject_cast<QLabel*>(object());
str = label->text();
#ifndef QT_NO_TEXTHTMLPARSER
@@ -436,6 +462,7 @@ QString QAccessibleDisplay::text(QAccessible::Text t) const
if (label->buddy())
str = qt_accStripAmp(str);
#endif
+#endif // QT_CONFIG(label)
#ifndef QT_NO_LCDNUMBER
} else if (qobject_cast<QLCDNumber*>(object())) {
QLCDNumber *l = qobject_cast<QLCDNumber*>(object());
@@ -470,21 +497,15 @@ QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >
QAccessibleDisplay::relations(QAccessible::Relation match /* = QAccessible::AllRelations */) const
{
QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > rels = QAccessibleWidget::relations(match);
+#if QT_CONFIG(shortcut) && QT_CONFIG(label)
if (match & QAccessible::Labelled) {
- QVarLengthArray<QObject *, 4> relatedObjects;
-
-#ifndef QT_NO_SHORTCUT
if (QLabel *label = qobject_cast<QLabel*>(object())) {
- relatedObjects.append(label->buddy());
- }
-#endif
- for (int i = 0; i < relatedObjects.count(); ++i) {
const QAccessible::Relation rel = QAccessible::Labelled;
- QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(relatedObjects.at(i));
- if (iface)
+ if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(label->buddy()))
rels.append(qMakePair(iface, rel));
}
}
+#endif
return rels;
}
@@ -501,33 +522,41 @@ QString QAccessibleDisplay::imageDescription() const
#ifndef QT_NO_TOOLTIP
return widget()->toolTip();
#else
- return QString::null;
+ return QString();
#endif
}
/*! \internal */
QSize QAccessibleDisplay::imageSize() const
{
+#if QT_CONFIG(label)
QLabel *label = qobject_cast<QLabel *>(widget());
if (!label)
+#endif
return QSize();
+#if QT_CONFIG(label)
const QPixmap *pixmap = label->pixmap();
if (!pixmap)
return QSize();
return pixmap->size();
+#endif
}
/*! \internal */
QPoint QAccessibleDisplay::imagePosition() const
{
+#if QT_CONFIG(label)
QLabel *label = qobject_cast<QLabel *>(widget());
if (!label)
+#endif
return QPoint();
+#if QT_CONFIG(label)
const QPixmap *pixmap = label->pixmap();
if (!pixmap)
return QPoint();
return QPoint(label->mapToGlobal(label->pos()));
+#endif
}
#ifndef QT_NO_GROUPBOX
@@ -670,11 +699,13 @@ void QAccessibleLineEdit::setText(QAccessible::Text t, const QString &text)
}
QString newText = text;
+#if QT_CONFIG(validator)
if (lineEdit()->validator()) {
int pos = 0;
if (lineEdit()->validator()->validate(newText, pos) != QValidator::Acceptable)
return;
}
+#endif
lineEdit()->setText(newText);
}
diff --git a/src/widgets/accessible/simplewidgets_p.h b/src/widgets/accessible/simplewidgets_p.h
index 8bd0af8261..1e4ae5ab67 100644
--- a/src/widgets/accessible/simplewidgets_p.h
+++ b/src/widgets/accessible/simplewidgets_p.h
@@ -65,6 +65,7 @@ class QToolButton;
class QGroupBox;
class QProgressBar;
+#if QT_CONFIG(abstractbutton)
class QAccessibleButton : public QAccessibleWidget
{
Q_DECLARE_TR_FUNCTIONS(QAccessibleButton)
@@ -83,6 +84,7 @@ public:
protected:
QAbstractButton *button() const;
};
+#endif
#ifndef QT_NO_TOOLBUTTON
class QAccessibleToolButton : public QAccessibleButton
diff --git a/src/widgets/configure.json b/src/widgets/configure.json
index e7007f71b7..ab8ced3849 100644
--- a/src/widgets/configure.json
+++ b/src/widgets/configure.json
@@ -20,9 +20,9 @@
"libraries": {
"gtk3": {
- "label": "GTK+",
+ "label": "GTK+ >= 3.6",
"sources": [
- { "type": "pkgConfig", "args": "gtk+-3.0" }
+ { "type": "pkgConfig", "args": "gtk+-3.0 >= 3.6" }
]
}
},
@@ -117,11 +117,24 @@
"condition": "features.tableview",
"output": [ "publicFeature", "feature" ]
},
+ "abstractbutton": {
+ "label": "QAbstractButton",
+ "purpose": "Abstract base class of button widgets, providing functionality common to buttons.",
+ "section": "Widgets",
+ "output": [ "publicFeature" ]
+ },
+ "commandlinkbutton": {
+ "label": "QCommandLinkButton",
+ "purpose": "Provides a Vista style command link button.",
+ "section": "Widgets",
+ "condition": "features.pushbutton",
+ "output": [ "publicFeature" ]
+ },
"datetimeedit": {
"label": "QDateTimeEdit",
"purpose": "Supports editing dates and times.",
"section": "Widgets",
- "condition": "features.calendarwidget && features.datestring",
+ "condition": "features.calendarwidget && features.datestring && features.textdate",
"output": [ "publicFeature", "feature" ]
},
"stackedwidget": {
@@ -150,6 +163,26 @@
"condition": "features.rubberband",
"output": [ "publicFeature", "feature" ]
},
+ "widgettextcontrol": {
+ "label": "QWidgetTextControl",
+ "purpose": "Provides text control functionality to other widgets.",
+ "section": "Widgets",
+ "output": [ "privateFeature" ]
+ },
+ "label": {
+ "label": "QLabel",
+ "purpose": "Provides a text or image display.",
+ "section": "Widgets",
+ "condition": "features.widgettextcontrol",
+ "output": [ "publicFeature" ]
+ },
+ "formlayout": {
+ "label": "QFormLayout",
+ "purpose": "Manages forms of input widgets and their associated labels.",
+ "section": "Widgets",
+ "condition": "features.label",
+ "output": [ "publicFeature" ]
+ },
"lcdnumber": {
"label": "QLCDNumber",
"purpose": "Provides LCD-like digits.",
@@ -160,15 +193,23 @@
"label": "QMenu",
"purpose": "Provides popup-menus.",
"section": "Widgets",
- "condition": "features.action",
+ "condition": "features.action && features.pushbutton",
"output": [ "publicFeature", "feature" ]
},
"lineedit": {
"label": "QLineEdit",
"purpose": "Provides single-line edits.",
"section": "Widgets",
+ "condition": "features.widgettextcontrol",
"output": [ "publicFeature", "feature" ]
},
+ "radiobutton": {
+ "label": "QRadioButton",
+ "purpose": "Provides a radio button with a text label.",
+ "section": "Widgets",
+ "condition": "features.abstractbutton",
+ "output": [ "publicFeature" ]
+ },
"spinbox": {
"label": "QSpinBox",
"purpose": "Provides spin boxes handling integers and discrete sets of values.",
@@ -204,11 +245,25 @@
"condition": "features.combobox && features.stringlistmodel",
"output": [ "publicFeature", "feature" ]
},
+ "checkbox": {
+ "label": "QCheckBox(",
+ "purpose": "Provides a checkbox with a text label.",
+ "section": "Widgets",
+ "condition": "features.abstractbutton",
+ "output": [ "publicFeature" ]
+ },
+ "pushbutton": {
+ "label": "QPushButton",
+ "purpose": "Provides a command button.",
+ "section": "Widgets",
+ "condition": "features.abstractbutton && features.action",
+ "output": [ "publicFeature" ]
+ },
"toolbutton": {
"label": "QToolButton",
"purpose": "Provides quick-access buttons to commands and options.",
"section": "Widgets",
- "condition": "features.action",
+ "condition": "features.abstractbutton && features.action",
"output": [ "publicFeature", "feature" ]
},
"toolbar": {
@@ -235,7 +290,7 @@
"label": "QButtonGroup",
"purpose": "Supports organizing groups of button widgets.",
"section": "Widgets",
- "condition": "features.groupbox",
+ "condition": "features.abstractbutton && features.groupbox",
"output": [ "publicFeature", "feature" ]
},
"mainwindow": {
@@ -291,10 +346,17 @@
"section": "Widgets",
"output": [ "publicFeature", "feature" ]
},
+ "abstractslider": {
+ "label": "QAbstractSlider",
+ "purpose": "Common super class for widgets like QScrollBar, QSlider and QDial.",
+ "section": "Widgets",
+ "output": [ "publicFeature" ]
+ },
"slider": {
"label": "QSlider",
"purpose": "Provides sliders controlling a bounded value.",
"section": "Widgets",
+ "condition": "features.abstractslider",
"output": [ "publicFeature", "feature" ]
},
"scrollbar": {
@@ -318,11 +380,17 @@
"condition": "features.scrollbar",
"output": [ "publicFeature", "feature" ]
},
+ "scroller": {
+ "label": "QScroller",
+ "purpose": "Enables kinetic scrolling for any scrolling widget or graphics item.",
+ "section": "Widgets",
+ "output": [ "publicFeature" ]
+ },
"graphicsview": {
"label": "QGraphicsView",
"purpose": "Provides a canvas/sprite framework.",
"section": "Widgets",
- "condition": "features.scrollarea",
+ "condition": "features.scrollarea && features.widgettextcontrol",
"output": [ "publicFeature", "feature" ]
},
"graphicseffect": {
@@ -336,7 +404,7 @@
"label": "QTextEdit",
"purpose": "Supports rich text editing.",
"section": "Widgets",
- "condition": "features.scrollarea && features.properties",
+ "condition": "features.scrollarea && features.properties && features.widgettextcontrol",
"output": [ "publicFeature", "feature" ]
},
"syntaxhighlighter": {
@@ -356,6 +424,7 @@
"label": "QToolTip",
"purpose": "Supports presentation of tooltips.",
"section": "Widgets",
+ "condition": "features.label",
"output": [ "publicFeature", "feature" ]
},
"statustip": {
@@ -381,7 +450,15 @@
"label": "QCalendarWidget",
"purpose": "Provides a monthly based calendar widget allowing the user to select a date.",
"section": "Widgets",
- "condition": "features.tableview && features.menu && features.textdate && features.spinbox && features.toolbutton",
+ "condition": [
+ "features.label",
+ "features.menu",
+ "features.pushbutton",
+ "features.spinbox",
+ "features.tableview",
+ "features.textdate",
+ "features.toolbutton"
+ ],
"output": [ "publicFeature", "feature" ]
},
"keysequenceedit": {
@@ -391,59 +468,133 @@
"condition": "features.lineedit && features.shortcut",
"output": [ "publicFeature", "feature" ]
},
+ "dialog" : {
+ "label": "QDialog",
+ "purpose": "Base class of dialog windows.",
+ "section": "Dialogs",
+ "output": [ "publicFeature" ]
+ },
+ "dialogbuttonbox": {
+ "label": "QDialogButtonBox",
+ "purpose": "Presents buttons in a layout that is appropriate for the current widget style.",
+ "section": "Dialogs",
+ "condition": "features.dialog && features.pushbutton",
+ "output": [ "publicFeature" ]
+ },
"messagebox": {
"label": "QMessageBox",
"purpose": "Provides message boxes displaying informative messages and simple questions.",
"section": "Dialogs",
+ "condition" : [
+ "features.checkbox",
+ "features.dialog",
+ "features.dialogbuttonbox",
+ "features.label",
+ "features.pushbutton"
+ ],
"output": [ "publicFeature", "feature" ]
},
"colordialog": {
"label": "QColorDialog",
"purpose": "Provides a dialog widget for specifying colors.",
"section": "Dialogs",
- "condition": "features.spinbox",
+ "condition": [
+ "features.dialog",
+ "features.dialogbuttonbox",
+ "features.label",
+ "features.pushbutton",
+ "features.spinbox"
+ ],
"output": [ "publicFeature", "feature" ]
},
"filedialog": {
"label": "QFileDialog",
"purpose": "Provides a dialog widget for selecting files or directories.",
"section": "Dialogs",
- "condition": "features.dirmodel && features.treeview && features.combobox && features.toolbutton && features.buttongroup && features.tooltip && features.splitter && features.stackedwidget && features.proxymodel",
+ "condition": [
+ "features.buttongroup",
+ "features.combobox",
+ "features.dialog",
+ "features.dialogbuttonbox",
+ "features.dirmodel",
+ "features.label",
+ "features.proxymodel",
+ "features.splitter",
+ "features.stackedwidget",
+ "features.treeview",
+ "features.toolbutton"
+ ],
"output": [ "publicFeature", "feature" ]
},
"fontdialog": {
"label": "QFontDialog",
"purpose": "Provides a dialog widget for selecting fonts.",
"section": "Dialogs",
- "condition": "features.stringlistmodel && features.combobox && features.validator && features.groupbox",
+ "condition": [
+ "features.checkbox",
+ "features.combobox",
+ "features.dialog",
+ "features.dialogbuttonbox",
+ "features.groupbox",
+ "features.label",
+ "features.pushbutton",
+ "features.stringlistmodel",
+ "features.validator"
+ ],
"output": [ "publicFeature", "feature" ]
},
"progressdialog": {
"label": "QProgressDialog",
"purpose": "Provides feedback on the progress of a slow operation.",
"section": "Dialogs",
- "condition": "features.progressbar",
+ "condition": [
+ "features.dialog",
+ "features.label",
+ "features.pushbutton",
+ "features.progressbar"
+ ],
"output": [ "publicFeature", "feature" ]
},
"inputdialog": {
"label": "QInputDialog",
"purpose": "Provides a simple convenience dialog to get a single value from the user.",
"section": "Dialogs",
- "condition": "features.combobox && features.spinbox && features.stackedwidget && features.textedit",
+ "condition": [
+ "features.combobox",
+ "features.dialog",
+ "features.dialogbuttonbox",
+ "features.label",
+ "features.pushbutton",
+ "features.spinbox",
+ "features.stackedwidget",
+ "features.textedit"
+ ],
"output": [ "publicFeature", "feature" ]
},
"errormessage": {
"label": "QErrorMessage",
"purpose": "Provides an error message display dialog.",
"section": "Dialogs",
- "condition": "features.textedit",
+ "condition": [
+ "features.checkbox",
+ "features.dialog",
+ "features.textedit",
+ "features.label",
+ "features.pushbutton",
+ "features.textedit"
+ ],
"output": [ "publicFeature", "feature" ]
},
"wizard": {
"label": "QWizard",
"purpose": "Provides a framework for multi-page click-through dialogs.",
"section": "Dialogs",
- "condition": "features.properties",
+ "condition": [
+ "features.dialog",
+ "features.pushbutton",
+ "features.properties",
+ "features.label"
+ ],
"output": [ "publicFeature", "feature" ]
},
"dirmodel": {
diff --git a/src/widgets/dialogs/dialogs.pri b/src/widgets/dialogs/dialogs.pri
index 4f4a9b1517..8614d2bcc6 100644
--- a/src/widgets/dialogs/dialogs.pri
+++ b/src/widgets/dialogs/dialogs.pri
@@ -3,8 +3,6 @@
HEADERS += \
dialogs/qcolordialog.h \
dialogs/qfscompleter_p.h \
- dialogs/qdialog.h \
- dialogs/qdialog_p.h \
dialogs/qerrormessage.h \
dialogs/qfiledialog.h \
dialogs/qfiledialog_p.h \
@@ -30,7 +28,6 @@ else: FORMS += dialogs/qfiledialog.ui
INCLUDEPATH += $$PWD
SOURCES += \
dialogs/qcolordialog.cpp \
- dialogs/qdialog.cpp \
dialogs/qerrormessage.cpp \
dialogs/qfiledialog.cpp \
dialogs/qfontdialog.cpp \
@@ -42,4 +39,13 @@ SOURCES += \
dialogs/qfileinfogatherer.cpp \
dialogs/qwizard.cpp \
+qtConfig(dialog) {
+ HEADERS += \
+ dialogs/qdialog.h \
+ dialogs/qdialog_p.h
+
+ SOURCES += \
+ dialogs/qdialog.cpp
+}
+
RESOURCES += dialogs/qmessagebox.qrc
diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp
index 39eacae596..dbcd2d7fe2 100644
--- a/src/widgets/dialogs/qcolordialog.cpp
+++ b/src/widgets/dialogs/qcolordialog.cpp
@@ -355,7 +355,7 @@ void QWellArray::paintCell(QPainter* p, int row, int col, const QRect &rect)
paintCellContents(p, row, col, opt.rect.adjusted(dfw, dfw, -dfw, -dfw));
}
-/*!
+/*
Reimplement this function to change the contents of the well array.
*/
void QWellArray::paintCellContents(QPainter *p, int row, int col, const QRect &r)
@@ -441,16 +441,12 @@ void QWellArray::focusInEvent(QFocusEvent*)
emit currentChanged(curRow, curCol);
}
-/*!\reimp
-*/
void QWellArray::focusOutEvent(QFocusEvent*)
{
updateCell(curRow, curCol);
}
-/*\reimp
-*/
void QWellArray::keyPressEvent(QKeyEvent* e)
{
switch(e->key()) { // Look at the key code
@@ -2250,10 +2246,13 @@ bool QColorDialogPrivate::handleColorPickingMouseButtonRelease(QMouseEvent *e)
bool QColorDialogPrivate::handleColorPickingKeyPress(QKeyEvent *e)
{
Q_Q(QColorDialog);
+#if QT_CONFIG(shortcut)
if (e->matches(QKeySequence::Cancel)) {
releaseColorPicking();
q->setCurrentColor(beforeScreenColorPicking);
- } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
+ } else
+#endif
+ if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
q->setCurrentColor(grabScreenColor(QCursor::pos()));
releaseColorPicking();
}
diff --git a/src/widgets/dialogs/qcolordialog.h b/src/widgets/dialogs/qcolordialog.h
index 3b56f0b5d1..fb5b843ce4 100644
--- a/src/widgets/dialogs/qcolordialog.h
+++ b/src/widgets/dialogs/qcolordialog.h
@@ -41,13 +41,14 @@
#define QCOLORDIALOG_H
#include <QtWidgets/qtwidgetsglobal.h>
+
+#ifndef QT_NO_COLORDIALOG
+
#include <QtWidgets/qdialog.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_COLORDIALOG
-
class QColorDialogPrivate;
class Q_WIDGETS_EXPORT QColorDialog : public QDialog
@@ -124,8 +125,8 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QColorDialog::ColorDialogOptions)
-#endif // QT_NO_COLORDIALOG
-
QT_END_NAMESPACE
+#endif // QT_NO_COLORDIALOG
+
#endif // QCOLORDIALOG_H
diff --git a/src/widgets/dialogs/qdialog.cpp b/src/widgets/dialogs/qdialog.cpp
index e5715ecd57..8e74c659fa 100644
--- a/src/widgets/dialogs/qdialog.cpp
+++ b/src/widgets/dialogs/qdialog.cpp
@@ -43,7 +43,6 @@
#include "qevent.h"
#include "qdesktopwidget.h"
-#include "qpushbutton.h"
#include "qapplication.h"
#include "qlayout.h"
#include "qsizegrip.h"
@@ -367,6 +366,7 @@ QDialog::~QDialog()
default default button becomes the default button. This is what a
push button calls when it loses focus.
*/
+#if QT_CONFIG(pushbutton)
void QDialogPrivate::setDefault(QPushButton *pushButton)
{
Q_Q(QDialog);
@@ -411,6 +411,7 @@ void QDialogPrivate::hideDefault()
list.at(i)->setDefault(false);
}
}
+#endif
void QDialogPrivate::resetModalitySetByOpen()
{
@@ -644,6 +645,7 @@ void QDialog::keyPressEvent(QKeyEvent *e)
#endif
if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) {
switch (e->key()) {
+#if QT_CONFIG(pushbutton)
case Qt::Key_Enter:
case Qt::Key_Return: {
QList<QPushButton*> list = findChildren<QPushButton*>();
@@ -657,6 +659,7 @@ void QDialog::keyPressEvent(QKeyEvent *e)
}
}
break;
+#endif
default:
e->ignore();
return;
@@ -716,6 +719,7 @@ void QDialog::setVisible(bool visible)
and actually catches most cases... If not, then they simply
have to use [widget*]->setFocus() themselves...
*/
+#if QT_CONFIG(pushbutton)
if (d->mainDef && fw->focusPolicy() == Qt::NoFocus) {
QWidget *first = fw;
while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
@@ -733,6 +737,7 @@ void QDialog::setVisible(bool visible)
}
}
}
+#endif
if (fw && !fw->hasFocus()) {
QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason);
QApplication::sendEvent(fw, &e);
@@ -760,10 +765,12 @@ void QDialog::setVisible(bool visible)
d->eventLoop->exit();
}
+#if QT_CONFIG(pushbutton)
const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
if (d->mainDef && isActiveWindow()
&& theme->themeHint(QPlatformTheme::DialogSnapToDefaultButton).toBool())
QCursor::setPos(d->mainDef->mapToGlobal(d->mainDef->rect().center()));
+#endif
}
/*!\reimp */
diff --git a/src/widgets/dialogs/qdialog.h b/src/widgets/dialogs/qdialog.h
index d88ff4a841..72250172d3 100644
--- a/src/widgets/dialogs/qdialog.h
+++ b/src/widgets/dialogs/qdialog.h
@@ -43,6 +43,8 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qwidget.h>
+QT_REQUIRE_CONFIG(dialog);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/dialogs/qdialog_p.h b/src/widgets/dialogs/qdialog_p.h
index ae9e3bcc93..9ee89863f6 100644
--- a/src/widgets/dialogs/qdialog_p.h
+++ b/src/widgets/dialogs/qdialog_p.h
@@ -56,9 +56,13 @@
#include "QtCore/qeventloop.h"
#include "QtCore/qpointer.h"
#include "QtWidgets/qdialog.h"
+#if QT_CONFIG(pushbutton)
#include "QtWidgets/qpushbutton.h"
+#endif
#include <qpa/qplatformdialoghelper.h>
+QT_REQUIRE_CONFIG(dialog);
+
QT_BEGIN_NAMESPACE
class QSizeGrip;
@@ -69,7 +73,11 @@ class Q_WIDGETS_EXPORT QDialogPrivate : public QWidgetPrivate
public:
QDialogPrivate()
- : mainDef(0), orientation(Qt::Horizontal),extension(0), doShowExtension(false),
+ :
+#if QT_CONFIG(pushbutton)
+ mainDef(0),
+#endif
+ orientation(Qt::Horizontal),extension(0), doShowExtension(false),
#ifndef QT_NO_SIZEGRIP
resizer(0),
sizeGripEnabled(false),
@@ -84,7 +92,9 @@ public:
QVariant styleHint(QPlatformDialogHelper::StyleHint hint) const;
void deletePlatformHelper();
+#if QT_CONFIG(pushbutton)
QPointer<QPushButton> mainDef;
+#endif
Qt::Orientation orientation;
QWidget *extension;
bool doShowExtension;
@@ -95,9 +105,11 @@ public:
#endif
QPoint lastRMBPress;
+#if QT_CONFIG(pushbutton)
void setDefault(QPushButton *);
void setMainDefault(QPushButton *);
void hideDefault();
+#endif
void resetModalitySetByOpen();
int rescode;
diff --git a/src/widgets/dialogs/qerrormessage.cpp b/src/widgets/dialogs/qerrormessage.cpp
index 5fcbe3fe9d..8200135abe 100644
--- a/src/widgets/dialogs/qerrormessage.cpp
+++ b/src/widgets/dialogs/qerrormessage.cpp
@@ -62,6 +62,13 @@
QT_BEGIN_NAMESPACE
+namespace {
+struct Message {
+ QString content;
+ QString type;
+};
+}
+
class QErrorMessagePrivate : public QDialogPrivate
{
Q_DECLARE_PUBLIC(QErrorMessage)
@@ -70,7 +77,7 @@ public:
QCheckBox * again;
QTextEdit * errors;
QLabel * icon;
- std::queue<QPair<QString, QString> > pending;
+ std::queue<Message> pending;
QSet<QString> doNotShow;
QSet<QString> doNotShowType;
QString currentMessage;
@@ -163,14 +170,20 @@ static void jump(QtMsgType t, const QMessageLogContext & /*context*/, const QStr
switch (t) {
case QtDebugMsg:
- default:
rich = QErrorMessage::tr("Debug Message:");
break;
case QtWarningMsg:
rich = QErrorMessage::tr("Warning:");
break;
+ case QtCriticalMsg:
+ rich = QErrorMessage::tr("Critical Error:");
+ break;
case QtFatalMsg:
rich = QErrorMessage::tr("Fatal Error:");
+ break;
+ case QtInfoMsg:
+ rich = QErrorMessage::tr("Information:");
+ break;
}
rich = QString::fromLatin1("<p><b>%1</b></p>").arg(rich);
rich += Qt::convertFromPlainText(m, Qt::WhiteSpaceNormal);
@@ -297,9 +310,8 @@ bool QErrorMessagePrivate::isMessageToBeShown(const QString &message, const QStr
bool QErrorMessagePrivate::nextPending()
{
while (!pending.empty()) {
- QPair<QString,QString> &pendingMessage = pending.front();
- QString message = qMove(pendingMessage.first);
- QString type = qMove(pendingMessage.second);
+ QString message = std::move(pending.front().content);
+ QString type = std::move(pending.front().type);
pending.pop();
if (isMessageToBeShown(message, type)) {
#ifndef QT_NO_TEXTHTMLPARSER
@@ -349,7 +361,7 @@ void QErrorMessage::showMessage(const QString &message, const QString &type)
Q_D(QErrorMessage);
if (!d->isMessageToBeShown(message, type))
return;
- d->pending.push(qMakePair(message, type));
+ d->pending.push({message, type});
if (!isVisible() && d->nextPending())
show();
}
diff --git a/src/widgets/dialogs/qerrormessage.h b/src/widgets/dialogs/qerrormessage.h
index 5ffa568c10..976ba9abd5 100644
--- a/src/widgets/dialogs/qerrormessage.h
+++ b/src/widgets/dialogs/qerrormessage.h
@@ -41,13 +41,14 @@
#define QERRORMESSAGE_H
#include <QtWidgets/qtwidgetsglobal.h>
+
+#ifndef QT_NO_ERRORMESSAGE
+
#include <QtWidgets/qdialog.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_ERRORMESSAGE
-
class QErrorMessagePrivate;
class Q_WIDGETS_EXPORT QErrorMessage: public QDialog
@@ -72,8 +73,8 @@ private:
Q_DISABLE_COPY(QErrorMessage)
};
-#endif // QT_NO_ERRORMESSAGE
-
QT_END_NAMESPACE
+#endif // QT_NO_ERRORMESSAGE
+
#endif // QERRORMESSAGE_H
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index 5892ec6a75..78e304950a 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -860,7 +860,7 @@ void QFileDialog::setVisible(bool visible)
}
}
- if (d->usingWidgets())
+ if (visible && d->usingWidgets())
d->qFileDialogUi->fileNameEdit->setFocus();
QDialog::setVisible(visible);
@@ -1461,6 +1461,19 @@ void QFileDialog::selectNameFilter(const QString &filter)
}
/*!
+ * \since 5.9
+ * \return The mimetype of the file that the user selected in the file dialog.
+ */
+QString QFileDialog::selectedMimeTypeFilter() const
+{
+ Q_D(const QFileDialog);
+ if (!d->usingWidgets())
+ return d->selectedMimeTypeFilter_sys();
+
+ return d->options->initiallySelectedMimeTypeFilter();
+}
+
+/*!
\since 4.4
Returns the filter that the user selected in the file dialog.
@@ -1579,9 +1592,19 @@ QStringList QFileDialog::mimeTypeFilters() const
*/
void QFileDialog::selectMimeTypeFilter(const QString &filter)
{
- const QString text = nameFilterForMime(filter);
- if (!text.isEmpty())
- selectNameFilter(text);
+ Q_D(QFileDialog);
+ d->options->setInitiallySelectedMimeTypeFilter(filter);
+
+ const QString filterForMime = nameFilterForMime(filter);
+
+ if (!d->usingWidgets()) {
+ d->selectMimeTypeFilter_sys(filter);
+ if (d->selectedMimeTypeFilter_sys().isEmpty() && !filterForMime.isEmpty()) {
+ selectNameFilter(filterForMime);
+ }
+ } else if (!filterForMime.isEmpty()) {
+ selectNameFilter(filterForMime);
+ }
}
#endif // QT_NO_MIMETYPE
@@ -2223,7 +2246,7 @@ QStringList QFileDialog::getOpenFileNames(QWidget *parent,
}
/*!
- This is a convenience static function that will return or or more existing
+ This is a convenience static function that will return one or more existing
files selected by the user. If the user presses Cancel, it returns an
empty list.
@@ -3790,12 +3813,12 @@ void QFileDialogPrivate::_q_nativeEnterDirectory(const QUrl &directory)
bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
Q_Q(QFileDialog);
-
+#if QT_CONFIG(shortcut)
if (event->matches(QKeySequence::Cancel)) {
q->reject();
return true;
}
-
+#endif
switch (event->key()) {
case Qt::Key_Backspace:
_q_navigateToParent();
@@ -3997,7 +4020,9 @@ void QFileDialogLineEdit::keyPressEvent(QKeyEvent *e)
int key = e->key();
QLineEdit::keyPressEvent(e);
+#if QT_CONFIG(shortcut)
if (!e->matches(QKeySequence::Cancel) && key != Qt::Key_Back)
+#endif
e->accept();
}
diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h
index 4ade50793d..733dd03092 100644
--- a/src/widgets/dialogs/qfiledialog.h
+++ b/src/widgets/dialogs/qfiledialog.h
@@ -44,13 +44,14 @@
#include <QtCore/qdir.h>
#include <QtCore/qstring.h>
#include <QtCore/qurl.h>
+
+#ifndef QT_NO_FILEDIALOG
+
#include <QtWidgets/qdialog.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_FILEDIALOG
-
class QModelIndex;
class QItemSelection;
struct QFileDialogArgs;
@@ -62,7 +63,6 @@ class QAbstractProxyModel;
class Q_WIDGETS_EXPORT QFileDialog : public QDialog
{
Q_OBJECT
- Q_FLAGS(Options)
Q_PROPERTY(ViewMode viewMode READ viewMode WRITE setViewMode)
Q_PROPERTY(FileMode fileMode READ fileMode WRITE setFileMode)
Q_PROPERTY(AcceptMode acceptMode READ acceptMode WRITE setAcceptMode)
@@ -97,6 +97,7 @@ public:
};
Q_ENUM(Option)
Q_DECLARE_FLAGS(Options, Option)
+ Q_FLAG(Options)
QFileDialog(QWidget *parent, Qt::WindowFlags f);
explicit QFileDialog(QWidget *parent = Q_NULLPTR,
@@ -125,6 +126,7 @@ public:
void setNameFilters(const QStringList &filters);
QStringList nameFilters() const;
void selectNameFilter(const QString &filter);
+ QString selectedMimeTypeFilter() const;
QString selectedNameFilter() const;
#ifndef QT_NO_MIMETYPE
@@ -312,8 +314,8 @@ inline void QFileDialog::setDirectory(const QDir &adirectory)
Q_DECLARE_OPERATORS_FOR_FLAGS(QFileDialog::Options)
-#endif // QT_NO_FILEDIALOG
-
QT_END_NAMESPACE
+#endif // QT_NO_FILEDIALOG
+
#endif // QFILEDIALOG_H
diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h
index afebad4457..b665b54a9b 100644
--- a/src/widgets/dialogs/qfiledialog_p.h
+++ b/src/widgets/dialogs/qfiledialog_p.h
@@ -258,6 +258,8 @@ public:
void selectFile_sys(const QUrl &filename);
QList<QUrl> selectedFiles_sys() const;
void setFilter_sys();
+ void selectMimeTypeFilter_sys(const QString &filter);
+ QString selectedMimeTypeFilter_sys() const;
void selectNameFilter_sys(const QString &filter);
QString selectedNameFilter_sys() const;
//////////////////////////////////////////////
@@ -400,6 +402,20 @@ inline void QFileDialogPrivate::setFilter_sys()
helper->setFilter();
}
+inline void QFileDialogPrivate::selectMimeTypeFilter_sys(const QString &filter)
+{
+ if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
+ helper->selectMimeTypeFilter(filter);
+}
+
+QString QFileDialogPrivate::selectedMimeTypeFilter_sys() const
+{
+ if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
+ return helper->selectedMimeTypeFilter();
+
+ return QString();
+}
+
inline void QFileDialogPrivate::selectNameFilter_sys(const QString &filter)
{
if (QPlatformFileDialogHelper *helper = platformFileDialogHelper())
diff --git a/src/widgets/dialogs/qfileinfogatherer.cpp b/src/widgets/dialogs/qfileinfogatherer.cpp
index 6df020dd58..08c5a40c7c 100644
--- a/src/widgets/dialogs/qfileinfogatherer.cpp
+++ b/src/widgets/dialogs/qfileinfogatherer.cpp
@@ -65,6 +65,18 @@ Q_AUTOTEST_EXPORT bool qt_test_isFetchedRoot()
}
#endif
+static QString translateDriveName(const QFileInfo &drive)
+{
+ QString driveName = drive.absoluteFilePath();
+#ifdef Q_OS_WIN
+ if (driveName.startsWith(QLatin1Char('/'))) // UNC host
+ return drive.fileName();
+ if (driveName.endsWith(QLatin1Char('/')))
+ driveName.chop(1);
+#endif // Q_OS_WIN
+ return driveName;
+}
+
/*!
Creates thread
*/
@@ -82,6 +94,16 @@ QFileInfoGatherer::QFileInfoGatherer(QObject *parent)
watcher = new QFileSystemWatcher(this);
connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(list(QString)));
connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFile(QString)));
+
+# if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ const QVariant listener = watcher->property("_q_driveListener");
+ if (listener.canConvert<QObject *>()) {
+ if (QObject *driveListener = listener.value<QObject *>()) {
+ connect(driveListener, SIGNAL(driveAdded()), this, SLOT(driveAdded()));
+ connect(driveListener, SIGNAL(driveRemoved(QString)), this, SLOT(driveRemoved()));
+ }
+ }
+# endif // Q_OS_WIN && !Q_OS_WINRT
#endif
start(LowPriority);
}
@@ -106,6 +128,20 @@ void QFileInfoGatherer::setResolveSymlinks(bool enable)
#endif
}
+void QFileInfoGatherer::driveAdded()
+{
+ fetchExtendedInformation(QString(), QStringList());
+}
+
+void QFileInfoGatherer::driveRemoved()
+{
+ QStringList drives;
+ const QFileInfoList driveInfoList = QDir::drives();
+ for (const QFileInfo &fi : driveInfoList)
+ drives.append(translateDriveName(fi));
+ newListOfFiles(QString(), drives);
+}
+
bool QFileInfoGatherer::resolveSymlinks() const
{
#ifdef Q_OS_WIN
@@ -260,18 +296,6 @@ QExtendedInformation QFileInfoGatherer::getInfo(const QFileInfo &fileInfo) const
return info;
}
-static QString translateDriveName(const QFileInfo &drive)
-{
- QString driveName = drive.absoluteFilePath();
-#if defined(Q_OS_WIN)
- if (driveName.startsWith(QLatin1Char('/'))) // UNC host
- return drive.fileName();
- if (driveName.endsWith(QLatin1Char('/')))
- driveName.chop(1);
-#endif
- return driveName;
-}
-
/*
Get specific file info's, batch the files so update when we have 100
items and every 200ms after that
diff --git a/src/widgets/dialogs/qfileinfogatherer_p.h b/src/widgets/dialogs/qfileinfogatherer_p.h
index 3186e9d015..0018b6c387 100644
--- a/src/widgets/dialogs/qfileinfogatherer_p.h
+++ b/src/widgets/dialogs/qfileinfogatherer_p.h
@@ -180,6 +180,10 @@ public Q_SLOTS:
void setResolveSymlinks(bool enable);
void setIconProvider(QFileIconProvider *provider);
+private Q_SLOTS:
+ void driveAdded();
+ void driveRemoved();
+
private:
void run() Q_DECL_OVERRIDE;
// called by run():
diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp
index 955e93a26f..b20a1449eb 100644
--- a/src/widgets/dialogs/qfontdialog.cpp
+++ b/src/widgets/dialogs/qfontdialog.cpp
@@ -867,8 +867,7 @@ QFont QFontDialog::selectedFont() const
\value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons. (Useful for "live dialogs".)
\value DontUseNativeDialog Use Qt's standard font dialog on the Mac instead of Apple's
- native font panel. (Currently, the native dialog is never used,
- but this is likely to change in future Qt releases.)
+ native font panel.
\value ScalableFonts Show scalable fonts
\value NonScalableFonts Show non scalable fonts
\value MonospacedFonts Show monospaced fonts
diff --git a/src/widgets/dialogs/qfontdialog.h b/src/widgets/dialogs/qfontdialog.h
index 276f8f5e83..da13a5ab99 100644
--- a/src/widgets/dialogs/qfontdialog.h
+++ b/src/widgets/dialogs/qfontdialog.h
@@ -42,13 +42,14 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtGui/qwindowdefs.h>
-#include <QtWidgets/qdialog.h>
#include <QtGui/qfont.h>
-QT_BEGIN_NAMESPACE
+#ifndef QT_NO_FONTDIALOG
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_NAMESPACE
-#ifndef QT_NO_FONTDIALOG
class QFontDialogPrivate;
@@ -117,8 +118,8 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QFontDialog::FontDialogOptions)
-#endif // QT_NO_FONTDIALOG
-
QT_END_NAMESPACE
+#endif // QT_NO_FONTDIALOG
+
#endif // QFONTDIALOG_H
diff --git a/src/widgets/dialogs/qinputdialog.h b/src/widgets/dialogs/qinputdialog.h
index 2fbea908cb..7b43e774a7 100644
--- a/src/widgets/dialogs/qinputdialog.h
+++ b/src/widgets/dialogs/qinputdialog.h
@@ -41,14 +41,15 @@
#define QINPUTDIALOG_H
#include <QtWidgets/qtwidgetsglobal.h>
-#include <QtWidgets/qdialog.h>
#include <QtCore/qstring.h>
#include <QtWidgets/qlineedit.h>
-QT_BEGIN_NAMESPACE
+#ifndef QT_NO_INPUTDIALOG
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_NAMESPACE
-#ifndef QT_NO_INPUTDIALOG
class QInputDialogPrivate;
@@ -209,8 +210,8 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QInputDialog::InputDialogOptions)
-#endif // QT_NO_INPUTDIALOG
-
QT_END_NAMESPACE
+#endif // QT_NO_INPUTDIALOG
+
#endif // QINPUTDIALOG_H
diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp
index 98d070e493..fe32611ed8 100644
--- a/src/widgets/dialogs/qmessagebox.cpp
+++ b/src/widgets/dialogs/qmessagebox.cpp
@@ -1405,7 +1405,7 @@ void QMessageBox::changeEvent(QEvent *ev)
void QMessageBox::keyPressEvent(QKeyEvent *e)
{
Q_D(QMessageBox);
-
+#if QT_CONFIG(shortcut)
if (e->matches(QKeySequence::Cancel)) {
if (d->detectedEscapeButton) {
#ifdef Q_OS_MAC
@@ -1416,7 +1416,7 @@ void QMessageBox::keyPressEvent(QKeyEvent *e)
}
return;
}
-
+#endif // QT_CONFIG(shortcut)
#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
@@ -1834,7 +1834,7 @@ void QMessageBox::aboutQt(QWidget *parent, const QString &title)
"<p>Qt and the Qt logo are trademarks of The Qt Company Ltd.</p>"
"<p>Qt is The Qt Company Ltd product developed as an open source "
"project. See <a href=\"http://%3/\">%3</a> for more information.</p>"
- ).arg(QStringLiteral("2016"),
+ ).arg(QStringLiteral("2017"),
QStringLiteral("qt.io/licensing"),
QStringLiteral("qt.io"));
QMessageBox *msgBox = new QMessageBox(parent);
diff --git a/src/widgets/dialogs/qmessagebox.h b/src/widgets/dialogs/qmessagebox.h
index c6a55964fe..40e5c701fe 100644
--- a/src/widgets/dialogs/qmessagebox.h
+++ b/src/widgets/dialogs/qmessagebox.h
@@ -41,13 +41,14 @@
#define QMESSAGEBOX_H
#include <QtWidgets/qtwidgetsglobal.h>
+
+#ifndef QT_NO_MESSAGEBOX
+
#include <QtWidgets/qdialog.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_MESSAGEBOX
-
class QLabel;
class QMessageBoxPrivate;
class QAbstractButton;
@@ -56,7 +57,6 @@ class QCheckBox;
class Q_WIDGETS_EXPORT QMessageBox : public QDialog
{
Q_OBJECT
- Q_FLAGS(StandardButtons)
Q_PROPERTY(QString text READ text WRITE setText)
Q_PROPERTY(Icon icon READ icon WRITE setIcon)
Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
@@ -131,6 +131,7 @@ public:
typedef StandardButton Button; // obsolete
Q_DECLARE_FLAGS(StandardButtons, StandardButton)
+ Q_FLAG(StandardButtons)
explicit QMessageBox(QWidget *parent = Q_NULLPTR);
QMessageBox(Icon icon, const QString &title, const QString &text,
@@ -322,8 +323,8 @@ QString s = QApplication::tr("Executable '%1' requires Qt "\
str)).arg(QString::fromLatin1(qVersion())); QMessageBox::critical(0, QApplication::tr(\
"Incompatible Qt Library Error"), s, QMessageBox::Abort, 0); qFatal("%s", s.toLatin1().data()); }}
-#endif // QT_NO_MESSAGEBOX
-
QT_END_NAMESPACE
+#endif // QT_NO_MESSAGEBOX
+
#endif // QMESSAGEBOX_H
diff --git a/src/widgets/dialogs/qprogressdialog.h b/src/widgets/dialogs/qprogressdialog.h
index a5e333259f..f4e63fb088 100644
--- a/src/widgets/dialogs/qprogressdialog.h
+++ b/src/widgets/dialogs/qprogressdialog.h
@@ -41,13 +41,14 @@
#define QPROGRESSDIALOG_H
#include <QtWidgets/qtwidgetsglobal.h>
+
+#ifndef QT_NO_PROGRESSDIALOG
+
#include <QtWidgets/qdialog.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_PROGRESSDIALOG
-
class QPushButton;
class QLabel;
class QProgressBar;
@@ -127,8 +128,8 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_disconnectOnClose())
};
-#endif // QT_NO_PROGRESSDIALOG
-
QT_END_NAMESPACE
+#endif // QT_NO_PROGRESSDIALOG
+
#endif // QPROGRESSDIALOG_H
diff --git a/src/widgets/dialogs/qsidebar.cpp b/src/widgets/dialogs/qsidebar.cpp
index 713ccb6556..9bb046db61 100644
--- a/src/widgets/dialogs/qsidebar.cpp
+++ b/src/widgets/dialogs/qsidebar.cpp
@@ -274,7 +274,7 @@ void QUrlModel::addUrls(const QList<QUrl> &list, int row, bool move)
continue;
insertRows(row, 1);
setUrl(index(row, 0), url, idx);
- watching.append(qMakePair(idx, cleanUrl));
+ watching.append({idx, cleanUrl});
}
}
@@ -326,7 +326,7 @@ void QUrlModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto
{
QModelIndex parent = topLeft.parent();
for (int i = 0; i < watching.count(); ++i) {
- QModelIndex index = watching.at(i).first;
+ QModelIndex index = watching.at(i).index;
if (index.model() && topLeft.model()) {
Q_ASSERT(index.model() == topLeft.model());
}
@@ -335,7 +335,7 @@ void QUrlModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto
&& index.column() >= topLeft.column()
&& index.column() <= bottomRight.column()
&& index.parent() == parent) {
- changed(watching.at(i).second);
+ changed(watching.at(i).path);
}
}
}
@@ -349,12 +349,12 @@ void QUrlModel::layoutChanged()
const int numPaths = watching.count();
paths.reserve(numPaths);
for (int i = 0; i < numPaths; ++i)
- paths.append(watching.at(i).second);
+ paths.append(watching.at(i).path);
watching.clear();
for (int i = 0; i < numPaths; ++i) {
QString path = paths.at(i);
QModelIndex newIndex = fileSystemModel->index(path);
- watching.append(QPair<QModelIndex, QString>(newIndex, path));
+ watching.append({newIndex, path});
if (newIndex.isValid())
changed(path);
}
diff --git a/src/widgets/dialogs/qsidebar_p.h b/src/widgets/dialogs/qsidebar_p.h
index 3e177e7e68..0685e81b2b 100644
--- a/src/widgets/dialogs/qsidebar_p.h
+++ b/src/widgets/dialogs/qsidebar_p.h
@@ -108,9 +108,16 @@ private:
void changed(const QString &path);
void addIndexToWatch(const QString &path, const QModelIndex &index);
QFileSystemModel *fileSystemModel;
- QVector<QPair<QModelIndex, QString> > watching;
+ struct WatchItem {
+ QModelIndex index;
+ QString path;
+ };
+ friend class QTypeInfo<WatchItem>;
+
+ QVector<WatchItem> watching;
QList<QUrl> invalidUrls;
};
+Q_DECLARE_TYPEINFO(QUrlModel::WatchItem, Q_MOVABLE_TYPE);
class Q_AUTOTEST_EXPORT QSidebar : public QListView
{
diff --git a/src/widgets/dialogs/qwizard.cpp b/src/widgets/dialogs/qwizard.cpp
index 9153d7ea41..d1abbc85d2 100644
--- a/src/widgets/dialogs/qwizard.cpp
+++ b/src/widgets/dialogs/qwizard.cpp
@@ -1089,7 +1089,7 @@ void QWizardPrivate::recreateLayout(const QWizardLayoutInfo &info)
// ### hardcoded for now:
titleFont = QFont(QLatin1String("Segoe UI"), 12);
QPalette pal(titleLabel->palette());
- pal.setColor(QPalette::Text, "#003399");
+ pal.setColor(QPalette::Text, QColor(0x00, 0x33, 0x99));
titleLabel->setPalette(pal);
}
@@ -1465,8 +1465,10 @@ void QWizardPrivate::updateButtonTexts()
// Vista: Add shortcut for 'next'. Note: native dialogs use ALT-Right
// even in RTL mode, so do the same, even if it might be counter-intuitive.
// The shortcut for 'back' is set in class QVistaBackButton.
+#if QT_CONFIG(shortcut)
if (btns[QWizard::NextButton])
btns[QWizard::NextButton]->setShortcut(isVistaThemeEnabled() ? QKeySequence(Qt::ALT | Qt::Key_Right) : QKeySequence());
+#endif
}
void QWizardPrivate::updateButtonLayout()
@@ -3255,7 +3257,7 @@ void QWizard::paintEvent(QPaintEvent * event)
#endif
}
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
/*!
\reimp
*/
diff --git a/src/widgets/dialogs/qwizard.h b/src/widgets/dialogs/qwizard.h
index 9ce68b6566..3236ee90df 100644
--- a/src/widgets/dialogs/qwizard.h
+++ b/src/widgets/dialogs/qwizard.h
@@ -41,13 +41,14 @@
#define QWIZARD_H
#include <QtWidgets/qtwidgetsglobal.h>
+
+#ifndef QT_NO_WIZARD
+
#include <QtWidgets/qdialog.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_WIZARD
-
class QAbstractButton;
class QWizardPage;
class QWizardPrivate;
@@ -55,7 +56,6 @@ class QWizardPrivate;
class Q_WIDGETS_EXPORT QWizard : public QDialog
{
Q_OBJECT
- Q_FLAGS(WizardOptions)
Q_PROPERTY(WizardStyle wizardStyle READ wizardStyle WRITE setWizardStyle)
Q_PROPERTY(WizardOptions options READ options WRITE setOptions)
Q_PROPERTY(Qt::TextFormat titleFormat READ titleFormat WRITE setTitleFormat)
@@ -120,6 +120,7 @@ public:
Q_ENUM(WizardOption)
Q_DECLARE_FLAGS(WizardOptions, WizardOption)
+ Q_FLAG(WizardOptions)
explicit QWizard(QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags());
~QWizard();
@@ -188,7 +189,7 @@ protected:
bool event(QEvent *event) Q_DECL_OVERRIDE;
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
bool nativeEvent(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE;
#endif
void done(int result) Q_DECL_OVERRIDE;
diff --git a/src/widgets/dialogs/qwizard_win.cpp b/src/widgets/dialogs/qwizard_win.cpp
index 80e37dab25..4ab01aca66 100644
--- a/src/widgets/dialogs/qwizard_win.cpp
+++ b/src/widgets/dialogs/qwizard_win.cpp
@@ -49,6 +49,7 @@
#include "qwizard.h"
#include "qpaintengine.h"
#include "qapplication.h"
+#include <QtCore/QOperatingSystemVersion>
#include <QtCore/QVariant>
#include <QtCore/QDebug>
#include <QtGui/QMouseEvent>
@@ -214,8 +215,7 @@ void QVistaHelper::disconnectBackButton()
QColor QVistaHelper::basicWindowFrameColor()
{
DWORD rgb;
- HWND handle = QApplicationPrivate::getHWNDForWidget(QApplication::desktop());
- const HANDLE hTheme = OpenThemeData(handle, L"WINDOW");
+ const HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
GetThemeColor(hTheme, WP_CAPTION, CS_ACTIVE,
wizard->isActiveWindow() ? TMT_FILLCOLORHINT : TMT_BORDERCOLORHINT, &rgb);
BYTE r = GetRValue(rgb);
@@ -257,8 +257,7 @@ static LOGFONT getCaptionLogFont(HANDLE hTheme)
static bool getCaptionQFont(int dpi, QFont *result)
{
- const HANDLE hTheme =
- OpenThemeData(QApplicationPrivate::getHWNDForWidget(QApplication::desktop()), L"WINDOW");
+ const HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
if (!hTheme)
return false;
// Call into QWindowsNativeInterface to convert the LOGFONT into a QFont.
@@ -589,8 +588,7 @@ bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const Q
if (vistaState() == VistaAero) {
const QRect rectDp = QRect(rect.topLeft() * QVistaHelper::m_devicePixelRatio,
rect.size() * QVistaHelper::m_devicePixelRatio);
- HWND handle = QApplicationPrivate::getHWNDForWidget(QApplication::desktop());
- const HANDLE hTheme = OpenThemeData(handle, L"WINDOW");
+ const HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
if (!hTheme) return false;
// Set up a memory DC and bitmap that we'll draw into
HDC dcMem;
@@ -718,7 +716,7 @@ int QVistaHelper::topOffset()
if (vistaState() != VistaAero)
return titleBarSize() + 3;
static const int aeroOffset =
- QSysInfo::WindowsVersion == QSysInfo::WV_WINDOWS7 ?
+ QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8 ?
QStyleHelper::dpiScaled(4) : QStyleHelper::dpiScaled(13);
return aeroOffset + titleBarSize();
}
diff --git a/src/widgets/effects/qgraphicseffect.h b/src/widgets/effects/qgraphicseffect.h
index 06ee78f2a0..8e07e51dca 100644
--- a/src/widgets/effects/qgraphicseffect.h
+++ b/src/widgets/effects/qgraphicseffect.h
@@ -62,7 +62,6 @@ class QGraphicsEffectPrivate;
class Q_WIDGETS_EXPORT QGraphicsEffect : public QObject
{
Q_OBJECT
- Q_FLAGS(ChangeFlags)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
public:
enum ChangeFlag {
@@ -72,6 +71,7 @@ public:
SourceInvalidated = 0x8
};
Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag)
+ Q_FLAG(ChangeFlags)
enum PixmapPadMode {
NoPad,
@@ -155,7 +155,6 @@ class QGraphicsBlurEffectPrivate;
class Q_WIDGETS_EXPORT QGraphicsBlurEffect: public QGraphicsEffect
{
Q_OBJECT
- Q_FLAGS(BlurHint BlurHints)
Q_PROPERTY(qreal blurRadius READ blurRadius WRITE setBlurRadius NOTIFY blurRadiusChanged)
Q_PROPERTY(BlurHints blurHints READ blurHints WRITE setBlurHints NOTIFY blurHintsChanged)
public:
@@ -164,7 +163,9 @@ public:
QualityHint = 0x01,
AnimationHint = 0x02
};
+ Q_FLAG(BlurHint)
Q_DECLARE_FLAGS(BlurHints, BlurHint)
+ Q_FLAG(BlurHints)
QGraphicsBlurEffect(QObject *parent = Q_NULLPTR);
~QGraphicsBlurEffect();
diff --git a/src/widgets/graphicsview/qgraph_p.h b/src/widgets/graphicsview/qgraph_p.h
index b0bf3c91c9..b42d4cf2e3 100644
--- a/src/widgets/graphicsview/qgraph_p.h
+++ b/src/widgets/graphicsview/qgraph_p.h
@@ -250,7 +250,7 @@ public:
}
strVertices += QString::fromLatin1("\"%1\" [label=\"%2\"]\n").arg(v->toString()).arg(v->toString());
}
- return QString::fromLatin1("%1\n%2\n").arg(strVertices).arg(edges);
+ return QString::fromLatin1("%1\n%2\n").arg(strVertices, edges);
}
#endif
diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp
index 6e10d18e11..60e9039b4a 100644
--- a/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp
+++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp
@@ -892,7 +892,7 @@ bool QGraphicsAnchorLayoutPrivate::replaceVertex(Orientation orientation, Anchor
AnchorVertex *otherV = replaceVertex_helper(ad, oldV, newV);
#if defined(QT_DEBUG)
- ad->name = QString::fromLatin1("%1 --to--> %2").arg(ad->from->toString()).arg(ad->to->toString());
+ ad->name = QString::fromLatin1("%1 --to--> %2").arg(ad->from->toString(), ad->to->toString());
#endif
bool newFeasible;
@@ -1755,7 +1755,7 @@ void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstIt
data->from = v1;
data->to = v2;
#ifdef QT_DEBUG
- data->name = QString::fromLatin1("%1 --to--> %2").arg(v1->toString()).arg(v2->toString());
+ data->name = QString::fromLatin1("%1 --to--> %2").arg(v1->toString(), v2->toString());
#endif
// ### bit to track internal anchors, since inside AnchorData methods
// we don't have access to the 'q' pointer.
@@ -2575,10 +2575,12 @@ void QGraphicsAnchorLayoutPrivate::identifyFloatItems(const QSet<AnchorData *> &
for (const AnchorData *ad : visited)
identifyNonFloatItems_helper(ad, &nonFloating);
- QSet<QGraphicsLayoutItem *> allItems;
- foreach (QGraphicsLayoutItem *item, items)
- allItems.insert(item);
- m_floatItems[orientation] = allItems - nonFloating;
+ QSet<QGraphicsLayoutItem *> floatItems;
+ for (QGraphicsLayoutItem *item : qAsConst(items)) {
+ if (!nonFloating.contains(item))
+ floatItems.insert(item);
+ }
+ m_floatItems[orientation] = std::move(floatItems);
}
diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.h b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h
index b6d8a12658..8da338dff7 100644
--- a/src/widgets/graphicsview/qgraphicsanchorlayout_p.h
+++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h
@@ -260,7 +260,7 @@ inline QString AnchorVertex::toString() const
{
if (m_type == Pair) {
const AnchorVertexPair *vp = static_cast<const AnchorVertexPair *>(this);
- return QString::fromLatin1("(%1, %2)").arg(vp->m_first->toString()).arg(vp->m_second->toString());
+ return QString::fromLatin1("(%1, %2)").arg(vp->m_first->toString(), vp->m_second->toString());
} else if (!m_item) {
return QString::fromLatin1("NULL_%1").arg(quintptr(this));
}
diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp
index 4fc52e6ad4..f2b8b66fed 100644
--- a/src/widgets/graphicsview/qgraphicsitem.cpp
+++ b/src/widgets/graphicsview/qgraphicsitem.cpp
@@ -7191,9 +7191,6 @@ void QGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
}
}
-/*!
- obsolete
-*/
bool _qt_movableAncestorIsSelected(const QGraphicsItem *item)
{
const QGraphicsItem *parent = item->parentItem();
diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp
index 41f5eddd99..9d7412340f 100644
--- a/src/widgets/graphicsview/qgraphicsview.cpp
+++ b/src/widgets/graphicsview/qgraphicsview.cpp
@@ -2996,12 +2996,12 @@ void QGraphicsView::contextMenuEvent(QContextMenuEvent *event)
}
#endif // QT_NO_CONTEXTMENU
+#if QT_CONFIG(draganddrop)
/*!
\reimp
*/
void QGraphicsView::dropEvent(QDropEvent *event)
{
-#ifndef QT_NO_DRAGANDDROP
Q_D(QGraphicsView);
if (!d->scene || !d->sceneInteractionAllowed)
return;
@@ -3020,10 +3020,6 @@ void QGraphicsView::dropEvent(QDropEvent *event)
delete d->lastDragDropEvent;
d->lastDragDropEvent = 0;
-
-#else
- Q_UNUSED(event)
-#endif
}
/*!
@@ -3031,7 +3027,6 @@ void QGraphicsView::dropEvent(QDropEvent *event)
*/
void QGraphicsView::dragEnterEvent(QDragEnterEvent *event)
{
-#ifndef QT_NO_DRAGANDDROP
Q_D(QGraphicsView);
if (!d->scene || !d->sceneInteractionAllowed)
return;
@@ -3054,9 +3049,6 @@ void QGraphicsView::dragEnterEvent(QDragEnterEvent *event)
event->setAccepted(true);
event->setDropAction(sceneEvent.dropAction());
}
-#else
- Q_UNUSED(event)
-#endif
}
/*!
@@ -3064,7 +3056,6 @@ void QGraphicsView::dragEnterEvent(QDragEnterEvent *event)
*/
void QGraphicsView::dragLeaveEvent(QDragLeaveEvent *event)
{
-#ifndef QT_NO_DRAGANDDROP
Q_D(QGraphicsView);
if (!d->scene || !d->sceneInteractionAllowed)
return;
@@ -3094,9 +3085,6 @@ void QGraphicsView::dragLeaveEvent(QDragLeaveEvent *event)
// Accept the originating event if the scene accepted the scene event.
if (sceneEvent.isAccepted())
event->setAccepted(true);
-#else
- Q_UNUSED(event)
-#endif
}
/*!
@@ -3104,7 +3092,6 @@ void QGraphicsView::dragLeaveEvent(QDragLeaveEvent *event)
*/
void QGraphicsView::dragMoveEvent(QDragMoveEvent *event)
{
-#ifndef QT_NO_DRAGANDDROP
Q_D(QGraphicsView);
if (!d->scene || !d->sceneInteractionAllowed)
return;
@@ -3123,10 +3110,8 @@ void QGraphicsView::dragMoveEvent(QDragMoveEvent *event)
event->setAccepted(sceneEvent.isAccepted());
if (sceneEvent.isAccepted())
event->setDropAction(sceneEvent.dropAction());
-#else
- Q_UNUSED(event)
-#endif
}
+#endif // QT_CONFIG(draganddrop)
/*!
\reimp
diff --git a/src/widgets/graphicsview/qgraphicsview.h b/src/widgets/graphicsview/qgraphicsview.h
index 327a75c374..64d5f5b430 100644
--- a/src/widgets/graphicsview/qgraphicsview.h
+++ b/src/widgets/graphicsview/qgraphicsview.h
@@ -244,10 +244,12 @@ protected:
#ifndef QT_NO_CONTEXTMENU
void contextMenuEvent(QContextMenuEvent *event) Q_DECL_OVERRIDE;
#endif
+#if QT_CONFIG(draganddrop)
void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE;
void dragLeaveEvent(QDragLeaveEvent *event) Q_DECL_OVERRIDE;
void dragMoveEvent(QDragMoveEvent *event) Q_DECL_OVERRIDE;
void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE;
+#endif
void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
bool focusNextPrevChild(bool next) Q_DECL_OVERRIDE;
void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
diff --git a/src/widgets/itemviews/qabstractitemdelegate.cpp b/src/widgets/itemviews/qabstractitemdelegate.cpp
index 8cd2a957be..f63e258e8e 100644
--- a/src/widgets/itemviews/qabstractitemdelegate.cpp
+++ b/src/widgets/itemviews/qabstractitemdelegate.cpp
@@ -537,11 +537,13 @@ bool QAbstractItemDelegatePrivate::tryFixup(QWidget *editor)
#ifndef QT_NO_LINEEDIT
if (QLineEdit *e = qobject_cast<QLineEdit*>(editor)) {
if (!e->hasAcceptableInput()) {
+#if QT_CONFIG(validator)
if (const QValidator *validator = e->validator()) {
QString text = e->text();
validator->fixup(text);
e->setText(text);
}
+#endif
return e->hasAcceptableInput();
}
}
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp
index e234f56799..d24456edef 100644
--- a/src/widgets/itemviews/qabstractitemview.cpp
+++ b/src/widgets/itemviews/qabstractitemview.cpp
@@ -64,7 +64,7 @@
#ifndef QT_NO_ACCESSIBILITY
#include <qaccessible.h>
#endif
-#ifndef QT_NO_GESTURES
+#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
# include <qscroller.h>
#endif
@@ -196,7 +196,7 @@ void QAbstractItemViewPrivate::checkMouseMove(const QPersistentModelIndex &index
}
}
-#ifndef QT_NO_GESTURES
+#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
// stores and restores the selection and current item when flicking
void QAbstractItemViewPrivate::_q_scrollerStateChanged()
@@ -1737,7 +1737,7 @@ bool QAbstractItemView::viewportEvent(QEvent *event)
break;
case QEvent::ScrollPrepare:
executeDelayedItemsLayout();
-#ifndef QT_NO_GESTURES
+#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
connect(QScroller::scroller(d->viewport), SIGNAL(stateChanged(QScroller::State)), this, SLOT(_q_scrollerStateChanged()), Qt::UniqueConnection);
#endif
break;
diff --git a/src/widgets/itemviews/qabstractitemview.h b/src/widgets/itemviews/qabstractitemview.h
index d6c5d58934..f315ea6e4c 100644
--- a/src/widgets/itemviews/qabstractitemview.h
+++ b/src/widgets/itemviews/qabstractitemview.h
@@ -62,7 +62,6 @@ class QAbstractItemViewPrivate;
class Q_WIDGETS_EXPORT QAbstractItemView : public QAbstractScrollArea
{
Q_OBJECT
- Q_FLAGS(EditTriggers)
Q_PROPERTY(bool autoScroll READ hasAutoScroll WRITE setAutoScroll)
Q_PROPERTY(int autoScrollMargin READ autoScrollMargin WRITE setAutoScrollMargin)
Q_PROPERTY(EditTriggers editTriggers READ editTriggers WRITE setEditTriggers)
@@ -118,6 +117,7 @@ public:
};
Q_DECLARE_FLAGS(EditTriggers, EditTrigger)
+ Q_FLAG(EditTriggers)
enum ScrollMode {
ScrollPerItem,
@@ -367,7 +367,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed())
Q_PRIVATE_SLOT(d_func(), void _q_layoutChanged())
Q_PRIVATE_SLOT(d_func(), void _q_headerDataChanged())
-#ifndef QT_NO_GESTURES
+#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
Q_PRIVATE_SLOT(d_func(), void _q_scrollerStateChanged())
#endif
diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h
index d21ae573cd..5e3858f491 100644
--- a/src/widgets/itemviews/qabstractitemview_p.h
+++ b/src/widgets/itemviews/qabstractitemview_p.h
@@ -89,18 +89,6 @@ class QTypeInfo<QItemViewPaintPair> : public QTypeInfoMerger<QItemViewPaintPair,
typedef QVector<QItemViewPaintPair> QItemViewPaintPairs;
-class QEmptyModel : public QAbstractItemModel
-{
-public:
- explicit QEmptyModel(QObject *parent = 0) : QAbstractItemModel(parent) {}
- QModelIndex index(int, int, const QModelIndex &) const override { return QModelIndex(); }
- QModelIndex parent(const QModelIndex &) const override { return QModelIndex(); }
- int rowCount(const QModelIndex &) const override { return 0; }
- int columnCount(const QModelIndex &) const override { return 0; }
- bool hasChildren(const QModelIndex &) const override { return false; }
- QVariant data(const QModelIndex &, int) const override { return QVariant(); }
-};
-
class Q_AUTOTEST_EXPORT QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate
{
Q_DECLARE_PUBLIC(QAbstractItemView)
diff --git a/src/widgets/itemviews/qdatawidgetmapper.cpp b/src/widgets/itemviews/qdatawidgetmapper.cpp
index b213a0859c..99704c7911 100644
--- a/src/widgets/itemviews/qdatawidgetmapper.cpp
+++ b/src/widgets/itemviews/qdatawidgetmapper.cpp
@@ -89,11 +89,11 @@ public:
: model->index(itemPos, currentIdx(), rootIndex);
}
- inline void flipEventFilters(QAbstractItemDelegate *oldDelegate,
- QAbstractItemDelegate *newDelegate)
+ void flipEventFilters(QAbstractItemDelegate *oldDelegate,
+ QAbstractItemDelegate *newDelegate) const
{
- for (QList<WidgetMapper>::const_iterator it = widgetMap.cbegin(), end = widgetMap.cend(); it != end; ++it) {
- QWidget *w = it->widget;
+ for (const WidgetMapper &e : widgetMap) {
+ QWidget *w = e.widget;
if (!w)
continue;
w->removeEventFilter(oldDelegate);
@@ -111,11 +111,6 @@ public:
struct WidgetMapper
{
- inline WidgetMapper(QWidget *w = 0, int c = 0, const QModelIndex &i = QModelIndex())
- : widget(w), section(c), currentIndex(i) {}
- inline WidgetMapper(QWidget *w, int c, const QModelIndex &i, const QByteArray &p)
- : widget(w), section(c), currentIndex(i), property(p) {}
-
QPointer<QWidget> widget;
int section;
QPersistentModelIndex currentIndex;
@@ -127,14 +122,15 @@ public:
bool commit(const WidgetMapper &m);
- QList<WidgetMapper> widgetMap;
+ std::vector<WidgetMapper> widgetMap;
};
+Q_DECLARE_TYPEINFO(QDataWidgetMapperPrivate::WidgetMapper, Q_MOVABLE_TYPE);
int QDataWidgetMapperPrivate::findWidget(QWidget *w) const
{
- for (QList<WidgetMapper>::const_iterator it = widgetMap.cbegin(), end = widgetMap.cend(); it != end; ++it) {
- if (it->widget == w)
- return int(std::distance(widgetMap.cbegin(), it));
+ for (const WidgetMapper &e : widgetMap) {
+ if (e.widget == w)
+ return int(&e - &widgetMap.front());
}
return -1;
}
@@ -171,8 +167,8 @@ void QDataWidgetMapperPrivate::populate(WidgetMapper &m)
void QDataWidgetMapperPrivate::populate()
{
- for (QList<WidgetMapper>::iterator it = widgetMap.begin(), end = widgetMap.end(); it != end; ++it)
- populate(*it);
+ for (WidgetMapper &e : widgetMap)
+ populate(e);
}
static bool qContainsIndex(const QModelIndex &idx, const QModelIndex &topLeft,
@@ -187,9 +183,9 @@ void QDataWidgetMapperPrivate::_q_dataChanged(const QModelIndex &topLeft, const
if (topLeft.parent() != rootIndex)
return; // not in our hierarchy
- for (QList<WidgetMapper>::iterator it = widgetMap.begin(), end = widgetMap.end(); it != end; ++it) {
- if (qContainsIndex(it->currentIndex, topLeft, bottomRight))
- populate(*it);
+ for (WidgetMapper &e : widgetMap) {
+ if (qContainsIndex(e.currentIndex, topLeft, bottomRight))
+ populate(e);
}
}
@@ -202,7 +198,7 @@ void QDataWidgetMapperPrivate::_q_commitData(QWidget *w)
if (idx == -1)
return; // not our widget
- commit(widgetMap.at(idx));
+ commit(widgetMap[idx]);
}
void QDataWidgetMapperPrivate::_q_closeEditor(QWidget *w, QAbstractItemDelegate::EndEditHint hint)
@@ -479,7 +475,7 @@ void QDataWidgetMapper::addMapping(QWidget *widget, int section)
Q_D(QDataWidgetMapper);
removeMapping(widget);
- d->widgetMap.append(QDataWidgetMapperPrivate::WidgetMapper(widget, section, d->indexAt(section)));
+ d->widgetMap.push_back({widget, section, d->indexAt(section), QByteArray()});
widget->installEventFilter(d->delegate);
}
@@ -497,7 +493,7 @@ void QDataWidgetMapper::addMapping(QWidget *widget, int section, const QByteArra
Q_D(QDataWidgetMapper);
removeMapping(widget);
- d->widgetMap.append(QDataWidgetMapperPrivate::WidgetMapper(widget, section, d->indexAt(section), propertyName));
+ d->widgetMap.push_back({widget, section, d->indexAt(section), propertyName});
widget->installEventFilter(d->delegate);
}
@@ -514,7 +510,7 @@ void QDataWidgetMapper::removeMapping(QWidget *widget)
if (idx == -1)
return;
- d->widgetMap.removeAt(idx);
+ d->widgetMap.erase(d->widgetMap.begin() + idx);
widget->removeEventFilter(d->delegate);
}
@@ -532,7 +528,7 @@ int QDataWidgetMapper::mappedSection(QWidget *widget) const
if (idx == -1)
return -1;
- return d->widgetMap.at(idx).section;
+ return d->widgetMap[idx].section;
}
/*!
@@ -550,7 +546,7 @@ QByteArray QDataWidgetMapper::mappedPropertyName(QWidget *widget) const
int idx = d->findWidget(widget);
if (idx == -1)
return QByteArray();
- const QDataWidgetMapperPrivate::WidgetMapper &m = d->widgetMap.at(idx);
+ const auto &m = d->widgetMap[idx];
if (m.property.isEmpty())
return m.widget->metaObject()->userProperty().name();
else
@@ -567,9 +563,9 @@ QWidget *QDataWidgetMapper::mappedWidgetAt(int section) const
{
Q_D(const QDataWidgetMapper);
- for (QList<QDataWidgetMapperPrivate::WidgetMapper>::const_iterator it = d->widgetMap.cbegin(), end = d->widgetMap.cend(); it != end; ++it) {
- if (it->section == section)
- return it->widget;
+ for (auto &e : d->widgetMap) {
+ if (e.section == section)
+ return e.widget;
}
return 0;
@@ -606,8 +602,8 @@ bool QDataWidgetMapper::submit()
{
Q_D(QDataWidgetMapper);
- for (QList<QDataWidgetMapperPrivate::WidgetMapper>::const_iterator it = d->widgetMap.cbegin(), end = d->widgetMap.cend(); it != end; ++it) {
- if (!d->commit(*it))
+ for (auto &e : d->widgetMap) {
+ if (!d->commit(e))
return false;
}
@@ -746,9 +742,9 @@ void QDataWidgetMapper::clearMapping()
{
Q_D(QDataWidgetMapper);
- QList<QDataWidgetMapperPrivate::WidgetMapper> copy;
+ decltype(d->widgetMap) copy;
d->widgetMap.swap(copy); // a C++98 move
- for (QList<QDataWidgetMapperPrivate::WidgetMapper>::const_reverse_iterator it = copy.crbegin(), end = copy.crend(); it != end; ++it) {
+ for (auto it = copy.crbegin(), end = copy.crend(); it != end; ++it) {
if (it->widget)
it->widget->removeEventFilter(d->delegate);
}
diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp
index e15fc558bf..e0e993ce77 100644
--- a/src/widgets/itemviews/qheaderview.cpp
+++ b/src/widgets/itemviews/qheaderview.cpp
@@ -2479,7 +2479,10 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e)
if (d->shouldAutoScroll(e->pos()))
d->startAutoScroll();
if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()
- || !d->sectionIndicator->isHidden()) {
+#if QT_CONFIG(label)
+ || !d->sectionIndicator->isHidden()
+#endif
+ ) {
int visual = visualIndexAt(pos);
if (visual == -1)
return;
@@ -2548,7 +2551,11 @@ void QHeaderView::mouseReleaseEvent(QMouseEvent *e)
int pos = d->orientation == Qt::Horizontal ? e->x() : e->y();
switch (d->state) {
case QHeaderViewPrivate::MoveSection:
- if (!d->sectionIndicator->isHidden()) { // moving
+ if (true
+#if QT_CONFIG(label)
+ && !d->sectionIndicator->isHidden()
+#endif
+ ) { // moving
int from = visualIndex(d->section);
Q_ASSERT(from != -1);
int to = visualIndex(d->target);
@@ -3139,9 +3146,11 @@ int QHeaderViewPrivate::sectionHandleAt(int position)
void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
{
Q_Q(QHeaderView);
+#if QT_CONFIG(label)
if (!sectionIndicator) {
sectionIndicator = new QLabel(viewport);
}
+#endif
int w, h;
int p = q->sectionViewportPosition(section);
@@ -3152,7 +3161,9 @@ void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
w = viewport->width();
h = q->sectionSize(section);
}
+#if QT_CONFIG(label)
sectionIndicator->resize(w, h);
+#endif
QPixmap pm(w, h);
pm.fill(QColor(0, 0, 0, 45));
@@ -3163,12 +3174,15 @@ void QHeaderViewPrivate::setupSectionIndicator(int section, int position)
q->paintSection(&painter, rect, section);
painter.end();
+#if QT_CONFIG(label)
sectionIndicator->setPixmap(pm);
+#endif
sectionIndicatorOffset = position - qMax(p, 0);
}
void QHeaderViewPrivate::updateSectionIndicator(int section, int position)
{
+#if QT_CONFIG(label)
if (!sectionIndicator)
return;
@@ -3183,6 +3197,7 @@ void QHeaderViewPrivate::updateSectionIndicator(int section, int position)
sectionIndicator->move(0, position - sectionIndicatorOffset);
sectionIndicator->show();
+#endif
}
/*!
diff --git a/src/widgets/itemviews/qheaderview_p.h b/src/widgets/itemviews/qheaderview_p.h
index 6affe7af95..d6b119512c 100644
--- a/src/widgets/itemviews/qheaderview_p.h
+++ b/src/widgets/itemviews/qheaderview_p.h
@@ -58,7 +58,9 @@
#include "QtCore/qbitarray.h"
#include "QtWidgets/qapplication.h"
+#if QT_CONFIG(label)
#include "QtWidgets/qlabel.h"
+#endif
QT_BEGIN_NAMESPACE
@@ -99,7 +101,9 @@ public:
lastSectionSize(0),
lastSectionLogicalIdx(-1), // Only trust when we stretch last section
sectionIndicatorOffset(0),
+#if QT_CONFIG(label)
sectionIndicator(0),
+#endif
globalResizeMode(QHeaderView::Interactive),
sectionStartposRecalc(true),
resizeContentsPrecision(1000)
@@ -296,7 +300,9 @@ public:
int lastSectionLogicalIdx; // Only trust if we stretch LastSection
int sectionIndicatorOffset;
Qt::Alignment defaultAlignment;
+#if QT_CONFIG(label)
QLabel *sectionIndicator;
+#endif
QHeaderView::ResizeMode globalResizeMode;
QList<QPersistentModelIndex> persistentHiddenSections;
mutable bool sectionStartposRecalc;
diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp
index 747d5db782..6a6220cd0a 100644
--- a/src/widgets/itemviews/qitemdelegate.cpp
+++ b/src/widgets/itemviews/qitemdelegate.cpp
@@ -62,7 +62,6 @@
#include <private/qtextengine_p.h>
#include <qdebug.h>
#include <qlocale.h>
-#include <qdialog.h>
#include <qmath.h>
#include <limits.h>
diff --git a/src/widgets/itemviews/qitemeditorfactory.cpp b/src/widgets/itemviews/qitemeditorfactory.cpp
index 5356ce3ad0..c535cf5f9e 100644
--- a/src/widgets/itemviews/qitemeditorfactory.cpp
+++ b/src/widgets/itemviews/qitemeditorfactory.cpp
@@ -45,7 +45,9 @@
#include <qcombobox.h>
#include <qdatetimeedit.h>
+#if QT_CONFIG(label)
#include <qlabel.h>
+#endif
#include <qlineedit.h>
#include <qspinbox.h>
#include <limits.h>
@@ -53,6 +55,7 @@
#include <qapplication.h>
#include <qdebug.h>
+#include <vector>
#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -189,9 +192,11 @@ QByteArray QItemEditorFactory::valuePropertyName(int userType) const
QItemEditorFactory::~QItemEditorFactory()
{
//we make sure we delete all the QItemEditorCreatorBase
- //this has to be done only once, hence the QSet
- QSet<QItemEditorCreatorBase*> set = creatorMap.values().toSet();
- qDeleteAll(set);
+ //this has to be done only once, hence the sort-unique idiom
+ std::vector<QItemEditorCreatorBase*> creators(creatorMap.cbegin(), creatorMap.cend());
+ std::sort(creators.begin(), creators.end());
+ const auto it = std::unique(creators.begin(), creators.end());
+ qDeleteAll(creators.begin(), it);
}
/*!
@@ -261,8 +266,10 @@ QWidget *QDefaultItemEditorFactory::createEditor(int userType, QWidget *parent)
ed->setFrame(false);
return ed; }
#endif
+#if QT_CONFIG(label)
case QVariant::Pixmap:
return new QLabel(parent);
+#endif
#ifndef QT_NO_SPINBOX
case QVariant::Double: {
QDoubleSpinBox *sb = new QDoubleSpinBox(parent);
diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp
index 0f5e83b83b..3ef5b788c6 100644
--- a/src/widgets/itemviews/qlistview.cpp
+++ b/src/widgets/itemviews/qlistview.cpp
@@ -1994,7 +1994,9 @@ int QCommonListViewBase::horizontalScrollToValue(const int /*index*/, QListView:
QListModeViewBase::QListModeViewBase(QListView *q, QListViewPrivate *d)
: QCommonListViewBase(q, d)
{
+#if QT_CONFIG(draganddrop)
dd->defaultDropAction = Qt::CopyAction;
+#endif
}
#ifndef QT_NO_DRAGANDDROP
@@ -2337,13 +2339,7 @@ void QListModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
bool QListModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max)
{
doStaticLayout(info);
- if (batchStartRow > max) { // stop items layout
- flowPositions.resize(flowPositions.count());
- segmentPositions.resize(segmentPositions.count());
- segmentStartRows.resize(segmentStartRows.count());
- return true; // done
- }
- return false; // not done
+ return batchStartRow > max; // returning true stops items layout
}
QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) const
@@ -2477,9 +2473,7 @@ void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info)
if (info.wrap && (flowPosition + deltaFlowPosition >= segEndPosition)) {
segmentExtents.append(flowPosition);
flowPosition = info.spacing + segStartPosition;
- segPosition += deltaSegPosition;
- if (info.wrap)
- segPosition += info.spacing;
+ segPosition += info.spacing + deltaSegPosition;
segmentPositions.append(segPosition);
segmentStartRows.append(row);
deltaSegPosition = 0;
diff --git a/src/widgets/itemviews/qlistwidget.h b/src/widgets/itemviews/qlistwidget.h
index c70e0522b7..85ca639e50 100644
--- a/src/widgets/itemviews/qlistwidget.h
+++ b/src/widgets/itemviews/qlistwidget.h
@@ -252,8 +252,9 @@ public:
bool isItemHidden(const QListWidgetItem *item) const;
void setItemHidden(const QListWidgetItem *item, bool hide);
+#if QT_CONFIG(draganddrop)
void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE;
-
+#endif
public Q_SLOTS:
void scrollToItem(const QListWidgetItem *item, QAbstractItemView::ScrollHint hint = EnsureVisible);
void clear();
diff --git a/src/widgets/itemviews/qstyleditemdelegate.cpp b/src/widgets/itemviews/qstyleditemdelegate.cpp
index e4115c9e60..4149d3ac3a 100644
--- a/src/widgets/itemviews/qstyleditemdelegate.cpp
+++ b/src/widgets/itemviews/qstyleditemdelegate.cpp
@@ -67,7 +67,6 @@
#include <private/qlayoutengine_p.h>
#include <qdebug.h>
#include <qlocale.h>
-#include <qdialog.h>
#include <qtableview.h>
#include <limits.h>
diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp
index c7cc1d155e..ed6482a8bc 100644
--- a/src/widgets/itemviews/qtableview.cpp
+++ b/src/widgets/itemviews/qtableview.cpp
@@ -49,7 +49,9 @@
#include <qevent.h>
#include <qbitarray.h>
#include <qscrollbar.h>
+#if QT_CONFIG(abstractbutton)
#include <qabstractbutton.h>
+#endif
#include <private/qtableview_p.h>
#include <private/qheaderview_p.h>
#include <private/qscrollbar_p.h>
@@ -578,6 +580,7 @@ bool QSpanCollection::checkConsistency() const
}
#endif
+#if QT_CONFIG(abstractbutton)
class QTableCornerButton : public QAbstractButton
{
Q_OBJECT
@@ -600,6 +603,7 @@ public:
style()->drawControl(QStyle::CE_Header, &opt, &painter, this);
}
};
+#endif
void QTableViewPrivate::init()
{
@@ -619,9 +623,11 @@ void QTableViewPrivate::init()
tabKeyNavigation = true;
+#if QT_CONFIG(abstractbutton)
cornerWidget = new QTableCornerButton(q);
cornerWidget->setFocusPolicy(Qt::NoFocus);
QObject::connect(cornerWidget, SIGNAL(clicked()), q, SLOT(selectAll()));
+#endif
}
/*!
@@ -2121,6 +2127,7 @@ void QTableView::updateGeometries()
if (d->horizontalHeader->isHidden())
QMetaObject::invokeMethod(d->horizontalHeader, "updateGeometries");
+#if QT_CONFIG(abstractbutton)
// update cornerWidget
if (d->horizontalHeader->isHidden() || d->verticalHeader->isHidden()) {
d->cornerWidget->setHidden(true);
@@ -2128,6 +2135,7 @@ void QTableView::updateGeometries()
d->cornerWidget->setHidden(false);
d->cornerWidget->setGeometry(verticalLeft, horizontalTop, width, height);
}
+#endif
// update scroll bars
@@ -2642,6 +2650,7 @@ bool QTableView::wordWrap() const
return d->wrapItemText;
}
+#if QT_CONFIG(abstractbutton)
/*!
\property QTableView::cornerButtonEnabled
\brief whether the button in the top-left corner is enabled
@@ -2664,6 +2673,7 @@ bool QTableView::isCornerButtonEnabled() const
Q_D(const QTableView);
return d->cornerWidget->isEnabled();
}
+#endif
/*!
\internal
diff --git a/src/widgets/itemviews/qtableview.h b/src/widgets/itemviews/qtableview.h
index 8c9ac379bc..b1c38d521f 100644
--- a/src/widgets/itemviews/qtableview.h
+++ b/src/widgets/itemviews/qtableview.h
@@ -58,7 +58,9 @@ class Q_WIDGETS_EXPORT QTableView : public QAbstractItemView
Q_PROPERTY(Qt::PenStyle gridStyle READ gridStyle WRITE setGridStyle)
Q_PROPERTY(bool sortingEnabled READ isSortingEnabled WRITE setSortingEnabled)
Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap)
+#if QT_CONFIG(abstractbutton)
Q_PROPERTY(bool cornerButtonEnabled READ isCornerButtonEnabled WRITE setCornerButtonEnabled)
+#endif
public:
explicit QTableView(QWidget *parent = Q_NULLPTR);
@@ -103,8 +105,10 @@ public:
void setWordWrap(bool on);
bool wordWrap() const;
+#if QT_CONFIG(abstractbutton)
void setCornerButtonEnabled(bool enable);
bool isCornerButtonEnabled() const;
+#endif
QRect visualRect(const QModelIndex &index) const Q_DECL_OVERRIDE;
void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) Q_DECL_OVERRIDE;
diff --git a/src/widgets/itemviews/qtableview_p.h b/src/widgets/itemviews/qtableview_p.h
index 2ca158d657..d2f45d557d 100644
--- a/src/widgets/itemviews/qtableview_p.h
+++ b/src/widgets/itemviews/qtableview_p.h
@@ -192,7 +192,9 @@ public:
QVector<int> rowsToUpdate;
QHeaderView *horizontalHeader;
QHeaderView *verticalHeader;
+#if QT_CONFIG(abstractbutton)
QWidget *cornerWidget;
+#endif
bool sortingEnabled;
bool geometryRecursionBlock;
QPoint visualCursor; // (Row,column) cell coordinates to track through span navigation.
diff --git a/src/widgets/itemviews/qtablewidget.h b/src/widgets/itemviews/qtablewidget.h
index 5dde93f628..b91bcf7ce4 100644
--- a/src/widgets/itemviews/qtablewidget.h
+++ b/src/widgets/itemviews/qtablewidget.h
@@ -331,8 +331,9 @@ protected:
QModelIndex indexFromItem(QTableWidgetItem *item) const;
QTableWidgetItem *itemFromIndex(const QModelIndex &index) const;
+#if QT_CONFIG(draganddrop)
void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE;
-
+#endif
private:
void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE;
diff --git a/src/widgets/itemviews/qtreewidget.h b/src/widgets/itemviews/qtreewidget.h
index 36ba9985bd..fc0bccf2fe 100644
--- a/src/widgets/itemviews/qtreewidget.h
+++ b/src/widgets/itemviews/qtreewidget.h
@@ -360,8 +360,9 @@ protected:
QModelIndex indexFromItem(const QTreeWidgetItem *item, int column = 0) const;
QModelIndex indexFromItem(QTreeWidgetItem *item, int column = 0) const; // ### Qt 6: remove
QTreeWidgetItem *itemFromIndex(const QModelIndex &index) const;
+#if QT_CONFIG(draganddrop)
void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE;
-
+#endif
private:
void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE;
diff --git a/src/widgets/kernel/kernel.pri b/src/widgets/kernel/kernel.pri
index ad2180bbfd..c91be918b6 100644
--- a/src/widgets/kernel/kernel.pri
+++ b/src/widgets/kernel/kernel.pri
@@ -15,7 +15,6 @@ HEADERS += \
kernel/qwidgetbackingstore_p.h \
kernel/qboxlayout.h \
kernel/qdesktopwidget.h \
- kernel/qformlayout.h \
kernel/qgridlayout.h \
kernel/qlayout.h \
kernel/qlayout_p.h \
@@ -45,7 +44,6 @@ SOURCES += \
kernel/qapplication.cpp \
kernel/qwidgetbackingstore.cpp \
kernel/qboxlayout.cpp \
- kernel/qformlayout.cpp \
kernel/qgridlayout.cpp \
kernel/qlayout.cpp \
kernel/qlayoutengine.cpp \
@@ -84,3 +82,8 @@ qtConfig(opengl) {
HEADERS += kernel/qopenglwidget.h
SOURCES += kernel/qopenglwidget.cpp
}
+
+qtConfig(formlayout) {
+ HEADERS += kernel/qformlayout.h
+ SOURCES += kernel/qformlayout.cpp
+}
diff --git a/src/widgets/kernel/qaction.cpp b/src/widgets/kernel/qaction.cpp
index e0700d877e..4582a55394 100644
--- a/src/widgets/kernel/qaction.cpp
+++ b/src/widgets/kernel/qaction.cpp
@@ -625,7 +625,7 @@ QActionGroup *QAction::actionGroup() const
it is displayed to the left of the menu text. There is no default
icon.
- If a null icon (QIcon::isNull() is passed into this function,
+ If a null icon (QIcon::isNull()) is passed into this function,
the icon of the action is cleared.
*/
void QAction::setIcon(const QIcon &icon)
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index 5908d3036b..0e4ee30c19 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -408,7 +408,6 @@ QWidget *QApplicationPrivate::focus_widget = 0; // has keyboard input foc
QWidget *QApplicationPrivate::hidden_focus_widget = 0; // will get keyboard input focus after show()
QWidget *QApplicationPrivate::active_window = 0; // toplevel with keyboard focus
#ifndef QT_NO_WHEELEVENT
-int QApplicationPrivate::wheel_scroll_lines; // number of lines to scroll
QPointer<QWidget> QApplicationPrivate::wheel_widget;
#endif
bool qt_in_tab_key_event = false;
@@ -642,19 +641,12 @@ void QApplicationPrivate::initialize()
if (qEnvironmentVariableIntValue("QT_USE_NATIVE_WINDOWS") > 0)
QCoreApplication::setAttribute(Qt::AA_NativeWindows);
-#ifndef QT_NO_WHEELEVENT
- QApplicationPrivate::wheel_scroll_lines = 3;
-#endif
-
if (qt_is_gui_used)
initializeMultitouch();
if (QApplication::desktopSettingsAware())
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
QApplicationPrivate::enabledAnimations = theme->themeHint(QPlatformTheme::UiEffects).toInt();
-#ifndef QT_NO_WHEELEVENT
- QApplicationPrivate::wheel_scroll_lines = theme->themeHint(QPlatformTheme::WheelScrollLines).toInt();
-#endif
}
is_app_running = true; // no longer starting up
@@ -2169,11 +2161,14 @@ QWidget *qt_tlw_for_window(QWindow *wnd)
// QTBUG-32177, wnd might be a QQuickView embedded via window container.
while (wnd && !wnd->isTopLevel()) {
QWindow *parent = wnd->parent();
+ if (!parent)
+ break;
+
// Don't end up in windows not belonging to this application
- if (parent && parent->type() != Qt::ForeignWindow)
- wnd = wnd->parent();
- else
+ if (parent->handle() && parent->handle()->isForeignWindow())
break;
+
+ wnd = wnd->parent();
}
if (wnd) {
const auto tlws = qApp->topLevelWidgets();
@@ -2455,26 +2450,11 @@ bool QApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWin
for (int i = 0; i < modalWindowList.count(); ++i) {
QWindow *modalWindow = modalWindowList.at(i);
- {
- // check if the modal window is our window or a (transient) parent of our window
- QWindow *w = window;
- while (w) {
- if (w == modalWindow) {
- *blockingWindow = 0;
- return false;
- }
- QWindow *p = w->parent();
- if (!p)
- p = w->transientParent();
- w = p;
- }
-
- // Embedded in-process windows are not visible in normal parent-child chain,
- // so check the native parent chain, too.
- const QPlatformWindow *platWin = window->handle();
- const QPlatformWindow *modalPlatWin = modalWindow->handle();
- if (platWin && modalPlatWin && platWin->isEmbedded(modalPlatWin))
- return false;
+ // A window is not blocked by another modal window if the two are
+ // the same, or if the window is a child of the modal window.
+ if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients)) {
+ *blockingWindow = 0;
+ return false;
}
Qt::WindowModality windowModality = modalWindow->modality();
@@ -3202,17 +3182,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
if (!w->hasMouseTracking()
&& mouse->type() == QEvent::MouseMove && mouse->buttons() == 0) {
// but still send them through all application event filters (normally done by notify_helper)
- for (int i = 0; d->extraData && i < d->extraData->eventFilters.size(); ++i) {
- QObject *obj = d->extraData->eventFilters.at(i);
- if (!obj)
- continue;
- if (Q_UNLIKELY(obj->d_func()->threadData != w->d_func()->threadData)) {
- qWarning("QApplication: Object event filter cannot be in a different thread.");
- continue;
- }
- if (obj->eventFilter(w, w == receiver ? mouse : &me))
- break;
- }
+ d->sendThroughApplicationEventFilters(w, w == receiver ? mouse : &me);
res = true;
} else {
w->setAttribute(Qt::WA_NoMouseReplay, false);
@@ -3558,9 +3528,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
touchEvent->setTarget(widget);
for (int i = 0; i < touchEvent->_touchPoints.size(); ++i) {
QTouchEvent::TouchPoint &pt = touchEvent->_touchPoints[i];
- QRectF rect = pt.rect();
- rect.translate(offset);
- pt.d->rect = rect;
+ pt.d->pos = pt.pos() + offset;
pt.d->startPos = pt.startPos() + offset;
pt.d->lastPos = pt.lastPos() + offset;
}
@@ -4066,16 +4034,18 @@ int QApplication::keyboardInputInterval()
or \l{QAbstractItemView::ScrollPerPixel}{scroll one pixel}.
By default, this property has a value of 3.
+
+ \sa QStyleHints::wheelScrollLines()
*/
#ifndef QT_NO_WHEELEVENT
int QApplication::wheelScrollLines()
{
- return QApplicationPrivate::wheel_scroll_lines;
+ return styleHints()->wheelScrollLines();
}
void QApplication::setWheelScrollLines(int lines)
{
- QApplicationPrivate::wheel_scroll_lines = lines;
+ styleHints()->setWheelScrollLines(lines);
}
#endif
@@ -4257,12 +4227,10 @@ bool QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEven
QTouchEvent::TouchPoint &touchPoint = touchEvent->_touchPoints[i];
// preserve the sub-pixel resolution
- QRectF rect = touchPoint.screenRect();
- const QPointF screenPos = rect.center();
+ const QPointF screenPos = touchPoint.screenRect().center();
const QPointF delta = screenPos - screenPos.toPoint();
- rect.moveCenter(widget->mapFromGlobal(screenPos.toPoint()) + delta);
- touchPoint.d->rect = rect;
+ touchPoint.d->pos = widget->mapFromGlobal(screenPos.toPoint()) + delta;
touchPoint.d->startPos = widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta;
touchPoint.d->lastPos = widget->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta;
diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h
index 73c75bbc14..271844a23e 100644
--- a/src/widgets/kernel/qapplication_p.h
+++ b/src/widgets/kernel/qapplication_p.h
@@ -91,12 +91,6 @@ extern Q_GUI_EXPORT bool qt_is_gui_used;
extern QClipboard *qt_clipboard;
#endif
-#if defined (Q_OS_WIN32) || defined (Q_OS_CYGWIN)
-extern QSysInfo::WinVersion qt_winver;
-#elif defined (Q_OS_MAC)
-extern QSysInfo::MacVersion qt_macver;
-#endif
-
typedef QHash<QByteArray, QFont> FontHash;
FontHash *qt_app_fonts_hash();
diff --git a/src/widgets/kernel/qdesktopwidget_p.h b/src/widgets/kernel/qdesktopwidget_p.h
index 4846a868aa..dade4fe45e 100644
--- a/src/widgets/kernel/qdesktopwidget_p.h
+++ b/src/widgets/kernel/qdesktopwidget_p.h
@@ -56,6 +56,7 @@
#include "private/qwidget_p.h"
#include <QtCore/qalgorithms.h>
+#include <QtGui/qscreen.h>
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/kernel/qformlayout.cpp b/src/widgets/kernel/qformlayout.cpp
index 6b134379c6..c66a6d5673 100644
--- a/src/widgets/kernel/qformlayout.cpp
+++ b/src/widgets/kernel/qformlayout.cpp
@@ -1167,12 +1167,12 @@ QLayoutItem* QFormLayoutPrivate::replaceAt(int index, QLayoutItem *newitem)
*/
/*!
- \since 5.8
- \struct QFormLayout::TakeRowResult
+ \class QFormLayout::TakeRowResult
\brief Contains the result of a QFormLayout::takeRow() call.
-
+ \inmodule QtWidgets
+ \since 5.8
\sa QFormLayout::takeRow()
*/
diff --git a/src/widgets/kernel/qformlayout.h b/src/widgets/kernel/qformlayout.h
index b4185374fd..5ec27433d3 100644
--- a/src/widgets/kernel/qformlayout.h
+++ b/src/widgets/kernel/qformlayout.h
@@ -43,6 +43,8 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/QLayout>
+QT_REQUIRE_CONFIG(formlayout);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/kernel/qgesture.cpp b/src/widgets/kernel/qgesture.cpp
index 2f33066389..3962cbe6c5 100644
--- a/src/widgets/kernel/qgesture.cpp
+++ b/src/widgets/kernel/qgesture.cpp
@@ -819,7 +819,6 @@ void QTapAndHoldGesture::setPosition(const QPointF &value)
later the touch is still down, it will trigger the QTapAndHoldGesture.
The default value is 700 milliseconds.
*/
-// static
void QTapAndHoldGesture::setTimeout(int msecs)
{
QTapAndHoldGesturePrivate::Timeout = msecs;
@@ -832,7 +831,6 @@ void QTapAndHoldGesture::setTimeout(int msecs)
later the touch is still down, it will trigger the QTapAndHoldGesture.
The default value is 700 milliseconds.
*/
-// static
int QTapAndHoldGesture::timeout()
{
return QTapAndHoldGesturePrivate::Timeout;
diff --git a/src/widgets/kernel/qgesture.h b/src/widgets/kernel/qgesture.h
index 034d1d88c1..4dd6e82fd1 100644
--- a/src/widgets/kernel/qgesture.h
+++ b/src/widgets/kernel/qgesture.h
@@ -135,7 +135,6 @@ class Q_WIDGETS_EXPORT QPinchGesture : public QGesture
{
Q_OBJECT
Q_DECLARE_PRIVATE(QPinchGesture)
- Q_FLAGS(ChangeFlags ChangeFlag)
public:
enum ChangeFlag {
@@ -143,7 +142,9 @@ public:
RotationAngleChanged = 0x2,
CenterPointChanged = 0x4
};
+ Q_FLAG(ChangeFlag)
Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag)
+ Q_FLAG(ChangeFlags)
Q_PROPERTY(ChangeFlags totalChangeFlags READ totalChangeFlags WRITE setTotalChangeFlags)
Q_PROPERTY(ChangeFlags changeFlags READ changeFlags WRITE setChangeFlags)
diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp
index 1a341d155b..f88ed350c7 100644
--- a/src/widgets/kernel/qlayout.cpp
+++ b/src/widgets/kernel/qlayout.cpp
@@ -49,7 +49,9 @@
#include "qvariant.h"
#include "qwidget_p.h"
#include "qlayout_p.h"
+#if QT_CONFIG(formlayout)
#include "qformlayout.h"
+#endif
QT_BEGIN_NAMESPACE
@@ -320,8 +322,10 @@ int QLayout::spacing() const
return boxlayout->spacing();
} else if (const QGridLayout* gridlayout = qobject_cast<const QGridLayout*>(this)) {
return gridlayout->spacing();
+#if QT_CONFIG(formlayout)
} else if (const QFormLayout* formlayout = qobject_cast<const QFormLayout*>(this)) {
return formlayout->spacing();
+#endif
} else {
Q_D(const QLayout);
if (d->insideSpacing >=0) {
@@ -347,8 +351,10 @@ void QLayout::setSpacing(int spacing)
boxlayout->setSpacing(spacing);
} else if (QGridLayout* gridlayout = qobject_cast<QGridLayout*>(this)) {
gridlayout->setSpacing(spacing);
+#if QT_CONFIG(formlayout)
} else if (QFormLayout* formlayout = qobject_cast<QFormLayout*>(this)) {
formlayout->setSpacing(spacing);
+#endif
} else {
Q_D(QLayout);
d->insideSpacing = spacing;
@@ -575,7 +581,7 @@ void QLayoutPrivate::doResize(const QSize &r)
QWidget *mw = q->parentWidget();
QRect rect = mw->testAttribute(Qt::WA_LayoutOnEntireRect) ? mw->rect() : mw->contentsRect();
const int mbTop = rect.top();
- rect.setTop(rect.top() + mbh);
+ rect.setTop(mbTop + mbh);
q->setGeometry(rect);
#ifndef QT_NO_MENUBAR
if (menubar)
diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp
index 147e0774e7..23948892f0 100644
--- a/src/widgets/kernel/qopenglwidget.cpp
+++ b/src/widgets/kernel/qopenglwidget.cpp
@@ -537,6 +537,7 @@ public:
w(widget) { }
void beginPaint() Q_DECL_OVERRIDE;
+ void endPaint() Q_DECL_OVERRIDE;
QOpenGLWidget *w;
};
@@ -631,6 +632,16 @@ void QOpenGLWidgetPaintDevicePrivate::beginPaint()
}
}
+void QOpenGLWidgetPaintDevicePrivate::endPaint()
+{
+ QOpenGLWidgetPrivate *wd = static_cast<QOpenGLWidgetPrivate *>(QWidgetPrivate::get(w));
+ if (!wd->initialized)
+ return;
+
+ if (!wd->inPaintGL)
+ QOpenGLContextPrivate::get(wd->context)->defaultFboRedirect = 0;
+}
+
void QOpenGLWidgetPaintDevice::ensureActiveTarget()
{
QOpenGLWidgetPaintDevicePrivate *d = static_cast<QOpenGLWidgetPaintDevicePrivate *>(d_ptr.data());
@@ -643,6 +654,9 @@ void QOpenGLWidgetPaintDevice::ensureActiveTarget()
else
wd->fbo->bind();
+ if (!wd->inPaintGL)
+ QOpenGLContextPrivate::get(wd->context)->defaultFboRedirect = wd->fbo->handle();
+
// When used as a viewport, drawing is done via opening a QPainter on the widget
// without going through paintEvent(). We will have to make sure a glFlush() is done
// before the texture is accessed also in this case.
diff --git a/src/widgets/kernel/qsizepolicy.cpp b/src/widgets/kernel/qsizepolicy.cpp
index e902bb522c..b5a0cd3940 100644
--- a/src/widgets/kernel/qsizepolicy.cpp
+++ b/src/widgets/kernel/qsizepolicy.cpp
@@ -232,7 +232,7 @@ QT_BEGIN_NAMESPACE
Returns the control type associated with the widget for which
this size policy applies.
*/
-QSizePolicy::ControlType QSizePolicy::controlType() const
+QSizePolicy::ControlType QSizePolicy::controlType() const Q_DECL_NOTHROW
{
return QSizePolicy::ControlType(1 << bits.ctype);
}
@@ -253,30 +253,9 @@ QSizePolicy::ControlType QSizePolicy::controlType() const
\sa QStyle::layoutSpacing()
*/
-void QSizePolicy::setControlType(ControlType type)
+void QSizePolicy::setControlType(ControlType type) Q_DECL_NOTHROW
{
- /*
- The control type is a flag type, with values 0x1, 0x2, 0x4, 0x8, 0x10,
- etc. In memory, we pack it onto the available bits (CTSize) in
- setControlType(), and unpack it here.
-
- Example:
-
- 0x00000001 maps to 0
- 0x00000002 maps to 1
- 0x00000004 maps to 2
- 0x00000008 maps to 3
- etc.
- */
-
- int i = 0;
- while (true) {
- if (type & (0x1 << i)) {
- bits.ctype = i;
- return;
- }
- ++i;
- }
+ bits.ctype = toControlTypeFieldValue(type);
}
/*!
@@ -395,6 +374,18 @@ void QSizePolicy::setControlType(ControlType type)
\fn void QSizePolicy::transpose()
Swaps the horizontal and vertical policies and stretches.
+
+ \sa transposed()
+*/
+
+/*!
+ \fn QSizePolicy QSizePolicy::transposed() const
+ \since 5.9
+
+ Returns a size policy object with the horizontal and vertical
+ policies and stretches swapped.
+
+ \sa transpose()
*/
/*!
diff --git a/src/widgets/kernel/qsizepolicy.h b/src/widgets/kernel/qsizepolicy.h
index 63b578fbf3..6cb4e147e9 100644
--- a/src/widgets/kernel/qsizepolicy.h
+++ b/src/widgets/kernel/qsizepolicy.h
@@ -42,9 +42,25 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtCore/qobject.h>
+#include <QtCore/qalgorithms.h>
QT_BEGIN_NAMESPACE
+// gcc < 4.8.0 has problems with init'ing variant members in constexpr ctors
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54922
+#if !defined(Q_CC_GNU) || defined(Q_CC_INTEL) || defined(Q_CC_CLANG) || Q_CC_GNU >= 408
+# define QT_SIZEPOLICY_CONSTEXPR Q_DECL_CONSTEXPR
+# if defined(Q_COMPILER_UNIFORM_INIT)
+# define QT_SIZEPOLICY_CONSTEXPR_AND_UNIFORM_INIT Q_DECL_CONSTEXPR
+# endif // uniform-init
+#endif
+
+#ifndef QT_SIZEPOLICY_CONSTEXPR
+# define QT_SIZEPOLICY_CONSTEXPR
+#endif
+#ifndef QT_SIZEPOLICY_CONSTEXPR_AND_UNIFORM_INIT
+# define QT_SIZEPOLICY_CONSTEXPR_AND_UNIFORM_INIT
+#endif
class QVariant;
class QSizePolicy;
@@ -54,7 +70,6 @@ Q_DECL_CONST_FUNCTION inline uint qHash(QSizePolicy key, uint seed = 0) Q_DECL_N
class Q_WIDGETS_EXPORT QSizePolicy
{
Q_GADGET
- Q_FLAGS(ControlTypes)
public:
enum PolicyFlag {
@@ -93,57 +108,92 @@ public:
ToolButton = 0x00004000
};
Q_DECLARE_FLAGS(ControlTypes, ControlType)
+ Q_FLAG(ControlTypes)
- QSizePolicy() : data(0) { }
+ QT_SIZEPOLICY_CONSTEXPR QSizePolicy() Q_DECL_NOTHROW : data(0) { }
- QSizePolicy(Policy horizontal, Policy vertical, ControlType type = DefaultType)
+#if defined(Q_COMPILER_UNIFORM_INIT) && !defined(Q_QDOC)
+ QT_SIZEPOLICY_CONSTEXPR QSizePolicy(Policy horizontal, Policy vertical, ControlType type = DefaultType) Q_DECL_NOTHROW
+ : bits{0, 0, quint32(horizontal), quint32(vertical),
+ type == DefaultType ? 0 : toControlTypeFieldValue(type), 0, 0, 0}
+ {}
+#else
+ QSizePolicy(Policy horizontal, Policy vertical, ControlType type = DefaultType) Q_DECL_NOTHROW
: data(0) {
bits.horPolicy = horizontal;
bits.verPolicy = vertical;
setControlType(type);
}
- Policy horizontalPolicy() const { return static_cast<Policy>(bits.horPolicy); }
- Policy verticalPolicy() const { return static_cast<Policy>(bits.verPolicy); }
- ControlType controlType() const;
+#endif // uniform-init
+ QT_SIZEPOLICY_CONSTEXPR Policy horizontalPolicy() const Q_DECL_NOTHROW { return static_cast<Policy>(bits.horPolicy); }
+ QT_SIZEPOLICY_CONSTEXPR Policy verticalPolicy() const Q_DECL_NOTHROW { return static_cast<Policy>(bits.verPolicy); }
+ ControlType controlType() const Q_DECL_NOTHROW;
- void setHorizontalPolicy(Policy d) { bits.horPolicy = d; }
- void setVerticalPolicy(Policy d) { bits.verPolicy = d; }
- void setControlType(ControlType type);
+ Q_DECL_RELAXED_CONSTEXPR void setHorizontalPolicy(Policy d) Q_DECL_NOTHROW { bits.horPolicy = d; }
+ Q_DECL_RELAXED_CONSTEXPR void setVerticalPolicy(Policy d) Q_DECL_NOTHROW { bits.verPolicy = d; }
+ void setControlType(ControlType type) Q_DECL_NOTHROW;
- Qt::Orientations expandingDirections() const {
+ QT_SIZEPOLICY_CONSTEXPR Qt::Orientations expandingDirections() const Q_DECL_NOTHROW {
return ( (verticalPolicy() & ExpandFlag) ? Qt::Vertical : Qt::Orientations() )
| ( (horizontalPolicy() & ExpandFlag) ? Qt::Horizontal : Qt::Orientations() ) ;
}
- void setHeightForWidth(bool b) { bits.hfw = b; }
- bool hasHeightForWidth() const { return bits.hfw; }
- void setWidthForHeight(bool b) { bits.wfh = b; }
- bool hasWidthForHeight() const { return bits.wfh; }
+ Q_DECL_RELAXED_CONSTEXPR void setHeightForWidth(bool b) Q_DECL_NOTHROW { bits.hfw = b; }
+ QT_SIZEPOLICY_CONSTEXPR bool hasHeightForWidth() const Q_DECL_NOTHROW { return bits.hfw; }
+ Q_DECL_RELAXED_CONSTEXPR void setWidthForHeight(bool b) Q_DECL_NOTHROW { bits.wfh = b; }
+ QT_SIZEPOLICY_CONSTEXPR bool hasWidthForHeight() const Q_DECL_NOTHROW { return bits.wfh; }
- bool operator==(const QSizePolicy& s) const { return data == s.data; }
- bool operator!=(const QSizePolicy& s) const { return data != s.data; }
+ QT_SIZEPOLICY_CONSTEXPR bool operator==(const QSizePolicy& s) const Q_DECL_NOTHROW { return data == s.data; }
+ QT_SIZEPOLICY_CONSTEXPR bool operator!=(const QSizePolicy& s) const Q_DECL_NOTHROW { return data != s.data; }
friend Q_DECL_CONST_FUNCTION uint qHash(QSizePolicy key, uint seed) Q_DECL_NOTHROW { return qHash(key.data, seed); }
operator QVariant() const;
- int horizontalStretch() const { return static_cast<int>(bits.horStretch); }
- int verticalStretch() const { return static_cast<int>(bits.verStretch); }
- void setHorizontalStretch(int stretchFactor) { bits.horStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); }
- void setVerticalStretch(int stretchFactor) { bits.verStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); }
-
- bool retainSizeWhenHidden() const { return bits.retainSizeWhenHidden; }
- void setRetainSizeWhenHidden(bool retainSize) { bits.retainSizeWhenHidden = retainSize; }
+ QT_SIZEPOLICY_CONSTEXPR int horizontalStretch() const Q_DECL_NOTHROW { return static_cast<int>(bits.horStretch); }
+ QT_SIZEPOLICY_CONSTEXPR int verticalStretch() const Q_DECL_NOTHROW { return static_cast<int>(bits.verStretch); }
+ Q_DECL_RELAXED_CONSTEXPR void setHorizontalStretch(int stretchFactor) { bits.horStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); }
+ Q_DECL_RELAXED_CONSTEXPR void setVerticalStretch(int stretchFactor) { bits.verStretch = static_cast<quint32>(qBound(0, stretchFactor, 255)); }
- void transpose();
+ QT_SIZEPOLICY_CONSTEXPR bool retainSizeWhenHidden() const Q_DECL_NOTHROW { return bits.retainSizeWhenHidden; }
+ Q_DECL_RELAXED_CONSTEXPR void setRetainSizeWhenHidden(bool retainSize) Q_DECL_NOTHROW { bits.retainSizeWhenHidden = retainSize; }
+ Q_DECL_RELAXED_CONSTEXPR void transpose() Q_DECL_NOTHROW { *this = transposed(); }
+#ifndef Q_QDOC
+ QT_SIZEPOLICY_CONSTEXPR_AND_UNIFORM_INIT
+#endif
+ QSizePolicy transposed() const Q_DECL_NOTHROW Q_REQUIRED_RESULT
+ {
+ return QSizePolicy(bits.transposed());
+ }
private:
#ifndef QT_NO_DATASTREAM
friend Q_WIDGETS_EXPORT QDataStream &operator<<(QDataStream &, const QSizePolicy &);
friend Q_WIDGETS_EXPORT QDataStream &operator>>(QDataStream &, QSizePolicy &);
#endif
- QSizePolicy(int i) : data(i) { }
+ QT_SIZEPOLICY_CONSTEXPR QSizePolicy(int i) Q_DECL_NOTHROW : data(i) { }
+ struct Bits;
+ QT_SIZEPOLICY_CONSTEXPR explicit QSizePolicy(Bits b) Q_DECL_NOTHROW : bits(b) { }
+
+ static Q_DECL_RELAXED_CONSTEXPR quint32 toControlTypeFieldValue(ControlType type) Q_DECL_NOTHROW
+ {
+ /*
+ The control type is a flag type, with values 0x1, 0x2, 0x4, 0x8, 0x10,
+ etc. In memory, we pack it onto the available bits (CTSize) in
+ setControlType(), and unpack it here.
+
+ Example:
+
+ 0x00000001 maps to 0
+ 0x00000002 maps to 1
+ 0x00000004 maps to 2
+ 0x00000008 maps to 3
+ etc.
+ */
+
+ return qCountTrailingZeroBits(static_cast<quint32>(type));
+ }
struct Bits {
quint32 horStretch : 8;
@@ -154,6 +204,19 @@ private:
quint32 hfw : 1;
quint32 wfh : 1;
quint32 retainSizeWhenHidden : 1;
+
+ QT_SIZEPOLICY_CONSTEXPR_AND_UNIFORM_INIT
+ Bits transposed() const Q_DECL_NOTHROW
+ {
+ return {verStretch, // \ swap
+ horStretch, // /
+ verPolicy, // \ swap
+ horPolicy, // /
+ ctype,
+ hfw, // \ don't swap (historic behavior)
+ wfh, // /
+ retainSizeWhenHidden};
+ }
};
union {
Bits bits;
@@ -163,6 +226,8 @@ private:
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
// Can't add in Qt 5, as QList<QSizePolicy> would be BiC:
Q_DECLARE_TYPEINFO(QSizePolicy, Q_PRIMITIVE_TYPE);
+#else
+Q_DECLARE_TYPEINFO(QSizePolicy, Q_RELOCATABLE_TYPE);
#endif
Q_DECLARE_OPERATORS_FOR_FLAGS(QSizePolicy::ControlTypes)
@@ -176,16 +241,9 @@ Q_WIDGETS_EXPORT QDataStream &operator>>(QDataStream &, QSizePolicy &);
Q_WIDGETS_EXPORT QDebug operator<<(QDebug dbg, const QSizePolicy &);
#endif
-inline void QSizePolicy::transpose() {
- Policy hData = horizontalPolicy();
- Policy vData = verticalPolicy();
- int hStretch = horizontalStretch();
- int vStretch = verticalStretch();
- setHorizontalPolicy(vData);
- setVerticalPolicy(hData);
- setHorizontalStretch(vStretch);
- setVerticalStretch(hStretch);
-}
+
+#undef QT_SIZEPOLICY_CONSTEXPR
+#undef QT_SIZEPOLICY_CONSTEXPR_AND_UNIFORM_INIT
QT_END_NAMESPACE
diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp
index a92dc2cbf7..48afeb1dcc 100644
--- a/src/widgets/kernel/qtooltip.cpp
+++ b/src/widgets/kernel/qtooltip.cpp
@@ -43,18 +43,19 @@
#include <qapplication.h>
#include <qdesktopwidget.h>
#include <qevent.h>
-#include <qlabel.h>
#include <qpointer.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qstylepainter.h>
#include <qtimer.h>
-#include <qtooltip.h>
#include <private/qeffects_p.h>
#include <qtextdocument.h>
#include <qdebug.h>
#include <private/qstylesheetstyle_p.h>
+
#ifndef QT_NO_TOOLTIP
+#include <qlabel.h>
+#include <qtooltip.h>
#if 0 // Used to be included in Qt4 for Q_WS_MAC
# include <private/qcore_mac_p.h>
diff --git a/src/widgets/kernel/qwhatsthis.cpp b/src/widgets/kernel/qwhatsthis.cpp
index 6061af5f38..4286019717 100644
--- a/src/widgets/kernel/qwhatsthis.cpp
+++ b/src/widgets/kernel/qwhatsthis.cpp
@@ -462,11 +462,13 @@ bool QWhatsThisPrivate::eventFilter(QObject *o, QEvent *e)
case QEvent::KeyPress:
{
QKeyEvent* kev = (QKeyEvent*)e;
-
+#if QT_CONFIG(shortcut)
if (kev->matches(QKeySequence::Cancel)) {
QWhatsThis::leaveWhatsThisMode();
return true;
- } else if (customWhatsThis) {
+ } else
+#endif
+ if (customWhatsThis) {
return false;
} else if (kev->key() == Qt::Key_Menu ||
(kev->key() == Qt::Key_F10 &&
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 7e9e4f0a98..bd67e0be32 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -1477,12 +1477,16 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
qt_window_private(win)->positionPolicy = topData()->posIncludesFrame ?
QWindowPrivate::WindowFrameInclusive : QWindowPrivate::WindowFrameExclusive;
- win->create();
- // Enable nonclient-area events for QDockWidget and other NonClientArea-mouse event processing.
- if ((flags & Qt::Desktop) == Qt::Window)
+
+ if (q->windowType() != Qt::Desktop || q->testAttribute(Qt::WA_NativeWindow)) {
+ win->create();
+ // Enable nonclient-area events for QDockWidget and other NonClientArea-mouse event processing.
win->handle()->setFrameStrutEventsEnabled(true);
+ }
data.window_flags = win->flags();
+ if (!win->isTopLevel()) // In a Widget world foreign windows can only be top level
+ data.window_flags &= ~Qt::ForeignWindow;
if (!topData()->role.isNull())
QXcbWindowFunctions::setWmWindowRole(win, topData()->role.toLatin1());
@@ -1499,10 +1503,13 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
}
setWindowModified_helper();
- WId id = win->winId();
- // See the QPlatformWindow::winId() documentation
- Q_ASSERT(id != WId(0));
- setWinId(id);
+
+ if (win->handle()) {
+ WId id = win->winId();
+ // See the QPlatformWindow::winId() documentation
+ Q_ASSERT(id != WId(0));
+ setWinId(id);
+ }
// Check children and create windows for them if necessary
q_createNativeChildrenAndSetParent(q);
@@ -5246,8 +5253,6 @@ static void sendResizeEvents(QWidget *target)
\sa render(), QPixmap
*/
-
-/* INVOKABLE since used by QPixmap::grabWidget(). */
QPixmap QWidget::grab(const QRect &rectangle)
{
Q_D(QWidget);
@@ -6382,6 +6387,24 @@ void QWidget::setWindowRole(const QString &role)
\sa mouseMoveEvent()
*/
+/*!
+ \property QWidget::tabletTracking
+ \brief whether tablet tracking is enabled for the widget
+ \since 5.9
+
+ If tablet tracking is disabled (the default), the widget only
+ receives tablet move events when the stylus is in contact with
+ the tablet, or at least one stylus button is pressed,
+ while the stylus is being moved.
+
+ If tablet tracking is enabled, the widget receives tablet move
+ events even while hovering in proximity. This is useful for
+ monitoring position as well as the auxiliary properties such
+ as rotation and tilt, and providing feedback in the UI.
+
+ \sa tabletEvent()
+*/
+
/*!
Sets the widget's focus proxy to widget \a w. If \a w is 0, the
@@ -6593,11 +6616,6 @@ void QWidget::setFocus(Qt::FocusReason reason)
} else {
f->d_func()->updateFocusChild();
}
-
- if (QTLWExtra *extra = f->window()->d_func()->maybeTopData()) {
- if (extra->window)
- emit extra->window->focusObjectChanged(f);
- }
}
void QWidgetPrivate::setFocus_sys()
@@ -6632,6 +6650,11 @@ void QWidgetPrivate::updateFocusChild()
w = w->isWindow() ? 0 : w->parentWidget();
}
}
+
+ if (QTLWExtra *extra = q->window()->d_func()->maybeTopData()) {
+ if (extra->window)
+ emit extra->window->focusObjectChanged(q);
+ }
}
/*!
@@ -6673,9 +6696,15 @@ void QWidget::clearFocus()
w->d_func()->focus_child = 0;
w = w->parentWidget();
}
- // Since focus_child is the basis for the top level QWidgetWindow's focusObject()
- // we need to report this change to the rest of Qt, but we match setFocus() and
- // do it at the end of the function.
+
+ // Since we've unconditionally cleared the focus_child of our parents, we need
+ // to report this to the rest of Qt. Note that the focus_child is not the same
+ // thing as the application's focusWidget, which is why this piece of code is
+ // not inside the hasFocus() block below.
+ if (QTLWExtra *extra = window()->d_func()->maybeTopData()) {
+ if (extra->window)
+ emit extra->window->focusObjectChanged(extra->window->focusObject());
+ }
#ifndef QT_NO_GRAPHICSVIEW
QWExtra *topData = d_func()->extra;
@@ -6698,15 +6727,6 @@ void QWidget::clearFocus()
#endif
}
}
-
- // Since we've unconditionally cleared the focus_child of our parents, we need
- // to report this to the rest of Qt. Note that the focus_child is not the same
- // thing as the application's focusWidget, which is why this piece of code is
- // not inside the hasFocus() block above.
- if (QTLWExtra *extra = window()->d_func()->maybeTopData()) {
- if (extra->window)
- emit extra->window->focusObjectChanged(extra->window->focusObject());
- }
}
@@ -6754,12 +6774,12 @@ void QWidget::clearFocus()
bool QWidget::focusNextPrevChild(bool next)
{
- Q_D(QWidget);
QWidget* p = parentWidget();
bool isSubWindow = (windowType() == Qt::SubWindow);
if (!isWindow() && !isSubWindow && p)
return p->focusNextPrevChild(next);
#ifndef QT_NO_GRAPHICSVIEW
+ Q_D(QWidget);
if (d->extra && d->extra->proxyWidget)
return d->extra->proxyWidget->focusNextPrevChild(next);
#endif
@@ -8786,6 +8806,9 @@ bool QWidget::event(QEvent *event)
#endif
#ifndef QT_NO_TABLETEVENT
case QEvent::TabletMove:
+ if (static_cast<QTabletEvent *>(event)->buttons() == Qt::NoButton && !testAttribute(Qt::WA_TabletTracking))
+ break;
+ Q_FALLTHROUGH();
case QEvent::TabletPress:
case QEvent::TabletRelease:
tabletEvent((QTabletEvent*)event);
@@ -9018,6 +9041,7 @@ bool QWidget::event(QEvent *event)
case QEvent::IconTextChange:
case QEvent::ModifiedChange:
case QEvent::MouseTrackingChange:
+ case QEvent::TabletTrackingChange:
case QEvent::ParentChange:
case QEvent::LocaleChange:
case QEvent::MacSizeChange:
@@ -9189,6 +9213,8 @@ bool QWidget::event(QEvent *event)
const QWindow *win = te->window;
d->setWinId((win && win->handle()) ? win->handle()->winId() : 0);
}
+ if (d->data.fnt.d->dpi != logicalDpiY())
+ d->updateFont(d->data.fnt);
#ifndef QT_NO_OPENGL
d->renderToTextureReallyDirty = 1;
#endif
@@ -9422,7 +9448,13 @@ void QWidget::wheelEvent(QWheelEvent *event)
The default implementation ignores the event.
- \sa QEvent::ignore(), QEvent::accept(), event(),
+ If tablet tracking is switched off, tablet move events only occur if the
+ stylus is in contact with the tablet, or at least one stylus button is
+ pressed, while the stylus is being moved. If tablet tracking is switched on,
+ tablet move events occur even while the stylus is hovering in proximity of
+ the tablet, with no buttons pressed.
+
+ \sa QEvent::ignore(), QEvent::accept(), event(), setTabletTracking(),
QTabletEvent
*/
@@ -10353,7 +10385,7 @@ void QWidget::updateGeometry()
a window, causing the widget to be hidden. You must call show() to make
the widget visible again..
- \sa windowType(), {Window Flags Example}
+ \sa windowType(), setWindowFlag(), {Window Flags Example}
*/
void QWidget::setWindowFlags(Qt::WindowFlags flags)
{
@@ -10361,6 +10393,23 @@ void QWidget::setWindowFlags(Qt::WindowFlags flags)
d->setWindowFlags(flags);
}
+/*!
+ \since 5.9
+
+ Sets the window flag \a flag on this widget if \a on is true;
+ otherwise clears the flag.
+
+ \sa setWindowFlags(), windowFlags(), windowType()
+*/
+void QWidget::setWindowFlag(Qt::WindowType flag, bool on)
+{
+ Q_D(QWidget);
+ if (on)
+ d->setWindowFlags(data->window_flags | flag);
+ else
+ d->setWindowFlags(data->window_flags & ~flag);
+}
+
/*! \internal
Implemented in QWidgetPrivate so that QMdiSubWindowPrivate can reimplement it.
@@ -11174,6 +11223,10 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
QEvent e(QEvent::MouseTrackingChange);
QApplication::sendEvent(this, &e);
break; }
+ case Qt::WA_TabletTracking: {
+ QEvent e(QEvent::TabletTrackingChange);
+ QApplication::sendEvent(this, &e);
+ break; }
case Qt::WA_NativeWindow: {
d->createTLExtra();
if (on)
@@ -12710,7 +12763,6 @@ void QWidget::activateWindow()
}
/*!
- \fn int QWidget::metric(PaintDeviceMetric m) const
Internal implementation of the virtual QPaintDevice::metric()
function.
@@ -12719,8 +12771,6 @@ void QWidget::activateWindow()
*/
int QWidget::metric(PaintDeviceMetric m) const
{
- Q_D(const QWidget);
-
QWindow *topLevelWindow = 0;
QScreen *screen = 0;
if (QWidget *topLevel = window()) {
@@ -12748,16 +12798,16 @@ int QWidget::metric(PaintDeviceMetric m) const
} else if (m == PdmDepth) {
return screen->depth();
} else if (m == PdmDpiX) {
- if (d->extra && d->extra->customDpiX)
- return d->extra->customDpiX;
- else if (d->parent)
- return static_cast<QWidget *>(d->parent)->metric(m);
+ for (const QWidget *p = this; p; p = p->parentWidget()) {
+ if (p->d_func()->extra && p->d_func()->extra->customDpiX)
+ return p->d_func()->extra->customDpiX;
+ }
return qRound(screen->logicalDotsPerInchX());
} else if (m == PdmDpiY) {
- if (d->extra && d->extra->customDpiY)
- return d->extra->customDpiY;
- else if (d->parent)
- return static_cast<QWidget *>(d->parent)->metric(m);
+ for (const QWidget *p = this; p; p = p->parentWidget()) {
+ if (p->d_func()->extra && p->d_func()->extra->customDpiY)
+ return p->d_func()->extra->customDpiY;
+ }
return qRound(screen->logicalDotsPerInchY());
} else if (m == PdmPhysicalDpiX) {
return qRound(screen->physicalDotsPerInchX());
@@ -12934,6 +12984,9 @@ void QWidget::setMask(const QBitmap &bitmap)
*/
void QWidget::clearMask()
{
+ Q_D(QWidget);
+ if (!d->extra || !d->extra->hasMask)
+ return;
setMask(QRegion());
}
diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h
index 58413c6bd3..1c378924a0 100644
--- a/src/widgets/kernel/qwidget.h
+++ b/src/widgets/kernel/qwidget.h
@@ -161,6 +161,7 @@ class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
#endif
Q_PROPERTY(bool mouseTracking READ hasMouseTracking WRITE setMouseTracking)
+ Q_PROPERTY(bool tabletTracking READ hasTabletTracking WRITE setTabletTracking)
Q_PROPERTY(bool isActiveWindow READ isActiveWindow)
Q_PROPERTY(Qt::FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy)
Q_PROPERTY(bool focus READ hasFocus)
@@ -328,6 +329,9 @@ public:
bool hasMouseTracking() const;
bool underMouse() const;
+ void setTabletTracking(bool enable);
+ bool hasTabletTracking() const;
+
void setMask(const QBitmap &);
void setMask(const QRegion &);
QRegion mask() const;
@@ -562,6 +566,7 @@ public:
void setWindowFlags(Qt::WindowFlags type);
inline Qt::WindowFlags windowFlags() const;
+ void setWindowFlag(Qt::WindowType, bool on = true);
void overrideWindowFlags(Qt::WindowFlags type);
inline Qt::WindowType windowType() const;
@@ -808,6 +813,12 @@ inline bool QWidget::hasMouseTracking() const
inline bool QWidget::underMouse() const
{ return testAttribute(Qt::WA_UnderMouse); }
+inline void QWidget::setTabletTracking(bool enable)
+{ setAttribute(Qt::WA_TabletTracking, enable); }
+
+inline bool QWidget::hasTabletTracking() const
+{ return testAttribute(Qt::WA_TabletTracking); }
+
inline bool QWidget::updatesEnabled() const
{ return !testAttribute(Qt::WA_UpdatesDisabled); }
diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp
index 910704498c..781ad9600d 100644
--- a/src/widgets/kernel/qwidgetbackingstore.cpp
+++ b/src/widgets/kernel/qwidgetbackingstore.cpp
@@ -164,23 +164,11 @@ static void showYellowThing_win(QWidget *widget, const QRegion &region, int msec
return;
const HDC hdc = reinterpret_cast<HDC>(hdcV);
- HBRUSH brush;
- static int i = 0;
- switch (i) {
- case 0:
- brush = CreateSolidBrush(RGB(255, 255, 0));
- break;
- case 1:
- brush = CreateSolidBrush(RGB(255, 200, 55));
- break;
- case 2:
- brush = CreateSolidBrush(RGB(200, 255, 55));
- break;
- case 3:
- brush = CreateSolidBrush(RGB(200, 200, 0));
- break;
- }
- i = (i + 1) & 3;
+ static const COLORREF colors[] = {RGB(255, 255, 0), RGB(255, 200, 55), RGB(200, 255, 55), RGB(200, 200, 0)};
+
+ static size_t i = 0;
+ const HBRUSH brush = CreateSolidBrush(colors[i]);
+ i = (i + 1) % (sizeof(colors) / sizeof(colors[0]));
for (const QRect &rect : region) {
RECT winRect;
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 3e15b6977a..31f2d672bb 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -285,6 +285,7 @@ bool QWidgetWindow::event(QEvent *event)
return true;
case QEvent::WindowStateChange:
+ QWindow::event(event); // Update QWindow::Visibility and emit signals.
handleWindowStateChangedEvent(static_cast<QWindowStateChangeEvent *>(event));
return true;
@@ -957,8 +958,8 @@ void QWidgetWindow::handleWindowStateChangedEvent(QWindowStateChangeEvent *event
// Sent event if the state changed (that is, it is not triggered by
// QWidget::setWindowState(), which also sends an event to the widget).
- if (widgetState != int(m_widget->data->window_state)) {
- m_widget->data->window_state = widgetState;
+ if (widgetState != Qt::WindowStates::Int(m_widget->data->window_state)) {
+ m_widget->data->window_state = uint(widgetState);
QWindowStateChangeEvent widgetEvent(eventState);
QGuiApplication::sendSpontaneousEvent(m_widget, &widgetEvent);
}
@@ -973,22 +974,26 @@ bool QWidgetWindow::nativeEvent(const QByteArray &eventType, void *message, long
void QWidgetWindow::handleTabletEvent(QTabletEvent *event)
{
static QPointer<QWidget> qt_tablet_target = 0;
- if (event->type() == QEvent::TabletPress) {
- QWidget *widget = m_widget->childAt(event->pos());
- if (!widget)
- widget = m_widget;
- qt_tablet_target = widget;
+ QWidget *widget = qt_tablet_target;
+
+ if (!widget) {
+ widget = m_widget->childAt(event->pos());
+ if (event->type() == QEvent::TabletPress) {
+ if (!widget)
+ widget = m_widget;
+ qt_tablet_target = widget;
+ }
}
- if (qt_tablet_target) {
+ if (widget) {
QPointF delta = event->globalPosF() - event->globalPos();
- QPointF mapped = qt_tablet_target->mapFromGlobal(event->globalPos()) + delta;
+ QPointF mapped = widget->mapFromGlobal(event->globalPos()) + delta;
QTabletEvent ev(event->type(), mapped, event->globalPosF(), event->device(), event->pointerType(),
event->pressure(), event->xTilt(), event->yTilt(), event->tangentialPressure(),
event->rotation(), event->z(), event->modifiers(), event->uniqueId(), event->button(), event->buttons());
ev.setTimestamp(event->timestamp());
- QGuiApplication::sendSpontaneousEvent(qt_tablet_target, &ev);
+ QGuiApplication::sendSpontaneousEvent(widget, &ev);
event->setAccepted(ev.isAccepted());
}
diff --git a/src/widgets/kernel/qwidgetwindow_p.h b/src/widgets/kernel/qwidgetwindow_p.h
index edf2383596..a81355160e 100644
--- a/src/widgets/kernel/qwidgetwindow_p.h
+++ b/src/widgets/kernel/qwidgetwindow_p.h
@@ -56,6 +56,7 @@
#include <QtCore/private/qobject_p.h>
#include <QtGui/private/qevent_p.h>
+#include <QtWidgets/qwidget.h>
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp
index bb25a3a986..7ae63e54b3 100644
--- a/src/widgets/kernel/qwindowcontainer.cpp
+++ b/src/widgets/kernel/qwindowcontainer.cpp
@@ -241,6 +241,14 @@ QWindow *QWindowContainer::containedWindow() const
QWindowContainer::~QWindowContainer()
{
Q_D(QWindowContainer);
+
+ // Call destroy() explicitly first. The dtor would do this too, but
+ // QEvent::PlatformSurface delivery relies on virtuals. Getting
+ // SurfaceAboutToBeDestroyed can be essential for OpenGL, Vulkan, etc.
+ // QWindow subclasses in particular. Keep these working.
+ if (d->window)
+ d->window->destroy();
+
delete d->window;
}
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index 69c9230b4b..752e385aa5 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -48,8 +48,14 @@
#include <qcache.h>
#include <qdockwidget.h>
#include <qdrawutil.h>
+#if QT_CONFIG(dialogbuttonbox)
#include <qdialogbuttonbox.h>
+#endif
+#if QT_CONFIG(formlayout)
#include <qformlayout.h>
+#else
+#include <qlayout.h>
+#endif
#include <qgroupbox.h>
#include <qmath.h>
#include <qmenu.h>
@@ -410,6 +416,8 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
proxy()->drawItemPixmap(p, opt->rect, Qt::AlignCenter, pixmap);
break;
}
+#else
+ Q_UNUSED(d);
#endif // QT_NO_TABBAR
case PE_FrameTabWidget:
case PE_FrameWindow:
@@ -1099,7 +1107,7 @@ void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *w
|| opt->shape == QTabBar::TriangularEast
|| opt->shape == QTabBar::TriangularWest;
if (verticalTabs)
- tr.setRect(0, 0, tr.height(), tr.width()); //0, 0 as we will have a translate transform
+ tr.setRect(0, 0, tr.height(), tr.width()); // 0, 0 as we will have a translate transform
int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt, widget);
int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt, widget);
@@ -1122,7 +1130,7 @@ void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *w
// right widget
if (!opt->rightButtonSize.isEmpty()) {
tr.setRight(tr.right() - 4 -
- (verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width()));
+ (verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width()));
}
// icon
@@ -1134,12 +1142,12 @@ void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *w
}
QSize tabIconSize = opt->icon.actualSize(iconSize,
(opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
- (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off );
- // High-dpi icons do not need adjustmet; make sure tabIconSize is not larger than iconSize
+ (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
+ // High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize
tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
*iconRect = QRect(tr.left(), tr.center().y() - tabIconSize.height() / 2,
- tabIconSize.width(), tabIconSize .height());
+ tabIconSize.width(), tabIconSize.height());
if (!verticalTabs)
*iconRect = proxyStyle->visualRect(opt->direction, opt->rect, *iconRect);
tr.setLeft(tr.left() + tabIconSize.width() + 4);
@@ -2309,6 +2317,9 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
default:
break;
}
+#if !QT_CONFIG(tabbar) && !QT_CONFIG(itemviews)
+ Q_UNUSED(d);
+#endif
}
/*!
@@ -3053,6 +3064,9 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt,
break;
}
return r;
+#if !QT_CONFIG(tabwidget) && !QT_CONFIG(itemviews)
+ Q_UNUSED(d);
+#endif
}
#ifndef QT_NO_DIAL
@@ -4358,6 +4372,9 @@ QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex
default:
qWarning("QCommonStyle::subControlRect: Case %d not handled", cc);
}
+#if !QT_CONFIG(slider) && !QT_CONFIG(spinbox) && !QT_CONFIG(toolbutton) && !QT_CONFIG(groupbox)
+ Q_UNUSED(widget);
+#endif
return ret;
}
@@ -4879,8 +4896,12 @@ QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
QRect decorationRect, displayRect, checkRect;
d->viewItemLayout(vopt, &checkRect, &decorationRect, &displayRect, true);
sz = (decorationRect|displayRect|checkRect).size();
+ if (decorationRect.isValid() && sz.height() == decorationRect.height())
+ sz.rheight() += 2; // Prevent icons from overlapping.
}
break;
+#else
+ Q_UNUSED(d);
#endif // QT_NO_ITEMVIEWS
#ifndef QT_NO_SPINBOX
case CT_SpinBox:
@@ -4927,9 +4948,11 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
case SH_ScrollBar_ContextMenu:
ret = true;
break;
+#if QT_CONFIG(dialogbuttonbox)
case SH_DialogButtons_DefaultButton: // This value not used anywhere.
ret = QDialogButtonBox::AcceptRole;
break;
+#endif
#ifndef QT_NO_GROUPBOX
case SH_GroupBox_TextLabelVerticalAlignment:
ret = Qt::AlignVCenter;
@@ -5117,11 +5140,13 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
case SH_TabBar_ElideMode:
ret = Qt::ElideNone;
break;
+#if QT_CONFIG(dialogbuttonbox)
case SH_DialogButtonLayout:
ret = QDialogButtonBox::WinLayout;
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
ret = theme->themeHint(QPlatformTheme::DialogButtonBoxLayout).toInt();
break;
+#endif
case SH_ComboBox_PopupFrameStyle:
ret = QFrame::StyledPanel | QFrame::Plain;
break;
@@ -5167,12 +5192,14 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
ret = QWizard::ClassicStyle;
break;
#endif
+#if QT_CONFIG(formlayout)
case SH_FormLayoutWrapPolicy:
ret = QFormLayout::DontWrapRows;
break;
case SH_FormLayoutFieldGrowthPolicy:
ret = QFormLayout::AllNonFixedFieldsGrow;
break;
+#endif
case SH_FormLayoutFormAlignment:
ret = Qt::AlignLeft | Qt::AlignTop;
break;
@@ -5244,6 +5271,7 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
return ret;
}
+#if QT_CONFIG(imageformat_xpm)
static QPixmap cachedPixmapFromXPM(const char * const *xpm)
{
QPixmap result;
@@ -5256,6 +5284,7 @@ static QPixmap cachedPixmapFromXPM(const char * const *xpm)
}
static inline QPixmap titleBarMenuCachedPixmapFromXPM() { return cachedPixmapFromXPM(qt_menu_xpm); }
+#endif // QT_CONFIG(imageformat_xpm)
#ifndef QT_NO_IMAGEFORMAT_PNG
static inline QString clearText16IconPath()
@@ -5264,6 +5293,7 @@ static inline QString clearText16IconPath()
}
#endif // !QT_NO_IMAGEFORMAT_PNG
+#if defined(Q_OS_WIN) || QT_CONFIG(imageformat_png)
static QIcon clearTextIcon(bool rtl)
{
const QString directionalThemeName = rtl
@@ -5287,6 +5317,7 @@ static QIcon clearTextIcon(bool rtl)
#endif // !QT_NO_IMAGEFORMAT_PNG
return icon;
}
+#endif
/*! \reimp */
QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *option,
@@ -5631,6 +5662,9 @@ QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *opti
}
#endif //QT_NO_IMAGEFORMAT_XPM
+#if !QT_CONFIG(imageformat_png) && !QT_CONFIG(imageformat_xpm) && !QT_CONFIG(imageformat_png)
+ Q_UNUSED(rtl);
+#endif
return QPixmap();
}
diff --git a/src/widgets/styles/qdrawutil.cpp b/src/widgets/styles/qdrawutil.cpp
index fa80a7a6ca..0b0583ea94 100644
--- a/src/widgets/styles/qdrawutil.cpp
+++ b/src/widgets/styles/qdrawutil.cpp
@@ -797,7 +797,11 @@ typedef QVarLengthArray<QPainter::PixmapFragment, 16> QPixmapFragmentsArray;
void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins,
const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins,
- const QTileRules &rules, QDrawBorderPixmap::DrawingHints hints)
+ const QTileRules &rules
+#ifndef Q_CLANG_QDOC
+ , QDrawBorderPixmap::DrawingHints hints
+#endif
+ )
{
QPainter::PixmapFragment d;
d.opacity = 1.0;
diff --git a/src/widgets/styles/qdrawutil.h b/src/widgets/styles/qdrawutil.h
index 121221dfc9..d5582f2c90 100644
--- a/src/widgets/styles/qdrawutil.h
+++ b/src/widgets/styles/qdrawutil.h
@@ -119,7 +119,7 @@ struct QTileRules
Qt::TileRule vertical;
};
-#ifndef Q_QDOC
+#ifndef Q_CLANG_QDOC
// For internal use only.
namespace QDrawBorderPixmap
{
@@ -151,7 +151,7 @@ Q_WIDGETS_EXPORT void qDrawBorderPixmap(QPainter *painter,
const QRect &sourceRect,
const QMargins &sourceMargins,
const QTileRules &rules = QTileRules()
-#ifndef Q_QDOC
+#ifndef Q_CLANG_QDOC
, QDrawBorderPixmap::DrawingHints hints = QDrawBorderPixmap::DrawingHints()
#endif
);
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index 6f61bff403..c874b12e45 100644
--- a/src/widgets/styles/qfusionstyle.cpp
+++ b/src/widgets/styles/qfusionstyle.cpp
@@ -43,7 +43,12 @@
#if QT_CONFIG(style_fusion) || defined(QT_PLUGIN)
#include "qcommonstyle_p.h"
#include <qcombobox.h>
+#if QT_CONFIG(pushbutton)
#include <qpushbutton.h>
+#endif
+#if QT_CONFIG(abstractbutton)
+#include <qabstractbutton.h>
+#endif
#include <qpainter.h>
#include <qdir.h>
#include <qstyleoption.h>
@@ -52,9 +57,11 @@
#include <qfont.h>
#include <qgroupbox.h>
#include <qpixmapcache.h>
-#include <qdialogbuttonbox.h>
#include <qscrollbar.h>
#include <qspinbox.h>
+#if QT_CONFIG(abstractslider)
+#include <qabstractslider.h>
+#endif
#include <qslider.h>
#include <qsplitter.h>
#include <qprogressbar.h>
@@ -84,7 +91,7 @@ static const int windowsRightBorder = 15; // right border on windows
static const int groupBoxBottomMargin = 0; // space below the groupbox
static const int groupBoxTopMargin = 3;
-
+#if QT_CONFIG(imageformat_xpm)
/* XPM */
static const char * const dock_widget_close_xpm[] = {
"11 13 7 1",
@@ -171,7 +178,7 @@ static const char * const qt_titlebar_context_help[] = {
" ",
" ## ",
" ## "};
-
+#endif // QT_CONFIG(imageformat_xpm)
static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50)
{
@@ -901,8 +908,6 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
return;
}
- BEGIN_STYLE_PIXMAPCACHE(QString::fromLatin1("pushbutton-%1").arg(isDefault))
- r = rect.adjusted(0, 1, -1, 0);
bool isEnabled = option->state & State_Enabled;
bool hasFocus = (option->state & State_HasFocus && option->state & State_KeyboardFocusChange);
@@ -916,6 +921,9 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
if (isDefault)
buttonColor = mergedColors(buttonColor, highlightedOutline.lighter(130), 90);
+ BEGIN_STYLE_PIXMAPCACHE(QStringLiteral("pushbutton-") + buttonColor.name(QColor::HexArgb))
+ r = rect.adjusted(0, 1, -1, 0);
+
p->setRenderHint(QPainter::Antialiasing, true);
p->translate(0.5, -0.5);
@@ -1946,9 +1954,13 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
Q_D (const QFusionStyle);
+#if QT_CONFIG(spinbox) || QT_CONFIG(slider)
QColor buttonColor = d->buttonColor(option->palette);
+#endif
+#if QT_CONFIG(slider)
QColor gradientStartColor = buttonColor.lighter(118);
QColor gradientStopColor = buttonColor;
+#endif
QColor outline = d->outline(option->palette);
QColor alphaCornerColor;
@@ -2366,6 +2378,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
bool hover = (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_MouseOver);
bool sunken = (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_Sunken);
qt_fusion_draw_mdibutton(painter, titleBar, contextHelpButtonRect, hover, sunken);
+#if QT_CONFIG(imageformat_xpm)
QImage image(qt_titlebar_context_help);
QColor alpha = textColor;
alpha.setAlpha(128);
@@ -2373,6 +2386,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
image.setColor(2, alpha.rgba());
painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->drawImage(contextHelpButtonRect.adjusted(4, 4, -4, -4), image);
+#endif
}
}
@@ -2435,7 +2449,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
int oldMin = styleObject->property("_q_stylemin").toInt();
int oldMax = styleObject->property("_q_stylemax").toInt();
QRect oldRect = styleObject->property("_q_stylerect").toRect();
- int oldState = styleObject->property("_q_stylestate").toInt();
+ QStyle::State oldState = static_cast<QStyle::State>(styleObject->property("_q_stylestate").value<QStyle::State::Int>());
uint oldActiveControls = styleObject->property("_q_stylecontrols").toUInt();
// a scrollbar is transient when the the scrollbar itself and
@@ -2458,7 +2472,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
styleObject->setProperty("_q_stylemin", scrollBar->minimum);
styleObject->setProperty("_q_stylemax", scrollBar->maximum);
styleObject->setProperty("_q_stylerect", scrollBar->rect);
- styleObject->setProperty("_q_stylestate", static_cast<int>(scrollBar->state));
+ styleObject->setProperty("_q_stylestate", static_cast<QStyle::State::Int>(scrollBar->state));
styleObject->setProperty("_q_stylecontrols", static_cast<uint>(scrollBar->activeSubControls));
#ifndef QT_NO_ANIMATION
@@ -3274,7 +3288,10 @@ void QFusionStyle::polish(QApplication *app)
void QFusionStyle::polish(QWidget *widget)
{
QCommonStyle::polish(widget);
- if (qobject_cast<QAbstractButton*>(widget)
+ if (false
+#if QT_CONFIG(abstractbutton)
+ || qobject_cast<QAbstractButton*>(widget)
+#endif
#if QT_CONFIG(combobox)
|| qobject_cast<QComboBox *>(widget)
#endif
@@ -3287,7 +3304,9 @@ void QFusionStyle::polish(QWidget *widget)
#if QT_CONFIG(splitter)
|| qobject_cast<QSplitterHandle *>(widget)
#endif
+#if QT_CONFIG(abstractslider)
|| qobject_cast<QAbstractSlider *>(widget)
+#endif
#if QT_CONFIG(spinbox)
|| qobject_cast<QAbstractSpinBox *>(widget)
#endif
@@ -3313,7 +3332,10 @@ void QFusionStyle::polish(QPalette &pal)
void QFusionStyle::unpolish(QWidget *widget)
{
QCommonStyle::unpolish(widget);
- if (qobject_cast<QAbstractButton*>(widget)
+ if (false
+#if QT_CONFIG(abstractbutton)
+ || qobject_cast<QAbstractButton*>(widget)
+#endif
#if QT_CONFIG(combobox)
|| qobject_cast<QComboBox *>(widget)
#endif
@@ -3326,7 +3348,9 @@ void QFusionStyle::unpolish(QWidget *widget)
#if QT_CONFIG(splitter)
|| qobject_cast<QSplitterHandle *>(widget)
#endif
+#if QT_CONFIG(abstractslider)
|| qobject_cast<QAbstractSlider *>(widget)
+#endif
#if QT_CONFIG(spinbox)
|| qobject_cast<QAbstractSpinBox *>(widget)
#endif
diff --git a/src/widgets/styles/qmacstyle.qdoc b/src/widgets/styles/qmacstyle.qdoc
index f8bd1f57a9..a77843a4dd 100644
--- a/src/widgets/styles/qmacstyle.qdoc
+++ b/src/widgets/styles/qmacstyle.qdoc
@@ -143,45 +143,6 @@
\reimp
*/
-/*!
- \enum QMacStyle::FocusRectPolicy
-
- This type is used to signify a widget's focus rectangle policy.
-
- \value FocusEnabled show a focus rectangle when the widget has focus.
- \value FocusDisabled never show a focus rectangle for the widget.
- \value FocusDefault show a focus rectangle when the widget has
- focus and the widget is a QSpinWidget, QDateTimeEdit, QLineEdit,
- QListBox, QListView, editable QTextEdit, or one of their
- subclasses.
-*/
-
-/*! \fn void QMacStyle::setFocusRectPolicy(QWidget *w, FocusRectPolicy policy)
- \obsolete
- Sets the focus rectangle policy of \a w. The \a policy can be one of
- \l{QMacStyle::FocusRectPolicy}.
-
- This is now simply an interface to the Qt::WA_MacShowFocusRect attribute and the
- FocusDefault value does nothing anymore. If you want to set a widget back
- to its default value, you must save the old value of the attribute before
- you change it.
-
- \sa focusRectPolicy(), QWidget::setAttribute()
-*/
-
-/*! \fn QMacStyle::FocusRectPolicy QMacStyle::focusRectPolicy(const QWidget *w)
- \obsolete
- Returns the focus rectangle policy for the widget \a w.
-
- The focus rectangle policy can be one of \l{QMacStyle::FocusRectPolicy}.
-
- In 4.3 and up this function will simply test for the
- Qt::WA_MacShowFocusRect attribute and will never return
- QMacStyle::FocusDefault.
-
- \sa setFocusRectPolicy(), QWidget::testAttribute()
-*/
-
/*! \fn void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy)
\obsolete
diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm
index f23f6c00b2..a9aab10e0f 100644
--- a/src/widgets/styles/qmacstyle_mac.mm
+++ b/src/widgets/styles/qmacstyle_mac.mm
@@ -52,12 +52,14 @@
#include <private/qcore_mac_p.h>
#include <private/qcombobox_p.h>
+#include <private/qtabbar_p.h>
#include <private/qpainter_p.h>
#include <qapplication.h>
#include <qbitmap.h>
-#include <qcheckbox.h>
#include <qcombobox.h>
+#if QT_CONFIG(dialogbuttonbox)
#include <qdialogbuttonbox.h>
+#endif
#include <qdockwidget.h>
#include <qevent.h>
#include <qfocusframe.h>
@@ -74,7 +76,9 @@
#include <qpixmapcache.h>
#include <qpointer.h>
#include <qprogressbar.h>
+#if QT_CONFIG(pushbutton)
#include <qpushbutton.h>
+#endif
#include <qradiobutton.h>
#include <qrubberband.h>
#include <qscrollbar.h>
@@ -84,6 +88,7 @@
#include <qtoolbutton.h>
#include <qtreeview.h>
#include <qtableview.h>
+#include <qoperatingsystemversion.h>
#include <qwizard.h>
#include <qdebug.h>
#include <qlibrary.h>
@@ -186,11 +191,33 @@ static const QColor mainWindowGradientEnd(200, 200, 200);
static const int DisclosureOffset = 4;
+// Tab bar colors
+// active: window is active
+// selected: tab is selected
+// hovered: tab is hovered
+static const QColor tabBarTabBackgroundActive(190, 190, 190);
+static const QColor tabBarTabBackgroundActiveHovered(178, 178, 178);
+static const QColor tabBarTabBackgroundActiveSelected(211, 211, 211);
+static const QColor tabBarTabBackground(227, 227, 227);
+static const QColor tabBarTabBackgroundSelected(246, 246, 246);
+static const QColor tabBarTabLineActive(160, 160, 160);
+static const QColor tabBarTabLineActiveHovered(150, 150, 150);
+static const QColor tabBarTabLine(210, 210, 210);
+static const QColor tabBarTabLineSelected(189, 189, 189);
+static const QColor tabBarCloseButtonBackgroundHovered(162, 162, 162);
+static const QColor tabBarCloseButtonBackgroundPressed(153, 153, 153);
+static const QColor tabBarCloseButtonBackgroundSelectedHovered(192, 192, 192);
+static const QColor tabBarCloseButtonBackgroundSelectedPressed(181, 181, 181);
+static const QColor tabBarCloseButtonCross(100, 100, 100);
+static const QColor tabBarCloseButtonCrossSelected(115, 115, 115);
+
+static const int closeButtonSize = 14;
+static const qreal closeButtonCornerRadius = 2.0;
+
// Resolve these at run-time, since the functions was moved in Leopard.
typedef HIRect * (*PtrHIShapeGetBounds)(HIShapeRef, HIRect *);
static PtrHIShapeGetBounds ptrHIShapeGetBounds = 0;
-static int closeButtonSize = 12;
#ifndef QT_NO_TABBAR
static bool isVerticalTabs(const QTabBar::Shape shape) {
return (shape == QTabBar::RoundedEast
@@ -213,41 +240,35 @@ static bool isInMacUnifiedToolbarArea(QWindow *window, int windowY)
}
-void drawTabCloseButton(QPainter *p, bool hover, bool active, bool selected)
+void drawTabCloseButton(QPainter *p, bool hover, bool selected, bool pressed)
{
- // draw background circle
p->setRenderHints(QPainter::Antialiasing);
QRect rect(0, 0, closeButtonSize, closeButtonSize);
- QColor background;
+ const int width = rect.width();
+ const int height = rect.height();
+
if (hover) {
- background = QColor(124, 124, 124);
- } else {
- if (active) {
- if (selected)
- background = QColor(104, 104, 104);
- else
- background = QColor(83, 83, 83);
+ // draw background circle
+ QColor background;
+ if (selected) {
+ background = pressed ? tabBarCloseButtonBackgroundSelectedPressed : tabBarCloseButtonBackgroundSelectedHovered;
} else {
- if (selected)
- background = QColor(144, 144, 144);
- else
- background = QColor(114, 114, 114);
+ background = pressed ? tabBarCloseButtonBackgroundPressed : tabBarCloseButtonBackgroundHovered;
}
+ p->setPen(Qt::transparent);
+ p->setBrush(background);
+ p->drawRoundedRect(rect, closeButtonCornerRadius, closeButtonCornerRadius);
}
- p->setPen(Qt::transparent);
- p->setBrush(background);
- p->drawEllipse(rect);
// draw cross
- int min = 3;
- int max = 9;
+ const int margin = 3;
QPen crossPen;
- crossPen.setColor(QColor(194, 194, 194));
- crossPen.setWidthF(1.3);
+ crossPen.setColor(selected ? tabBarCloseButtonCrossSelected : tabBarCloseButtonCross);
+ crossPen.setWidthF(1.1);
crossPen.setCapStyle(Qt::FlatCap);
p->setPen(crossPen);
- p->drawLine(min, min, max, max);
- p->drawLine(min, max, max, min);
+ p->drawLine(margin, margin, width - margin, height - margin);
+ p->drawLine(margin, height - margin, width - margin, margin);
}
#ifndef QT_NO_TABBAR
@@ -274,108 +295,71 @@ QRect rotateTabPainter(QPainter *p, QTabBar::Shape shape, QRect tabRect)
return tabRect;
}
-void drawTabShape(QPainter *p, const QStyleOptionTab *tabOpt, bool isUnified)
+void drawTabShape(QPainter *p, const QStyleOptionTab *tabOpt, bool isUnified, int tabOverlap)
{
- QRect r = tabOpt->rect;
- p->translate(tabOpt->rect.x(), tabOpt->rect.y());
- r.moveLeft(0);
- r.moveTop(0);
- QRect tabRect = rotateTabPainter(p, tabOpt->shape, r);
+ QRect rect = tabOpt->rect;
+
+ switch (tabOpt->shape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ rect.adjust(-tabOverlap, 0, 0, 0);
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ rect.adjust(0, -tabOverlap, 0, 0);
+ break;
+ default:
+ break;
+ }
- int width = tabRect.width();
- int height = 20;
- bool active = (tabOpt->state & QStyle::State_Active);
- bool selected = (tabOpt->state & QStyle::State_Selected);
+ p->translate(rect.x(), rect.y());
+ rect.moveLeft(0);
+ rect.moveTop(0);
+ const QRect tabRect = rotateTabPainter(p, tabOpt->shape, rect);
- if (selected) {
- QRect rect(1, 0, width - 2, height);
+ const int width = tabRect.width();
+ const int height = tabRect.height();
+ const bool active = (tabOpt->state & QStyle::State_Active);
+ const bool selected = (tabOpt->state & QStyle::State_Selected);
+ const QRect bodyRect(1, 1, width - 2, height - 2);
+ const QRect topLineRect(1, 0, width - 2, 1);
+ const QRect bottomLineRect(1, height - 1, width - 2, 1);
+ if (selected) {
// fill body
if (tabOpt->documentMode && isUnified) {
p->save();
p->setCompositionMode(QPainter::CompositionMode_Source);
- p->fillRect(rect, QColor(Qt::transparent));
+ p->fillRect(tabRect, QColor(Qt::transparent));
p->restore();
} else if (active) {
- p->fillRect(rect, QColor(167, 167, 167));
+ p->fillRect(bodyRect, tabBarTabBackgroundActiveSelected);
+ // top line
+ p->fillRect(topLineRect, tabBarTabLineSelected);
} else {
- QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
- gradient.setColorAt(0, QColor(216, 216, 216));
- gradient.setColorAt(0.5, QColor(215, 215, 215));
- gradient.setColorAt(1, QColor(210, 210, 210));
- p->fillRect(rect, gradient);
- }
-
- // draw border
- QColor borderSides;
- QColor borderBottom;
- if (active) {
- borderSides = QColor(88, 88, 88);
- borderBottom = QColor(88, 88, 88);
- } else {
- borderSides = QColor(121, 121, 121);
- borderBottom = QColor(116, 116, 116);
+ p->fillRect(bodyRect, tabBarTabBackgroundSelected);
}
-
- p->setPen(borderSides);
-
- int bottom = height;
- // left line
- p->drawLine(0, 1, 0, bottom-2);
- // right line
- p->drawLine(width-1, 1, width-1, bottom-2);
-
- // bottom line
- if (active) {
- p->setPen(QColor(168, 168, 168));
- p->drawLine(3, bottom-1, width-3, bottom-1);
- }
- p->setPen(borderBottom);
- p->drawLine(2, bottom, width-2, bottom);
-
- int w = 3;
- QRectF rectangleLeft(1, height - w, w, w);
- QRectF rectangleRight(width - 2, height - 1, w, w);
- int startAngle = 180 * 16;
- int spanAngle = 90 * 16;
- p->setRenderHint(QPainter::Antialiasing);
- p->drawArc(rectangleLeft, startAngle, spanAngle);
- p->drawArc(rectangleRight, startAngle, -spanAngle);
} else {
// when the mouse is over non selected tabs they get a new color
- bool hover = (tabOpt->state & QStyle::State_MouseOver);
+ const bool hover = (tabOpt->state & QStyle::State_MouseOver);
if (hover) {
- QRect rect(1, 2, width - 1, height - 1);
- p->fillRect(rect, QColor(110, 110, 110));
- }
-
- // seperator lines between tabs
- bool west = (tabOpt->shape == QTabBar::RoundedWest || tabOpt->shape == QTabBar::TriangularWest);
- bool drawOnRight = !west;
- if ((!drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)
- || (drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)) {
- QColor borderColor;
- QColor borderHighlightColor;
- if (active) {
- borderColor = QColor(64, 64, 64);
- borderHighlightColor = QColor(140, 140, 140);
- } else {
- borderColor = QColor(135, 135, 135);
- borderHighlightColor = QColor(178, 178, 178);
- }
-
- int x = drawOnRight ? width : 0;
-
- // tab seperator line
- p->setPen(borderColor);
- p->drawLine(x, 2, x, height + 1);
-
- // tab seperator highlight
- p->setPen(borderHighlightColor);
- p->drawLine(x-1, 2, x-1, height + 1);
- p->drawLine(x+1, 2, x+1, height + 1);
+ // fill body
+ p->fillRect(bodyRect, tabBarTabBackgroundActiveHovered);
+ // bottom line
+ p->fillRect(bottomLineRect, tabBarTabLineActiveHovered);
}
}
+
+ // separator lines between tabs
+ const QRect leftLineRect(0, 1, 1, height - 2);
+ const QRect rightLineRect(width - 1, 1, 1, height - 2);
+ const QColor separatorLineColor = active ? tabBarTabLineActive : tabBarTabLine;
+ p->fillRect(leftLineRect, separatorLineColor);
+ p->fillRect(rightLineRect, separatorLineColor);
}
void drawTabBase(QPainter *p, const QStyleOptionTabBarBase *tbb, const QWidget *w)
@@ -386,53 +370,25 @@ void drawTabBase(QPainter *p, const QStyleOptionTabBarBase *tbb, const QWidget *
} else {
r.setHeight(w->height());
}
- QRect tabRect = rotateTabPainter(p, tbb->shape, r);
- int width = tabRect.width();
- int height = tabRect.height();
- bool active = (tbb->state & QStyle::State_Active);
-
- // top border lines
- QColor borderHighlightTop;
- QColor borderTop;
- if (active) {
- borderTop = QColor(64, 64, 64);
- borderHighlightTop = QColor(174, 174, 174);
- } else {
- borderTop = QColor(135, 135, 135);
- borderHighlightTop = QColor(207, 207, 207);
- }
- p->setPen(borderHighlightTop);
- p->drawLine(tabRect.x(), 0, width, 0);
- p->setPen(borderTop);
- p->drawLine(tabRect.x(), 1, width, 1);
-
- // center block
- QRect centralRect(tabRect.x(), 2, width, height - 2);
- if (active) {
- QColor mainColor = QColor(120, 120, 120);
- p->fillRect(centralRect, mainColor);
- } else {
- QLinearGradient gradient(centralRect.topLeft(), centralRect.bottomLeft());
- gradient.setColorAt(0, QColor(165, 165, 165));
- gradient.setColorAt(0.5, QColor(164, 164, 164));
- gradient.setColorAt(1, QColor(158, 158, 158));
- p->fillRect(centralRect, gradient);
- }
-
- // bottom border lines
- QColor borderHighlightBottom;
- QColor borderBottom;
- if (active) {
- borderHighlightBottom = QColor(153, 153, 153);
- borderBottom = QColor(64, 64, 64);
- } else {
- borderHighlightBottom = QColor(177, 177, 177);
- borderBottom = QColor(127, 127, 127);
- }
- p->setPen(borderHighlightBottom);
- p->drawLine(tabRect.x(), height - 2, width, height - 2);
- p->setPen(borderBottom);
- p->drawLine(tabRect.x(), height - 1, width, height - 1);
+ const QRect tabRect = rotateTabPainter(p, tbb->shape, r);
+ const int width = tabRect.width();
+ const int height = tabRect.height();
+ const bool active = (tbb->state & QStyle::State_Active);
+
+ // fill body
+ const QRect bodyRect(0, 1, width, height - 1);
+ const QColor bodyColor = active ? tabBarTabBackgroundActive : tabBarTabBackground;
+ p->fillRect(bodyRect, bodyColor);
+
+ // top line
+ const QRect topLineRect(0, 0, width, 1);
+ const QColor topLineColor = active ? tabBarTabLineActive : tabBarTabLine;
+ p->fillRect(topLineRect, topLineColor);
+
+ // bottom line
+ const QRect bottomLineRect(0, height - 1, width, 1);
+ const QColor bottomLineColor = active ? tabBarTabLineActive : tabBarTabLine;
+ p->fillRect(bottomLineRect, bottomLineColor);
}
#endif
@@ -661,12 +617,16 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
}
if (ct == QStyle::CT_CustomBase && widg) {
+#if QT_CONFIG(pushbutton)
if (qobject_cast<const QPushButton *>(widg))
ct = QStyle::CT_PushButton;
+#endif
else if (qobject_cast<const QRadioButton *>(widg))
ct = QStyle::CT_RadioButton;
+#if QT_CONFIG(checkbox)
else if (qobject_cast<const QCheckBox *>(widg))
ct = QStyle::CT_CheckBox;
+#endif
#ifndef QT_NO_COMBOBOX
else if (qobject_cast<const QComboBox *>(widg))
ct = QStyle::CT_ComboBox;
@@ -700,6 +660,7 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
}
switch (ct) {
+#if QT_CONFIG(pushbutton)
case QStyle::CT_PushButton: {
const QPushButton *psh = qobject_cast<const QPushButton *>(widg);
// If this comparison is false, then the widget was not a push button.
@@ -742,6 +703,7 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg
// Since there's no default size we return the large size...
ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
}
+#endif
#if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam
} else if (ct == QStyle::CT_RadioButton) {
QRadioButton *rdo = static_cast<QRadioButton *>(widg);
@@ -1016,7 +978,7 @@ static QAquaWidgetSize qt_aqua_guess_size(const QWidget *widg, QSize large, QSiz
void QMacStylePrivate::drawFocusRing(QPainter *p, const QRect &targetRect, int hMargin, int vMargin, qreal radius) const
{
- qreal pixelRatio = p->device()->devicePixelRatioF();
+ const qreal pixelRatio = p->device()->devicePixelRatioF();
static const QString keyFormat = QLatin1String("$qt_focusring%1-%2-%3-%4");
const QString &key = keyFormat.arg(hMargin).arg(vMargin).arg(radius).arg(pixelRatio);
QPixmap focusRingPixmap;
@@ -1027,20 +989,38 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRect &targetRect, int h
focusRingPixmap.fill(Qt::transparent);
focusRingPixmap.setDevicePixelRatio(pixelRatio);
{
+ const CGFloat focusRingWidth = radius > 0 ? 3.5 : 6;
QMacAutoReleasePool pool;
+ QMacCGContext ctx(&focusRingPixmap);
+ CGContextBeginTransparencyLayer(ctx, NULL);
+ CGContextSetAlpha(ctx, 0.5); // As applied to the stroke color below
+
+ [NSGraphicsContext saveGraphicsState];
+ [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:ctx
+ flipped:NO]];
+ CGRect focusRingRect = CGRectMake(hMargin, vMargin, size, size);
NSBezierPath *focusRingPath;
- if (radius > 0)
- focusRingPath = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(hMargin, vMargin, size, size)
+ if (radius > 0) {
+ const CGFloat roundedRectInset = -1.5;
+ focusRingPath = [NSBezierPath bezierPathWithRoundedRect:CGRectInset(focusRingRect, roundedRectInset, roundedRectInset)
xRadius:radius
yRadius:radius];
- else
- focusRingPath = [NSBezierPath bezierPathWithRect:NSMakeRect(hMargin, vMargin, size, size)];
- [NSGraphicsContext saveGraphicsState];
- QMacCGContext gc(&focusRingPixmap);
- [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:(CGContextRef)gc
- flipped:NO]];
- NSSetFocusRingStyle(NSFocusRingOnly);
- [focusRingPath fill];
+ } else {
+ const CGFloat outerClipInset = -focusRingWidth / 2;
+ NSBezierPath *focusRingClipPath = [NSBezierPath bezierPathWithRect:CGRectInset(focusRingRect, outerClipInset, outerClipInset)];
+ const CGFloat innerClipInset = 1;
+ NSBezierPath *focusRingInnerClipPath = [NSBezierPath bezierPathWithRect:CGRectInset(focusRingRect, innerClipInset, innerClipInset)];
+ [focusRingClipPath appendBezierPath:focusRingInnerClipPath.bezierPathByReversingPath];
+ [focusRingClipPath setClip];
+ focusRingPath = [NSBezierPath bezierPathWithRect:focusRingRect];
+ focusRingPath.lineJoinStyle = NSRoundLineJoinStyle;
+ }
+
+ focusRingPath.lineWidth = focusRingWidth;
+ [[NSColor keyboardFocusIndicatorColor] setStroke];
+ [focusRingPath stroke];
+
+ CGContextEndTransparencyLayer(ctx);
[NSGraphicsContext restoreGraphicsState];
}
QPixmapCache::insert(key, focusRingPixmap);
@@ -1077,6 +1057,50 @@ void QMacStylePrivate::drawFocusRing(QPainter *p, const QRect &targetRect, int h
QRect(focusRingPixmap.width() - shCornerSize, svCornerSize, shCornerSize, focusRingPixmap.width() - 2 * svCornerSize));
}
+#ifndef QT_NO_TABBAR
+void QMacStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect) const
+{
+ Q_ASSERT(textRect);
+ QRect tr = opt->rect;
+ const bool verticalTabs = opt->shape == QTabBar::RoundedEast
+ || opt->shape == QTabBar::RoundedWest
+ || opt->shape == QTabBar::TriangularEast
+ || opt->shape == QTabBar::TriangularWest;
+ if (verticalTabs)
+ tr.setRect(0, 0, tr.height(), tr.width()); // 0, 0 as we will have a translate transform
+
+ int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt, widget);
+ int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt, widget);
+ const int hpadding = 4;
+ const int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt, widget) / 2;
+ if (opt->shape == QTabBar::RoundedSouth || opt->shape == QTabBar::TriangularSouth)
+ verticalShift = -verticalShift;
+ tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
+
+ // left widget
+ if (!opt->leftButtonSize.isEmpty()) {
+ const int buttonSize = verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width();
+ tr.setLeft(tr.left() + 4 + buttonSize);
+ // make text aligned to center
+ if (opt->rightButtonSize.isEmpty())
+ tr.setRight(tr.right() - 4 - buttonSize);
+ }
+ // right widget
+ if (!opt->rightButtonSize.isEmpty()) {
+ const int buttonSize = verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width();
+ tr.setRight(tr.right() - 4 - buttonSize);
+ // make text aligned to center
+ if (opt->leftButtonSize.isEmpty())
+ tr.setLeft(tr.left() + 4 + buttonSize);
+ }
+
+ if (!verticalTabs)
+ tr = proxyStyle->visualRect(opt->direction, opt->rect, tr);
+
+ *textRect = tr;
+}
+#endif //QT_NO_TABBAR
+
QAquaWidgetSize QMacStylePrivate::effectiveAquaSizeConstrain(const QStyleOption *option,
const QWidget *widg,
QStyle::ContentsType ct,
@@ -1286,6 +1310,7 @@ void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn,
}
}
+#if QT_CONFIG(pushbutton)
bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option)
{
QMacStyle *macStyle = qobject_cast<QMacStyle *>(pushButton->style());
@@ -1295,6 +1320,7 @@ bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOpti
macStyle->d_func()->initHIThemePushButton(option, pushButton, kThemeStateActive, &bdi);
return bdi.kind == kThemeBevelButton;
}
+#endif
/**
Creates a HIThemeButtonDrawInfo structure that specifies the correct button
@@ -1312,8 +1338,6 @@ void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThem
bdi->adornment = kThemeAdornmentFocus;
if (combo->activeSubControls & QStyle::SC_ComboBoxArrow)
bdi->state = kThemeStatePressed;
- else if (tds == kThemeStateInactive && QSysInfo::MacintoshVersion < QSysInfo::MV_10_10)
- bdi->state = kThemeStateActive;
else
bdi->state = tds;
@@ -1634,7 +1658,7 @@ void QMacStylePrivate::getSliderInfo(QStyle::ComplexControl cc, const QStyleOpti
|| slider->tickPosition == QSlider::TicksBothSides;
tdi->bounds = qt_hirectForQRect(slider->rect);
- if (isScrollbar || QSysInfo::MacintoshVersion < QSysInfo::MV_10_10) {
+ if (isScrollbar) {
tdi->min = slider->minimum;
tdi->max = slider->maximum;
tdi->value = slider->sliderPosition;
@@ -1946,7 +1970,6 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD
const bool button = opt->type == QStyleOption::SO_Button;
const bool viewItem = opt->type == QStyleOption::SO_ViewItem;
const bool pressed = bdi->state == kThemeStatePressed;
- const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10;
if (button && pressed) {
if (bdi->kind == kThemePushButton) {
@@ -1985,7 +2008,7 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD
HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
if (button && pressed)
bdi->state = kThemeStateActive;
- else if (usingYosemiteOrLater && viewItem)
+ else if (viewItem)
bdi->state = kThemeStateInactive;
HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
}
@@ -1993,34 +2016,7 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD
if (!combo && !button && bdi->value == kThemeButtonOff) {
pm = activePixmap;
- } else if (!usingYosemiteOrLater && (combo || button)) {
- QImage image = activePixmap.toImage();
-
- for (int y = 0; y < height; ++y) {
- QRgb *scanLine = reinterpret_cast<QRgb *>(image.scanLine(y));
-
- for (int x = 0; x < width; ++x) {
- QRgb &pixel = scanLine[x];
-
- int darkest = qRed(pixel);
- int mid = qGreen(pixel);
- int lightest = qBlue(pixel);
-
- if (darkest > mid)
- qSwap(darkest, mid);
- if (mid > lightest)
- qSwap(mid, lightest);
- if (darkest > mid)
- qSwap(darkest, mid);
-
- int gray = (mid + 2 * lightest) / 3;
- if (pressed)
- gray *= 0.88;
- pixel = qRgba(gray, gray, gray, qAlpha(pixel));
- }
- }
- pm = QPixmap::fromImage(image);
- } else if ((usingYosemiteOrLater && combo && !editableCombo) || button) {
+ } else if ((combo && !editableCombo) || button) {
QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi->kind);
NSButton *bc = (NSButton *)cocoaControl(cw);
[bc highlight:pressed];
@@ -2034,7 +2030,7 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD
rect.adjust(0, 0, -5, 0);
drawNSViewInRect(cw, bc, rect, p);
return;
- } else if (usingYosemiteOrLater && (editableCombo || viewItem)) {
+ } else if (editableCombo || viewItem) {
QImage image = activePixmap.toImage();
for (int y = 0; y < height; ++y) {
@@ -2473,6 +2469,26 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
ret = int([NSWindow frameRectForContentRect:NSZeroRect
styleMask:NSTitledWindowMask].size.height);
break;
+ case QStyle::PM_TabBarTabHSpace:
+ switch (d->aquaSizeConstrain(opt, widget)) {
+ case QAquaSizeLarge:
+ ret = QCommonStyle::pixelMetric(metric, opt, widget);
+ break;
+ case QAquaSizeSmall:
+ ret = 20;
+ break;
+ case QAquaSizeMini:
+ ret = 16;
+ break;
+ case QAquaSizeUnknown:
+ const QStyleOptionTab *tb = qstyleoption_cast<const QStyleOptionTab *>(opt);
+ if (tb && tb->documentMode)
+ ret = 30;
+ else
+ ret = QCommonStyle::pixelMetric(metric, opt, widget);
+ break;
+ }
+ break;
case PM_TabBarTabVSpace:
ret = 4;
break;
@@ -2481,10 +2497,10 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
ret = 0;
break;
case PM_TabBarBaseHeight:
- ret = 0;
+ ret = 21;
break;
case PM_TabBarTabOverlap:
- ret = 0;
+ ret = 1;
break;
case PM_TabBarBaseOverlap:
switch (d->aquaSizeConstrain(opt, widget)) {
@@ -2661,20 +2677,6 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
case PM_LayoutHorizontalSpacing:
case PM_LayoutVerticalSpacing:
return -1;
- case QStyle::PM_TabBarTabHSpace:
- switch (d->aquaSizeConstrain(opt, widget)) {
- case QAquaSizeLarge:
- case QAquaSizeUnknown:
- ret = QCommonStyle::pixelMetric(metric, opt, widget);
- break;
- case QAquaSizeSmall:
- ret = 20;
- break;
- case QAquaSizeMini:
- ret = 16;
- break;
- }
- break;
case PM_MenuHMargin:
ret = 0;
break;
@@ -2942,9 +2944,11 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w
case SH_TabBar_ElideMode:
ret = Qt::ElideRight;
break;
+#if QT_CONFIG(dialogbuttonbox)
case SH_DialogButtonLayout:
ret = QDialogButtonBox::MacLayout;
break;
+#endif
case SH_FormLayoutWrapPolicy:
ret = QFormLayout::DontWrapRows;
break;
@@ -3100,23 +3104,6 @@ QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOpt
return icon.pixmap(qt_getWindow(widget), QSize(size, size));
}
-void QMacStyle::setFocusRectPolicy(QWidget *w, FocusRectPolicy policy)
-{
- switch (policy) {
- case FocusDefault:
- break;
- case FocusEnabled:
- case FocusDisabled:
- w->setAttribute(Qt::WA_MacShowFocusRect, policy == FocusEnabled);
- break;
- }
-}
-
-QMacStyle::FocusRectPolicy QMacStyle::focusRectPolicy(const QWidget *w)
-{
- return w->testAttribute(Qt::WA_MacShowFocusRect) ? FocusEnabled : FocusDisabled;
-}
-
void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy)
{
QWidget *wadget = const_cast<QWidget *>(widget);
@@ -3317,32 +3304,60 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
}
break;
case PE_IndicatorMenuCheckMark: {
- const int checkw = 8;
- const int checkh = 8;
- const int xoff = qMax(0, (opt->rect.width() - checkw) / 2);
- const int yoff = qMax(0, (opt->rect.width() - checkh) / 2);
- const int x1 = xoff + opt->rect.x();
- const int y1 = yoff + opt->rect.y() + checkw/2;
- const int x2 = xoff + opt->rect.x() + checkw/4;
- const int y2 = yoff + opt->rect.y() + checkh;
- const int x3 = xoff + opt->rect.x() + checkw;
- const int y3 = yoff + opt->rect.y();
-
- QVector<QLineF> a(2);
- a << QLineF(x1, y1, x2, y2);
- a << QLineF(x2, y2, x3, y3);
- if (opt->palette.currentColorGroup() == QPalette::Active) {
- if (opt->state & State_On)
- p->setPen(QPen(opt->palette.highlightedText().color(), 3));
- else
- p->setPen(QPen(opt->palette.text().color(), 3));
- } else {
- p->setPen(QPen(QColor(100, 100, 100), 3));
- }
- p->save();
- p->setRenderHint(QPainter::Antialiasing);
- p->drawLines(a);
- p->restore();
+ if (!(opt->state & State_On))
+ break;
+ QColor pc;
+ if (opt->state & State_Selected)
+ pc = opt->palette.highlightedText().color();
+ else
+ pc = opt->palette.text().color();
+ QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(static_cast<CGFloat>(pc.redF()),
+ static_cast<CGFloat>(pc.greenF()),
+ static_cast<CGFloat>(pc.blueF()),
+ static_cast<CGFloat>(pc.alphaF()));
+ // kCTFontUIFontSystem and others give the same result
+ // as kCTFontUIFontMenuItemMark. However, the latter is
+ // more reminiscent to HITheme's kThemeMenuItemMarkFont.
+ // See also the font for small- and mini-sized widgets,
+ // where we end up using the generic system font type.
+ const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
+ (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
+ kCTFontUIFontMenuItemMark;
+ // Similarly for the font size, where there is a small difference
+ // between regular combobox and item view items, and and menu items.
+ // However, we ignore any difference for small- and mini-sized widgets.
+ const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
+ QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
+
+ CGContextSaveGState(cg);
+ CGContextSetShouldSmoothFonts(cg, NO); // Same as HITheme and Cocoa menu checkmarks
+
+ // Baseline alignment tweaks for QComboBox and QMenu
+ const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
+ (opt->state & State_Small) ? 1.0 :
+ 0.75;
+
+ CGContextTranslateCTM(cg, 0, opt->rect.bottom());
+ CGContextScaleCTM(cg, 1, -1);
+ // Translate back to the original position and add rect origin and offset
+ CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
+
+ // CTFont has severe difficulties finding the checkmark character among its
+ // glyphs. Fortunately, CTLine knows its ways inside the Cocoa labyrinth.
+ static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
+ static const int numValues = sizeof(keys) / sizeof(keys[0]);
+ const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
+ Q_STATIC_ASSERT((sizeof(values) / sizeof(values[0])) == numValues);
+ QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values,
+ numValues, NULL, NULL);
+ // U+2713: CHECK MARK
+ QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@"\u2713", attributes);
+ QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
+
+ CTLineDraw((CTLineRef)line, cg);
+ CGContextFlush(cg); // CTLineDraw's documentation says it doesn't flush
+
+ CGContextRestoreGState(cg);
break; }
case PE_IndicatorViewItemCheck:
case PE_IndicatorRadioButton:
@@ -3513,10 +3528,18 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
case PE_FrameStatusBarItem:
break;
case PE_IndicatorTabClose: {
- bool hover = (opt->state & State_MouseOver);
- bool selected = (opt->state & State_Selected);
- bool active = (opt->state & State_Active);
- drawTabCloseButton(p, hover, active, selected);
+ // Make close button visible only on the hovered tab.
+ if (QTabBar *tabBar = qobject_cast<QTabBar*>(w->parentWidget())) {
+ const QTabBarPrivate *tabBarPrivate = static_cast<QTabBarPrivate *>(QObjectPrivate::get(tabBar));
+ const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex();
+ if (hoveredTabIndex != -1 && ((w == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) ||
+ (w == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide)))) {
+ const bool hover = (opt->state & State_MouseOver);
+ const bool selected = (opt->state & State_Selected);
+ const bool pressed = (opt->state & State_Sunken);
+ drawTabCloseButton(p, hover, selected, pressed);
+ }
+ }
} break;
case PE_PanelStatusBar: {
// Fill the status bar with the titlebar gradient.
@@ -3581,7 +3604,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
QWindow *window = w && w->window() ? w->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
- const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10;
switch (ce) {
case CE_HeaderSection:
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
@@ -3802,10 +3824,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
// takes precedence over a normal default button
if (btn->features & QStyleOptionButton::AutoDefaultButton
&& opt->state & State_Active && opt->state & State_HasFocus) {
- if (usingYosemiteOrLater)
- d->autoDefaultButton = opt->styleObject;
- else
- d->setAutoDefaultButton(opt->styleObject);
+ d->autoDefaultButton = opt->styleObject;
} else if (d->autoDefaultButton == opt->styleObject) {
d->setAutoDefaultButton(0);
}
@@ -3813,8 +3832,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
if (!d->autoDefaultButton) {
if (btn->features & QStyleOptionButton::DefaultButton && opt->state & State_Active) {
d->defaultButton = opt->styleObject;
- if (!usingYosemiteOrLater && !d->animation(opt->styleObject))
- d->startAnimation(new QStyleAnimation(opt->styleObject));
} else if (d->defaultButton == opt->styleObject) {
if (QStyleAnimation *animation = d->animation(opt->styleObject)) {
animation->updateTarget();
@@ -3835,42 +3852,18 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
HIThemeButtonDrawInfo bdi;
d->initHIThemePushButton(btn, w, tds, &bdi);
- if (usingYosemiteOrLater) {
- if (!hasMenu) {
- // HITheme is not drawing a nice focus frame around buttons.
- // We'll do it ourselves further down.
- bdi.adornment &= ~kThemeAdornmentFocus;
-
- // We can't rely on an animation existing to test for the default look. That means a bit
- // more logic (notice that the logic is slightly different for the bevel and the label).
- if (tds == kThemeStateActive
- && (btn->features & QStyleOptionButton::DefaultButton
- || (btn->features & QStyleOptionButton::AutoDefaultButton
- && d->autoDefaultButton == btn->styleObject)))
- bdi.adornment |= kThemeAdornmentDefault;
- }
- } else {
- // the default button animation is paused meanwhile any button
- // is pressed or an auto-default button is animated instead
- if (QStyleAnimation *defaultAnimation = d->animation(d->defaultButton)) {
- if (d->pressedButton || d->autoDefaultButton) {
- if (defaultAnimation->state() == QStyleAnimation::Running) {
- defaultAnimation->pause();
- defaultAnimation->updateTarget();
- }
- } else if (defaultAnimation->state() == QStyleAnimation::Paused) {
- defaultAnimation->resume();
- }
- }
-
- if (!d->pressedButton) {
- QStyleAnimation* animation = d->animation(opt->styleObject);
- if (animation && animation->state() == QStyleAnimation::Running) {
- bdi.adornment |= kThemeAdornmentDefault;
- bdi.animation.time.start = d->defaultButtonStart;
- bdi.animation.time.current = CFAbsoluteTimeGetCurrent();
- }
- }
+ if (!hasMenu) {
+ // HITheme is not drawing a nice focus frame around buttons.
+ // We'll do it ourselves further down.
+ bdi.adornment &= ~kThemeAdornmentFocus;
+
+ // We can't rely on an animation existing to test for the default look. That means a bit
+ // more logic (notice that the logic is slightly different for the bevel and the label).
+ if (tds == kThemeStateActive
+ && (btn->features & QStyleOptionButton::DefaultButton
+ || (btn->features & QStyleOptionButton::AutoDefaultButton
+ && d->autoDefaultButton == btn->styleObject)))
+ bdi.adornment |= kThemeAdornmentDefault;
}
// Unlike Carbon, we want the button to always be drawn inside its bounds.
@@ -3888,7 +3881,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
newRect.size.width -= QMacStylePrivate::PushButtonRightOffset - 4;
}
- if (hasMenu && usingYosemiteOrLater && bdi.kind != kThemeBevelButton) {
+ if (hasMenu && bdi.kind != kThemeBevelButton) {
QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind);
cw.first = QCocoaPullDownButton;
NSPopUpButton *pdb = (NSPopUpButton *)d->cocoaControl(cw);
@@ -3902,7 +3895,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
else
HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0);
- if (usingYosemiteOrLater && btn->state & State_HasFocus) {
+ if (btn->state & State_HasFocus) {
CGRect focusRect = newRect;
if (bdi.kind == kThemePushButton)
focusRect.size.height += 1; // Another thing HITheme and Cocoa seem to disagree about.
@@ -3932,7 +3925,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
d->drawFocusRing(p, focusTargetRect.adjusted(-hMargin, -vMargin, hMargin, vMargin), hMargin, vMargin, radius);
}
- if (hasMenu && (!usingYosemiteOrLater || bdi.kind == kThemeBevelButton)) {
+ if (hasMenu && bdi.kind == kThemeBevelButton) {
int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w);
QRect ir = btn->rect;
int arrowXOffset = bdi.kind == kThemePushButton ? 6 :
@@ -3973,7 +3966,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
bool hasIcon = !btn.icon.isNull();
bool hasText = !btn.text.isEmpty();
- if (!hasMenu && QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10) {
+ if (!hasMenu) {
if (tds == kThemeStatePressed
|| (tds == kThemeStateActive
&& ((btn.features & QStyleOptionButton::DefaultButton && !d->autoDefaultButton)
@@ -4077,17 +4070,12 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
QStyleOptionComboBox comboCopy = *cb;
comboCopy.direction = Qt::LeftToRight;
- if (opt->state & QStyle::State_Small)
- comboCopy.rect.translate(0, w ? 0 : (QSysInfo::macVersion() >= QSysInfo::MV_10_10 ? 0 : -2)); // Supports Qt Quick Controls
- else if (QSysInfo::macVersion() == QSysInfo::MV_10_9)
- comboCopy.rect.translate(0, 1);
QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w);
}
break;
#ifndef QT_NO_TABBAR
case CE_TabBarTabShape:
if (const QStyleOptionTab *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
-
if (tabOpt->documentMode) {
p->save();
bool isUnified = false;
@@ -4097,7 +4085,9 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
isUnified = isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowTabStart.y());
}
- drawTabShape(p, tabOpt, isUnified);
+ const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt, w);
+ drawTabShape(p, tabOpt, isUnified, tabOverlap);
+
p->restore();
return;
}
@@ -4143,12 +4133,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
tdi.adornment = kHIThemeTabAdornmentNone;
tdi.kind = kHIThemeTabKindNormal;
- if (!usingYosemiteOrLater) {
- if (!verticalTabs)
- tabRect.setY(tabRect.y() - 1);
- else
- tabRect.setX(tabRect.x() - 1);
- }
QStyleOptionTab::TabPosition tp = tabOpt->position;
QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
@@ -4212,15 +4196,13 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
QStyleOptionTab myTab = *tab;
ThemeTabDirection ttd = getTabDirection(myTab.shape);
bool verticalTabs = ttd == kThemeTabWest || ttd == kThemeTabEast;
- bool selected = (myTab.state & QStyle::State_Selected);
// Check to see if we use have the same as the system font
// (QComboMenuItem is internal and should never be seen by the
// outside world, unless they read the source, in which case, it's
// their own fault).
bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem");
- bool isSelectedAndNeedsShadow = selected && !usingYosemiteOrLater;
- if (isSelectedAndNeedsShadow || verticalTabs || nonDefaultFont || !tab->icon.isNull()
+ if (verticalTabs || nonDefaultFont || !tab->icon.isNull()
|| !myTab.leftButtonSize.isEmpty() || !myTab.rightButtonSize.isEmpty()) {
int heightOffset = 0;
if (verticalTabs) {
@@ -4231,23 +4213,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
}
myTab.rect.setHeight(myTab.rect.height() + heightOffset);
- if (myTab.documentMode || isSelectedAndNeedsShadow) {
- p->save();
- rotateTabPainter(p, myTab.shape, myTab.rect);
-
- QColor shadowColor = QColor(myTab.documentMode ? Qt::white : Qt::black);
- shadowColor.setAlpha(75);
- QPalette np = tab->palette;
- np.setColor(QPalette::WindowText, shadowColor);
-
- QRect nr = proxy()->subElementRect(SE_TabBarTabText, opt, w);
- nr.moveTop(-1);
- int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextHideMnemonic;
- proxy()->drawItemText(p, nr, alignment, np, tab->state & State_Enabled,
- tab->text, QPalette::WindowText);
- p->restore();
- }
-
QCommonStyle::drawControl(ce, &myTab, p, w);
} else {
p->save();
@@ -4427,61 +4392,27 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
p->setPen(mi->palette.buttonText().color());
if (mi->checked) {
- // Use the HIThemeTextInfo foo to draw the check mark correctly, if we do it,
- // we somehow need to use a special encoding as it doesn't look right with our
- // drawText().
- p->save();
- CGContextSetShouldAntialias(cg, true);
- CGContextSetShouldSmoothFonts(cg, true);
- QColor textColor = p->pen().color();
- CGFloat colorComp[] = { static_cast<CGFloat>(textColor.redF()), static_cast<CGFloat>(textColor.greenF()),
- static_cast<CGFloat>(textColor.blueF()), static_cast<CGFloat>(textColor.alphaF()) };
- CGContextSetFillColorSpace(cg, qt_mac_genericColorSpace());
- CGContextSetFillColor(cg, colorComp);
- HIThemeTextInfo tti;
- tti.version = qt_mac_hitheme_version;
- tti.state = tds;
- if (active && enabled)
- tti.state = kThemeStatePressed;
- switch (widgetSize) {
- case QAquaSizeUnknown:
- case QAquaSizeLarge:
- tti.fontID = kThemeMenuItemMarkFont;
- break;
- case QAquaSizeSmall:
- tti.fontID = kThemeSmallSystemFont;
- break;
- case QAquaSizeMini:
- tti.fontID = kThemeMiniSystemFont;
- break;
- }
- tti.horizontalFlushness = kHIThemeTextHorizontalFlushLeft;
- tti.verticalFlushness = kHIThemeTextVerticalFlushCenter;
- tti.options = kHIThemeTextBoxOptionNone;
- tti.truncationPosition = kHIThemeTextTruncationNone;
- tti.truncationMaxLines = 1;
- QCFString checkmark;
-#if 0
- if (mi->checkType == QStyleOptionMenuItem::Exclusive)
- checkmark = QString(QChar(kDiamondUnicode));
- else
-#endif
- checkmark = QString(QChar(kCheckUnicode));
- int mw = checkcol + macItemFrame;
- int mh = contentRect.height() - 2 * macItemFrame;
- int xp = contentRect.x();
- xp += macItemFrame;
- CGFloat outWidth, outHeight, outBaseline;
- HIThemeGetTextDimensions(checkmark, 0, &tti, &outWidth, &outHeight,
- &outBaseline);
+ QStyleOption checkmarkOpt;
+ checkmarkOpt.initFrom(w);
+
+ const int mw = checkcol + macItemFrame;
+ const int mh = contentRect.height() + macItemFrame;
+ const int xp = contentRect.x() + macItemFrame;
+ checkmarkOpt.rect = QRect(xp, contentRect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
+
+ checkmarkOpt.state |= State_On; // Always on. Never rendered when off.
+ checkmarkOpt.state.setFlag(State_Selected, active);
+ checkmarkOpt.state.setFlag(State_Enabled, enabled);
if (widgetSize == QAquaSizeMini)
- outBaseline += 1;
- QRect r(xp, contentRect.y(), mw, mh);
- r.translate(0, p->fontMetrics().ascent() - int(outBaseline) + 1);
- HIRect bounds = qt_hirectForQRect(r);
- HIThemeDrawTextBox(checkmark, &bounds, &tti,
- cg, kHIThemeOrientationNormal);
- p->restore();
+ checkmarkOpt.state |= State_Mini;
+ else if (widgetSize == QAquaSizeSmall)
+ checkmarkOpt.state |= State_Small;
+
+ // We let drawPrimitive(PE_IndicatorMenuCheckMark) pick the right color
+ checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
+ checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
+
+ proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p, w);
}
if (!mi->icon.isNull()) {
QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
@@ -4654,7 +4585,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
tdi.value = pb->progress;
tdi.attributes = vertical ? 0 : kThemeTrackHorizontal;
- if (isIndeterminate || (tdi.value < tdi.max && !usingYosemiteOrLater)) {
+ if (isIndeterminate) {
if (QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject)))
tdi.trackInfo.progress.phase = animation->animationStep();
else if (opt->styleObject)
@@ -4736,8 +4667,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
HIThemeSplitterDrawInfo sdi;
sdi.version = qt_mac_hitheme_version;
sdi.state = tds;
- sdi.adornment = qt_mac_is_metal(w) || usingYosemiteOrLater ?
- kHIThemeSplitterAdornmentMetal : kHIThemeSplitterAdornmentNone;
+ sdi.adornment = kHIThemeSplitterAdornmentMetal;
HIRect hirect = qt_hirectForQRect(opt->rect);
HIThemeDrawPaneSplitter(&hirect, &sdi, cg, kHIThemeOrientationNormal);
} else {
@@ -5000,6 +4930,73 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt,
}
}
break;
+ case SE_TabBarTabText:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ d->tabLayout(tab, widget, &rect);
+ }
+ break;
+ case SE_TabBarTabLeftButton:
+ case SE_TabBarTabRightButton:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ bool selected = tab->state & State_Selected;
+ int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget);
+ int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget);
+ int hpadding = 5;
+
+ bool verticalTabs = tab->shape == QTabBar::RoundedEast
+ || tab->shape == QTabBar::RoundedWest
+ || tab->shape == QTabBar::TriangularEast
+ || tab->shape == QTabBar::TriangularWest;
+
+ QRect tr = tab->rect;
+ if (tab->shape == QTabBar::RoundedSouth || tab->shape == QTabBar::TriangularSouth)
+ verticalShift = -verticalShift;
+ if (verticalTabs) {
+ qSwap(horizontalShift, verticalShift);
+ horizontalShift *= -1;
+ verticalShift *= -1;
+ }
+ if (tab->shape == QTabBar::RoundedWest || tab->shape == QTabBar::TriangularWest)
+ horizontalShift = -horizontalShift;
+
+ tr.adjust(0, 0, horizontalShift, verticalShift);
+ if (selected)
+ {
+ tr.setBottom(tr.bottom() - verticalShift);
+ tr.setRight(tr.right() - horizontalShift);
+ }
+
+ QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
+ int w = size.width();
+ int h = size.height();
+ int midHeight = static_cast<int>(qCeil(float(tr.height() - h) / 2));
+ int midWidth = ((tr.width() - w) / 2);
+
+ bool atTheTop = true;
+ switch (tab->shape) {
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ atTheTop = (sr == SE_TabBarTabLeftButton);
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ atTheTop = (sr == SE_TabBarTabRightButton);
+ break;
+ default:
+ if (sr == SE_TabBarTabLeftButton)
+ rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
+ else
+ rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
+ rect = visualRect(tab->direction, tab->rect, rect);
+ }
+ if (verticalTabs) {
+ if (atTheTop)
+ rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
+ else
+ rect = QRect(midWidth, tr.y() + hpadding, w, h);
+ }
+ }
+ break;
#endif
case SE_LineEditContents:
rect = QCommonStyle::subElementRect(sr, opt, widget);
@@ -5287,7 +5284,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
QWindow *window = widget && widget->window() ? widget->window()->windowHandle() :
QStyleHelper::styleObjectWindow(opt->styleObject);
const_cast<QMacStylePrivate *>(d)->resolveCurrentNSView(window);
- const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10;
switch (cc) {
case CC_Slider:
case CC_ScrollBar:
@@ -5380,7 +5376,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
int oldMin = styleObject->property("_q_stylemin").toInt();
int oldMax = styleObject->property("_q_stylemax").toInt();
QRect oldRect = styleObject->property("_q_stylerect").toRect();
- int oldState = styleObject->property("_q_stylestate").toInt();
+ QStyle::State oldState = static_cast<QStyle::State>(styleObject->property("_q_stylestate").value<QStyle::State::Int>());
uint oldActiveControls = styleObject->property("_q_stylecontrols").toUInt();
// a scrollbar is transient when the scrollbar itself and
@@ -5403,7 +5399,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
styleObject->setProperty("_q_stylemin", slider->minimum);
styleObject->setProperty("_q_stylemax", slider->maximum);
styleObject->setProperty("_q_stylerect", slider->rect);
- styleObject->setProperty("_q_stylestate", static_cast<int>(slider->state));
+ styleObject->setProperty("_q_stylestate", static_cast<QStyle::State::Int>(slider->state));
styleObject->setProperty("_q_stylecontrols", static_cast<uint>(slider->activeSubControls));
QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
@@ -5532,7 +5528,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
} else {
d->stopAnimation(opt->styleObject);
- if (usingYosemiteOrLater && cc == CC_Slider) {
+ if (cc == CC_Slider) {
// Fix min and max positions. (See also getSliderInfo()
// for the slider values adjustments.)
// HITheme seems to have forgotten how to render
@@ -5595,22 +5591,20 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
if (cc == CC_Slider && slider->subControls & SC_SliderTickmarks) {
HIRect bounds;
- if (usingYosemiteOrLater) {
- // As part of fixing the min and max positions,
- // we need to adjust the tickmarks as well
- bounds = tdi.bounds;
- if (slider->orientation == Qt::Horizontal) {
- tdi.bounds.size.width += 2;
- tdi.bounds.origin.x -= 1;
- if (tdi.trackInfo.slider.thumbDir == kThemeThumbUpward)
- tdi.bounds.origin.y -= 2;
- } else {
- tdi.bounds.size.height += 3;
- tdi.bounds.origin.y -= 3;
- tdi.bounds.origin.y += 1;
- if (tdi.trackInfo.slider.thumbDir == kThemeThumbUpward) // pointing left
- tdi.bounds.origin.x -= 2;
- }
+ // As part of fixing the min and max positions,
+ // we need to adjust the tickmarks as well
+ bounds = tdi.bounds;
+ if (slider->orientation == Qt::Horizontal) {
+ tdi.bounds.size.width += 2;
+ tdi.bounds.origin.x -= 1;
+ if (tdi.trackInfo.slider.thumbDir == kThemeThumbUpward)
+ tdi.bounds.origin.y -= 2;
+ } else {
+ tdi.bounds.size.height += 3;
+ tdi.bounds.origin.y -= 3;
+ tdi.bounds.origin.y += 1;
+ if (tdi.trackInfo.slider.thumbDir == kThemeThumbUpward) // pointing left
+ tdi.bounds.origin.x -= 2;
}
if (qt_mac_is_metal(widget)) {
@@ -5634,10 +5628,9 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
cg,
kHIThemeOrientationNormal);
tdi.trackInfo.slider.thumbDir = kThemeThumbUpward;
- if (usingYosemiteOrLater) {
- if (slider->orientation == Qt::Vertical)
- tdi.bounds.origin.x -= 2;
- }
+ // 10.10 and above need a slight shift
+ if (slider->orientation == Qt::Vertical)
+ tdi.bounds.origin.x -= 2;
HIThemeDrawTrackTickMarks(&tdi, numMarks,
cg,
kHIThemeOrientationNormal);
@@ -5649,11 +5642,10 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
kHIThemeOrientationNormal);
}
- if (usingYosemiteOrLater)
- tdi.bounds = bounds;
+ tdi.bounds = bounds;
}
- if (usingYosemiteOrLater && cc == CC_Slider) {
+ if (cc == CC_Slider) {
// Still as part of fixing the min and max positions,
// we also adjust the knob position. We can do this
// because it's rendered separately from the track.
@@ -5745,11 +5737,11 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
HIThemeButtonDrawInfo bdi;
d->initComboboxBdi(combo, &bdi, widget, tds);
HIRect rect = qt_hirectForQRect(combo->rect);
- if (combo->editable && usingYosemiteOrLater)
+ if (combo->editable)
rect.origin.y += tds == kThemeStateInactive ? 1 : 2;
if (tds != kThemeStateInactive)
QMacStylePrivate::drawCombobox(rect, bdi, p);
- else if (!widget && combo->editable && usingYosemiteOrLater) {
+ else if (!widget && combo->editable) {
QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind);
NSView *cb = d->cocoaControl(cw);
QRect r = combo->rect.adjusted(3, 0, 0, 0);
@@ -5931,31 +5923,23 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
drawToolbarButtonArrow(tb->rect, tds, cg);
}
if (tb->state & State_On) {
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10) {
- QWindow *window = 0;
- if (widget && widget->window())
- window = widget->window()->windowHandle();
- else if (opt->styleObject)
- window = opt->styleObject->property("_q_styleObjectWindow").value<QWindow *>();
-
- NSView *view = window ? (NSView *)window->winId() : nil;
- bool isKey = false;
- if (view)
- isKey = [view.window isKeyWindow];
-
- QBrush brush(isKey ? QColor(0, 0, 0, 28)
- : QColor(0, 0, 0, 21));
- QPainterPath path;
- path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
- p->setRenderHint(QPainter::Antialiasing);
- p->fillPath(path, brush);
- } else {
- static QPixmap pm(QLatin1String(":/qt-project.org/mac/style/images/leopard-unified-toolbar-on.png"));
- p->save();
- p->setRenderHint(QPainter::SmoothPixmapTransform);
- QStyleHelper::drawBorderPixmap(pm, p, tb->rect, 2, 2, 2, 2);
- p->restore();
- }
+ QWindow *window = 0;
+ if (widget && widget->window())
+ window = widget->window()->windowHandle();
+ else if (opt->styleObject)
+ window = opt->styleObject->property("_q_styleObjectWindow").value<QWindow *>();
+
+ NSView *view = window ? (NSView *)window->winId() : nil;
+ bool isKey = false;
+ if (view)
+ isKey = [view.window isKeyWindow];
+
+ QBrush brush(isKey ? QColor(0, 0, 0, 28)
+ : QColor(0, 0, 0, 21));
+ QPainterPath path;
+ path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
+ p->setRenderHint(QPainter::Antialiasing);
+ p->fillPath(path, brush);
}
proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget);
} else {
@@ -6295,8 +6279,8 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
switch (sc) {
case SC_ComboBoxEditField:{
ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_10)
- ret.setHeight(ret.height() - 1);
+ // 10.10 and above need a slight shift
+ ret.setHeight(ret.height() - 1);
break; }
case SC_ComboBoxArrow:{
ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi);
@@ -6620,13 +6604,13 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
if (vertTabs)
sz = sz.transposed();
int defaultTabHeight;
- int defaultExtraSpace = proxy()->pixelMetric(PM_TabBarTabHSpace, tab, widget); // Remove spurious gcc warning (AFAIK)
+ int extraHSpace = proxy()->pixelMetric(PM_TabBarTabHSpace, tab, widget);
QFontMetrics fm = opt->fontMetrics;
switch (AquaSize) {
case QAquaSizeUnknown:
case QAquaSizeLarge:
if (tab->documentMode)
- defaultTabHeight = 23;
+ defaultTabHeight = 24;
else
defaultTabHeight = 21;
break;
@@ -6643,9 +6627,10 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
} else {
QSize textSize = fm.size(Qt::TextShowMnemonic, tab->text);
sz.rheight() = qMax(defaultTabHeight, textSize.height());
- sz.rwidth() = textSize.width() + defaultExtraSpace;
+ sz.rwidth() = textSize.width();
setWidth = true;
}
+ sz.rwidth() += extraHSpace;
if (vertTabs)
sz = sz.transposed();
@@ -6754,7 +6739,7 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
case CT_ComboBox: {
sz.rwidth() += 50;
const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
- if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_10 || (cb && !cb->editable))
+ if (cb && !cb->editable)
sz.rheight() += 2;
break;
}
diff --git a/src/widgets/styles/qmacstyle_mac_p.h b/src/widgets/styles/qmacstyle_mac_p.h
index 3642424a14..7296539356 100644
--- a/src/widgets/styles/qmacstyle_mac_p.h
+++ b/src/widgets/styles/qmacstyle_mac_p.h
@@ -100,10 +100,6 @@ public:
virtual int styleHint(StyleHint sh, const QStyleOption *opt = 0, const QWidget *w = 0,
QStyleHintReturn *shret = 0) const;
- enum FocusRectPolicy { FocusEnabled, FocusDisabled, FocusDefault };
- static void setFocusRectPolicy(QWidget *w, FocusRectPolicy policy);
- static FocusRectPolicy focusRectPolicy(const QWidget *w);
-
enum WidgetSizePolicy { SizeSmall, SizeLarge, SizeMini, SizeDefault
};
@@ -131,7 +127,9 @@ private:
Q_DISABLE_COPY(QMacStyle)
Q_DECLARE_PRIVATE(QMacStyle)
+#if QT_CONFIG(pushbutton)
friend bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option);
+#endif
};
#endif
diff --git a/src/widgets/styles/qmacstyle_mac_p_p.h b/src/widgets/styles/qmacstyle_mac_p_p.h
index 601dd643fb..9bbd0995a5 100644
--- a/src/widgets/styles/qmacstyle_mac_p_p.h
+++ b/src/widgets/styles/qmacstyle_mac_p_p.h
@@ -53,9 +53,13 @@
#include <private/qstylehelper_p.h>
#include <qapplication.h>
#include <qbitmap.h>
+#if QT_CONFIG(checkbox)
#include <qcheckbox.h>
+#endif
#include <qcombobox.h>
+#if QT_CONFIG(dialogbuttonbox)
#include <qdialogbuttonbox.h>
+#endif
#include <qdockwidget.h>
#include <qevent.h>
#include <qfocusframe.h>
@@ -74,7 +78,9 @@
#include <qpixmapcache.h>
#include <qpointer.h>
#include <qprogressbar.h>
+#if QT_CONFIG(pushbutton)
#include <qpushbutton.h>
+#endif
#include <qradiobutton.h>
#include <qrubberband.h>
#include <qsizegrip.h>
@@ -153,7 +159,9 @@ typedef void (^QCocoaDrawRectBlock)(NSRect, CGContextRef);
return sizes[controlSize]; \
} while (0)
+#if QT_CONFIG(pushbutton)
bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option);
+#endif
class QMacStylePrivate : public QCommonStylePrivate
{
@@ -220,6 +228,10 @@ public:
void drawFocusRing(QPainter *p, const QRect &targetRect, int hMargin, int vMargin, qreal radius = 0) const;
+#ifndef QT_NO_TABBAR
+ void tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect) const;
+#endif
+
public:
mutable QPointer<QObject> pressedButton;
mutable QPointer<QObject> defaultButton;
diff --git a/src/widgets/styles/qpixmapstyle.cpp b/src/widgets/styles/qpixmapstyle.cpp
index a947f5d079..de99b6ce7b 100644
--- a/src/widgets/styles/qpixmapstyle.cpp
+++ b/src/widgets/styles/qpixmapstyle.cpp
@@ -60,7 +60,9 @@
#include <QAbstractScrollArea>
#include <QScrollBar>
+#if QT_CONFIG(scroller)
#include <qscroller.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -194,7 +196,7 @@ void QPixmapStyle::polish(QWidget *widget)
view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
}
#endif
-#if QT_CONFIG(gestures)
+#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
QScroller::grabGesture(scrollArea->viewport(), QScroller::LeftMouseButtonGesture);
#endif
}
@@ -203,6 +205,9 @@ void QPixmapStyle::polish(QWidget *widget)
if (qobject_cast<QScrollBar*>(widget))
widget->setAttribute(Qt::WA_OpaquePaintEvent, false);
#endif
+#if !QT_CONFIG(progressbar) && !QT_CONFIG(combobox)
+ Q_UNUSED(d);
+#endif
QCommonStyle::polish(widget);
}
@@ -235,7 +240,7 @@ void QPixmapStyle::unpolish(QWidget *widget)
if (qstrcmp(widget->metaObject()->className(),"QComboBoxPrivateContainer") == 0)
widget->removeEventFilter(this);
-#if QT_CONFIG(gestures) && QT_CONFIG(scrollarea)
+#if QT_CONFIG(gestures) && QT_CONFIG(scrollarea) && QT_CONFIG(scroller)
if (QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget))
QScroller::ungrabGesture(scrollArea->viewport());
#endif
@@ -730,6 +735,8 @@ void QPixmapStyle::drawLineEdit(const QStyleOption *option,
#if QT_CONFIG(combobox)
if (widget && qobject_cast<const QComboBox*>(widget->parentWidget()))
return;
+#else
+ Q_UNUSED(widget);
#endif
const bool enabled = option->state & State_Enabled;
const bool focused = option->state & State_HasFocus;
@@ -925,6 +932,10 @@ void QPixmapStyle::drawSlider(const QStyleOptionComplex *option,
painter->drawPixmap(handle, d->pixmaps.value(pix).pixmap);
}
}
+#else
+ Q_UNUSED(option);
+ Q_UNUSED(painter);
+ Q_UNUSED(widget);
#endif // QT_CONFIG(slider)
}
@@ -964,6 +975,10 @@ void QPixmapStyle::drawScrollBar(const QStyleOptionComplex *option,
? SB_Horizontal : SB_Vertical;
drawCachedPixmap(control, rect, painter);
}
+#else
+ Q_UNUSED(option);
+ Q_UNUSED(painter);
+ Q_UNUSED(widget);
#endif // QT_CONFIG(slider)
}
@@ -1040,6 +1055,9 @@ QSize QPixmapStyle::sliderSizeFromContents(const QStyleOption *option,
else
return QSize(desc.size.width(), result.height());
#else // QT_CONFIG(slider)
+ Q_UNUSED(option);
+ Q_UNUSED(contentsSize);
+ Q_UNUSED(widget);
return QSize();
#endif // QT_CONFIG(slider)
}
@@ -1156,6 +1174,9 @@ QRect QPixmapStyle::scrollBarSubControlRect(const QStyleOptionComplex *option,
}
}
}
+#else
+ Q_UNUSED(option);
+ Q_UNUSED(sc);
#endif // QT_CONFIG(slider)
return QRect();
}
diff --git a/src/widgets/styles/qstylehelper.cpp b/src/widgets/styles/qstylehelper.cpp
index 9b381c383b..ffb898df57 100644
--- a/src/widgets/styles/qstylehelper.cpp
+++ b/src/widgets/styles/qstylehelper.cpp
@@ -415,6 +415,8 @@ QColor backgroundColor(const QPalette &pal, const QWidget* widget)
if (qobject_cast<const QScrollBar *>(widget) && widget->parent() &&
qobject_cast<const QAbstractScrollArea *>(widget->parent()->parent()))
return widget->parentWidget()->parentWidget()->palette().color(QPalette::Base);
+#else
+ Q_UNUSED(widget);
#endif
return pal.color(QPalette::Base);
}
diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp
index 6b0909ceb1..48068adac9 100644
--- a/src/widgets/styles/qstylesheetstyle.cpp
+++ b/src/widgets/styles/qstylesheetstyle.cpp
@@ -58,12 +58,16 @@
#include "private/qabstractscrollarea_p.h"
#include <qtooltip.h>
#include <qshareddata.h>
-#include <qradiobutton.h>
#include <qtoolbutton.h>
#include <qscrollbar.h>
+#if QT_CONFIG(abstractslider)
+#include <qabstractslider.h>
+#endif
#include <qstring.h>
#include <qfile.h>
+#if QT_CONFIG(checkbox)
#include <qcheckbox.h>
+#endif
#include <qstatusbar.h>
#include <qheaderview.h>
#include <private/qwindowsstyle_p_p.h>
@@ -73,10 +77,14 @@
#include <qmainwindow.h>
#include <qdockwidget.h>
#include <qmdisubwindow.h>
+#if QT_CONFIG(dialog)
#include <qdialog.h>
+#endif
#include <private/qwidget_p.h>
#include <QAbstractSpinBox>
+#if QT_CONFIG(label)
#include <QLabel>
+#endif
#include "qdrawutil.h"
#include <limits.h>
@@ -1415,11 +1423,13 @@ void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const Q
static inline QObject *parentObject(const QObject *obj)
{
+#if QT_CONFIG(tooltip)
if (qobject_cast<const QLabel *>(obj) && qstrcmp(obj->metaObject()->className(), "QTipLabel") == 0) {
QObject *p = qvariant_cast<QObject *>(obj->property("_q_stylesheet_parent"));
if (p)
return p;
}
+#endif
return obj->parent();
}
@@ -2421,9 +2431,11 @@ static bool unstylable(const QWidget *w)
static quint64 extendedPseudoClass(const QWidget *w)
{
quint64 pc = w->isWindow() ? quint64(PseudoClass_Window) : 0;
+#if QT_CONFIG(abstractslider)
if (const QAbstractSlider *slider = qobject_cast<const QAbstractSlider *>(w)) {
pc |= ((slider->orientation() == Qt::Vertical) ? PseudoClass_Vertical : PseudoClass_Horizontal);
} else
+#endif
#ifndef QT_NO_COMBOBOX
if (const QComboBox *combo = qobject_cast<const QComboBox *>(w)) {
if (combo->isEditable())
@@ -2589,7 +2601,7 @@ void QStyleSheetStyle::setPalette(QWidget *w)
if (!useStyleSheetPropagationInWidgetStyles || p.resolve() != 0) {
QPalette wp = w->palette();
- styleSheetCaches->customPaletteWidgets.insert(w, qMakePair(wp, p.resolve()));
+ styleSheetCaches->customPaletteWidgets.insert(w, {wp, p.resolve()});
if (useStyleSheetPropagationInWidgetStyles) {
p = p.resolve(wp);
@@ -2607,21 +2619,16 @@ void QStyleSheetStyle::unsetPalette(QWidget *w)
const bool useStyleSheetPropagationInWidgetStyles =
QCoreApplication::testAttribute(Qt::AA_UseStyleSheetPropagationInWidgetStyles);
- if (styleSheetCaches->customPaletteWidgets.contains(w)) {
- QPair<QPalette, uint> p = styleSheetCaches->customPaletteWidgets.value(w);
- styleSheetCaches->customPaletteWidgets.remove(w);
-
- QPalette original = p.first;
-
- if (useStyleSheetPropagationInWidgetStyles) {
- original.resolve(original.resolve() & p.second);
+ const auto it = styleSheetCaches->customPaletteWidgets.find(w);
+ if (it != styleSheetCaches->customPaletteWidgets.end()) {
+ auto customizedPalette = std::move(*it);
+ styleSheetCaches->customPaletteWidgets.erase(it);
- QPalette wp = w->palette();
- wp.resolve(wp.resolve() & ~p.second);
- wp.resolve(original);
- wp.resolve(wp.resolve() | original.resolve());
- original = wp;
- }
+ QPalette original;
+ if (useStyleSheetPropagationInWidgetStyles)
+ original = std::move(customizedPalette).reverted(w->palette());
+ else
+ original = customizedPalette.oldWidgetValue;
w->setPalette(original);
QWidget *ew = embeddedWidget(w);
@@ -2649,19 +2656,11 @@ void QStyleSheetStyle::unsetPalette(QWidget *w)
void QStyleSheetStyle::unsetStyleSheetFont(QWidget *w) const
{
- if (styleSheetCaches->customFontWidgets.contains(w)) {
- QPair<QFont, uint> f = styleSheetCaches->customFontWidgets.value(w);
- styleSheetCaches->customFontWidgets.remove(w);
-
- QFont original = f.first;
- original.resolve(original.resolve() & f.second);
-
- QFont font = w->font();
- font.resolve(font.resolve() & ~f.second);
- font.resolve(original);
- font.resolve(font.resolve() | original.resolve());
-
- w->setFont(font);
+ const auto it = styleSheetCaches->customFontWidgets.find(w);
+ if (it != styleSheetCaches->customFontWidgets.end()) {
+ auto customizedFont = std::move(*it);
+ styleSheetCaches->customFontWidgets.erase(it);
+ w->setFont(std::move(customizedFont).reverted(w->font()));
}
}
@@ -2822,7 +2821,10 @@ void QStyleSheetStyle::polish(QWidget *w)
#ifndef QT_NO_MENUBAR
|| qobject_cast<QMenuBar *>(w)
#endif
- || qobject_cast<QDialog *>(w)) {
+#if QT_CONFIG(dialog)
+ || qobject_cast<QDialog *>(w)
+#endif
+ ) {
w->setAttribute(Qt::WA_StyledBackground, true);
}
QWidget *ew = embeddedWidget(w);
@@ -4271,6 +4273,7 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op
case PE_PanelButtonTool:
case PE_PanelButtonCommand:
+#if QT_CONFIG(abstractbutton)
if (qobject_cast<const QAbstractButton *>(w) && rule.hasBackground() && rule.hasNativeBorder()) {
//the window style will draw the borders
ParentStyle::drawPrimitive(pe, opt, p, w);
@@ -4279,6 +4282,7 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op
}
return;
}
+#endif
if (!rule.hasNativeBorder()) {
rule.drawRule(p, rule.boxRect(opt->rect, QRenderRule::Margin));
return;
@@ -4735,10 +4739,12 @@ int QStyleSheetStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const
return rule.box()->spacing;
break;
case PM_CheckBoxLabelSpacing:
+#if QT_CONFIG(checkbox)
if (qobject_cast<const QCheckBox *>(w)) {
if (rule.hasBox() && rule.box()->spacing != -1)
return rule.box()->spacing;
}
+#endif
// assume group box
subRule = renderRule(w, opt, PseudoElement_GroupBoxTitle);
if (subRule.hasBox() && subRule.box()->spacing != -1)
@@ -5944,7 +5950,7 @@ void QStyleSheetStyle::updateStyleSheetFont(QWidget* w) const
if (rule.font.resolve()) {
QFont wf = w->font();
- styleSheetCaches->customFontWidgets.insert(w, qMakePair(wf, rule.font.resolve()));
+ styleSheetCaches->customFontWidgets.insert(w, {wf, rule.font.resolve()});
QFont font = rule.font.resolve(wf);
font.resolve(wf.resolve() | rule.font.resolve());
diff --git a/src/widgets/styles/qstylesheetstyle_p.h b/src/widgets/styles/qstylesheetstyle_p.h
index 55dd2df329..2d302305bd 100644
--- a/src/widgets/styles/qstylesheetstyle_p.h
+++ b/src/widgets/styles/qstylesheetstyle_p.h
@@ -189,12 +189,31 @@ public:
QHash<const QObject *, QRenderRules> renderRulesCache;
QHash<const void *, QCss::StyleSheet> styleSheetCache; // parsed style sheets
QSet<const QWidget *> autoFillDisabledWidgets;
- // widgets whose palettes and fonts we have tampered. stored value pair is
- // QPair<old widget value, resolve mask of stylesheet value>
- QHash<const QWidget *, QPair<QPalette, uint> > customPaletteWidgets;
- QHash<const QWidget *, QPair<QFont, uint> > customFontWidgets;
+ // widgets with whose palettes and fonts we have tampered:
+ template <typename T>
+ struct Tampered {
+ T oldWidgetValue;
+ uint resolveMask;
+
+ // only call this function on an rvalue *this (it mangles oldWidgetValue)
+ T reverted(T current)
+#ifdef Q_COMPILER_REF_QUALIFIERS
+ &&
+#endif
+ {
+ oldWidgetValue.resolve(oldWidgetValue.resolve() & resolveMask);
+ current.resolve(current.resolve() & ~resolveMask);
+ current.resolve(oldWidgetValue);
+ current.resolve(current.resolve() | oldWidgetValue.resolve());
+ return current;
+ }
+ };
+ QHash<const QWidget *, Tampered<QPalette>> customPaletteWidgets;
+ QHash<const QWidget *, Tampered<QFont>> customFontWidgets;
};
-
+template <typename T>
+class QTypeInfo<QStyleSheetStyleCaches::Tampered<T>>
+ : QTypeInfoMerger<QStyleSheetStyleCaches::Tampered<T>, T> {};
QT_END_NAMESPACE
#endif // QT_NO_STYLE_STYLESHEET
diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp
index 0ce8dde74c..b537931f49 100644
--- a/src/widgets/styles/qwindowsstyle.cpp
+++ b/src/widgets/styles/qwindowsstyle.cpp
@@ -1734,6 +1734,8 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai
step = (animation->animationStep() / 3) % chunkCount;
else
d->startAnimation(new QProgressStyleAnimation(d->animationFps, opt->styleObject));
+#else
+ Q_UNUSED(d);
#endif
int chunksInRow = 5;
int myY = pbBits.rect.y();
diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp
index 7f52d3d2f3..5a53627e95 100644
--- a/src/widgets/styles/qwindowsvistastyle.cpp
+++ b/src/widgets/styles/qwindowsvistastyle.cpp
@@ -39,6 +39,7 @@
#include "qwindowsvistastyle_p.h"
#include "qwindowsvistastyle_p_p.h"
+#include <qoperatingsystemversion.h>
#include <qscreen.h>
#include <qwindow.h>
#include <private/qstyleanimation_p.h>
@@ -599,6 +600,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
XPThemeData theme(widget, painter,
QWindowsXPStylePrivate::EditTheme,
EP_EDITBORDER_NOSCROLL, stateId, option->rect);
+ theme.noContent = true;
painter->save();
QRegion clipRegion = option->rect;
clipRegion -= option->rect.adjusted(2, 2, -2, -2);
@@ -773,6 +775,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
}
case PE_Widget:
{
+#if QT_CONFIG(dialogbuttonbox)
const QDialogButtonBox *buttonBox = 0;
if (qobject_cast<const QMessageBox *> (widget))
@@ -799,6 +802,7 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
theme.partId = TDLG_SECONDARYPANEL;
d->drawBackground(theme);
}
+#endif
}
break;
default:
@@ -1752,7 +1756,7 @@ void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyle
theme.stateId = stateId;
d->drawBackground(theme);
- if (QSysInfo::WindowsVersion < QSysInfo::WV_WINDOWS8) {
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) {
const QRect gripperBounds = QWindowsXPStylePrivate::scrollBarGripperBounds(flags, widget, &theme);
// Draw gripper if there is enough space
if (!gripperBounds.isEmpty() && flags & State_Enabled) {
@@ -2313,16 +2317,20 @@ void QWindowsVistaStyle::polish(QWidget *widget)
}
} else if (qobject_cast<QMessageBox *> (widget)) {
widget->setAttribute(Qt::WA_StyledBackground);
+#if QT_CONFIG(dialogbuttonbox)
QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
if (buttonBox)
buttonBox->setContentsMargins(0, 9, 0, 0);
+#endif
}
#ifndef QT_NO_INPUTDIALOG
else if (qobject_cast<QInputDialog *> (widget)) {
widget->setAttribute(Qt::WA_StyledBackground);
+#if QT_CONFIG(dialogbuttonbox)
QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
if (buttonBox)
buttonBox->setContentsMargins(0, 9, 0, 0);
+#endif
}
#endif // QT_NO_INPUTDIALOG
else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
@@ -2353,16 +2361,20 @@ void QWindowsVistaStyle::unpolish(QWidget *widget)
widget->setAttribute(Qt::WA_Hover, false);
else if (qobject_cast<QMessageBox *> (widget)) {
widget->setAttribute(Qt::WA_StyledBackground, false);
+#if QT_CONFIG(dialogbuttonbox)
QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
if (buttonBox)
buttonBox->setContentsMargins(0, 0, 0, 0);
+#endif
}
#ifndef QT_NO_INPUTDIALOG
else if (qobject_cast<QInputDialog *> (widget)) {
widget->setAttribute(Qt::WA_StyledBackground, false);
+#if QT_CONFIG(dialogbuttonbox)
QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
if (buttonBox)
buttonBox->setContentsMargins(0, 0, 0, 0);
+#endif
}
#endif // QT_NO_INPUTDIALOG
else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
diff --git a/src/widgets/styles/qwindowsvistastyle_p_p.h b/src/widgets/styles/qwindowsvistastyle_p_p.h
index e12203f0a9..db358e6f6c 100644
--- a/src/widgets/styles/qwindowsvistastyle_p_p.h
+++ b/src/widgets/styles/qwindowsvistastyle_p_p.h
@@ -63,9 +63,10 @@
#include <qapplication.h>
#include <qpixmapcache.h>
#include <qstyleoption.h>
+#if QT_CONFIG(pushbutton)
#include <qpushbutton.h>
+#endif
#include <qradiobutton.h>
-#include <qcheckbox.h>
#include <qlineedit.h>
#include <qgroupbox.h>
#include <qtoolbutton.h>
@@ -79,7 +80,9 @@
#include <qtreeview.h>
#include <qtextedit.h>
#include <qmessagebox.h>
+#if QT_CONFIG(dialogbuttonbox)
#include <qdialogbuttonbox.h>
+#endif
#include <qinputdialog.h>
#include <qtableview.h>
#include <qdatetime.h>
diff --git a/src/widgets/styles/qwindowsxpstyle.cpp b/src/widgets/styles/qwindowsxpstyle.cpp
index f999d823e0..b50c4b6be4 100644
--- a/src/widgets/styles/qwindowsxpstyle.cpp
+++ b/src/widgets/styles/qwindowsxpstyle.cpp
@@ -65,7 +65,9 @@
#include <qspinbox.h>
#include <qlistview.h>
#include <qstackedwidget.h>
+#if QT_CONFIG(pushbutton)
#include <qpushbutton.h>
+#endif
#include <qtoolbar.h>
#include <qlabel.h>
#include <qvarlengtharray.h>
@@ -397,13 +399,7 @@ HWND QWindowsXPStylePrivate::winId(const QWidget *widget)
return topLevelHwnd;
}
- if (QDesktopWidget *desktop = qApp->desktop())
- if (const HWND desktopHwnd = QApplicationPrivate::getHWNDForWidget(desktop))
- return desktopHwnd;
-
- Q_ASSERT(false);
-
- return 0;
+ return GetDesktopWindow();
}
/*! \internal
@@ -1143,7 +1139,10 @@ void QWindowsXPStyle::polish(QWidget *widget)
if (!QWindowsXPStylePrivate::useXP())
return;
- if (qobject_cast<QAbstractButton*>(widget)
+ if (false
+#if QT_CONFIG(abstractbutton)
+ || qobject_cast<QAbstractButton*>(widget)
+#endif
|| qobject_cast<QToolButton*>(widget)
|| qobject_cast<QTabBar*>(widget)
#ifndef QT_NO_COMBOBOX
@@ -1215,7 +1214,10 @@ void QWindowsXPStyle::unpolish(QWidget *widget)
// already in the map might be old (other style).
d->cleanupHandleMap();
}
- if (qobject_cast<QAbstractButton*>(widget)
+ if (false
+#if QT_CONFIG(abstractbutton)
+ || qobject_cast<QAbstractButton*>(widget)
+#endif
|| qobject_cast<QToolButton*>(widget)
|| qobject_cast<QTabBar*>(widget)
#ifndef QT_NO_COMBOBOX
diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp
index 3006f0c9ce..5a31eb4e52 100644
--- a/src/widgets/util/qcompleter.cpp
+++ b/src/widgets/util/qcompleter.cpp
@@ -493,7 +493,7 @@ QMatchData QCompletionEngine::filterHistory()
bool QCompletionEngine::matchHint(QString part, const QModelIndex& parent, QMatchData *hint)
{
if (c->cs == Qt::CaseInsensitive)
- part = part.toLower();
+ part = std::move(part).toLower();
const CacheItem& map = cache[parent];
@@ -512,7 +512,7 @@ bool QCompletionEngine::matchHint(QString part, const QModelIndex& parent, QMatc
bool QCompletionEngine::lookupCache(QString part, const QModelIndex& parent, QMatchData *m)
{
if (c->cs == Qt::CaseInsensitive)
- part = part.toLower();
+ part = std::move(part).toLower();
const CacheItem& map = cache[parent];
if (!map.contains(part))
return false;
@@ -548,7 +548,7 @@ void QCompletionEngine::saveInCache(QString part, const QModelIndex& parent, con
}
if (c->cs == Qt::CaseInsensitive)
- part = part.toLower();
+ part = std::move(part).toLower();
cache[parent][part] = m;
}
@@ -558,7 +558,7 @@ QIndexMapper QSortedModelEngine::indexHint(QString part, const QModelIndex& pare
const QAbstractItemModel *model = c->proxy->sourceModel();
if (c->cs == Qt::CaseInsensitive)
- part = part.toLower();
+ part = std::move(part).toLower();
const CacheItem& map = cache[parent];
@@ -1347,11 +1347,12 @@ bool QCompleter::eventFilter(QObject *o, QEvent *e)
}
// default implementation for keys not handled by the widget when popup is open
+#if QT_CONFIG(shortcut)
if (ke->matches(QKeySequence::Cancel)) {
d->popup->hide();
return true;
}
-
+#endif
switch (key) {
#ifdef QT_KEYPAD_NAVIGATION
case Qt::Key_Select:
diff --git a/src/widgets/util/qscroller.h b/src/widgets/util/qscroller.h
index 561dcfaefc..ca8d059f50 100644
--- a/src/widgets/util/qscroller.h
+++ b/src/widgets/util/qscroller.h
@@ -45,6 +45,8 @@
#include <QtCore/QPointF>
#include <QtWidgets/QScrollerProperties>
+QT_REQUIRE_CONFIG(scroller);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/util/qscrollerproperties.h b/src/widgets/util/qscrollerproperties.h
index 4fdc9bd32f..2fc1a5dc18 100644
--- a/src/widgets/util/qscrollerproperties.h
+++ b/src/widgets/util/qscrollerproperties.h
@@ -45,6 +45,8 @@
#include <QtCore/QMetaType>
#include <QtCore/QVariant>
+QT_REQUIRE_CONFIG(scroller);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp
index f7464d50ec..1e0d2ab857 100644
--- a/src/widgets/util/qsystemtrayicon.cpp
+++ b/src/widgets/util/qsystemtrayicon.cpp
@@ -46,8 +46,13 @@
#include "qlist.h"
#include "qevent.h"
#include "qpoint.h"
+#if QT_CONFIG(label)
#include "qlabel.h"
+#include "private/qlabel_p.h"
+#endif
+#if QT_CONFIG(pushbutton)
#include "qpushbutton.h"
+#endif
#include "qpainterpath.h"
#include "qpainter.h"
#include "qstyle.h"
@@ -55,10 +60,28 @@
#include "qapplication.h"
#include "qdesktopwidget.h"
#include "qbitmap.h"
-#include "private/qlabel_p.h"
QT_BEGIN_NAMESPACE
+static QIcon messageIcon2qIcon(QSystemTrayIcon::MessageIcon icon)
+{
+ QStyle::StandardPixmap stdIcon = QStyle::SP_CustomBase; // silence gcc 4.9.0 about uninited variable
+ switch (icon) {
+ case QSystemTrayIcon::Information:
+ stdIcon = QStyle::SP_MessageBoxInformation;
+ break;
+ case QSystemTrayIcon::Warning:
+ stdIcon = QStyle::SP_MessageBoxWarning;
+ break;
+ case QSystemTrayIcon::Critical:
+ stdIcon = QStyle::SP_MessageBoxCritical;
+ break;
+ case QSystemTrayIcon::NoIcon:
+ return QIcon();
+ }
+ return QApplication::style()->standardIcon(stdIcon);
+}
+
/*!
\class QSystemTrayIcon
\brief The QSystemTrayIcon class provides an icon for an application in the system tray.
@@ -382,11 +405,29 @@ bool QSystemTrayIcon::supportsMessages()
\sa show(), supportsMessages()
*/
void QSystemTrayIcon::showMessage(const QString& title, const QString& msg,
- QSystemTrayIcon::MessageIcon icon, int msecs)
+ QSystemTrayIcon::MessageIcon msgIcon, int msecs)
+{
+ Q_D(QSystemTrayIcon);
+ if (d->visible)
+ d->showMessage_sys(title, msg, messageIcon2qIcon(msgIcon), msgIcon, msecs);
+}
+
+/*!
+ \fn void QSystemTrayIcon::showMessage(const QString &title, const QString &message, const QIcon &icon, int millisecondsTimeoutHint)
+
+ \overload showMessage()
+
+ Shows a balloon message for the entry with the given \a title, \a message,
+ and custom icon \a icon for the time specified in \a millisecondsTimeoutHint.
+
+ \since 5.9
+*/
+void QSystemTrayIcon::showMessage(const QString &title, const QString &msg,
+ const QIcon &icon, int msecs)
{
Q_D(QSystemTrayIcon);
if (d->visible)
- d->showMessage_sys(title, msg, icon, msecs);
+ d->showMessage_sys(title, msg, icon, QSystemTrayIcon::NoIcon, msecs);
}
void QSystemTrayIconPrivate::_q_emitActivated(QPlatformSystemTrayIcon::ActivationReason reason)
@@ -398,9 +439,9 @@ void QSystemTrayIconPrivate::_q_emitActivated(QPlatformSystemTrayIcon::Activatio
//////////////////////////////////////////////////////////////////////
static QBalloonTip *theSolitaryBalloonTip = 0;
-void QBalloonTip::showBalloon(QSystemTrayIcon::MessageIcon icon, const QString& title,
- const QString& message, QSystemTrayIcon *trayIcon,
- const QPoint& pos, int timeout, bool showArrow)
+void QBalloonTip::showBalloon(const QIcon &icon, const QString &title,
+ const QString &message, QSystemTrayIcon *trayIcon,
+ const QPoint &pos, int timeout, bool showArrow)
{
hideBalloon();
if (message.isEmpty() && title.isEmpty())
@@ -434,8 +475,8 @@ bool QBalloonTip::isBalloonVisible()
return theSolitaryBalloonTip;
}
-QBalloonTip::QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title,
- const QString& message, QSystemTrayIcon *ti)
+QBalloonTip::QBalloonTip(const QIcon &icon, const QString &title,
+ const QString &message, QSystemTrayIcon *ti)
: QWidget(0, Qt::ToolTip),
trayIcon(ti),
timerId(-1),
@@ -444,6 +485,7 @@ QBalloonTip::QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title
setAttribute(Qt::WA_DeleteOnClose);
QObject::connect(ti, SIGNAL(destroyed()), this, SLOT(close()));
+#if QT_CONFIG(label)
QLabel *titleLabel = new QLabel;
titleLabel->installEventFilter(this);
titleLabel->setText(title);
@@ -451,17 +493,21 @@ QBalloonTip::QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title
f.setBold(true);
titleLabel->setFont(f);
titleLabel->setTextFormat(Qt::PlainText); // to maintain compat with windows
+#endif
const int iconSize = 18;
const int closeButtonSize = 15;
+#if QT_CONFIG(pushbutton)
QPushButton *closeButton = new QPushButton;
closeButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
closeButton->setIconSize(QSize(closeButtonSize, closeButtonSize));
closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
closeButton->setFixedSize(closeButtonSize, closeButtonSize);
QObject::connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
+#endif
+#if QT_CONFIG(label)
QLabel *msgLabel = new QLabel;
msgLabel->installEventFilter(this);
msgLabel->setText(message);
@@ -484,27 +530,13 @@ QBalloonTip::QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title
// to emulate the weird standard windows behavior.
msgLabel->setFixedSize(limit, msgLabel->heightForWidth(limit));
}
-
- QIcon si;
- switch (icon) {
- case QSystemTrayIcon::Warning:
- si = style()->standardIcon(QStyle::SP_MessageBoxWarning);
- break;
- case QSystemTrayIcon::Critical:
- si = style()->standardIcon(QStyle::SP_MessageBoxCritical);
- break;
- case QSystemTrayIcon::Information:
- si = style()->standardIcon(QStyle::SP_MessageBoxInformation);
- break;
- case QSystemTrayIcon::NoIcon:
- default:
- break;
- }
+#endif
QGridLayout *layout = new QGridLayout;
- if (!si.isNull()) {
+#if QT_CONFIG(label)
+ if (!icon.isNull()) {
QLabel *iconLabel = new QLabel;
- iconLabel->setPixmap(si.pixmap(iconSize, iconSize));
+ iconLabel->setPixmap(icon.pixmap(iconSize, iconSize));
iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
iconLabel->setMargin(2);
layout->addWidget(iconLabel, 0, 0);
@@ -512,9 +544,15 @@ QBalloonTip::QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title
} else {
layout->addWidget(titleLabel, 0, 0, 1, 2);
}
+#endif
+#if QT_CONFIG(pushbutton)
layout->addWidget(closeButton, 0, 2);
+#endif
+
+#if QT_CONFIG(label)
layout->addWidget(msgLabel, 1, 0, 1, 3);
+#endif
layout->setSizeConstraint(QLayout::SetFixedSize);
layout->setMargin(3);
setLayout(layout);
@@ -681,54 +719,6 @@ void QSystemTrayIconPrivate::remove_sys_qpa()
qpa_sys->cleanup();
}
-QRect QSystemTrayIconPrivate::geometry_sys_qpa() const
-{
- return qpa_sys->geometry();
-}
-
-void QSystemTrayIconPrivate::updateIcon_sys_qpa()
-{
- qpa_sys->updateIcon(icon);
-}
-
-void QSystemTrayIconPrivate::updateMenu_sys_qpa()
-{
-#if QT_CONFIG(menu)
- if (menu) {
- addPlatformMenu(menu);
- qpa_sys->updateMenu(menu->platformMenu());
- }
-#endif
-}
-
-void QSystemTrayIconPrivate::updateToolTip_sys_qpa()
-{
- qpa_sys->updateToolTip(toolTip);
-}
-
-void QSystemTrayIconPrivate::showMessage_sys_qpa(const QString &title,
- const QString &message,
- QSystemTrayIcon::MessageIcon icon,
- int msecs)
-{
- QIcon notificationIcon;
- switch (icon) {
- case QSystemTrayIcon::Information:
- notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
- break;
- case QSystemTrayIcon::Warning:
- notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
- break;
- case QSystemTrayIcon::Critical:
- notificationIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
- break;
- default:
- break;
- }
- qpa_sys->showMessage(title, message, notificationIcon,
- static_cast<QPlatformSystemTrayIcon::MessageIcon>(icon), msecs);
-}
-
void QSystemTrayIconPrivate::addPlatformMenu(QMenu *menu) const
{
#if QT_CONFIG(menu)
diff --git a/src/widgets/util/qsystemtrayicon.h b/src/widgets/util/qsystemtrayicon.h
index fb238c92b0..918dd0478e 100644
--- a/src/widgets/util/qsystemtrayicon.h
+++ b/src/widgets/util/qsystemtrayicon.h
@@ -101,6 +101,7 @@ public Q_SLOTS:
void setVisible(bool visible);
inline void show() { setVisible(true); }
inline void hide() { setVisible(false); }
+ void showMessage(const QString &title, const QString &msg, const QIcon &icon, int msecs = 10000);
void showMessage(const QString &title, const QString &msg,
QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int msecs = 10000);
diff --git a/src/widgets/util/qsystemtrayicon_p.h b/src/widgets/util/qsystemtrayicon_p.h
index 79e824f4b7..3f5cab40be 100644
--- a/src/widgets/util/qsystemtrayicon_p.h
+++ b/src/widgets/util/qsystemtrayicon_p.h
@@ -84,7 +84,8 @@ public:
void updateToolTip_sys();
void updateMenu_sys();
QRect geometry_sys() const;
- void showMessage_sys(const QString &title, const QString &msg, QSystemTrayIcon::MessageIcon icon, int secs);
+ void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon,
+ QSystemTrayIcon::MessageIcon msgIcon, int msecs);
static bool isSystemTrayAvailable_sys();
static bool supportsMessages_sys();
@@ -101,11 +102,7 @@ public:
private:
void install_sys_qpa();
void remove_sys_qpa();
- void updateIcon_sys_qpa();
- void updateToolTip_sys_qpa();
- void updateMenu_sys_qpa();
- QRect geometry_sys_qpa() const;
- void showMessage_sys_qpa(const QString &title, const QString &msg, QSystemTrayIcon::MessageIcon icon, int secs);
+
void addPlatformMenu(QMenu *menu) const;
};
@@ -113,16 +110,16 @@ class QBalloonTip : public QWidget
{
Q_OBJECT
public:
- static void showBalloon(QSystemTrayIcon::MessageIcon icon, const QString& title,
- const QString& msg, QSystemTrayIcon *trayIcon,
- const QPoint& pos, int timeout, bool showArrow = true);
+ static void showBalloon(const QIcon &icon, const QString &title,
+ const QString &msg, QSystemTrayIcon *trayIcon,
+ const QPoint &pos, int timeout, bool showArrow = true);
static void hideBalloon();
static bool isBalloonVisible();
static void updateBalloonPosition(const QPoint& pos);
private:
- QBalloonTip(QSystemTrayIcon::MessageIcon icon, const QString& title,
- const QString& msg, QSystemTrayIcon *trayIcon);
+ QBalloonTip(const QIcon &icon, const QString &title,
+ const QString &msg, QSystemTrayIcon *trayIcon);
~QBalloonTip();
void balloon(const QPoint&, int, bool);
diff --git a/src/widgets/util/qsystemtrayicon_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp
index 643f17a5fe..c0bf058681 100644
--- a/src/widgets/util/qsystemtrayicon_qpa.cpp
+++ b/src/widgets/util/qsystemtrayicon_qpa.cpp
@@ -76,7 +76,7 @@ void QSystemTrayIconPrivate::remove_sys()
QRect QSystemTrayIconPrivate::geometry_sys() const
{
if (qpa_sys)
- return geometry_sys_qpa();
+ return qpa_sys->geometry();
else
return QRect();
}
@@ -84,19 +84,23 @@ QRect QSystemTrayIconPrivate::geometry_sys() const
void QSystemTrayIconPrivate::updateIcon_sys()
{
if (qpa_sys)
- updateIcon_sys_qpa();
+ qpa_sys->updateIcon(icon);
}
void QSystemTrayIconPrivate::updateMenu_sys()
{
- if (qpa_sys)
- updateMenu_sys_qpa();
+#if QT_CONFIG(menu)
+ if (qpa_sys && menu) {
+ addPlatformMenu(menu);
+ qpa_sys->updateMenu(menu->platformMenu());
+ }
+#endif
}
void QSystemTrayIconPrivate::updateToolTip_sys()
{
if (qpa_sys)
- updateToolTip_sys_qpa();
+ qpa_sys->updateToolTip(toolTip);
}
bool QSystemTrayIconPrivate::isSystemTrayAvailable_sys()
@@ -118,10 +122,11 @@ bool QSystemTrayIconPrivate::supportsMessages_sys()
}
void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message,
- QSystemTrayIcon::MessageIcon icon, int msecs)
+ const QIcon &icon, QSystemTrayIcon::MessageIcon msgIcon, int msecs)
{
if (qpa_sys)
- showMessage_sys_qpa(title, message, icon, msecs);
+ qpa_sys->showMessage(title, message, icon,
+ static_cast<QPlatformSystemTrayIcon::MessageIcon>(msgIcon), msecs);
}
QT_END_NAMESPACE
diff --git a/src/widgets/util/qsystemtrayicon_win.cpp b/src/widgets/util/qsystemtrayicon_win.cpp
index 2da24e482b..d110cb8be4 100644
--- a/src/widgets/util/qsystemtrayicon_win.cpp
+++ b/src/widgets/util/qsystemtrayicon_win.cpp
@@ -81,11 +81,14 @@ struct Q_NOTIFYICONIDENTIFIER {
# define NIN_BALLOONTIMEOUT (WM_USER + 4)
# define NIN_BALLOONUSERCLICK (WM_USER + 5)
# define NIF_SHOWTIP 0x00000080
+# define NIIF_LARGE_ICON 0x00000020
# define NOTIFYICON_VERSION_4 4
#endif
#define Q_MSGFLT_ALLOW 1
+Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
+
typedef HRESULT (WINAPI *PtrShell_NotifyIconGetRect)(const Q_NOTIFYICONIDENTIFIER* identifier, RECT* iconLocation);
typedef BOOL (WINAPI *PtrChangeWindowMessageFilter)(UINT message, DWORD dwFlag);
typedef BOOL (WINAPI *PtrChangeWindowMessageFilterEx)(HWND hWnd, UINT message, DWORD action, void* pChangeFilterStruct);
@@ -107,7 +110,7 @@ public:
~QSystemTrayIconSys();
bool trayMessage(DWORD msg);
void setIconContents(NOTIFYICONDATA &data);
- bool showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs);
+ bool showMessage(const QString &title, const QString &message, const QIcon &icon, uint uSecs);
QRect findIconGeometry(UINT iconId);
HICON createIcon();
bool winEvent(MSG *m, long *result);
@@ -184,7 +187,7 @@ static inline HWND createTrayIconMessageWindow()
QSystemTrayIconSys::QSystemTrayIconSys(HWND hwnd, QSystemTrayIcon *object)
: m_hwnd(hwnd), hIcon(0), q(object)
- , notifyIconSize(NOTIFYICONDATA_V2_SIZE), version(NOTIFYICON_VERSION)
+ , notifyIconSize(sizeof(NOTIFYICONDATA)), version(NOTIFYICON_VERSION_4)
, ignoreNextMouseRelease(false)
{
@@ -237,11 +240,7 @@ void QSystemTrayIconSys::setIconContents(NOTIFYICONDATA &tnd)
qStringToLimitedWCharArray(tip, tnd.szTip, sizeof(tnd.szTip)/sizeof(wchar_t));
}
-#ifndef NIIF_LARGE_ICON
-# define NIIF_LARGE_ICON 0x00000020
-#endif
-
-bool QSystemTrayIconSys::showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs)
+bool QSystemTrayIconSys::showMessage(const QString &title, const QString &message, const QIcon &icon, uint uSecs)
{
NOTIFYICONDATA tnd;
memset(&tnd, 0, notifyIconSize);
@@ -249,23 +248,32 @@ bool QSystemTrayIconSys::showMessage(const QString &title, const QString &messag
qStringToLimitedWCharArray(title, tnd.szInfoTitle, 64);
tnd.uID = q_uNOTIFYICONID;
- switch (type) {
- case QSystemTrayIcon::Information:
+ tnd.dwInfoFlags = NIIF_USER;
+
+ HICON *phIcon = &tnd.hIcon;
+ QSize size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
+ if (version == NOTIFYICON_VERSION_4) {
+ const QSize largeIcon(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
+ QSize more = icon.actualSize(largeIcon);
+ if (more.height() > (largeIcon.height() * 3/4) || more.width() > (largeIcon.width() * 3/4)) {
+ tnd.dwInfoFlags |= NIIF_LARGE_ICON;
+ size = largeIcon;
+ }
+ phIcon = &tnd.hBalloonIcon;
+ }
+ QPixmap pm = icon.pixmap(size);
+ if (pm.isNull()) {
tnd.dwInfoFlags = NIIF_INFO;
- break;
- case QSystemTrayIcon::Warning:
- tnd.dwInfoFlags = NIIF_WARNING;
- break;
- case QSystemTrayIcon::Critical:
- tnd.dwInfoFlags = NIIF_ERROR;
- break;
- case QSystemTrayIcon::NoIcon:
- tnd.dwInfoFlags = hIcon ? NIIF_USER : NIIF_NONE;
- break;
+ } else {
+ if (pm.size() != size) {
+ qWarning("QSystemTrayIcon::showMessage: Wrong icon size (%dx%d), please add standard one: %dx%d",
+ pm.size().width(), pm.size().height(), size.width(), size.height());
+ pm = pm.scaled(size, Qt::IgnoreAspectRatio);
+ }
+ *phIcon = qt_pixmapToWinHICON(pm);
}
- if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA)
- tnd.dwInfoFlags |= NIIF_LARGE_ICON;
tnd.cbSize = notifyIconSize;
+ tnd.uVersion = version;
tnd.hWnd = m_hwnd;
tnd.uTimeout = uSecs;
tnd.uFlags = NIF_INFO | NIF_SHOWTIP;
@@ -296,8 +304,6 @@ bool QSystemTrayIconSys::trayMessage(DWORD msg)
return success;
}
-Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
-
HICON QSystemTrayIconSys::createIcon()
{
const HICON oldIcon = hIcon;
@@ -509,7 +515,8 @@ QRect QSystemTrayIconSys::findIconGeometry(UINT iconId)
void QSystemTrayIconPrivate::showMessage_sys(const QString &title,
const QString &messageIn,
- QSystemTrayIcon::MessageIcon type,
+ const QIcon &icon,
+ QSystemTrayIcon::MessageIcon,
int timeOut)
{
if (!sys || !allowsMessages())
@@ -522,7 +529,7 @@ void QSystemTrayIconPrivate::showMessage_sys(const QString &title,
if (message.isEmpty() && !title.isEmpty())
message.append(QLatin1Char(' '));
- sys->showMessage(title, message, type, uSecs);
+ sys->showMessage(title, message, icon, uSecs);
}
QRect QSystemTrayIconPrivate::geometry_sys() const
@@ -557,7 +564,8 @@ void QSystemTrayIconPrivate::updateIcon_sys()
void QSystemTrayIconPrivate::updateMenu_sys()
{
-
+#if QT_CONFIG(menu)
+#endif
}
void QSystemTrayIconPrivate::updateToolTip_sys()
diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp
index 0bde31fd61..cbd5d9eb80 100644
--- a/src/widgets/util/qsystemtrayicon_x11.cpp
+++ b/src/widgets/util/qsystemtrayicon_x11.cpp
@@ -37,7 +37,10 @@
**
****************************************************************************/
+#include "qtwidgetsglobal.h"
+#if QT_CONFIG(label)
#include "qlabel.h"
+#endif
#include "qpainter.h"
#include "qpixmap.h"
#include "qbitmap.h"
@@ -286,7 +289,7 @@ void QSystemTrayIconPrivate::install_sys()
QRect QSystemTrayIconPrivate::geometry_sys() const
{
if (qpa_sys)
- return geometry_sys_qpa();
+ return qpa_sys->geometry();
if (!sys)
return QRect();
return sys->globalGeometry();
@@ -309,7 +312,7 @@ void QSystemTrayIconPrivate::remove_sys()
void QSystemTrayIconPrivate::updateIcon_sys()
{
if (qpa_sys) {
- updateIcon_sys_qpa();
+ qpa_sys->updateIcon(icon);
return;
}
if (sys)
@@ -318,14 +321,18 @@ void QSystemTrayIconPrivate::updateIcon_sys()
void QSystemTrayIconPrivate::updateMenu_sys()
{
- if (qpa_sys)
- updateMenu_sys_qpa();
+#if QT_CONFIG(menu)
+ if (qpa_sys && menu) {
+ addPlatformMenu(menu);
+ qpa_sys->updateMenu(menu->platformMenu());
+ }
+#endif
}
void QSystemTrayIconPrivate::updateToolTip_sys()
{
if (qpa_sys) {
- updateToolTip_sys_qpa();
+ qpa_sys->updateToolTip(toolTip);
return;
}
if (!sys)
@@ -359,10 +366,11 @@ bool QSystemTrayIconPrivate::supportsMessages_sys()
}
void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message,
- QSystemTrayIcon::MessageIcon icon, int msecs)
+ const QIcon &icon, QSystemTrayIcon::MessageIcon msgIcon, int msecs)
{
if (qpa_sys) {
- showMessage_sys_qpa(title, message, icon, msecs);
+ qpa_sys->showMessage(title, message, icon,
+ static_cast<QPlatformSystemTrayIcon::MessageIcon>(msgIcon), msecs);
return;
}
if (!sys)
diff --git a/src/widgets/util/qundostack.cpp b/src/widgets/util/qundostack.cpp
index 033d4e9e05..dc0b6855ac 100644
--- a/src/widgets/util/qundostack.cpp
+++ b/src/widgets/util/qundostack.cpp
@@ -145,6 +145,36 @@ QUndoCommand::~QUndoCommand()
}
/*!
+ \since 5.9
+
+ Returns whether the command is obsolete.
+
+ The boolean is used for the automatic removal of commands that are not necessary in the
+ stack anymore. The isObsolete function is checked in the functions QUndoStack::push(),
+ QUndoStack::undo(), QUndoStack::redo(), and QUndoStack::setIndex().
+
+ \sa setObsolete(), mergeWith(), QUndoStack::push(), QUndoStack::undo(), QUndoStack::redo()
+*/
+
+bool QUndoCommand::isObsolete() const
+{
+ return d->obsolete;
+}
+
+/*!
+ \since 5.9
+
+ Sets whether the command is obsolete to \a obsolete.
+
+ \sa isObsolete(), mergeWith(), QUndoStack::push(), QUndoStack::undo(), QUndoStack::redo()
+*/
+
+void QUndoCommand::setObsolete(bool obsolete)
+{
+ d->obsolete = obsolete;
+}
+
+/*!
Returns the ID of this command.
A command ID is used in command compression. It must be an integer unique to
@@ -390,6 +420,28 @@ const QUndoCommand *QUndoCommand::child(int index) const
and to update the document's title to reflect that it contains unsaved
changes.
+ \section1 Obsolete Commands
+
+ QUndoStack is able to delete commands from the stack if the command is no
+ longer needed. One example may be to delete a command when two commands are
+ merged together in such a way that the merged command has no function. This
+ can be seen with move commands where the user moves their mouse to one part
+ of the screen and then moves it to the original position. The merged command
+ results in a mouse movement of 0. This command can be deleted since it serves
+ no purpose. Another example is with networking commands that fail due to connection
+ issues. In this case, the command is to be removed from the stack because the redo()
+ and undo() functions have no function since there was connection issues.
+
+ A command can be marked obsolete with the QUndoCommand::setObsolete() function.
+ The QUndoCommand::isObsolete() flag is checked in QUndoStack::push(),
+ QUndoStack::undo(), QUndoStack::redo(), and QUndoStack::setIndex() after calling
+ QUndoCommand::undo(), QUndoCommand::redo() and QUndoCommand:mergeWith() where
+ applicable.
+
+ If a command is set obsolete and the clean index is greater than or equal to the
+ current command index, then the clean index will be reset when the command is
+ deleted from the stack.
+
\sa QUndoCommand, QUndoView
*/
@@ -563,6 +615,11 @@ void QUndoStack::clear()
commands by calling QUndoCommand::mergeWith() on the most recently executed
command. If QUndoCommand::mergeWith() returns \c true, \a cmd is deleted.
+ After calling QUndoCommand::redo() and, if applicable, QUndoCommand::mergeWith(),
+ QUndoCommand::isObsolete() will be called for \a cmd or the merged command.
+ If QUndoCommand::isObsolete() returns \c true, then \a cmd or the merged command
+ will be deleted from the stack.
+
In all other cases \a cmd is simply pushed on the stack.
If commands were undone before \a cmd was pushed, the current command and
@@ -580,7 +637,8 @@ void QUndoStack::clear()
void QUndoStack::push(QUndoCommand *cmd)
{
Q_D(QUndoStack);
- cmd->redo();
+ if (!cmd->isObsolete())
+ cmd->redo();
bool macro = !d->macro_stack.isEmpty();
@@ -605,13 +663,25 @@ void QUndoStack::push(QUndoCommand *cmd)
if (try_merge && cur->mergeWith(cmd)) {
delete cmd;
- if (!macro) {
- emit indexChanged(d->index);
- emit canUndoChanged(canUndo());
- emit undoTextChanged(undoText());
- emit canRedoChanged(canRedo());
- emit redoTextChanged(redoText());
+
+ if (macro) {
+ if (cur->isObsolete())
+ delete d->macro_stack.constLast()->d->child_list.takeLast();
+ } else {
+ if (cur->isObsolete()) {
+ delete d->command_list.takeLast();
+
+ d->setIndex(d->index - 1, false);
+ } else {
+ emit indexChanged(d->index);
+ emit canUndoChanged(canUndo());
+ emit undoTextChanged(undoText());
+ emit canRedoChanged(canRedo());
+ emit redoTextChanged(redoText());
+ }
}
+ } else if (cmd->isObsolete()) {
+ delete cmd; // command should be deleted and NOT added to the stack
} else {
if (macro) {
d->macro_stack.constLast()->d->child_list.append(cmd);
@@ -712,6 +782,11 @@ int QUndoStack::cleanIndex() const
If the stack is empty, or if the bottom command on the stack has already been
undone, this function does nothing.
+ After the command is undone, if QUndoCommand::isObsolete() returns \c true,
+ then the command will be deleted from the stack. Additionally, if the clean
+ index is greater than or equal to the current command index, then the clean
+ index is reset.
+
\sa redo(), index()
*/
@@ -727,7 +802,18 @@ void QUndoStack::undo()
}
int idx = d->index - 1;
- d->command_list.at(idx)->undo();
+ QUndoCommand *cmd = d->command_list.at(idx);
+
+ if (!cmd->isObsolete())
+ cmd->undo();
+
+ if (cmd->isObsolete()) { // A separate check is done b/c the undo command may set obsolete flag
+ delete d->command_list.takeAt(idx);
+
+ if (d->clean_index > idx)
+ resetClean();
+ }
+
d->setIndex(idx, false);
}
@@ -738,6 +824,11 @@ void QUndoStack::undo()
If the stack is empty, or if the top command on the stack has already been
redone, this function does nothing.
+ If QUndoCommand::isObsolete() returns true for the current command, then
+ the command will be deleted from the stack. Additionally, if the clean
+ index is greater than or equal to the current command index, then the clean
+ index is reset.
+
\sa undo(), index()
*/
@@ -752,8 +843,20 @@ void QUndoStack::redo()
return;
}
- d->command_list.at(d->index)->redo();
- d->setIndex(d->index + 1, false);
+ int idx = d->index;
+ QUndoCommand *cmd = d->command_list.at(idx);
+
+ if (!cmd->isObsolete())
+ cmd->redo(); // A separate check is done b/c the undo command may set obsolete flag
+
+ if (cmd->isObsolete()) {
+ delete d->command_list.takeAt(idx);
+
+ if (d->clean_index > idx)
+ resetClean();
+ } else {
+ d->setIndex(d->index + 1, false);
+ }
}
/*!
@@ -805,10 +908,35 @@ void QUndoStack::setIndex(int idx)
idx = d->command_list.size();
int i = d->index;
- while (i < idx)
- d->command_list.at(i++)->redo();
- while (i > idx)
- d->command_list.at(--i)->undo();
+ while (i < idx) {
+ QUndoCommand *cmd = d->command_list.at(i);
+
+ if (!cmd->isObsolete())
+ cmd->redo(); // A separate check is done b/c the undo command may set obsolete flag
+
+ if (cmd->isObsolete()) {
+ delete d->command_list.takeAt(i);
+
+ if (d->clean_index > i)
+ resetClean();
+
+ idx--; // Subtract from idx because we removed a command
+ } else {
+ i++;
+ }
+ }
+
+ while (i > idx) {
+ QUndoCommand *cmd = d->command_list.at(--i);
+
+ cmd->undo();
+ if (cmd->isObsolete()) {
+ delete d->command_list.takeAt(i);
+
+ if (d->clean_index > i)
+ resetClean();
+ }
+ }
d->setIndex(idx, false);
}
diff --git a/src/widgets/util/qundostack.h b/src/widgets/util/qundostack.h
index ca918b0618..2a8f4decb6 100644
--- a/src/widgets/util/qundostack.h
+++ b/src/widgets/util/qundostack.h
@@ -69,6 +69,9 @@ public:
QString actionText() const;
void setText(const QString &text);
+ bool isObsolete() const;
+ void setObsolete(bool obsolete);
+
virtual int id() const;
virtual bool mergeWith(const QUndoCommand *other);
diff --git a/src/widgets/util/qundostack_p.h b/src/widgets/util/qundostack_p.h
index 1bfe992426..e92a1fe620 100644
--- a/src/widgets/util/qundostack_p.h
+++ b/src/widgets/util/qundostack_p.h
@@ -66,11 +66,12 @@ class QUndoGroup;
class QUndoCommandPrivate
{
public:
- QUndoCommandPrivate() : id(-1) {}
+ QUndoCommandPrivate() : id(-1), obsolete(false) {}
QList<QUndoCommand*> child_list;
QString text;
QString actionText;
int id;
+ bool obsolete;
};
#ifndef QT_NO_UNDOSTACK
diff --git a/src/widgets/util/util.pri b/src/widgets/util/util.pri
index cb19c1fc95..b9b62d9bb0 100644
--- a/src/widgets/util/util.pri
+++ b/src/widgets/util/util.pri
@@ -6,11 +6,6 @@ HEADERS += \
util/qcompleter.h \
util/qcompleter_p.h \
util/qsystemtrayicon_p.h \
- util/qscroller.h \
- util/qscroller_p.h \
- util/qscrollerproperties.h \
- util/qscrollerproperties_p.h \
- util/qflickgesture_p.h \
util/qundogroup.h \
util/qundostack.h \
util/qundostack_p.h \
@@ -20,13 +15,24 @@ SOURCES += \
util/qsystemtrayicon.cpp \
util/qcolormap.cpp \
util/qcompleter.cpp \
- util/qscroller.cpp \
- util/qscrollerproperties.cpp \
- util/qflickgesture.cpp \
util/qundogroup.cpp \
util/qundostack.cpp \
util/qundoview.cpp
+qtConfig(scroller) {
+ HEADERS += \
+ util/qscroller.h \
+ util/qscroller_p.h \
+ util/qscrollerproperties.h \
+ util/qscrollerproperties_p.h \
+ util/qflickgesture_p.h
+
+ SOURCES += \
+ util/qscroller.cpp \
+ util/qscrollerproperties.cpp \
+ util/qflickgesture.cpp \
+}
+
win32:!winrt {
SOURCES += util/qsystemtrayicon_win.cpp
} else: qtConfig(xcb) {
diff --git a/src/widgets/widgets/qabstractbutton.h b/src/widgets/widgets/qabstractbutton.h
index 7bf0e0b9d6..4e438bd851 100644
--- a/src/widgets/widgets/qabstractbutton.h
+++ b/src/widgets/widgets/qabstractbutton.h
@@ -45,6 +45,8 @@
#include <QtGui/qkeysequence.h>
#include <QtWidgets/qwidget.h>
+QT_REQUIRE_CONFIG(abstractbutton);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp
index 5d3a054922..abdd946c49 100644
--- a/src/widgets/widgets/qabstractscrollarea.cpp
+++ b/src/widgets/widgets/qabstractscrollarea.cpp
@@ -637,7 +637,6 @@ QWidget *QAbstractScrollArea::viewport() const
Returns the size of the viewport as if the scroll bars had no valid
scrolling range.
*/
-// ### still thinking about the name
QSize QAbstractScrollArea::maximumViewportSize() const
{
Q_D(const QAbstractScrollArea);
diff --git a/src/widgets/widgets/qabstractslider.cpp b/src/widgets/widgets/qabstractslider.cpp
index cc6a407bf8..0ea9250695 100644
--- a/src/widgets/widgets/qabstractslider.cpp
+++ b/src/widgets/widgets/qabstractslider.cpp
@@ -303,9 +303,7 @@ void QAbstractSlider::setOrientation(Qt::Orientation orientation)
d->orientation = orientation;
if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
- QSizePolicy sp = sizePolicy();
- sp.transpose();
- setSizePolicy(sp);
+ setSizePolicy(sizePolicy().transposed());
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
}
update();
diff --git a/src/widgets/widgets/qabstractslider.h b/src/widgets/widgets/qabstractslider.h
index 86d6830f10..8979685724 100644
--- a/src/widgets/widgets/qabstractslider.h
+++ b/src/widgets/widgets/qabstractslider.h
@@ -43,6 +43,8 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qwidget.h>
+QT_REQUIRE_CONFIG(abstractslider);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qabstractslider_p.h b/src/widgets/widgets/qabstractslider_p.h
index 600616061a..419ce2ba07 100644
--- a/src/widgets/widgets/qabstractslider_p.h
+++ b/src/widgets/widgets/qabstractslider_p.h
@@ -57,6 +57,8 @@
#include "private/qwidget_p.h"
#include "qstyle.h"
+QT_REQUIRE_CONFIG(abstractslider);
+
QT_BEGIN_NAMESPACE
class QAbstractSliderPrivate : public QWidgetPrivate
diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp
index 139ca0bc35..501d9560d9 100644
--- a/src/widgets/widgets/qabstractspinbox.cpp
+++ b/src/widgets/widgets/qabstractspinbox.cpp
@@ -694,6 +694,10 @@ void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit)
this, SLOT(_q_editorTextChanged(QString)));
connect(d->edit, SIGNAL(cursorPositionChanged(int,int)),
this, SLOT(_q_editorCursorPositionChanged(int,int)));
+ connect(d->edit, SIGNAL(cursorPositionChanged(int,int)),
+ this, SLOT(updateMicroFocus()));
+ connect(d->edit->d_func()->control, SIGNAL(updateMicroFocus()),
+ this, SLOT(updateMicroFocus()));
}
d->updateEditFieldGeometry();
d->edit->setContextMenuPolicy(Qt::NoContextMenu);
@@ -2116,8 +2120,8 @@ int QAbstractSpinBoxPrivate::variantCompare(const QVariant &arg1, const QVariant
default:
Q_ASSERT_X(0, "QAbstractSpinBoxPrivate::variantCompare",
qPrintable(QString::fromLatin1("Internal error 3 (%1 %2)").
- arg(QString::fromLatin1(arg1.typeName())).
- arg(QString::fromLatin1(arg2.typeName()))));
+ arg(QString::fromLatin1(arg1.typeName()),
+ QString::fromLatin1(arg2.typeName()))));
}
return -2;
}
diff --git a/src/widgets/widgets/qbuttongroup_p.h b/src/widgets/widgets/qbuttongroup_p.h
index b94dd170b4..93f3f4e0ec 100644
--- a/src/widgets/widgets/qbuttongroup_p.h
+++ b/src/widgets/widgets/qbuttongroup_p.h
@@ -1,31 +1,37 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWidgets module of the Qt Toolkit.
**
-** $QT_BEGIN_LICENSE:LGPL21$
+** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp
index b0ded70c4a..f81377a85c 100644
--- a/src/widgets/widgets/qcalendarwidget.cpp
+++ b/src/widgets/widgets/qcalendarwidget.cpp
@@ -765,13 +765,15 @@ bool QCalendarTextNavigator::eventFilter(QObject *o, QEvent *e)
if (m_widget) {
if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) {
QKeyEvent* ke = (QKeyEvent*)e;
- if ((ke->text().length() > 0 && ke->text()[0].isPrint()) || m_dateFrame) {
+ if ((ke->text().length() > 0 && ke->text().at(0).isPrint()) || m_dateFrame) {
if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Select) {
applyDate();
emit editingFinished();
removeDateLabel();
+#if QT_CONFIG(shortcut)
} else if (ke->matches(QKeySequence::Cancel)) {
removeDateLabel();
+#endif
} else if (e->type() == QEvent::KeyPress) {
createDateLabel();
m_dateValidator->handleKeyEvent(ke);
@@ -3107,12 +3109,14 @@ void QCalendarWidget::resizeEvent(QResizeEvent * event)
*/
void QCalendarWidget::keyPressEvent(QKeyEvent * event)
{
+#if QT_CONFIG(shortcut)
Q_D(QCalendarWidget);
if (d->yearEdit->isVisible()&& event->matches(QKeySequence::Cancel)) {
d->yearEdit->setValue(yearShown());
d->_q_yearEditingFinished();
return;
}
+#endif
QWidget::keyPressEvent(event);
}
diff --git a/src/widgets/widgets/qcheckbox.h b/src/widgets/widgets/qcheckbox.h
index 22f26b6667..8543c4c86f 100644
--- a/src/widgets/widgets/qcheckbox.h
+++ b/src/widgets/widgets/qcheckbox.h
@@ -43,6 +43,8 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qabstractbutton.h>
+QT_REQUIRE_CONFIG(checkbox);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp
index 4519265fb8..b18066c174 100644
--- a/src/widgets/widgets/qcombobox.cpp
+++ b/src/widgets/widgets/qcombobox.cpp
@@ -65,6 +65,7 @@
#include <private/qcombobox_p.h>
#include <private/qabstractitemmodel_p.h>
#include <private/qabstractscrollarea_p.h>
+#include <private/qlineedit_p.h>
#include <qdebug.h>
#if 0 /* Used to be included in Qt4 for Q_WS_MAC */ && !defined(QT_NO_EFFECTS) && QT_CONFIG(style_mac)
#include <private/qcore_mac_p.h>
@@ -681,10 +682,12 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
combo->hidePopup();
return true;
default:
+#if QT_CONFIG(shortcut)
if (keyEvent->matches(QKeySequence::Cancel)) {
combo->hidePopup();
return true;
}
+#endif
break;
}
break;
@@ -1790,6 +1793,7 @@ void QComboBox::setLineEdit(QLineEdit *edit)
connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(currentTextChanged(QString)));
connect(d->lineEdit, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(updateMicroFocus()));
connect(d->lineEdit, SIGNAL(selectionChanged()), this, SLOT(updateMicroFocus()));
+ connect(d->lineEdit->d_func()->control, SIGNAL(updateMicroFocus()), this, SLOT(updateMicroFocus()));
d->lineEdit->setFrame(false);
d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
d->updateFocusPolicy();
diff --git a/src/widgets/widgets/qcommandlinkbutton.h b/src/widgets/widgets/qcommandlinkbutton.h
index 4f81651ce4..d8215a256e 100644
--- a/src/widgets/widgets/qcommandlinkbutton.h
+++ b/src/widgets/widgets/qcommandlinkbutton.h
@@ -43,6 +43,8 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qpushbutton.h>
+QT_REQUIRE_CONFIG(commandlinkbutton);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp
index 2ca09800de..0eaa110bee 100644
--- a/src/widgets/widgets/qdatetimeedit.cpp
+++ b/src/widgets/widgets/qdatetimeedit.cpp
@@ -2663,11 +2663,13 @@ void QCalendarPopup::mouseReleaseEvent(QMouseEvent*)
bool QCalendarPopup::event(QEvent *event)
{
+#if QT_CONFIG(shortcut)
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->matches(QKeySequence::Cancel))
dateChanged = false;
}
+#endif
return QWidget::event(event);
}
diff --git a/src/widgets/widgets/qdatetimeedit.h b/src/widgets/widgets/qdatetimeedit.h
index 5c9f4e0f9d..b54b0e7cf0 100644
--- a/src/widgets/widgets/qdatetimeedit.h
+++ b/src/widgets/widgets/qdatetimeedit.h
@@ -58,7 +58,6 @@ class Q_WIDGETS_EXPORT QDateTimeEdit : public QAbstractSpinBox
{
Q_OBJECT
- Q_FLAGS(Sections)
Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged USER true)
Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged)
Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged)
@@ -92,6 +91,7 @@ public:
Q_ENUM(Section)
Q_DECLARE_FLAGS(Sections, Section)
+ Q_FLAG(Sections)
explicit QDateTimeEdit(QWidget *parent = Q_NULLPTR);
explicit QDateTimeEdit(const QDateTime &dt, QWidget *parent = Q_NULLPTR);
diff --git a/src/widgets/widgets/qdatetimeedit_p.h b/src/widgets/widgets/qdatetimeedit_p.h
index 730aa0f0b2..5302d6d9a7 100644
--- a/src/widgets/widgets/qdatetimeedit_p.h
+++ b/src/widgets/widgets/qdatetimeedit_p.h
@@ -57,7 +57,6 @@
#include "QtWidgets/qspinbox.h"
#include "QtWidgets/qtoolbutton.h"
#include "QtWidgets/qmenu.h"
-#include "QtWidgets/qlabel.h"
#include "QtWidgets/qdatetimeedit.h"
#include "private/qabstractspinbox_p.h"
#include "private/qdatetimeparser_p.h"
diff --git a/src/widgets/widgets/qdial.h b/src/widgets/widgets/qdial.h
index 3629ebf8f6..472b14fcdb 100644
--- a/src/widgets/widgets/qdial.h
+++ b/src/widgets/widgets/qdial.h
@@ -42,13 +42,14 @@
#define QDIAL_H
#include <QtWidgets/qtwidgetsglobal.h>
+
+#if QT_CONFIG(dial)
+
#include <QtWidgets/qabstractslider.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_DIAL
-
class QDialPrivate;
class QStyleOptionSlider;
@@ -98,8 +99,8 @@ private:
Q_DISABLE_COPY(QDial)
};
-#endif // QT_NO_DIAL
-
QT_END_NAMESPACE
+#endif // QT_CONFIG(dial)
+
#endif // QDIAL_H
diff --git a/src/widgets/widgets/qdialogbuttonbox.cpp b/src/widgets/widgets/qdialogbuttonbox.cpp
index 984669f29a..a3e55114bb 100644
--- a/src/widgets/widgets/qdialogbuttonbox.cpp
+++ b/src/widgets/widgets/qdialogbuttonbox.cpp
@@ -410,14 +410,9 @@ QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardBut
qWarning("QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
else
addButton(button, static_cast<QDialogButtonBox::ButtonRole>(role), doLayout);
-
-#if 0 // Used to be included in Qt4 for Q_WS_MAC
- // Since mnemonics is off by default on Mac, we add a Cmd-D
- // shortcut here to e.g. make the "Don't Save" button work nativly:
- if (sbutton == QDialogButtonBox::Discard)
- button->setShortcut(QKeySequence(QLatin1String("Ctrl+D")));
+#if QT_CONFIG(shortcut)
+ button->setShortcut(QGuiApplicationPrivate::platformTheme()->standardButtonShortcut(sbutton));
#endif
-
return button;
}
diff --git a/src/widgets/widgets/qdialogbuttonbox.h b/src/widgets/widgets/qdialogbuttonbox.h
index 699547c32f..af9e705234 100644
--- a/src/widgets/widgets/qdialogbuttonbox.h
+++ b/src/widgets/widgets/qdialogbuttonbox.h
@@ -43,6 +43,8 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qwidget.h>
+QT_REQUIRE_CONFIG(dialogbuttonbox);
+
QT_BEGIN_NAMESPACE
@@ -53,7 +55,6 @@ class QDialogButtonBoxPrivate;
class Q_WIDGETS_EXPORT QDialogButtonBox : public QWidget
{
Q_OBJECT
- Q_FLAGS(StandardButtons)
Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
Q_PROPERTY(StandardButtons standardButtons READ standardButtons WRITE setStandardButtons)
Q_PROPERTY(bool centerButtons READ centerButtons WRITE setCenterButtons)
@@ -104,6 +105,7 @@ public:
};
Q_DECLARE_FLAGS(StandardButtons, StandardButton)
+ Q_FLAG(StandardButtons)
enum ButtonLayout {
// keep this in sync with QMessageBox::ButtonLayout and QPlatformDialogHelper::ButtonLayout
diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp
index 53dbe490dc..8140fa6def 100644
--- a/src/widgets/widgets/qdockarealayout.cpp
+++ b/src/widgets/widgets/qdockarealayout.cpp
@@ -2605,12 +2605,16 @@ bool QDockAreaLayout::insertGap(const QList<int> &path, QLayoutItem *dockWidgetI
QLayoutItem *QDockAreaLayout::plug(const QList<int> &path)
{
+#if QT_CONFIG(tabbar)
Q_ASSERT(!path.isEmpty());
const int index = path.first();
Q_ASSERT(index >= 0 && index < QInternal::DockCount);
QLayoutItem *item = docks[index].plug(path.mid(1));
docks[index].reparentWidgets(mainWindow);
return item;
+#else
+ return nullptr;
+#endif
}
QLayoutItem *QDockAreaLayout::unplug(const QList<int> &path)
diff --git a/src/widgets/widgets/qdockwidget.cpp b/src/widgets/widgets/qdockwidget.cpp
index f51e3c7988..307a261a43 100644
--- a/src/widgets/widgets/qdockwidget.cpp
+++ b/src/widgets/widgets/qdockwidget.cpp
@@ -930,7 +930,9 @@ bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
}
if (state->dragging && !state->nca) {
- QPoint pos = event->globalPos() - state->pressPos;
+ QMargins windowMargins = q->window()->windowHandle()->frameMargins();
+ QPoint windowMarginOffset = QPoint(windowMargins.left(), windowMargins.top());
+ QPoint pos = event->globalPos() - state->pressPos - windowMarginOffset;
QDockWidgetGroupWindow *floatingTab = qobject_cast<QDockWidgetGroupWindow*>(parent);
if (floatingTab && !q->isFloating())
diff --git a/src/widgets/widgets/qdockwidget.h b/src/widgets/widgets/qdockwidget.h
index 7b3f8d0ddb..80df009007 100644
--- a/src/widgets/widgets/qdockwidget.h
+++ b/src/widgets/widgets/qdockwidget.h
@@ -57,7 +57,6 @@ class Q_WIDGETS_EXPORT QDockWidget : public QWidget
{
Q_OBJECT
- Q_FLAGS(DockWidgetFeatures)
Q_PROPERTY(bool floating READ isFloating WRITE setFloating)
Q_PROPERTY(DockWidgetFeatures features READ features WRITE setFeatures NOTIFY featuresChanged)
Q_PROPERTY(Qt::DockWidgetAreas allowedAreas READ allowedAreas
@@ -86,6 +85,7 @@ public:
Reserved = 0xff
};
Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature)
+ Q_FLAG(DockWidgetFeatures)
void setFeatures(DockWidgetFeatures features);
DockWidgetFeatures features() const;
diff --git a/src/widgets/widgets/qfontcombobox.h b/src/widgets/widgets/qfontcombobox.h
index c409d33fef..983d5224dd 100644
--- a/src/widgets/widgets/qfontcombobox.h
+++ b/src/widgets/widgets/qfontcombobox.h
@@ -54,7 +54,6 @@ class QFontComboBoxPrivate;
class Q_WIDGETS_EXPORT QFontComboBox : public QComboBox
{
Q_OBJECT
- Q_FLAGS(FontFilters)
Q_PROPERTY(QFontDatabase::WritingSystem writingSystem READ writingSystem WRITE setWritingSystem)
Q_PROPERTY(FontFilters fontFilters READ fontFilters WRITE setFontFilters)
Q_PROPERTY(QFont currentFont READ currentFont WRITE setCurrentFont NOTIFY currentFontChanged)
@@ -74,6 +73,7 @@ public:
ProportionalFonts = 0x8
};
Q_DECLARE_FLAGS(FontFilters, FontFilter)
+ Q_FLAG(FontFilters)
void setFontFilters(FontFilters filters);
FontFilters fontFilters() const;
diff --git a/src/widgets/widgets/qgroupbox.cpp b/src/widgets/widgets/qgroupbox.cpp
index a9b32ae065..fda68879d1 100644
--- a/src/widgets/widgets/qgroupbox.cpp
+++ b/src/widgets/widgets/qgroupbox.cpp
@@ -44,7 +44,9 @@
#include "qdrawutil.h"
#include "qevent.h"
#include "qlayout.h"
+#if QT_CONFIG(radiobutton)
#include "qradiobutton.h"
+#endif
#include "qstyle.h"
#include "qstyleoption.h"
#include "qstylepainter.h"
@@ -430,11 +432,13 @@ void QGroupBoxPrivate::_q_fixFocus(Qt::FocusReason reason)
QWidget * w = q;
while ((w = w->nextInFocusChain()) != q) {
if (q->isAncestorOf(w) && (w->focusPolicy() & Qt::TabFocus) == Qt::TabFocus && w->isVisibleTo(q)) {
+#if QT_CONFIG(radiobutton)
if (!best && qobject_cast<QRadioButton*>(w) && ((QRadioButton*)w)->isChecked())
// we prefer a checked radio button or a widget that
// already has focus, if there is one
best = w;
else
+#endif
if (!candidate)
// but we'll accept anything that takes focus
candidate = w;
diff --git a/src/widgets/widgets/qlabel.cpp b/src/widgets/widgets/qlabel.cpp
index fa0cff45c9..39e072234e 100644
--- a/src/widgets/widgets/qlabel.cpp
+++ b/src/widgets/widgets/qlabel.cpp
@@ -41,7 +41,9 @@
#include "qevent.h"
#include "qdrawutil.h"
#include "qapplication.h"
+#if QT_CONFIG(abstractbutton)
#include "qabstractbutton.h"
+#endif
#include "qstyle.h"
#include "qstyleoption.h"
#include <limits.h>
@@ -972,12 +974,14 @@ bool QLabel::event(QEvent *e)
QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
if (se->shortcutId() == d->shortcutId) {
QWidget * w = d->buddy;
- QAbstractButton *button = qobject_cast<QAbstractButton *>(w);
if (w->focusPolicy() != Qt::NoFocus)
w->setFocus(Qt::ShortcutFocusReason);
+#if QT_CONFIG(abstractbutton)
+ QAbstractButton *button = qobject_cast<QAbstractButton *>(w);
if (button && !se->isAmbiguous())
button->animateClick();
else
+#endif
window()->setAttribute(Qt::WA_KeyboardFocusChange);
return true;
}
diff --git a/src/widgets/widgets/qlabel.h b/src/widgets/widgets/qlabel.h
index 1f76937a63..3978e34d14 100644
--- a/src/widgets/widgets/qlabel.h
+++ b/src/widgets/widgets/qlabel.h
@@ -43,6 +43,8 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qframe.h>
+QT_REQUIRE_CONFIG(label);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp
index e5e832ab98..27dd186f04 100644
--- a/src/widgets/widgets/qlineedit.cpp
+++ b/src/widgets/widgets/qlineedit.cpp
@@ -64,6 +64,8 @@
#include "qdebug.h"
#include "qtextedit.h"
#include <private/qtextedit_p.h>
+#include <private/qwidgettextcontrol_p.h>
+
#ifndef QT_NO_ACCESSIBILITY
#include "qaccessible.h"
#endif
@@ -437,6 +439,7 @@ bool QLineEdit::hasFrame() const
\since 5.2
*/
+#if QT_CONFIG(action)
/*!
\overload
@@ -466,7 +469,7 @@ QAction *QLineEdit::addAction(const QIcon &icon, ActionPosition position)
addAction(result, position);
return result;
}
-
+#endif // QT_CONFIG(action)
/*!
\property QLineEdit::clearButtonEnabled
\brief Whether the line edit displays a clear button when it is not empty.
@@ -483,6 +486,7 @@ static const char clearButtonActionNameC[] = "_q_qlineeditclearaction";
void QLineEdit::setClearButtonEnabled(bool enable)
{
+#if QT_CONFIG(action)
Q_D(QLineEdit);
if (enable == isClearButtonEnabled())
return;
@@ -497,11 +501,16 @@ void QLineEdit::setClearButtonEnabled(bool enable)
d->removeAction(clearAction);
delete clearAction;
}
+#endif // QT_CONFIG(action)
}
bool QLineEdit::isClearButtonEnabled() const
{
+#if QT_CONFIG(action)
return findChild<QAction *>(QLatin1String(clearButtonActionNameC));
+#else
+ return false;
+#endif
}
void QLineEdit::setFrame(bool enable)
@@ -737,10 +746,10 @@ void QLineEdit::setCursorPosition(int pos)
d->control->setCursorPosition(pos);
}
+// ### What should this do if the point is outside of contentsRect? Currently returns 0.
/*!
Returns the cursor position under the point \a pos.
*/
-// ### What should this do if the point is outside of contentsRect? Currently returns 0.
int QLineEdit::cursorPositionAt(const QPoint &pos)
{
Q_D(QLineEdit);
@@ -1432,8 +1441,10 @@ bool QLineEdit::event(QEvent * e)
|| style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this))
d->setCursorVisible(true);
}
+#if QT_CONFIG(action)
} else if (e->type() == QEvent::ActionRemoved) {
d->removeAction(static_cast<QActionEvent *>(e)->action());
+#endif
} else if (e->type() == QEvent::Resize) {
d->positionSideWidgets();
}
diff --git a/src/widgets/widgets/qlineedit.h b/src/widgets/widgets/qlineedit.h
index 1bdcfaf848..4d32b11f06 100644
--- a/src/widgets/widgets/qlineedit.h
+++ b/src/widgets/widgets/qlineedit.h
@@ -174,9 +174,11 @@ public:
void getTextMargins(int *left, int *top, int *right, int *bottom) const;
QMargins textMargins() const;
+#if QT_CONFIG(action)
using QWidget::addAction;
void addAction(QAction *action, ActionPosition position);
QAction *addAction(const QIcon &icon, ActionPosition position);
+#endif
public Q_SLOTS:
void setText(const QString &);
@@ -239,6 +241,7 @@ public:
private:
friend class QAbstractSpinBox;
friend class QAccessibleLineEdit;
+ friend class QComboBox;
#ifdef QT_KEYPAD_NAVIGATION
friend class QDateTimeEdit;
#endif
diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp
index 9947d63279..7c5ba79cb6 100644
--- a/src/widgets/widgets/qlineedit_p.cpp
+++ b/src/widgets/widgets/qlineedit_p.cpp
@@ -196,6 +196,9 @@ void QLineEditPrivate::init(const QString& txt)
QObject::connect(control, SIGNAL(textChanged(QString)),
q, SLOT(updateMicroFocus()));
+ QObject::connect(control, SIGNAL(updateMicroFocus()),
+ q, SLOT(updateMicroFocus()));
+
// for now, going completely overboard with updates.
QObject::connect(control, SIGNAL(selectionChanged()),
q, SLOT(update()));
@@ -445,12 +448,14 @@ QIcon QLineEditPrivate::clearButtonIcon() const
void QLineEditPrivate::setClearButtonEnabled(bool enabled)
{
+#if QT_CONFIG(action)
for (const SideWidgetEntry &e : trailingSideWidgets) {
if (e.flags & SideWidgetClearButton) {
e.action->setEnabled(enabled);
break;
}
}
+#endif
}
void QLineEditPrivate::positionSideWidgets()
@@ -464,33 +469,37 @@ void QLineEditPrivate::positionSideWidgets()
QSize(p.widgetWidth, p.widgetHeight));
for (const SideWidgetEntry &e : leftSideWidgetList()) {
e.widget->setGeometry(widgetGeometry);
+#if QT_CONFIG(action)
if (e.action->isVisible())
widgetGeometry.moveLeft(widgetGeometry.left() + delta);
+#endif
}
widgetGeometry.moveLeft(contentRect.width() - p.widgetWidth - p.margin);
for (const SideWidgetEntry &e : rightSideWidgetList()) {
e.widget->setGeometry(widgetGeometry);
+#if QT_CONFIG(action)
if (e.action->isVisible())
widgetGeometry.moveLeft(widgetGeometry.left() - delta);
+#endif
}
}
}
-QLineEditPrivate::PositionIndexPair QLineEditPrivate::findSideWidget(const QAction *a) const
+QLineEditPrivate::SideWidgetLocation QLineEditPrivate::findSideWidget(const QAction *a) const
{
int i = 0;
for (const auto &e : leadingSideWidgets) {
if (a == e.action)
- return PositionIndexPair(QLineEdit::LeadingPosition, i);
+ return {QLineEdit::LeadingPosition, i};
++i;
}
i = 0;
for (const auto &e : trailingSideWidgets) {
if (a == e.action)
- return PositionIndexPair(QLineEdit::TrailingPosition, i);
+ return {QLineEdit::TrailingPosition, i};
++i;
}
- return PositionIndexPair(QLineEdit::LeadingPosition, -1);
+ return {QLineEdit::LeadingPosition, -1};
}
QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineEdit::ActionPosition position, int flags)
@@ -505,10 +514,12 @@ QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineE
QWidget *w = 0;
// Store flags about QWidgetAction here since removeAction() may be called from ~QAction,
// in which a qobject_cast<> no longer works.
+#if QT_CONFIG(action)
if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(newAction)) {
if ((w = widgetAction->requestWidget(q)))
flags |= SideWidgetCreatedByWidgetAction;
}
+#endif
if (!w) {
#if QT_CONFIG(toolbutton)
QLineEditIconButton *toolButton = new QLineEditIconButton(q);
@@ -523,11 +534,23 @@ QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineE
#endif
}
// If there is a 'before' action, it takes preference
- PositionIndexPair positionIndex = before ? findSideWidget(before) : PositionIndexPair(position, -1);
- SideWidgetEntryList &list = positionIndex.first == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
- if (positionIndex.second < 0)
- positionIndex.second = int(list.size());
- list.insert(list.begin() + positionIndex.second, SideWidgetEntry(w, newAction, flags));
+
+ // There's a bug in GHS compiler that causes internal error on the following code.
+ // The affected GHS compiler versions are 2016.5.4 and 2017.1. GHS internal reference
+ // to track the progress of this issue is TOOLS-26637.
+ // This temporary workaround allows to compile with GHS toolchain and should be
+ // removed when GHS provides a patch to fix the compiler issue.
+
+#if defined(Q_CC_GHS)
+ const SideWidgetLocation loc = {position, -1};
+ const auto location = before ? findSideWidget(before) : loc;
+#else
+ const auto location = before ? findSideWidget(before) : SideWidgetLocation{position, -1};
+#endif
+
+ SideWidgetEntryList &list = location.position == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
+ list.insert(location.isValid() ? list.begin() + location.index : list.end(),
+ SideWidgetEntry(w, newAction, flags));
positionSideWidgets();
w->show();
return w;
@@ -535,13 +558,14 @@ QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineE
void QLineEditPrivate::removeAction(QAction *action)
{
+#if QT_CONFIG(action)
Q_Q(QLineEdit);
- const PositionIndexPair positionIndex = findSideWidget(action);
- if (positionIndex.second == -1)
+ const auto location = findSideWidget(action);
+ if (!location.isValid())
return;
- SideWidgetEntryList &list = positionIndex.first == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
- SideWidgetEntry entry = list[positionIndex.second];
- list.erase(list.begin() + positionIndex.second);
+ SideWidgetEntryList &list = location.position == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
+ SideWidgetEntry entry = list[location.index];
+ list.erase(list.begin() + location.index);
if (entry.flags & SideWidgetCreatedByWidgetAction)
static_cast<QWidgetAction *>(entry.action)->releaseWidget(entry.widget);
else
@@ -550,6 +574,7 @@ void QLineEditPrivate::removeAction(QAction *action)
if (!hasSideWidgets()) // Last widget, remove connection
QObject::disconnect(q, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString)));
q->update();
+#endif // QT_CONFIG(action)
}
static bool isSideWidgetVisible(const QLineEditPrivate::SideWidgetEntry &e)
diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h
index a903c003e6..2d695f8411 100644
--- a/src/widgets/widgets/qlineedit_p.h
+++ b/src/widgets/widgets/qlineedit_p.h
@@ -235,15 +235,22 @@ public:
int effectiveRightTextMargin() const;
private:
- typedef QPair<QLineEdit::ActionPosition, int> PositionIndexPair;
+ struct SideWidgetLocation {
+ QLineEdit::ActionPosition position;
+ int index;
- PositionIndexPair findSideWidget(const QAction *a) const;
+ bool isValid() const { return index >= 0; }
+ };
+ friend class QTypeInfo<SideWidgetLocation>;
+
+ SideWidgetLocation findSideWidget(const QAction *a) const;
SideWidgetEntryList leadingSideWidgets;
SideWidgetEntryList trailingSideWidgets;
int lastTextSize;
};
Q_DECLARE_TYPEINFO(QLineEditPrivate::SideWidgetEntry, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(QLineEditPrivate::SideWidgetLocation, Q_PRIMITIVE_TYPE);
#endif // QT_NO_LINEEDIT
diff --git a/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm b/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm
index 8e565ecfe0..610df2125b 100644
--- a/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm
+++ b/src/widgets/widgets/qmaccocoaviewcontainer_mac.mm
@@ -44,6 +44,7 @@
#include <QtGui/QWindow>
#include <qpa/qplatformnativeinterface.h>
#include <private/qwidget_p.h>
+#include <private/qwindow_p.h>
/*!
\class QMacCocoaViewContainer
@@ -117,7 +118,9 @@ QMacCocoaViewContainerPrivate::~QMacCocoaViewContainerPrivate()
QMacCocoaViewContainer::QMacCocoaViewContainer(NSView *view, QWidget *parent)
: QWidget(*new QMacCocoaViewContainerPrivate, parent, 0)
{
+ // Ensures that we have a QWindow, even if we're not a top level widget
setAttribute(Qt::WA_NativeWindow);
+
setCocoaView(view);
}
@@ -149,23 +152,19 @@ void QMacCocoaViewContainer::setCocoaView(NSView *view)
[view retain];
d->nsview = view;
- QWindow *window = windowHandle();
+ // Get rid of QWindow completely, and re-create a new vanilla one, which
+ // we will then re-configure to be a foreign window.
+ destroy();
+ create();
- // Note that we only set the flag on the QWindow, and not the QWidget.
- // These two are not in sync, so from a QWidget standpoint the widget
- // is not a Window, and hence will be shown when the parent widget is
- // shown, like all QWidget children.
- window->setFlags(Qt::ForeignWindow);
- window->setProperty("_q_foreignWinId", view ? WId(view) : QVariant());
-
- // Destroying the platform window implies hiding the window, and we
- // also lose the geometry information that the platform window kept,
- // and fall back to the stale QWindow geometry, so we update the two
- // based on the widget visibility and geometry, which is up to date.
+ // Can't use QWindow::fromWinId() here due to QWidget controlling its
+ // QWindow, and can't use QWidget::createWindowContainer() due to the
+ // QMacCocoaViewContainer class being public API instead of a factory
+ // function.
+ QWindow *window = windowHandle();
window->destroy();
- window->setVisible(isVisible());
- window->setGeometry(geometry());
- window->create();
+ qt_window_private(window)->create(false, WId(view));
+ Q_ASSERT(window->handle());
[oldView release];
}
diff --git a/src/widgets/widgets/qmainwindow.h b/src/widgets/widgets/qmainwindow.h
index 9bd7eb1cd8..bab1176d8a 100644
--- a/src/widgets/widgets/qmainwindow.h
+++ b/src/widgets/widgets/qmainwindow.h
@@ -60,7 +60,6 @@ class Q_WIDGETS_EXPORT QMainWindow : public QWidget
{
Q_OBJECT
- Q_FLAGS(DockOptions)
Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
Q_PROPERTY(Qt::ToolButtonStyle toolButtonStyle READ toolButtonStyle WRITE setToolButtonStyle)
#ifndef QT_NO_DOCKWIDGET
@@ -89,6 +88,7 @@ public:
};
Q_ENUM(DockOption)
Q_DECLARE_FLAGS(DockOptions, DockOption)
+ Q_FLAG(DockOptions)
explicit QMainWindow(QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags());
~QMainWindow();
diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp
index 640154063e..d31fa3ddfa 100644
--- a/src/widgets/widgets/qmainwindowlayout.cpp
+++ b/src/widgets/widgets/qmainwindowlayout.cpp
@@ -2432,6 +2432,9 @@ QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, bool group)
}
#endif
+#if !QT_CONFIG(dockwidget) || !QT_CONFIG(tabbar)
+ Q_UNUSED(group);
+#endif
layoutState.unplug(path ,&savedState);
savedState.fitLayout();
diff --git a/src/widgets/widgets/qmdisubwindow.cpp b/src/widgets/widgets/qmdisubwindow.cpp
index a627c86871..a8cdca1719 100644
--- a/src/widgets/widgets/qmdisubwindow.cpp
+++ b/src/widgets/widgets/qmdisubwindow.cpp
@@ -1863,7 +1863,7 @@ void QMdiSubWindowPrivate::removeButtonsFromMenuBar()
topLevelWindow->removeEventFilter(q);
if (baseWidget && !drawTitleBarWhenMaximized())
topLevelWindow->setWindowModified(false);
- originalTitle = QString::null;
+ originalTitle.clear();
}
#endif // QT_NO_MENUBAR
@@ -2769,7 +2769,7 @@ bool QMdiSubWindow::eventFilter(QObject *object, QEvent *event)
#ifndef QT_NO_MENUBAR
} else if (maximizedButtonsWidget() && d->controlContainer->menuBar() && d->controlContainer->menuBar()
->cornerWidget(Qt::TopRightCorner) == maximizedButtonsWidget()) {
- d->originalTitle = QString::null;
+ d->originalTitle.clear();
if (d->baseWidget && d->baseWidget->windowTitle() == windowTitle())
d->updateWindowTitle(true);
else
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index 1925b58326..2b10ae7261 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -3456,7 +3456,9 @@ void QMenu::actionEvent(QActionEvent *e)
QObject::connect(menuItem, SIGNAL(activated()), e->action(), SLOT(trigger()));
QObject::connect(menuItem, SIGNAL(hovered()), e->action(), SIGNAL(hovered()));
copyActionToPlatformItem(e->action(), menuItem, d->platformMenu);
- QPlatformMenuItem* beforeItem = d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->before()));
+ QPlatformMenuItem *beforeItem = e->before()
+ ? d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->before()))
+ : nullptr;
d->platformMenu->insertMenuItem(menuItem, beforeItem);
} else if (e->type() == QEvent::ActionRemoved) {
QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast<quintptr>(e->action()));
diff --git a/src/widgets/widgets/qmenu.h b/src/widgets/widgets/qmenu.h
index 5d218ac1ba..e9a5db1112 100644
--- a/src/widgets/widgets/qmenu.h
+++ b/src/widgets/widgets/qmenu.h
@@ -98,8 +98,8 @@ public:
#else
// addAction(QString): Connect to a QObject slot / functor or function pointer (with context)
template<class Obj, typename Func1>
- inline typename QtPrivate::QEnableIf<!std::is_same<const char*, Func1>::value
- && QtPrivate::IsPointerToTypeDerivedFromQObject<Obj*>::Value, QAction *>::Type
+ inline typename std::enable_if<!std::is_same<const char*, Func1>::value
+ && QtPrivate::IsPointerToTypeDerivedFromQObject<Obj*>::Value, QAction *>::type
addAction(const QString &text, const Obj *object, Func1 slot, const QKeySequence &shortcut = 0)
{
QAction *result = addAction(text);
@@ -126,8 +126,8 @@ public:
}
// addAction(QIcon, QString): Connect to a QObject slot / functor or function pointer (with context)
template<class Obj, typename Func1>
- inline typename QtPrivate::QEnableIf<!std::is_same<const char*, Func1>::value
- && QtPrivate::IsPointerToTypeDerivedFromQObject<Obj*>::Value, QAction *>::Type
+ inline typename std::enable_if<!std::is_same<const char*, Func1>::value
+ && QtPrivate::IsPointerToTypeDerivedFromQObject<Obj*>::Value, QAction *>::type
addAction(const QIcon &actionIcon, const QString &text, const Obj *object, Func1 slot, const QKeySequence &shortcut = 0)
{
QAction *result = addAction(actionIcon, text);
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp
index b2ec8f2c08..c16b2a5ac1 100644
--- a/src/widgets/widgets/qmenubar.cpp
+++ b/src/widgets/widgets/qmenubar.cpp
@@ -1119,7 +1119,7 @@ void QMenuBar::keyPressEvent(QKeyEvent *e)
int clashCount = 0;
QAction *first = 0, *currentSelected = 0, *firstAfterCurrent = 0;
{
- QChar c = e->text()[0].toUpper();
+ const QChar c = e->text().at(0).toUpper();
for(int i = 0; i < d->actions.size(); ++i) {
if (d->actionRects.at(i).isNull())
continue;
@@ -1192,10 +1192,6 @@ QPlatformMenu *QMenuBarPrivate::getPlatformMenu(QAction *action)
QPlatformMenu *platformMenu = action->menu()->platformMenu();
if (!platformMenu && platformMenuBar) {
platformMenu = platformMenuBar->createMenu();
- // QPlatformMenuBar::createMenu() was introduced in Qt 5.7. Not all third party
- // platform themes are using it, so fallback to QPlatformTheme::createPlatformMenu().
- if (!platformMenu)
- platformMenu = QGuiApplicationPrivate::platformTheme()->createPlatformMenu();
if (platformMenu)
action->menu()->setPlatformMenu(platformMenu);
}
@@ -1505,6 +1501,7 @@ bool QMenuBar::eventFilter(QObject *object, QEvent *event)
case QEvent::FocusIn:
case QEvent::FocusOut:
case QEvent::ActivationChange:
+ case QEvent::Shortcut:
d->altPressed = false;
qApp->removeEventFilter(this);
break;
diff --git a/src/widgets/widgets/qplaintextedit_p.h b/src/widgets/widgets/qplaintextedit_p.h
index f0dd1c0ed4..803623c974 100644
--- a/src/widgets/widgets/qplaintextedit_p.h
+++ b/src/widgets/widgets/qplaintextedit_p.h
@@ -60,11 +60,12 @@
#include "QtWidgets/qmenu.h"
#include "QtGui/qabstracttextdocumentlayout.h"
#include "QtCore/qbasictimer.h"
-#include "private/qwidgettextcontrol_p.h"
#include "qplaintextedit.h"
#ifndef QT_NO_TEXTEDIT
+#include "private/qwidgettextcontrol_p.h"
+
QT_BEGIN_NAMESPACE
class QMimeData;
diff --git a/src/widgets/widgets/qprogressbar.cpp b/src/widgets/widgets/qprogressbar.cpp
index 64f19047b6..2b228cdb2c 100644
--- a/src/widgets/widgets/qprogressbar.cpp
+++ b/src/widgets/widgets/qprogressbar.cpp
@@ -508,9 +508,7 @@ void QProgressBar::setOrientation(Qt::Orientation orientation)
return;
d->orientation = orientation;
if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
- QSizePolicy sp = sizePolicy();
- sp.transpose();
- setSizePolicy(sp);
+ setSizePolicy(sizePolicy().transposed());
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
}
d->resetLayoutItemMargins();
diff --git a/src/widgets/widgets/qpushbutton.cpp b/src/widgets/widgets/qpushbutton.cpp
index 3b1440edb6..5b1e10eb32 100644
--- a/src/widgets/widgets/qpushbutton.cpp
+++ b/src/widgets/widgets/qpushbutton.cpp
@@ -40,8 +40,9 @@
#include "qapplication.h"
#include "qbitmap.h"
#include "qdesktopwidget.h"
-#include "qdialog.h"
+#if QT_CONFIG(dialog)
#include <private/qdialog_p.h>
+#endif
#include "qdrawutil.h"
#include "qevent.h"
#include "qfontmetrics.h"
@@ -55,7 +56,9 @@
#include "qtoolbar.h"
#include "qdebug.h"
#include "qlayoutitem.h"
+#if QT_CONFIG(dialogbuttonbox)
#include "qdialogbuttonbox.h"
+#endif
#if 0 // Used to be included in Qt4 for Q_WS_MAC
#include "private/qmacstyle_mac_p.h"
#include "private/qmacstyle_mac_p_p.h"
@@ -290,6 +293,7 @@ QPushButton::~QPushButton()
{
}
+#if QT_CONFIG(dialog)
QDialog *QPushButtonPrivate::dialogParent() const
{
Q_Q(const QPushButton);
@@ -301,6 +305,7 @@ QDialog *QPushButtonPrivate::dialogParent() const
}
return 0;
}
+#endif
/*!
Initialize \a option with the values from this QPushButton. This method is useful
@@ -364,10 +369,12 @@ void QPushButton::setDefault(bool enable)
if (d->defaultButton == enable)
return;
d->defaultButton = enable;
+#if QT_CONFIG(dialog)
if (d->defaultButton) {
if (QDialog *dlg = d->dialogParent())
dlg->d_func()->setMainDefault(this);
}
+#endif
update();
#ifndef QT_NO_ACCESSIBILITY
QAccessible::State s;
@@ -400,8 +407,7 @@ QSize QPushButton::sizeHint() const
initStyleOption(&opt);
// calculate contents size...
-#ifndef QT_NO_ICON
-
+#if !defined(QT_NO_ICON) && QT_CONFIG(dialogbuttonbox)
bool showButtonBoxIcons = qobject_cast<QDialogButtonBox*>(parentWidget())
&& style()->styleHint(QStyle::SH_DialogButtonBox_ButtonsHaveIcons);
@@ -477,9 +483,11 @@ void QPushButton::focusInEvent(QFocusEvent *e)
Q_D(QPushButton);
if (e->reason() != Qt::PopupFocusReason && autoDefault() && !d->defaultButton) {
d->defaultButton = true;
+#if QT_CONFIG(dialog)
QDialog *dlg = qobject_cast<QDialog*>(window());
if (dlg)
dlg->d_func()->setDefault(this);
+#endif
}
QAbstractButton::focusInEvent(e);
}
@@ -491,11 +499,13 @@ void QPushButton::focusOutEvent(QFocusEvent *e)
{
Q_D(QPushButton);
if (e->reason() != Qt::PopupFocusReason && autoDefault() && d->defaultButton) {
+#if QT_CONFIG(dialog)
QDialog *dlg = qobject_cast<QDialog*>(window());
if (dlg)
dlg->d_func()->setDefault(0);
else
d->defaultButton = false;
+#endif
}
QAbstractButton::focusOutEvent(e);
@@ -607,19 +617,21 @@ QPoint QPushButtonPrivate::adjustedMenuPosition()
QPoint globalPos = q->mapToGlobal(rect.topLeft());
int x = globalPos.x();
int y = globalPos.y();
+ const QRect availableGeometry = QApplication::desktop()->availableGeometry(q);
if (horizontal) {
- if (globalPos.y() + rect.height() + menuSize.height() <= QApplication::desktop()->availableGeometry(q).height()) {
+ if (globalPos.y() + rect.height() + menuSize.height() <= availableGeometry.bottom()) {
y += rect.height();
- } else {
+ } else if (globalPos.y() - menuSize.height() >= availableGeometry.y()) {
y -= menuSize.height();
}
if (q->layoutDirection() == Qt::RightToLeft)
x += rect.width() - menuSize.width();
} else {
- if (globalPos.x() + rect.width() + menu->sizeHint().width() <= QApplication::desktop()->availableGeometry(q).width())
+ if (globalPos.x() + rect.width() + menu->sizeHint().width() <= availableGeometry.right()) {
x += rect.width();
- else
+ } else if (globalPos.x() - menuSize.width() >= availableGeometry.x()) {
x -= menuSize.width();
+ }
}
return QPoint(x,y);
@@ -658,10 +670,12 @@ bool QPushButton::event(QEvent *e)
{
Q_D(QPushButton);
if (e->type() == QEvent::ParentChange) {
+#if QT_CONFIG(dialog)
if (QDialog *dialog = d->dialogParent()) {
if (d->defaultButton)
dialog->d_func()->setMainDefault(this);
}
+#endif
} else if (e->type() == QEvent::StyleChange
#ifdef Q_OS_MAC
|| e->type() == QEvent::MacSizeChange
@@ -676,7 +690,7 @@ bool QPushButton::event(QEvent *e)
}
#if 0 // Used to be included in Qt4 for Q_WS_MAC
-/*! \reimp */
+/* \reimp */
bool QPushButton::hitButton(const QPoint &pos) const
{
QStyleOptionButton opt;
diff --git a/src/widgets/widgets/qpushbutton.h b/src/widgets/widgets/qpushbutton.h
index b0d1ccacdb..ea9baa8ccb 100644
--- a/src/widgets/widgets/qpushbutton.h
+++ b/src/widgets/widgets/qpushbutton.h
@@ -43,6 +43,8 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qabstractbutton.h>
+QT_REQUIRE_CONFIG(pushbutton);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qpushbutton_p.h b/src/widgets/widgets/qpushbutton_p.h
index ee41c345c8..a32b599b94 100644
--- a/src/widgets/widgets/qpushbutton_p.h
+++ b/src/widgets/widgets/qpushbutton_p.h
@@ -43,6 +43,8 @@
#include <QtWidgets/private/qtwidgetsglobal_p.h>
#include "private/qabstractbutton_p.h"
+QT_REQUIRE_CONFIG(pushbutton);
+
//
// W A R N I N G
// -------------
@@ -79,7 +81,11 @@ public:
#endif
void resetLayoutItemMargins();
void _q_popupPressed();
+#if QT_CONFIG(dialog)
QDialog *dialogParent() const;
+#else
+ QDialog *dialogParent() const { return 0; };
+#endif
QPointer<QMenu> menu;
uint autoDefault : 2;
diff --git a/src/widgets/widgets/qradiobutton.h b/src/widgets/widgets/qradiobutton.h
index 2dcb0d0fdf..137ae01380 100644
--- a/src/widgets/widgets/qradiobutton.h
+++ b/src/widgets/widgets/qradiobutton.h
@@ -43,6 +43,8 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qabstractbutton.h>
+QT_REQUIRE_CONFIG(radiobutton);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qscrollbar.h b/src/widgets/widgets/qscrollbar.h
index 2b8a110c99..b99ad219eb 100644
--- a/src/widgets/widgets/qscrollbar.h
+++ b/src/widgets/widgets/qscrollbar.h
@@ -42,12 +42,12 @@
#include <QtWidgets/qtwidgetsglobal.h>
#include <QtWidgets/qwidget.h>
-#include <QtWidgets/qabstractslider.h>
-QT_BEGIN_NAMESPACE
+#if QT_CONFIG(scrollbar)
+#include <QtWidgets/qabstractslider.h>
-#ifndef QT_NO_SCROLLBAR
+QT_BEGIN_NAMESPACE
class QScrollBarPrivate;
class QStyleOptionSlider;
@@ -94,8 +94,8 @@ private:
#endif
};
-#endif // QT_NO_SCROLLBAR
-
QT_END_NAMESPACE
+#endif // QT_CONFIG(scrollbar)
+
#endif // QSCROLLBAR_H
diff --git a/src/widgets/widgets/qslider.h b/src/widgets/widgets/qslider.h
index 33b90ece06..001863c18d 100644
--- a/src/widgets/widgets/qslider.h
+++ b/src/widgets/widgets/qslider.h
@@ -41,13 +41,14 @@
#define QSLIDER_H
#include <QtWidgets/qtwidgetsglobal.h>
+
+#if QT_CONFIG(slider)
+
#include <QtWidgets/qabstractslider.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_SLIDER
-
class QSliderPrivate;
class QStyleOptionSlider;
class Q_WIDGETS_EXPORT QSlider : public QAbstractSlider
@@ -99,8 +100,8 @@ private:
Q_DECLARE_PRIVATE(QSlider)
};
-#endif // QT_NO_SLIDER
-
QT_END_NAMESPACE
+#endif // QT_CONFIG(slider)
+
#endif // QSLIDER_H
diff --git a/src/widgets/widgets/qsplitter.cpp b/src/widgets/widgets/qsplitter.cpp
index 910904e96e..e92347c65c 100644
--- a/src/widgets/widgets/qsplitter.cpp
+++ b/src/widgets/widgets/qsplitter.cpp
@@ -241,21 +241,24 @@ void QSplitterHandle::resizeEvent(QResizeEvent *event)
{
Q_D(const QSplitterHandle);
- // When splitters are only 1 or 0 pixel large we increase the
- // actual grab area to five pixels
+ // Ensure the actual grab area is at least 4 or 5 pixels
+ const int handleMargin = (5 - d->s->handleWidth()) / 2;
// Note that QSplitter uses contentsRect for layouting
// and ensures that handles are drawn on top of widgets
// We simply use the contents margins for draggin and only
// paint the mask area
- bool useTinyMode = (d->s->handleWidth() <= 1);
+ const bool useTinyMode = handleMargin > 0;
setAttribute(Qt::WA_MouseNoMask, useTinyMode);
if (useTinyMode) {
if (orientation() == Qt::Horizontal)
- setContentsMargins(2, 0, 2, 0);
+ setContentsMargins(handleMargin, 0, handleMargin, 0);
else
- setContentsMargins(0, 2, 0, 2);
+ setContentsMargins(0, handleMargin, 0, handleMargin);
setMask(QRegion(contentsRect()));
+ } else {
+ setContentsMargins(0, 0, 0, 0);
+ clearMask();
}
QWidget::resizeEvent(event);
@@ -731,6 +734,12 @@ void QSplitterPrivate::setSizes_helper(const QList<int> &sizes, bool clampNegati
doResize();
}
+bool QSplitterPrivate::shouldShowWidget(const QWidget *w) const
+{
+ Q_Q(const QSplitter);
+ return q->isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide));
+}
+
void QSplitterPrivate::setGeo(QSplitterLayoutStruct *sls, int p, int s, bool allowCollapse)
{
Q_Q(QSplitter);
@@ -827,8 +836,7 @@ void QSplitterPrivate::insertWidget_helper(int index, QWidget *widget, bool show
{
Q_Q(QSplitter);
QBoolBlocker b(blockChildAdd);
- bool needShow = show && q->isVisible() &&
- !(widget->isHidden() && widget->testAttribute(Qt::WA_WState_ExplicitShowHide));
+ const bool needShow = show && shouldShowWidget(widget);
if (widget->parentWidget() != q)
widget->setParent(q);
if (needShow)
@@ -1000,9 +1008,7 @@ void QSplitter::setOrientation(Qt::Orientation orientation)
return;
if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
- QSizePolicy sp = sizePolicy();
- sp.transpose();
- setSizePolicy(sp);
+ setSizePolicy(sizePolicy().transposed());
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
}
@@ -1125,6 +1131,66 @@ void QSplitter::insertWidget(int index, QWidget *widget)
}
/*!
+ \since 5.9
+
+ Replaces the widget in the splitter's layout at the given \a index by \a widget.
+
+ Returns the widget that has just been replaced if \a index is valid and \a widget
+ is not already a child of the splitter. Otherwise, it returns null and no replacement
+ or addition is made.
+
+ The geometry of the newly inserted widget will be the same as the widget it replaces.
+ Its visible and collapsed states are also inherited.
+
+ \note The splitter takes ownership of \a widget and sets the parent of the
+ replaced widget to null.
+
+ \sa insertWidget(), indexOf()
+*/
+QWidget *QSplitter::replaceWidget(int index, QWidget *widget)
+{
+ Q_D(QSplitter);
+ if (!widget) {
+ qWarning("QSplitter::replaceWidget: Widget can't be null");
+ return nullptr;
+ }
+
+ if (index < 0 || index >= d->list.count()) {
+ qWarning("QSplitter::replaceWidget: Index %d out of range", index);
+ return nullptr;
+ }
+
+ QSplitterLayoutStruct *s = d->list.at(index);
+ QWidget *current = s->widget;
+ if (current == widget) {
+ qWarning("QSplitter::replaceWidget: Trying to replace a widget with itself");
+ return nullptr;
+ }
+
+ if (widget->parentWidget() == this) {
+ qWarning("QSplitter::replaceWidget: Trying to replace a widget with one of its siblings");
+ return nullptr;
+ }
+
+ QBoolBlocker b(d->blockChildAdd);
+
+ const QRect geom = current->geometry();
+ const bool shouldShow = d->shouldShowWidget(current);
+
+ s->widget = widget;
+ current->setParent(nullptr);
+ widget->setParent(this);
+
+ // The splitter layout struct's geometry is already set and
+ // should not change. Only set the geometry on the new widget
+ widget->setGeometry(geom);
+ widget->lower();
+ widget->setVisible(shouldShow);
+
+ return current;
+}
+
+/*!
\fn int QSplitter::indexOf(QWidget *widget) const
Returns the index in the splitter's layout of the specified \a widget. This
@@ -1232,7 +1298,7 @@ void QSplitter::childEvent(QChildEvent *c)
if (c->added() && !d->blockChildAdd && !d->findWidget(w)) {
d->insertWidget_helper(d->list.count(), w, false);
} else if (c->polished() && !d->blockChildAdd) {
- if (isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide)))
+ if (d->shouldShowWidget(w))
w->show();
} else if (c->type() == QEvent::ChildRemoved) {
for (int i = 0; i < d->list.size(); ++i) {
@@ -1732,9 +1798,9 @@ QTextStream& operator>>(QTextStream& ts, QSplitter& splitter)
QString line = ts.readLine();
line = line.simplified();
line.replace(QLatin1Char(' '), QString());
- line = line.toUpper();
+ line = std::move(line).toUpper();
- splitter.restoreState(line.toLatin1());
+ splitter.restoreState(std::move(line).toLatin1());
return ts;
}
diff --git a/src/widgets/widgets/qsplitter.h b/src/widgets/widgets/qsplitter.h
index 9cfde9fed3..e9ef3c3f2d 100644
--- a/src/widgets/widgets/qsplitter.h
+++ b/src/widgets/widgets/qsplitter.h
@@ -71,6 +71,7 @@ public:
void addWidget(QWidget *widget);
void insertWidget(int index, QWidget *widget);
+ QWidget *replaceWidget(int index, QWidget *widget);
void setOrientation(Qt::Orientation);
Qt::Orientation orientation() const;
diff --git a/src/widgets/widgets/qsplitter_p.h b/src/widgets/widgets/qsplitter_p.h
index 4422d9a8a4..07b43e56b8 100644
--- a/src/widgets/widgets/qsplitter_p.h
+++ b/src/widgets/widgets/qsplitter_p.h
@@ -125,6 +125,7 @@ public:
int findWidgetJustBeforeOrJustAfter(int index, int delta, int &collapsibleSize) const;
void updateHandles();
void setSizes_helper(const QList<int> &sizes, bool clampNegativeSize = false);
+ bool shouldShowWidget(const QWidget *w) const;
};
diff --git a/src/widgets/widgets/qtabbar.cpp b/src/widgets/widgets/qtabbar.cpp
index f14e63c584..d2bd7285ca 100644
--- a/src/widgets/widgets/qtabbar.cpp
+++ b/src/widgets/widgets/qtabbar.cpp
@@ -177,8 +177,7 @@ void QTabBarPrivate::initBasicStyleOption(QStyleOptionTab *option, int tabIndex)
if (tab.textColor.isValid())
option->palette.setColor(q->foregroundRole(), tab.textColor);
else if (q->style()->inherits("QMacStyle")
- && isCurrent && !documentMode
- && (QSysInfo::MacintoshVersion < QSysInfo::MV_10_10 || q->isActiveWindow())) {
+ && isCurrent && !documentMode && q->isActiveWindow()) {
option->palette.setColor(QPalette::WindowText, Qt::white);
}
option->icon = tab.icon;
@@ -519,12 +518,14 @@ void QTabBarPrivate::layoutTabs()
maxExtent = maxWidth;
}
+ if (!expanding) {
+ // Mirror our front item.
+ tabChain[tabChainIndex].init();
+ tabChain[tabChainIndex].expansive = (tabAlignment != Qt::AlignRight)
+ && (tabAlignment != Qt::AlignJustify);
+ tabChain[tabChainIndex].empty = true;
+ }
Q_ASSERT(tabChainIndex == tabChain.count() - 1); // add an assert just to make sure.
- // Mirror our front item.
- tabChain[tabChainIndex].init();
- tabChain[tabChainIndex].expansive = (tabAlignment != Qt::AlignRight)
- && (tabAlignment != Qt::AlignJustify);
- tabChain[tabChainIndex].empty = true;
// Do the calculation
qGeomCalc(tabChain, 0, tabChain.count(), 0, qMax(available, last), 0);
@@ -664,6 +665,15 @@ QRect QTabBarPrivate::normalizedScrollRect(int index)
}
}
+int QTabBarPrivate::hoveredTabIndex() const
+{
+ if (dragInProgress)
+ return currentIndex;
+ if (hoverIndex >= 0)
+ return hoverIndex;
+ return -1;
+}
+
void QTabBarPrivate::makeVisible(int index)
{
Q_Q(QTabBar);
@@ -1053,6 +1063,17 @@ void QTabBar::removeTab(int index)
}
d->refresh();
d->autoHideTabs();
+ if (!d->hoverRect.isEmpty()) {
+ for (int i = 0; i < d->tabList.count(); ++i) {
+ const QRect area = tabRect(i);
+ if (area.contains(mapFromGlobal(QCursor::pos()))) {
+ d->hoverIndex = i;
+ d->hoverRect = area;
+ break;
+ }
+ }
+ update(d->hoverRect);
+ }
tabRemoved(index);
}
}
@@ -1577,20 +1598,28 @@ bool QTabBar::event(QEvent *event)
QHoverEvent *he = static_cast<QHoverEvent *>(event);
if (!d->hoverRect.contains(he->pos())) {
QRect oldHoverRect = d->hoverRect;
+ bool cursorOverTabs = false;
for (int i = 0; i < d->tabList.count(); ++i) {
QRect area = tabRect(i);
if (area.contains(he->pos())) {
+ d->hoverIndex = i;
d->hoverRect = area;
+ cursorOverTabs = true;
break;
}
}
+ if (!cursorOverTabs) {
+ d->hoverIndex = -1;
+ d->hoverRect = QRect();
+ }
if (he->oldPos() != QPoint(-1, -1))
update(oldHoverRect);
update(d->hoverRect);
}
return true;
- } else if (event->type() == QEvent::HoverLeave ) {
+ } else if (event->type() == QEvent::HoverLeave) {
QRect oldHoverRect = d->hoverRect;
+ d->hoverIndex = -1;
d->hoverRect = QRect();
update(oldHoverRect);
return true;
@@ -1756,7 +1785,10 @@ void QTabBar::paintEvent(QPaintEvent *)
p.drawControl(QStyle::CE_TabBarTab, tab);
else {
int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0, this);
- d->movingTab->setGeometry(tab.rect.adjusted(-taboverlap, 0, taboverlap, 0));
+ if (verticalTabs(d->shape))
+ d->movingTab->setGeometry(tab.rect.adjusted(0, -taboverlap, 0, taboverlap));
+ else
+ d->movingTab->setGeometry(tab.rect.adjusted(-taboverlap, 0, taboverlap, 0));
}
}
@@ -2035,7 +2067,10 @@ void QTabBarPrivate::setupMovableTab()
int taboverlap = q->style()->pixelMetric(QStyle::PM_TabBarTabOverlap, 0 ,q);
QRect grabRect = q->tabRect(pressedIndex);
- grabRect.adjust(-taboverlap, 0, taboverlap, 0);
+ if (verticalTabs(shape))
+ grabRect.adjust(0, -taboverlap, 0, taboverlap);
+ else
+ grabRect.adjust(-taboverlap, 0, taboverlap, 0);
QPixmap grabImage(grabRect.size() * q->devicePixelRatioF());
grabImage.setDevicePixelRatio(q->devicePixelRatioF());
@@ -2045,7 +2080,11 @@ void QTabBarPrivate::setupMovableTab()
QStyleOptionTab tab;
q->initStyleOption(&tab, pressedIndex);
- tab.rect.moveTopLeft(QPoint(taboverlap, 0));
+ tab.position = QStyleOptionTab::OnlyOneTab;
+ if (verticalTabs(shape))
+ tab.rect.moveTopLeft(QPoint(0, taboverlap));
+ else
+ tab.rect.moveTopLeft(QPoint(taboverlap, 0));
p.drawControl(QStyle::CE_TabBarTab, tab);
p.end();
@@ -2425,7 +2464,7 @@ void QTabBar::setMovable(bool movable)
This property is used as a hint for styles to draw the tabs in a different
way then they would normally look in a tab widget. On \macos this will
- look similar to the tabs in Safari or Leopard's Terminal.app.
+ look similar to the tabs in Safari or Sierra's Terminal.app.
\sa QTabWidget::documentMode
*/
diff --git a/src/widgets/widgets/qtabbar_p.h b/src/widgets/widgets/qtabbar_p.h
index e8d5503fdf..7c653a95e9 100644
--- a/src/widgets/widgets/qtabbar_p.h
+++ b/src/widgets/widgets/qtabbar_p.h
@@ -87,7 +87,7 @@ class QTabBarPrivate : public QWidgetPrivate
public:
QTabBarPrivate()
:currentIndex(-1), pressedIndex(-1), shape(QTabBar::RoundedNorth), layoutDirty(false),
- drawBase(true), scrollOffset(0), elideModeSetByUser(false), useScrollButtonsSetByUser(false), expanding(true), closeButtonOnTabs(false),
+ drawBase(true), scrollOffset(0), hoverIndex(-1), elideModeSetByUser(false), useScrollButtonsSetByUser(false), expanding(true), closeButtonOnTabs(false),
selectionBehaviorOnRemove(QTabBar::SelectRightTab), paintWithOffsets(true), movable(false),
dragInProgress(false), documentMode(false), autoHide(false), changeCurrentOnDrag(false),
switchTabCurrentIndex(-1), switchTabTimerId(0), movingTab(0)
@@ -192,6 +192,7 @@ public:
void moveTab(int index, int offset);
void moveTabFinished(int index);
QRect hoverRect;
+ int hoverIndex;
void refresh();
void layoutTabs();
@@ -202,6 +203,7 @@ public:
void setupMovableTab();
void autoHideTabs();
QRect normalizedScrollRect(int index = -1);
+ int hoveredTabIndex() const;
void initBasicStyleOption(QStyleOptionTab *option, int tabIndex) const;
diff --git a/src/widgets/widgets/qtabwidget.cpp b/src/widgets/widgets/qtabwidget.cpp
index 5dce76056c..be870133ee 100644
--- a/src/widgets/widgets/qtabwidget.cpp
+++ b/src/widgets/widgets/qtabwidget.cpp
@@ -209,7 +209,6 @@ public:
bool dirty;
QTabWidget::TabPosition pos;
QTabWidget::TabShape shape;
- int alignment;
QWidget *leftCornerWidget;
QWidget *rightCornerWidget;
};
@@ -732,7 +731,7 @@ QTabBar* QTabWidget::tabBar() const
return d->tabs;
}
-/*!
+/*
Ensures that the selected tab's page is visible and appropriately
sized.
*/
diff --git a/src/widgets/widgets/qtextedit.h b/src/widgets/widgets/qtextedit.h
index 3b523e3ed0..b0e19193a9 100644
--- a/src/widgets/widgets/qtextedit.h
+++ b/src/widgets/widgets/qtextedit.h
@@ -64,7 +64,6 @@ class Q_WIDGETS_EXPORT QTextEdit : public QAbstractScrollArea
{
Q_OBJECT
Q_DECLARE_PRIVATE(QTextEdit)
- Q_FLAGS(AutoFormatting)
Q_PROPERTY(AutoFormatting autoFormatting READ autoFormatting WRITE setAutoFormatting)
Q_PROPERTY(bool tabChangesFocus READ tabChangesFocus WRITE setTabChangesFocus)
Q_PROPERTY(QString documentTitle READ documentTitle WRITE setDocumentTitle)
@@ -100,6 +99,7 @@ public:
};
Q_DECLARE_FLAGS(AutoFormatting, AutoFormattingFlag)
+ Q_FLAG(AutoFormatting)
explicit QTextEdit(QWidget *parent = Q_NULLPTR);
explicit QTextEdit(const QString &text, QWidget *parent = Q_NULLPTR);
diff --git a/src/widgets/widgets/qtextedit_p.h b/src/widgets/widgets/qtextedit_p.h
index cca315ce30..13d0eb323a 100644
--- a/src/widgets/widgets/qtextedit_p.h
+++ b/src/widgets/widgets/qtextedit_p.h
@@ -61,13 +61,14 @@
#include "QtGui/qabstracttextdocumentlayout.h"
#include "QtCore/qbasictimer.h"
#include "QtCore/qurl.h"
-#include "private/qwidgettextcontrol_p.h"
#include "qtextedit.h"
-QT_BEGIN_NAMESPACE
-
#ifndef QT_NO_TEXTEDIT
+#include "private/qwidgettextcontrol_p.h"
+
+QT_BEGIN_NAMESPACE
+
class QMimeData;
class QTextEditPrivate : public QAbstractScrollAreaPrivate
{
@@ -135,9 +136,9 @@ public:
QBasicTimer deleteAllTimer;
#endif
};
-#endif // QT_NO_TEXTEDIT
-
QT_END_NAMESPACE
+#endif // QT_NO_TEXTEDIT
+
#endif // QTEXTEDIT_P_H
diff --git a/src/widgets/widgets/qtoolbar.h b/src/widgets/widgets/qtoolbar.h
index 0ea4d4afeb..e0f2d9b073 100644
--- a/src/widgets/widgets/qtoolbar.h
+++ b/src/widgets/widgets/qtoolbar.h
@@ -116,8 +116,8 @@ public:
#else
// addAction(QString): Connect to a QObject slot / functor or function pointer (with context)
template<class Obj, typename Func1>
- inline typename QtPrivate::QEnableIf<!std::is_same<const char*, Func1>::value
- && QtPrivate::IsPointerToTypeDerivedFromQObject<Obj*>::Value, QAction *>::Type
+ inline typename std::enable_if<!std::is_same<const char*, Func1>::value
+ && QtPrivate::IsPointerToTypeDerivedFromQObject<Obj*>::Value, QAction *>::type
addAction(const QString &text, const Obj *object, Func1 slot)
{
QAction *result = addAction(text);
@@ -134,8 +134,8 @@ public:
}
// addAction(QString): Connect to a QObject slot / functor or function pointer (with context)
template<class Obj, typename Func1>
- inline typename QtPrivate::QEnableIf<!std::is_same<const char*, Func1>::value
- && QtPrivate::IsPointerToTypeDerivedFromQObject<Obj*>::Value, QAction *>::Type
+ inline typename std::enable_if<!std::is_same<const char*, Func1>::value
+ && QtPrivate::IsPointerToTypeDerivedFromQObject<Obj*>::Value, QAction *>::type
addAction(const QIcon &actionIcon, const QString &text, const Obj *object, Func1 slot)
{
QAction *result = addAction(actionIcon, text);
diff --git a/src/widgets/widgets/qtoolbutton.h b/src/widgets/widgets/qtoolbutton.h
index 95d159f12d..e2470524da 100644
--- a/src/widgets/widgets/qtoolbutton.h
+++ b/src/widgets/widgets/qtoolbutton.h
@@ -41,13 +41,14 @@
#define QTOOLBUTTON_H
#include <QtWidgets/qtwidgetsglobal.h>
+
+#if QT_CONFIG(toolbutton)
+
#include <QtWidgets/qabstractbutton.h>
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_TOOLBUTTON
-
class QToolButtonPrivate;
class QMenu;
class QStyleOptionToolButton;
@@ -134,8 +135,8 @@ private:
};
-#endif // QT_NO_TOOLBUTTON
-
QT_END_NAMESPACE
+#endif // QT_CONFIG(toolbutton)
+
#endif // QTOOLBUTTON_H
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
index dacb4806ce..714f8bfda8 100644
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -1141,52 +1141,8 @@ void QWidgetTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget
case QEvent::ShortcutOverride:
if (d->interactionFlags & Qt::TextEditable) {
QKeyEvent* ke = static_cast<QKeyEvent *>(e);
- if (ke->modifiers() == Qt::NoModifier
- || ke->modifiers() == Qt::ShiftModifier
- || ke->modifiers() == Qt::KeypadModifier) {
- if (ke->key() < Qt::Key_Escape) {
- ke->accept();
- } else {
- switch (ke->key()) {
- case Qt::Key_Return:
- case Qt::Key_Enter:
- case Qt::Key_Delete:
- case Qt::Key_Home:
- case Qt::Key_End:
- case Qt::Key_Backspace:
- case Qt::Key_Left:
- case Qt::Key_Right:
- case Qt::Key_Up:
- case Qt::Key_Down:
- case Qt::Key_Tab:
- ke->accept();
- default:
- break;
- }
- }
-#ifndef QT_NO_SHORTCUT
- } else if (ke == QKeySequence::Copy
- || ke == QKeySequence::Paste
- || ke == QKeySequence::Cut
- || ke == QKeySequence::Redo
- || ke == QKeySequence::Undo
- || ke == QKeySequence::MoveToNextWord
- || ke == QKeySequence::MoveToPreviousWord
- || ke == QKeySequence::MoveToStartOfDocument
- || ke == QKeySequence::MoveToEndOfDocument
- || ke == QKeySequence::SelectNextWord
- || ke == QKeySequence::SelectPreviousWord
- || ke == QKeySequence::SelectStartOfLine
- || ke == QKeySequence::SelectEndOfLine
- || ke == QKeySequence::SelectStartOfBlock
- || ke == QKeySequence::SelectEndOfBlock
- || ke == QKeySequence::SelectStartOfDocument
- || ke == QKeySequence::SelectEndOfDocument
- || ke == QKeySequence::SelectAll
- ) {
+ if (isCommonTextEditShortcut(ke))
ke->accept();
-#endif
- }
}
break;
default:
diff --git a/src/widgets/widgets/qwidgettextcontrol_p.h b/src/widgets/widgets/qwidgettextcontrol_p.h
index f540a3c9ad..e2539a30e7 100644
--- a/src/widgets/widgets/qwidgettextcontrol_p.h
+++ b/src/widgets/widgets/qwidgettextcontrol_p.h
@@ -65,6 +65,8 @@
#include <QtCore/qmimedata.h>
#include <QtGui/private/qinputcontrol_p.h>
+QT_REQUIRE_CONFIG(widgettextcontrol);
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qwidgettextcontrol_p_p.h b/src/widgets/widgets/qwidgettextcontrol_p_p.h
index 35027ff82a..357ffdc6bd 100644
--- a/src/widgets/widgets/qwidgettextcontrol_p_p.h
+++ b/src/widgets/widgets/qwidgettextcontrol_p_p.h
@@ -62,6 +62,8 @@
#include "QtCore/qpointer.h"
#include "private/qobject_p.h"
+QT_REQUIRE_CONFIG(widgettextcontrol);
+
QT_BEGIN_NAMESPACE
class QMimeData;
diff --git a/src/widgets/widgets/widgets.pri b/src/widgets/widgets/widgets.pri
index abba3e0472..086585f0e6 100644
--- a/src/widgets/widgets/widgets.pri
+++ b/src/widgets/widgets/widgets.pri
@@ -3,21 +3,14 @@
HEADERS += \
widgets/qbuttongroup.h \
widgets/qbuttongroup_p.h \
- widgets/qabstractbutton.h \
- widgets/qabstractbutton_p.h \
- widgets/qabstractslider.h \
- widgets/qabstractslider_p.h \
widgets/qabstractspinbox.h \
widgets/qabstractspinbox_p.h \
widgets/qcalendarwidget.h \
- widgets/qcheckbox.h \
widgets/qcombobox.h \
widgets/qcombobox_p.h \
- widgets/qcommandlinkbutton.h \
widgets/qdatetimeedit.h \
widgets/qdatetimeedit_p.h \
widgets/qdial.h \
- widgets/qdialogbuttonbox.h \
widgets/qdockwidget.h \
widgets/qdockwidget_p.h \
widgets/qdockarealayout_p.h \
@@ -27,8 +20,6 @@ HEADERS += \
widgets/qgroupbox.h \
widgets/qkeysequenceedit.h \
widgets/qkeysequenceedit_p.h \
- widgets/qlabel.h \
- widgets/qlabel_p.h \
widgets/qlcdnumber.h \
widgets/qlineedit.h \
widgets/qlineedit_p.h \
@@ -43,9 +34,6 @@ HEADERS += \
widgets/qmenubar.h \
widgets/qmenubar_p.h \
widgets/qprogressbar.h \
- widgets/qpushbutton.h \
- widgets/qpushbutton_p.h \
- widgets/qradiobutton.h \
widgets/qrubberband.h \
widgets/qscrollbar.h \
widgets/qscrollbar_p.h \
@@ -77,8 +65,6 @@ HEADERS += \
widgets/qfocusframe.h \
widgets/qscrollarea.h \
widgets/qwidgetanimator_p.h \
- widgets/qwidgettextcontrol_p.h \
- widgets/qwidgettextcontrol_p_p.h \
widgets/qwidgetlinecontrol_p.h \
widgets/qtoolbararealayout_p.h \
widgets/qplaintextedit.h \
@@ -86,16 +72,11 @@ HEADERS += \
SOURCES += \
widgets/qbuttongroup.cpp \
- widgets/qabstractbutton.cpp \
- widgets/qabstractslider.cpp \
widgets/qabstractspinbox.cpp \
widgets/qcalendarwidget.cpp \
- widgets/qcheckbox.cpp \
widgets/qcombobox.cpp \
- widgets/qcommandlinkbutton.cpp \
widgets/qdatetimeedit.cpp \
widgets/qdial.cpp \
- widgets/qdialogbuttonbox.cpp \
widgets/qdockwidget.cpp \
widgets/qdockarealayout.cpp \
widgets/qeffects.cpp \
@@ -103,7 +84,6 @@ SOURCES += \
widgets/qframe.cpp \
widgets/qgroupbox.cpp \
widgets/qkeysequenceedit.cpp \
- widgets/qlabel.cpp \
widgets/qlcdnumber.cpp \
widgets/qlineedit_p.cpp \
widgets/qlineedit.cpp \
@@ -114,8 +94,6 @@ SOURCES += \
widgets/qmenu.cpp \
widgets/qmenubar.cpp \
widgets/qprogressbar.cpp \
- widgets/qpushbutton.cpp \
- widgets/qradiobutton.cpp \
widgets/qrubberband.cpp \
widgets/qscrollbar.cpp \
widgets/qsizegrip.cpp \
@@ -140,11 +118,88 @@ SOURCES += \
widgets/qfocusframe.cpp \
widgets/qscrollarea.cpp \
widgets/qwidgetanimator.cpp \
- widgets/qwidgettextcontrol.cpp \
widgets/qwidgetlinecontrol.cpp \
widgets/qtoolbararealayout.cpp \
widgets/qplaintextedit.cpp
+qtConfig(abstractbutton) {
+ HEADERS += \
+ widgets/qabstractbutton.h \
+ widgets/qabstractbutton_p.h
+
+ SOURCES += \
+ widgets/qabstractbutton.cpp
+}
+
+qtConfig(abstractslider) {
+ HEADERS += \
+ widgets/qabstractslider.h \
+ widgets/qabstractslider_p.h
+
+ SOURCES += \
+ widgets/qabstractslider.cpp
+}
+
+qtConfig(checkbox) {
+ HEADERS += \
+ widgets/qcheckbox.h
+
+ SOURCES += \
+ widgets/qcheckbox.cpp
+}
+
+qtConfig(commandlinkbutton) {
+ HEADERS += \
+ widgets/qcommandlinkbutton.h
+
+ SOURCES += \
+ widgets/qcommandlinkbutton.cpp
+}
+
+qtConfig(label) {
+ HEADERS += \
+ widgets/qlabel.h \
+ widgets/qlabel_p.h
+
+ SOURCES += \
+ widgets/qlabel.cpp
+}
+
+
+qtConfig(pushbutton) {
+ HEADERS += \
+ widgets/qpushbutton.h \
+ widgets/qpushbutton_p.h
+
+ SOURCES += \
+ widgets/qpushbutton.cpp
+}
+
+qtConfig(radiobutton) {
+ HEADERS += \
+ widgets/qradiobutton.h
+
+ SOURCES += \
+ widgets/qradiobutton.cpp
+}
+
+qtConfig(dialogbuttonbox) {
+ HEADERS += \
+ widgets/qdialogbuttonbox.h
+
+ SOURCES += \
+ widgets/qdialogbuttonbox.cpp
+}
+
+qtConfig(widgettextcontrol) {
+ HEADERS += \
+ widgets/qwidgettextcontrol_p.h \
+ widgets/qwidgettextcontrol_p_p.h
+
+ SOURCES += \
+ widgets/qwidgettextcontrol.cpp
+}
+
macx {
HEADERS += \
widgets/qmacnativewidget_mac.h \
diff --git a/src/winmain/qtmain_winrt.cpp b/src/winmain/qtmain_winrt.cpp
index b0e70608f9..13ca561d35 100644
--- a/src/winmain/qtmain_winrt.cpp
+++ b/src/winmain/qtmain_winrt.cpp
@@ -59,19 +59,7 @@
entry point within the newly created GUI thread.
*/
-#if _MSC_VER < 1900
-#include <new.h>
-
-typedef struct
-{
- int newmode;
-} _startupinfo;
-#endif // _MSC_VER < 1900
-
extern "C" {
-#if _MSC_VER < 1900
- int __getmainargs(int *argc, char ***argv, char ***env, int expandWildcards, _startupinfo *info);
-#endif
int main(int, char **);
}
@@ -102,7 +90,6 @@ typedef ITypedEventHandler<CoreApplicationView *, Activation::IActivatedEventArg
static QtMessageHandler defaultMessageHandler;
static void devMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
{
-#ifndef Q_OS_WINPHONE
static HANDLE shmem = 0;
static HANDLE event = 0;
if (!shmem)
@@ -121,7 +108,6 @@ static void devMessageHandler(QtMsgType type, const QMessageLogContext &context,
message.data(), (message.length() + 1) * sizeof(wchar_t));
UnmapViewOfFile(data);
SetEvent(event);
-#endif // !Q_OS_WINPHONE
defaultMessageHandler(type, context, message);
}
@@ -216,7 +202,6 @@ private:
// Check whether the app already runs
if (!app) {
-#if _MSC_VER >= 1900
// I*EventArgs have no launch arguments, hence we
// need to prepend the application binary manually
wchar_t fn[513];
@@ -224,7 +209,6 @@ private:
if (SUCCEEDED(res))
args.prepend(QString::fromWCharArray(fn, res).toUtf8().data());
-#endif _MSC_VER >= 1900
ResumeThread(mainThread);
@@ -252,7 +236,6 @@ private:
HRESULT __stdcall OnLaunched(ILaunchActivatedEventArgs *launchArgs) Q_DECL_OVERRIDE
{
-#if _MSC_VER >= 1900
ComPtr<IPrelaunchActivatedEventArgs> preArgs;
HRESULT hr = launchArgs->QueryInterface(preArgs.GetAddressOf());
if (SUCCEEDED(hr)) {
@@ -263,7 +246,7 @@ private:
}
commandLine = QString::fromWCharArray(GetCommandLine()).toUtf8();
-#endif
+
HString launchCommandLine;
launchArgs->get_Arguments(launchCommandLine.GetAddressOf());
if (launchCommandLine.IsValid()) {
@@ -329,9 +312,7 @@ private:
pidFile = CreateFile2(reinterpret_cast<LPCWSTR>(pidFileName.utf16()),
GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, &params);
// Install the develMode message handler
-#ifndef Q_OS_WINPHONE
defaultMessageHandler = qInstallMessageHandler(devMessageHandler);
-#endif
}
// Wait for debugger before continuing
if (debugWait) {
@@ -396,11 +377,6 @@ int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
int argc = 0;
char **argv = 0, **env = 0;
-#if _MSC_VER < 1900
- _startupinfo info = { _query_new_mode() };
- if (int init = __getmainargs(&argc, &argv, &env, false, &info))
- return init;
-#endif // _MSC_VER >= 1900
for (int i = 0; env && env[i]; ++i) {
QByteArray var(env[i]);
int split = var.indexOf('=');
diff --git a/src/xml/dom/qdom.cpp b/src/xml/dom/qdom.cpp
index dd9bb4f875..9affd697a0 100644
--- a/src/xml/dom/qdom.cpp
+++ b/src/xml/dom/qdom.cpp
@@ -6442,7 +6442,7 @@ void QDomDocumentPrivate::saveDocument(QTextStream& s, const int indent, QDomNod
if (enc.isEmpty())
enc = encoding.cap(5);
if (!enc.isEmpty())
- codec = QTextCodec::codecForName(enc.toLatin1().data());
+ codec = QTextCodec::codecForName(std::move(enc).toLatin1());
}
if (!codec)
codec = QTextCodec::codecForName("UTF-8");
diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp
index 1724076b84..bc7d00483a 100644
--- a/src/xml/sax/qxml.cpp
+++ b/src/xml/sax/qxml.cpp
@@ -1407,7 +1407,7 @@ QString QXmlInputSource::fromRawData(const QByteArray &data, bool beginning)
QString encoding = extractEncodingDecl(d->encodingDeclChars, &needMoreText);
if (!encoding.isEmpty()) {
- if (QTextCodec *codec = QTextCodec::codecForName(encoding.toLatin1())) {
+ if (QTextCodec *codec = QTextCodec::codecForName(std::move(encoding).toLatin1())) {
/* If the encoding is the same, we don't have to do toUnicode() all over again. */
if(codec->mibEnum() != mib) {
delete d->encMapper;
diff --git a/src/xml/sax/qxml.h b/src/xml/sax/qxml.h
index 49c8184d4b..77a5a78650 100644
--- a/src/xml/sax/qxml.h
+++ b/src/xml/sax/qxml.h
@@ -156,11 +156,13 @@ private:
struct Attribute {
QString qname, uri, localname, value;
};
+ friend class QTypeInfo<Attribute>;
typedef QList<Attribute> AttributeList;
AttributeList attList;
QXmlAttributesPrivate *d;
};
+Q_DECLARE_TYPEINFO(QXmlAttributes::Attribute, Q_MOVABLE_TYPE);
Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QXmlAttributes)
//
diff --git a/src/xml/sax/qxml_p.h b/src/xml/sax/qxml_p.h
index 5f3785a289..98dc2aea0c 100644
--- a/src/xml/sax/qxml_p.h
+++ b/src/xml/sax/qxml_p.h
@@ -85,6 +85,8 @@ private:
Q_DUMMY_COMPARISON_OPERATOR(ExternParameterEntity)
};
+ friend class QTypeInfo<ExternParameterEntity>;
+
struct ExternEntity
{
ExternEntity() {}
@@ -95,6 +97,8 @@ private:
QString notation;
Q_DUMMY_COMPARISON_OPERATOR(ExternEntity)
};
+ friend class QTypeInfo<ExternEntity>;
+
QMap<QString,ExternParameterEntity> externParameterEntities;
QMap<QString,QString> parameterEntities;
QMap<QString,ExternEntity> externEntities;
@@ -306,6 +310,8 @@ private:
};
Q_DECLARE_TYPEINFO(QXmlSimpleReaderPrivate::ParseState, Q_PRIMITIVE_TYPE);
Q_DECLARE_TYPEINFO(QXmlSimpleReaderPrivate::XmlRef, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QXmlSimpleReaderPrivate::ExternParameterEntity, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QXmlSimpleReaderPrivate::ExternEntity, Q_MOVABLE_TYPE);
QT_END_NAMESPACE